Files
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

481 lines
17 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING, List, Literal, NamedTuple, Optional, Union
import torch
import torch.nn as nn
from sglang.jit_kernel.dsv4 import linear_bf16_fp32, triton_create_paged_compress_data
from sglang.jit_kernel.dsv4.compress_old import (
CompressorDecodePlan,
CompressorPrefillPlan,
compress_forward,
compress_fused_norm_rope_inplace,
)
from sglang.srt.configs.deepseek_v4 import DeepSeekV4Config
from sglang.srt.environ import envs
from sglang.srt.layers.attention.dsa.triton_kernel import act_quant
from sglang.srt.layers.attention.dsa.utils import dsa_use_prefill_cp
from sglang.srt.layers.attention.dsv4.quant_k_cache import (
quant_to_nope_fp8_rope_bf16_pack_triton,
)
from sglang.srt.layers.layernorm import RMSNorm
from sglang.srt.layers.linear import ReplicatedLinear
from sglang.srt.layers.utils.cp_utils import cp_all_gather_rerange_output
from sglang.srt.layers.utils.multi_platform import MultiPlatformOp
from sglang.srt.mem_cache.deepseek_v4_compress_state import (
CompressStatePool,
)
from sglang.srt.mem_cache.deepseek_v4_memory_pool import DeepSeekV4TokenToKVPool
from sglang.srt.model_executor.forward_context import get_attn_backend
from sglang.srt.models.deepseek_v2 import _is_hip
from sglang.srt.runtime_context import get_parallel
from sglang.srt.utils import add_prefix, is_npu, set_weight_attrs
_is_npu = is_npu()
if TYPE_CHECKING:
from sglang.srt.layers.attention.base_attn_backend import AttentionBackend
from sglang.srt.layers.attention.deepseek_v4_backend import DeepseekV4AttnBackend
from sglang.srt.layers.rotary_embedding import RotaryEmbedding
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
class FusedCompressMetadata(NamedTuple):
write_loc: torch.Tensor
extra_data: Optional[torch.Tensor]
plan: Union[CompressorDecodePlan, CompressorPrefillPlan]
def copy_(self, other: FusedCompressMetadata) -> None:
from .metadata import maybe_copy_inplace
self.write_loc.copy_(other.write_loc)
maybe_copy_inplace(self.extra_data, src=other.extra_data)
self.plan.copy_(other.plan)
class CompressorBackendMixin:
def get_paged_compress_metadata(self, compress_ratio: int) -> FusedCompressMetadata:
attr_name = f"c{compress_ratio}_compress_metadata"
metadata = getattr(self.forward_metadata, attr_name)
assert isinstance(metadata, FusedCompressMetadata)
return metadata
def forward_compress(
self,
*,
kv_score_buffer: torch.Tensor,
kv_score_input: torch.Tensor,
ape: torch.Tensor,
head_dim: int,
norm: RMSNorm,
freqs_cis_cache: torch.Tensor,
rotate: bool,
forward_batch: ForwardBatch,
compress_ratio: int,
is_paged: bool = False,
) -> torch.Tensor:
from sglang.srt.layers.attention.dsa.dsa_indexer import rotate_activation
assert compress_ratio in (
4,
128,
), f"DSV4 supports CSA(4x) and HCA(128x) only, got {compress_ratio=}"
if is_paged:
metadata = self.get_paged_compress_metadata(compress_ratio)
coff = 2 if is_overlap_compress(compress_ratio) else 1
if compress_ratio == 128 and envs.SGLANG_OPT_USE_ONLINE_COMPRESS.get():
kv_score_buffer = kv_score_buffer.view(-1, 1, head_dim * 3)
else:
last_dim = 2 * head_dim * coff
assert kv_score_buffer.shape[-1] == last_dim
kv_score_buffer = kv_score_buffer.view(-1, compress_ratio, last_dim)
else:
plan = make_compressor_plan(compress_ratio, forward_batch)
metadata = (forward_batch.req_pool_indices.to(torch.int32), None, plan)
indices, extra_data, plan = metadata
if _is_hip:
if not is_paged:
raise NotImplementedError("HIP fused compressor expects paged metadata")
from sglang.srt.layers.attention.dsv4.fused_compress_triton import (
hip_compress_forward,
hip_compress_fused_norm_rope_hadamard_inplace,
hip_compress_fused_norm_rope_inplace,
)
kv_compressed = hip_compress_forward(
kv_score_buffer=kv_score_buffer,
kv_score_input=kv_score_input,
ape=ape,
indices=indices,
plan=plan,
compress_ratio=compress_ratio,
head_dim=head_dim,
extra_data=extra_data,
)
norm_eps = (
norm.variance_epsilon if hasattr(norm, "variance_epsilon") else norm.eps
)
if rotate:
hip_compress_fused_norm_rope_hadamard_inplace(
kv_compressed,
norm.weight,
norm_eps,
freqs_cis_cache,
plan,
head_dim,
)
else:
hip_compress_fused_norm_rope_inplace(
kv_compressed,
norm.weight,
norm_eps,
freqs_cis_cache,
plan,
)
return kv_compressed
kv_compressed = compress_forward(
kv_score_buffer=kv_score_buffer,
kv_score_input=kv_score_input,
ape=ape,
indices=indices,
plan=plan,
compress_ratio=compress_ratio,
head_dim=head_dim,
extra_data=extra_data,
)
compress_fused_norm_rope_inplace(
kv_compressed,
norm.weight,
norm.variance_epsilon,
freqs_cis_cache,
plan,
)
return rotate_activation(kv_compressed) if rotate else kv_compressed
def forward_core_compressor(
self,
x: torch.Tensor,
forward_batch: ForwardBatch,
layer_id: int,
compressor: Compressor,
) -> None:
if forward_batch.forward_mode.is_idle():
return
token_to_kv_pool = self.token_to_kv_pool
if TYPE_CHECKING:
assert isinstance(token_to_kv_pool, DeepSeekV4TokenToKVPool)
new_compressed_kv = compressor(x, forward_batch, attn_backend=self)
core_metadata = self.forward_metadata.core_metadata
out_loc = (
core_metadata.c4_out_loc
if compressor.ratio == 4
else core_metadata.c128_out_loc
)
if out_loc.shape[0] > new_compressed_kv.shape[0]:
out_loc = out_loc[: new_compressed_kv.shape[0]]
if envs.SGLANG_OPT_USE_FUSED_STORE_CACHE.get():
token_to_kv_pool.set_extra_key_buffer_fused(
layer_id=layer_id,
loc=out_loc,
cache_k=new_compressed_kv,
)
else:
pack = quant_to_nope_fp8_rope_bf16_pack_triton(new_compressed_kv.bfloat16())
token_to_kv_pool.set_extra_key_buffer(layer_id, out_loc, pack)
def forward_indexer_compressor(
self,
x: torch.Tensor,
forward_batch: ForwardBatch,
layer_id: int,
compressor: Compressor,
) -> None:
assert is_overlap_compress(compressor.ratio)
token_to_kv_pool = self.token_to_kv_pool
if TYPE_CHECKING:
assert isinstance(token_to_kv_pool, DeepSeekV4TokenToKVPool)
new_compressed_kv = compressor(x, forward_batch, attn_backend=self)
out_loc = self.forward_metadata.core_metadata.c4_out_loc
if out_loc.shape[0] > new_compressed_kv.shape[0]:
out_loc = out_loc[: new_compressed_kv.shape[0]]
if self.enable_deepseek_v4_fp4_indexer:
token_to_kv_pool.set_index_k_fp4(
layer_id=layer_id,
loc=out_loc,
cache_k=new_compressed_kv,
)
elif envs.SGLANG_OPT_USE_FUSED_STORE_CACHE.get():
token_to_kv_pool.set_index_k_fused(
layer_id=layer_id,
loc=out_loc,
cache_k=new_compressed_kv,
)
else:
new_compressed_kv_fp8, new_compressed_kv_scale = act_quant(
new_compressed_kv
)
token_to_kv_pool.set_index_k_scale_buffer(
layer_id=layer_id,
loc=out_loc,
index_k=new_compressed_kv_fp8,
index_k_scale=new_compressed_kv_scale,
)
def is_overlap_compress(compress_ratio: int) -> bool:
return compress_ratio == 4
def make_compressor_plan(
compress_ratio: Literal[4, 128],
forward_batch: ForwardBatch,
) -> Union[CompressorDecodePlan, CompressorPrefillPlan]:
if forward_batch.forward_mode.is_decode():
seq_lens_32 = forward_batch.seq_lens.to(torch.int32)
return CompressorDecodePlan(compress_ratio, seq_lens_32)
if forward_batch.forward_mode.is_prefill():
assert not forward_batch.forward_mode.is_target_verify()
extend_lens_list = forward_batch.extend_seq_lens_cpu
seq_lens_cpu = forward_batch.seq_lens_cpu
assert extend_lens_list is not None and seq_lens_cpu is not None
return CompressorPrefillPlan.generate(
compress_ratio=compress_ratio,
num_q_tokens=sum(extend_lens_list),
seq_lens=seq_lens_cpu,
extend_lens=torch.tensor(extend_lens_list),
device=forward_batch.seq_lens.device,
)
elif forward_batch.forward_mode.is_target_verify():
raise NotImplementedError("target verify mode to be implemented")
else:
raise NotImplementedError(f"unsupported mode {forward_batch.forward_mode=}")
def create_paged_compressor_data(
compress_ratio: Literal[4, 128],
*,
is_prefill: bool,
token_to_kv_pool: DeepSeekV4TokenToKVPool,
req_to_token: torch.Tensor,
req_pool_indices: torch.Tensor,
seq_lens: torch.Tensor,
extend_lens: Optional[torch.Tensor] = None,
seq_lens_cpu: Optional[List[int]] = None,
extend_lens_cpu: Optional[List[int]] = None,
use_prefill_cuda_graph: bool = False,
num_q_tokens: Optional[int] = None,
) -> FusedCompressMetadata:
swa_page_size = token_to_kv_pool.swa_page_size
ring_size = token_to_kv_pool.get_ring_size(compress_ratio=compress_ratio)
# assert ring_size % compress_ratio == 0
def clip_down(positions: torch.Tensor) -> torch.Tensor:
return positions // compress_ratio * compress_ratio
def get_raw_loc(positions: torch.Tensor) -> torch.Tensor:
positions = positions.masked_fill(positions < 0, 0)
if compress_ratio == 128:
state_loc = req_pool_indices * ring_size + positions % ring_size
else:
loc = req_to_token[req_pool_indices, positions]
swa_loc = token_to_kv_pool.translate_loc_from_full_to_swa(loc)
swa_pages = swa_loc // swa_page_size
state_loc = swa_pages * ring_size + swa_loc % ring_size
return (state_loc // compress_ratio).to(torch.int32)
is_overlap = is_overlap_compress(compress_ratio)
if is_prefill:
assert extend_lens is not None
write_loc, extra_data = triton_create_paged_compress_data(
compress_ratio=compress_ratio,
is_overlap=is_overlap,
swa_page_size=swa_page_size,
ring_size=ring_size,
req_pool_indices=req_pool_indices,
seq_lens=seq_lens,
extend_seq_lens=extend_lens,
req_to_token=req_to_token,
full_to_swa_index_mapping=token_to_kv_pool.full_to_swa_index_mapping,
)
plan_kwargs: dict
if seq_lens_cpu is None:
assert num_q_tokens is not None
plan_kwargs = dict(
num_q_tokens=num_q_tokens,
seq_lens=seq_lens,
extend_lens=extend_lens,
)
else:
assert extend_lens_cpu is not None
plan_kwargs = dict(
num_q_tokens=sum(extend_lens_cpu),
seq_lens=torch.tensor(seq_lens_cpu),
extend_lens=torch.tensor(extend_lens_cpu),
)
plan = CompressorPrefillPlan.generate(
compress_ratio=compress_ratio,
device=seq_lens.device,
use_cuda_graph=use_prefill_cuda_graph,
**plan_kwargs,
)
else:
write_positions = clip_down(seq_lens - 1)
write_loc = get_raw_loc(write_positions)
if is_overlap:
write_overlap_loc = get_raw_loc(write_positions - compress_ratio)
extra_data = write_overlap_loc.view(-1, 1)
elif _is_hip:
extra_data = get_raw_loc(write_positions - compress_ratio)
else:
extra_data = None
plan = CompressorDecodePlan(compress_ratio, seq_lens.to(torch.int32))
return FusedCompressMetadata(write_loc=write_loc, extra_data=extra_data, plan=plan)
class Compressor(MultiPlatformOp):
def __init__(
self,
config: DeepSeekV4Config,
layer_id: int,
is_in_indexer: bool,
freqs_cis: torch.Tensor,
compress_ratio: Literal[0, 4, 128],
head_dim: int,
rotate: bool = False,
prefix: str = "",
rotary_emb: Optional[RotaryEmbedding] = None,
) -> None:
super().__init__()
self.layer_id = layer_id
self.is_in_indexer = is_in_indexer
self.dim = config.hidden_size
self.head_dim = head_dim
self.rope_head_dim = getattr(config, "qk_rope_head_dim", 64)
assert compress_ratio != 0, "compress_ratio should not be 0"
self.ratio = compress_ratio
self.overlap = self.ratio == 4
self.rotate = rotate
self.coff = coff = 1 + self.overlap
self.ape = nn.Parameter(
torch.empty(self.ratio, coff * self.head_dim, dtype=torch.float32)
)
set_weight_attrs(self.ape, {"weight_loader": self.load_ape_weight})
wkv_gate_dtype = torch.bfloat16
self.wkv_gate = ReplicatedLinear(
self.dim,
2 * coff * self.head_dim,
bias=False,
quant_config=None,
prefix=add_prefix("wkv_gate", prefix),
params_dtype=wkv_gate_dtype,
)
self.norm = RMSNorm(
self.head_dim, eps=config.rms_norm_eps, weight_dtype=torch.float32
)
self.rotary_emb = rotary_emb
self.freqs_cis = freqs_cis
self.ape_converted = False
def _apply_ape_hotfix(self):
self.ape_converted = True
if _is_npu:
return
if self.overlap:
ape = torch.chunk(self.ape.data, 2, dim=-1)
ape = torch.cat([ape[0], ape[1]], dim=0)
self.ape.data.copy_(ape.view(self.ratio, -1))
def apply_ape_hotfix(self):
assert not self.ape_converted
self._apply_ape_hotfix()
def load_ape_weight(self, param: torch.Tensor, loaded_weight: torch.Tensor) -> None:
assert param is self.ape
assert loaded_weight.shape == param.shape
param.data.copy_(loaded_weight)
self._apply_ape_hotfix()
def get_state_pool(self, attn_backend: AttentionBackend) -> CompressStatePool:
token_to_kv_pool = attn_backend.token_to_kv_pool
assert isinstance(token_to_kv_pool, DeepSeekV4TokenToKVPool)
if self.is_in_indexer:
ret = token_to_kv_pool.get_indexer_compress_states(self.layer_id)
else:
ret = token_to_kv_pool.get_attention_compress_states(self.layer_id)
assert isinstance(ret, CompressStatePool)
return ret
def compute_kv_score(self, x: torch.Tensor, forward_batch: ForwardBatch):
kv_score = linear_bf16_fp32(x, self.wkv_gate.weight)
# CUDA path: delegate to backend
if dsa_use_prefill_cp(forward_batch):
kv_score = cp_all_gather_rerange_output(
kv_score,
get_parallel().attn_cp_size,
forward_batch,
torch.cuda.current_stream(),
)
return kv_score
def forward_native(
self,
x: torch.Tensor,
forward_batch: ForwardBatch,
attn_backend: Optional[AttentionBackend] = None,
) -> torch.Tensor:
if forward_batch.forward_mode.is_idle():
assert x.shape[0] == 0
return x.new_empty(0, self.head_dim)
kv_score = self.compute_kv_score(x, forward_batch)
if TYPE_CHECKING:
assert isinstance(attn_backend, DeepseekV4AttnBackend)
kv_score_buffer = self.get_state_pool(attn_backend).kv_score_buffer.kv_score
return attn_backend.forward_compress(
kv_score_buffer=kv_score_buffer,
kv_score_input=kv_score,
ape=self.ape.view(-1, self.head_dim),
head_dim=self.head_dim,
norm=self.norm,
freqs_cis_cache=self.freqs_cis,
rotate=self.rotate,
compress_ratio=self.ratio,
forward_batch=forward_batch,
is_paged=True,
)
def forward_npu(
self,
x: torch.Tensor,
forward_batch: ForwardBatch,
attn_backend: Optional[AttentionBackend] = None,
) -> torch.Tensor:
if forward_batch.forward_mode.is_idle():
assert x.shape[0] == 0
return x.new_empty(0, self.head_dim)
if dsa_use_prefill_cp(forward_batch):
x = cp_all_gather_rerange_output(
x,
get_parallel().attn_cp_size,
forward_batch,
torch.cuda.current_stream(),
)
return get_attn_backend().forward_compress(self, x, forward_batch)