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

603 lines
22 KiB
Python

from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Optional
import torch
from sglang.srt.configs.model_config import (
get_minimax_sparse_attention_config,
get_minimax_sparse_disable_value_layer_ids,
get_minimax_sparse_layer_ids,
get_minimax_sparse_score_type,
)
from sglang.srt.layers.attention.base_attn_backend import AttentionBackend
from sglang.srt.layers.attention.minimax_sparse_ops.minimax_sparse import (
minimax_sparse_decode,
minimax_sparse_prefill,
)
from sglang.srt.mem_cache.memory_pool import MiniMaxSparseKVPool
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
if TYPE_CHECKING:
from sglang.srt.model_executor.model_runner import ModelRunner
logger = logging.getLogger(__name__)
class MiniMaxSparseAttnBackend(AttentionBackend):
def __init__(self, runner: ModelRunner):
assert isinstance(runner.token_to_kv_pool, MiniMaxSparseKVPool)
self.kv_pool = runner.token_to_kv_pool
self.req_to_token = runner.req_to_token_pool.req_to_token
self.max_context_len = int(runner.model_config.context_len)
hf_config = runner.model_config.hf_config
sparse_cfg = get_minimax_sparse_attention_config(hf_config)
self.idx_head_dim = sparse_cfg["sparse_index_dim"]
self.dense_layer_ids, self.sparse_layer_ids = get_minimax_sparse_layer_ids(
sparse_cfg
)
self.disable_value_layer_ids: set[int] = set(
get_minimax_sparse_disable_value_layer_ids(sparse_cfg)
)
self.score_type: str = get_minimax_sparse_score_type(sparse_cfg)
# Plain Python int so it is safe inside CUDA graphs (no .item() at graph time).
self._max_seqlen_q: int = 1
self._max_seqlen_k: int = 1
self.block_size_q = 1
self.block_size_k = sparse_cfg["sparse_block_size"]
if "sparse_init_block" in sparse_cfg:
self.init_blocks = sparse_cfg["sparse_init_block"]
else:
init_tokens = sparse_cfg["sparse_init_tokens"]
self.init_blocks = (
init_tokens + self.block_size_k - 1
) // self.block_size_k
if "sparse_local_block" in sparse_cfg:
self.local_blocks = sparse_cfg["sparse_local_block"]
else:
local_tokens = sparse_cfg["sparse_local_tokens"]
self.local_blocks = (
local_tokens + self.block_size_k - 1
) // self.block_size_k + 1
self.topk_blocks = sparse_cfg["sparse_topk_blocks"]
# MSA (fmha_sm100) is SM100-only; fall back to the Triton sparse path when
# the kernel is unavailable or its constraints don't hold.
from sglang.srt.environ import envs
from sglang.srt.layers.attention.minimax_sparse_ops.msa import (
msa_available,
)
# MSA (fmha_sm100) is bf16/fp16-only; an fp8 main KV cache must stay on the
# Triton sparse path (it dequants fp8 on load).
_main_kv_is_fp8 = self.kv_pool.main_pool.dtype in (
torch.float8_e4m3fn,
torch.float8_e5m2,
)
self.use_msa = (
not envs.SGLANG_DISABLE_MSA.get()
and msa_available()
and self.block_size_k == 128
and self.kv_pool.page_size == self.block_size_k
and self.topk_blocks in (4, 8, 16, 32)
and not _main_kv_is_fp8
)
if (
not self.use_msa
and not envs.SGLANG_DISABLE_MSA.get()
and msa_available()
and self.block_size_k == 128
and self.kv_pool.page_size != self.block_size_k
):
logger.warning(
"MiniMax-M3 MSA decode disabled: page_size=%d != sparse block size "
"%d. Pass --page-size 128 (with an attention backend that allows it, "
"e.g. fa4) to enable the faster MSA kernel; falling back to the "
"Triton sparse path.",
self.kv_pool.page_size,
self.block_size_k,
)
self._msa_dec_meta = None
if self.use_msa:
from sglang.srt.runtime_context import get_parallel
self.num_q_heads = (
runner.model_config.num_attention_heads // get_parallel().attn_tp_size
)
self.num_kv_heads = self.kv_pool.main_pool.head_num
self._msa_nb_max = (
self.max_context_len + self.block_size_k - 1
) // self.block_size_k
self._msa_cg: dict[int, tuple] = {}
self.page_size = self.kv_pool.page_size
self.use_dense_sparse_decode = (
envs.SGLANG_OPT_USE_MINIMAX_DENSE_SPARSE_DECODE.get()
and self.block_size_k % self.page_size == 0
)
# MSA fmha_sm100 decode is NOT cuda-graph-safe: captured/replayed it returns
# wrong results (~14% GSM8K loss on B200). Gate capture via cuda_graph_config,
# not legacy disable_* flags — they disagree under config-native flags and would
# capture the unsafe MSA decode kernel.
from sglang.srt.model_executor.cuda_graph_config import (
Backend,
Phase,
check_cuda_graph_backend,
)
_sa = getattr(runner, "server_args", None)
_decode_cuda_graph = not check_cuda_graph_backend(
Phase.DECODE, Backend.DISABLED
)
self._use_msa_decode = self.use_msa and (
not _decode_cuda_graph or envs.SGLANG_OPT_USE_MSA_DECODE_UNDER_GRAPH.get()
)
# MSA + spec decode + cuda graph crashes mid-capture: TARGET_VERIFY batches
# route to forward_extend, dereferencing absent extend metadata. Fail at startup.
if (
self.use_msa
and _decode_cuda_graph
and getattr(_sa, "speculative_algorithm", None) is not None
):
raise NotImplementedError(
"MiniMax-M3 MSA attention does not support speculative decoding under "
"CUDA graph. Use --disable-cuda-graph, set SGLANG_DISABLE_MSA=1, or "
"disable speculative decoding."
)
self._msa_owns_decode = self._use_msa_decode and not (
self.use_dense_sparse_decode and self.kv_pool.main_pool.head_num == 1
)
self.dense_backend: Optional[AttentionBackend] = None
logger.info(
f"[MiniMaxSparse] Backend initialized "
f"(score_type={self.score_type!r}, "
f"main_attn={'MSA' if self.use_msa else 'triton'}, "
f"disable_value_layers={sorted(self.disable_value_layer_ids)})"
)
def init_forward_metadata_out_graph(
self, forward_batch: ForwardBatch, in_capture: bool = False
):
# cuda-graph replay views are a SimpleNamespace without extend_seq_lens_cpu,
# and TARGET_VERIFY sets it to None despite is_extend() — getattr covers both.
self._msa_dec_meta = None
extend_lens = getattr(forward_batch, "extend_seq_lens_cpu", None)
if extend_lens is not None:
self._max_seqlen_q = int(max(extend_lens))
else:
self._max_seqlen_q = 1
if in_capture and forward_batch.forward_mode.is_decode_or_idle():
self._max_seqlen_k = self.max_context_len
else:
self._max_seqlen_k = int(forward_batch.seq_lens_cpu.max().item())
# Build plan + page table eager (outside capture) so captured forward_decode
# runs only device-side ops; host-side code can't be captured.
if self._msa_owns_decode and forward_batch.forward_mode.is_decode_or_idle():
self._prepare_msa_decode_meta(forward_batch)
def _prepare_msa_decode_meta(self, forward_batch: ForwardBatch):
from sglang.srt.layers.attention.minimax_sparse_ops.msa import (
build_msa_decode_cg_plan,
update_msa_decode_cg_meta,
)
bs = forward_batch.seq_lens.shape[0]
if bs == 0:
return
entry = self._msa_cg.get(bs)
if entry is None:
device = forward_batch.seq_lens.device
plan = build_msa_decode_cg_plan(
self.num_q_heads,
self.num_kv_heads,
self.block_size_k,
self.topk_blocks,
bs,
device=device,
)
kv_indices_buf = torch.zeros(
bs * self._msa_nb_max, dtype=torch.int32, device=device
)
entry = (plan, kv_indices_buf)
self._msa_cg[bs] = entry
plan, kv_indices_buf = entry
update_msa_decode_cg_meta(
plan,
kv_indices_buf,
self.req_to_token,
forward_batch.req_pool_indices,
forward_batch.seq_lens,
self.block_size_k,
self.topk_blocks,
self.num_q_heads,
self.num_kv_heads,
)
self._msa_dec_meta = (kv_indices_buf, plan)
def init_forward_metadata_in_graph(self, forward_batch: ForwardBatch):
pass
def init_cuda_graph_state(self, max_bs: int, max_num_tokens: int):
pass
def get_cuda_graph_seq_len_fill_value(self):
return 1
@staticmethod
def _is_sparse_kv_cached_by_fusion(
forward_batch: ForwardBatch, layer_id: int
) -> bool:
layer_ids = forward_batch.minimax_m3_precached_sparse_layers
return layer_ids is not None and layer_id in layer_ids
def forward(
self,
q,
k,
v,
layer,
forward_batch: ForwardBatch,
save_kv_cache: bool = True,
**kwargs,
):
if forward_batch.forward_mode.is_idle():
idx_q = kwargs.get("idx_q")
num_idx_heads = idx_q.shape[1]
disable_value = layer.layer_id in self.disable_value_layer_ids
idx_out: Optional[torch.Tensor] = (
None
if disable_value
else q.new_zeros(q.shape[0], num_idx_heads * self.idx_head_dim)
)
out = q.new_zeros(q.shape[0], layer.tp_q_head_num * layer.v_head_dim)
return idx_out, out
else:
return super().forward(
q, k, v, layer, forward_batch, save_kv_cache, **kwargs
)
def forward_extend(
self,
q: torch.Tensor,
k: torch.Tensor,
v: torch.Tensor,
layer,
forward_batch: ForwardBatch,
save_kv_cache=True,
*,
idx_q: torch.Tensor,
idx_k: torch.Tensor,
idx_v: Optional[torch.Tensor],
):
disable_value = layer.layer_id in self.disable_value_layer_ids
kv_cached_by_fusion = self._is_sparse_kv_cached_by_fusion(
forward_batch, layer.layer_id
)
if not kv_cached_by_fusion:
self.kv_pool.set_fused_kv_index_buffer(
layer,
forward_batch.out_cache_loc,
k,
v,
idx_k,
None if disable_value else idx_v,
)
k_cache, v_cache = self.kv_pool.get_kv_buffer(layer.layer_id)
if disable_value:
idx_k_cache = self.kv_pool.get_index_k_buffer(layer.layer_id)
idx_v_cache = None
else:
idx_k_cache, idx_v_cache = self.kv_pool.get_index_kv_buffer(layer.layer_id)
cu_seqlens = torch.cat(
[
torch.zeros(
1, dtype=torch.int32, device=forward_batch.extend_seq_lens.device
),
forward_batch.extend_seq_lens.to(torch.int32).cumsum(0).to(torch.int32),
]
)
seq_lens = forward_batch.seq_lens.to(torch.int32)
if forward_batch.extend_prefix_lens is not None:
prefix_lens = forward_batch.extend_prefix_lens.to(torch.int32)
else:
prefix_lens = torch.zeros_like(seq_lens)
# DP attention pads q beyond the real token count for collective alignment;
# trim to actual tokens so the sparse kernel sees consistent shapes.
if forward_batch.extend_seq_lens_cpu is not None:
actual_num_tokens = int(sum(forward_batch.extend_seq_lens_cpu))
else:
actual_num_tokens = int(cu_seqlens[-1].item())
original_num_tokens = q.shape[0]
if actual_num_tokens < original_num_tokens:
q = q[:actual_num_tokens]
idx_q = idx_q[:actual_num_tokens]
idx_o, o = minimax_sparse_prefill(
q,
k_cache,
v_cache,
None,
idx_q,
idx_k_cache,
idx_v_cache,
None,
self.req_to_token,
forward_batch.req_pool_indices,
cu_seqlens,
seq_lens,
prefix_lens,
self._max_seqlen_q,
self._max_seqlen_k,
self.block_size_q,
self.block_size_k,
self.topk_blocks,
self.init_blocks,
self.local_blocks,
score_type=self.score_type,
disable_index_value=disable_value,
use_msa=self.use_msa,
seqlens_cpu=forward_batch.extend_seq_lens_cpu,
)
if actual_num_tokens < original_num_tokens:
pad_len = original_num_tokens - actual_num_tokens
o = torch.cat([o, o.new_zeros(pad_len, *o.shape[1:])], dim=0)
if idx_o is not None:
idx_o = torch.cat(
[idx_o, idx_o.new_zeros(pad_len, *idx_o.shape[1:])], dim=0
)
return (
(
None
if idx_o is None
else idx_o.reshape(original_num_tokens, -1).contiguous()
),
o.reshape(original_num_tokens, -1).contiguous(),
)
def _dense_sparse_main_decode(
self,
q: torch.Tensor,
page_table: torch.Tensor,
real_seq_lens: torch.Tensor,
k_cache: torch.Tensor,
v_cache: torch.Tensor,
layer,
forward_batch: ForwardBatch,
) -> torch.Tensor:
from sglang.srt.layers.attention.trtllm_mha_backend import TRTLLMHAAttnBackend
if isinstance(self.dense_backend, TRTLLMHAAttnBackend):
import flashinfer
ps = self.page_size
nkv = 1
head_dim = q.size(-1)
# [max_slots, nkv, D] -> [num_pages, page_size, nkv, D]
# -> [num_pages, nkv, page_size, D] (HND, trtllm default)
kc = k_cache.view(-1, ps, nkv, head_dim).permute(0, 2, 1, 3)
vc = v_cache.view(-1, ps, nkv, head_dim).permute(0, 2, 1, 3)
return flashinfer.decode.trtllm_batch_decode_with_kv_cache( # type: ignore
query=q.contiguous(),
kv_cache=(kc, vc),
workspace_buffer=self.dense_backend.workspace_buffer,
block_tables=page_table,
seq_lens=real_seq_lens,
max_seq_len=self.topk_blocks * self.block_size_k,
bmm1_scale=layer.scaling,
bmm2_scale=1.0,
)
raise NotImplementedError(
"dense sparse decode currently supports trtllm_mha only (fa3 is TODO)"
)
def forward_decode(
self,
q: torch.Tensor,
k: torch.Tensor,
v: torch.Tensor,
layer,
forward_batch: ForwardBatch,
save_kv_cache: bool = True,
*,
idx_q: torch.Tensor,
idx_k: torch.Tensor,
idx_v: Optional[torch.Tensor],
**kwargs,
):
assert len(kwargs) == 0
disable_value = layer.layer_id in self.disable_value_layer_ids
self.kv_pool.set_fused_kv_index_buffer(
layer,
forward_batch.out_cache_loc,
k,
v,
idx_k,
None if disable_value else idx_v,
)
k_cache, v_cache = self.kv_pool.get_kv_buffer(layer.layer_id)
if disable_value:
idx_k_cache = self.kv_pool.get_index_k_buffer(layer.layer_id)
idx_v_cache = None
else:
idx_k_cache, idx_v_cache = self.kv_pool.get_index_kv_buffer(layer.layer_id)
attn_fn = None
if self.use_dense_sparse_decode and k_cache.shape[1] == 1:
def attn_fn(main_q, page_table, real_seq_lens):
return self._dense_sparse_main_decode(
main_q,
page_table,
real_seq_lens,
k_cache,
v_cache,
layer,
forward_batch,
)
msa_kv_indices = msa_plan = None
if self._use_msa_decode and attn_fn is None:
if self._msa_dec_meta is not None:
msa_kv_indices, msa_plan = self._msa_dec_meta
elif q.shape[0] > 0:
# Rebuilding the plan inline would run host-side code inside
# CUDA-graph capture; fail loudly instead.
raise RuntimeError(
"MSA decode metadata missing: init_forward_metadata_out_graph "
"did not prepare the plan for this forward (gate mismatch)."
)
idx_o, o = minimax_sparse_decode(
q,
None,
k_cache,
v_cache,
idx_q,
None,
idx_k_cache,
idx_v_cache,
self.req_to_token,
forward_batch.req_pool_indices,
forward_batch.seq_lens,
self._max_seqlen_k,
1,
self.block_size_k,
self.topk_blocks,
self.init_blocks,
self.local_blocks,
score_type=self.score_type,
disable_index_value=disable_value,
dense_main_attn_fn=attn_fn,
page_size=self.page_size,
use_msa=self._use_msa_decode,
msa_kv_indices=msa_kv_indices,
msa_plan=msa_plan,
)
return (
None if idx_o is None else idx_o.reshape(q.shape[0], -1).contiguous(),
o.reshape(q.shape[0], -1).contiguous(),
)
class MiniMaxHybridAttnBackend(AttentionBackend):
def __init__(
self,
dense_backend: AttentionBackend,
sparse_backend: MiniMaxSparseAttnBackend,
sparse_layer_ids: list[int],
):
self.dense = dense_backend
self.sparse = sparse_backend
self.sparse_layer_ids = sparse_layer_ids
self.sparse.dense_backend = dense_backend
def init_forward_metadata(self, forward_batch: ForwardBatch):
self.sparse.init_forward_metadata(forward_batch)
self.dense.init_forward_metadata(forward_batch)
def init_forward_metadata_out_graph(
self, forward_batch: ForwardBatch, in_capture: bool = False
):
self.sparse.init_forward_metadata_out_graph(forward_batch, in_capture)
self.dense.init_forward_metadata_out_graph(forward_batch, in_capture)
def init_forward_metadata_in_graph(self, forward_batch: ForwardBatch):
self.sparse.init_forward_metadata_in_graph(forward_batch)
self.dense.init_forward_metadata_in_graph(forward_batch)
def init_cuda_graph_state(self, max_bs: int, max_num_tokens: int):
self.dense.init_cuda_graph_state(max_bs, max_num_tokens)
self.sparse.init_cuda_graph_state(max_bs, max_num_tokens)
def get_cuda_graph_seq_len_fill_value(self):
return self.sparse.get_cuda_graph_seq_len_fill_value()
def forward(
self,
q,
k,
v,
layer,
forward_batch: ForwardBatch,
save_kv_cache: bool = True,
**kwargs,
):
if layer.layer_id in self.sparse_layer_ids:
return self.sparse.forward(
q, k, v, layer, forward_batch, save_kv_cache, **kwargs
)
# DP attention pads q to an even length but flashinfer builds qo_indptr from
# extend_seq_lens, so padded q.shape[0] != qo_indptr[-1] and paged-prefill
# raises. Trim q and re-pad output; k/v stay untrimmed so KV-cache writes
# align with out_cache_loc.
mode = forward_batch.forward_mode
if mode.is_extend() and forward_batch.extend_seq_lens_cpu is not None:
actual_num_tokens = int(sum(forward_batch.extend_seq_lens_cpu))
original_num_tokens = q.shape[0]
if actual_num_tokens < original_num_tokens:
o = self.dense.forward(
q[:actual_num_tokens],
k,
v,
layer,
forward_batch,
save_kv_cache,
**kwargs,
)
pad_len = original_num_tokens - actual_num_tokens
return torch.cat([o, o.new_zeros(pad_len, *o.shape[1:])], dim=0)
return self.dense.forward(
q, k, v, layer, forward_batch, save_kv_cache, **kwargs
)
def forward_extend(
self,
q,
k,
v,
layer,
forward_batch: ForwardBatch,
save_kv_cache: bool = True,
**kwargs,
):
if layer.layer_id in self.sparse_layer_ids:
return self.sparse.forward_extend(
q, k, v, layer, forward_batch, save_kv_cache, **kwargs
)
else:
return self.dense.forward_extend(
q, k, v, layer, forward_batch, save_kv_cache, **kwargs
)
def forward_decode(
self,
q,
k,
v,
layer,
forward_batch: ForwardBatch,
save_kv_cache: bool = True,
**kwargs,
):
if layer.layer_id in self.sparse_layer_ids:
return self.sparse.forward_decode(
q, k, v, layer, forward_batch, save_kv_cache, **kwargs
)
else:
return self.dense.forward_decode(
q, k, v, layer, forward_batch, save_kv_cache, **kwargs
)