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
952 lines
39 KiB
Python
952 lines
39 KiB
Python
from __future__ import annotations
|
||
|
||
import threading
|
||
from typing import TYPE_CHECKING, Optional, Tuple, Union
|
||
|
||
import torch
|
||
from flash_attn_interface import flash_attn_varlen_func
|
||
from flash_attn_interface import flash_attn_with_kvcache as mate_flash_attn_with_kvcache
|
||
from flash_attn_interface import get_scheduler_metadata
|
||
|
||
from sglang.srt.distributed import get_pp_group, get_pp_indices
|
||
from sglang.srt.environ import envs
|
||
from sglang.srt.hardware_backend.musa.layers.utils.cp_utils import (
|
||
musa_cp_attn_forward_extend as cp_attn_forward_extend,
|
||
)
|
||
from sglang.srt.layers.attention.flashattention_backend import (
|
||
FlashAttentionBackend,
|
||
FlashAttentionMultiStepBackend,
|
||
merge_state_v2_wrapper,
|
||
)
|
||
from sglang.srt.layers.radix_attention import AttentionType
|
||
from sglang.srt.layers.utils.cp_utils import (
|
||
cp_allgather_and_save_kv_cache,
|
||
)
|
||
from sglang.srt.mem_cache.memory_pool import KVWriteLoc
|
||
from sglang.srt.runtime_context import get_server_args
|
||
|
||
if TYPE_CHECKING:
|
||
from sglang.srt.layers.radix_attention import RadixAttention
|
||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
||
from sglang.srt.model_executor.model_runner import ModelRunner
|
||
|
||
# Global workspace buffer for MLA
|
||
_MATE_MLA_WORKSPACE_SIZE_BYTES = 128 * 1024 * 1024
|
||
|
||
# Cache for non-MLA scheduler metadata by prefix
|
||
_MATE_NO_MLA_SCHEDULER_METADATA_DICT: dict = {}
|
||
_MATE_NO_MLA_SCHEDULER_METADATA_LOCK = threading.Lock()
|
||
|
||
# Global reference to the current backend instance (set during __init__)
|
||
_CURRENT_BACKEND: Optional[MusaFlashAttentionBackend] = None
|
||
|
||
|
||
def _compute_scheduler_metadata(
|
||
backend: MusaFlashAttentionBackend,
|
||
cu_seqlens_q: torch.Tensor,
|
||
cu_seqlens_k_new: Optional[torch.Tensor],
|
||
cache_seqlens: torch.Tensor,
|
||
max_seqlen_q: int,
|
||
page_size: int,
|
||
causal: bool,
|
||
window_size: Tuple[int, int],
|
||
num_splits: int,
|
||
) -> Tuple[torch.Tensor, bool] | torch.Tensor:
|
||
"""Compute scheduler metadata based on backend's current state."""
|
||
global _MATE_NO_MLA_SCHEDULER_METADATA_DICT
|
||
|
||
layer = backend._current_layer
|
||
current_layer_id = layer.layer_id
|
||
batch_size = cu_seqlens_q.shape[-1] - 1
|
||
|
||
# Determine if scheduler metadata should be updated
|
||
should_update = True
|
||
pp_group = get_pp_group()
|
||
pp_rank = pp_group.rank_in_group
|
||
start_layer_id, _ = get_pp_indices(
|
||
backend.num_hidden_layers, pp_group.rank_in_group, pp_group.world_size
|
||
)
|
||
if backend._current_can_run_tbo and pp_rank == 0:
|
||
start_layer_id += (
|
||
backend.first_k_dense_replace
|
||
if backend.first_k_dense_replace is not None
|
||
else 0
|
||
)
|
||
|
||
if backend.full_attention_interval is not None:
|
||
start_layer_id += backend.full_attention_interval - 1
|
||
|
||
if current_layer_id > start_layer_id:
|
||
should_update = False
|
||
|
||
if envs.SGLANG_MUSA_FA3_FORCE_UPDATE_METADATA.get():
|
||
should_update = True
|
||
|
||
if backend.use_mla:
|
||
from sglang.srt.runtime_context import get_buffer
|
||
|
||
workspace = get_buffer(
|
||
"musa_mate_mla_workspace",
|
||
lambda: torch.empty(
|
||
_MATE_MLA_WORKSPACE_SIZE_BYTES, device=backend.device, dtype=torch.uint8
|
||
),
|
||
)
|
||
return (workspace, not should_update)
|
||
else:
|
||
with _MATE_NO_MLA_SCHEDULER_METADATA_LOCK:
|
||
if (
|
||
should_update
|
||
or backend._current_prefix not in _MATE_NO_MLA_SCHEDULER_METADATA_DICT
|
||
):
|
||
_MATE_NO_MLA_SCHEDULER_METADATA_DICT[backend._current_prefix] = (
|
||
get_scheduler_metadata(
|
||
batch_size=batch_size,
|
||
num_heads_q=layer.tp_q_head_num,
|
||
num_heads_kv=layer.tp_k_head_num,
|
||
headdim=layer.qk_head_dim,
|
||
headdim_v=layer.v_head_dim,
|
||
cache_seqlens=cache_seqlens,
|
||
cu_seqlens_q=cu_seqlens_q,
|
||
cu_seqlens_k_new=cu_seqlens_k_new,
|
||
max_seqlen_q=max_seqlen_q,
|
||
max_seqlen_k=backend._current_max_seqlen_k,
|
||
page_size=page_size,
|
||
causal=causal,
|
||
window_size=window_size,
|
||
num_splits=num_splits,
|
||
)
|
||
)
|
||
return _MATE_NO_MLA_SCHEDULER_METADATA_DICT[backend._current_prefix]
|
||
|
||
|
||
def flash_attn_with_kvcache(
|
||
q: torch.Tensor,
|
||
k_cache: torch.Tensor,
|
||
v_cache: torch.Tensor,
|
||
k: Optional[torch.Tensor] = None,
|
||
v: Optional[torch.Tensor] = None,
|
||
qv: Optional[torch.Tensor] = None,
|
||
rotary_cos: Optional[torch.Tensor] = None,
|
||
rotary_sin: Optional[torch.Tensor] = None,
|
||
cache_seqlens: Optional[Union[int, torch.Tensor]] = None,
|
||
cache_batch_idx: Optional[torch.Tensor] = None,
|
||
cache_leftpad: Optional[torch.Tensor] = None,
|
||
page_table: Optional[torch.Tensor] = None,
|
||
cu_seqlens_q: Optional[torch.Tensor] = None,
|
||
cu_seqlens_k_new: Optional[torch.Tensor] = None,
|
||
max_seqlen_q: Optional[int] = None,
|
||
rotary_seqlens: Optional[torch.Tensor] = None,
|
||
q_descale: Optional[torch.Tensor] = None,
|
||
k_descale: Optional[torch.Tensor] = None,
|
||
v_descale: Optional[torch.Tensor] = None,
|
||
softmax_scale: Optional[float] = None,
|
||
causal: bool = False,
|
||
window_size: Tuple[int, int] = (-1, -1),
|
||
attention_chunk: int = 0,
|
||
softcap: float = 0.0,
|
||
rotary_interleaved: bool = True,
|
||
scheduler_metadata: Optional[torch.Tensor] = None,
|
||
num_splits: int = 0,
|
||
pack_gqa=None,
|
||
sm_margin: int = 0,
|
||
return_softmax_lse: bool = False,
|
||
sinks=None,
|
||
score_mod=None,
|
||
aux_tensors=None,
|
||
ver=3,
|
||
):
|
||
"""MUSA flash_attn_with_kvcache wrapper that auto-injects scheduler_metadata."""
|
||
if ver != 3:
|
||
raise ValueError("Only ver=3 is supported for MUSA FA3.")
|
||
|
||
if scheduler_metadata is None and _CURRENT_BACKEND is not None:
|
||
backend = _CURRENT_BACKEND
|
||
# Ensure backend has been properly set up for this call
|
||
if backend._current_layer is not None:
|
||
page_size = k_cache.shape[1] if k_cache is not None else 1
|
||
scheduler_metadata = _compute_scheduler_metadata(
|
||
backend=backend,
|
||
cu_seqlens_q=cu_seqlens_q,
|
||
cu_seqlens_k_new=cu_seqlens_k_new,
|
||
cache_seqlens=cache_seqlens,
|
||
max_seqlen_q=max_seqlen_q,
|
||
page_size=page_size,
|
||
causal=causal,
|
||
window_size=window_size,
|
||
num_splits=num_splits,
|
||
)
|
||
|
||
return mate_flash_attn_with_kvcache(
|
||
q=q,
|
||
k_cache=k_cache,
|
||
v_cache=v_cache,
|
||
k=k,
|
||
v=v,
|
||
qv=qv,
|
||
rotary_cos=rotary_cos,
|
||
rotary_sin=rotary_sin,
|
||
cache_seqlens=cache_seqlens,
|
||
cache_batch_idx=cache_batch_idx,
|
||
cache_leftpad=cache_leftpad,
|
||
page_table=page_table,
|
||
cu_seqlens_q=cu_seqlens_q,
|
||
cu_seqlens_k_new=cu_seqlens_k_new,
|
||
max_seqlen_q=max_seqlen_q,
|
||
rotary_seqlens=rotary_seqlens,
|
||
q_descale=q_descale,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
softmax_scale=softmax_scale,
|
||
causal=causal,
|
||
window_size=window_size,
|
||
attention_chunk=attention_chunk,
|
||
softcap=softcap,
|
||
rotary_interleaved=rotary_interleaved,
|
||
scheduler_metadata=scheduler_metadata,
|
||
num_splits=num_splits,
|
||
pack_gqa=pack_gqa,
|
||
sm_margin=sm_margin,
|
||
return_softmax_lse=return_softmax_lse,
|
||
sinks=sinks,
|
||
)
|
||
|
||
|
||
class MusaFlashAttentionBackend(FlashAttentionBackend):
|
||
def __init__(self, model_runner: ModelRunner, **kwargs):
|
||
super().__init__(model_runner, **kwargs)
|
||
self.num_hidden_layers = model_runner.model_config.num_hidden_layers
|
||
self.first_k_dense_replace = model_runner.model_config.first_k_dense_replace
|
||
self.full_attention_interval = model_runner.model_config.full_attention_interval
|
||
|
||
# State for current attention call (simplified from thread‑local context)
|
||
self._current_layer: Optional[RadixAttention] = None
|
||
self._current_prefix: str = ""
|
||
self._current_max_seqlen_k: int = 0
|
||
self._current_can_run_tbo: bool = False
|
||
|
||
# Disable default scheduler metadata for fa3
|
||
self._get_scheduler_metadata = None
|
||
|
||
# Register this backend as the global current instance for the wrapper
|
||
global _CURRENT_BACKEND
|
||
_CURRENT_BACKEND = self
|
||
|
||
def _set_current_state(
|
||
self, layer: RadixAttention, prefix: str, max_seqlen_k: int, can_run_tbo: bool
|
||
):
|
||
"""Set the dynamic state for the upcoming flash attention call."""
|
||
self._current_layer = layer
|
||
self._current_prefix = prefix
|
||
self._current_max_seqlen_k = max_seqlen_k
|
||
self._current_can_run_tbo = can_run_tbo
|
||
|
||
def forward_extend(
|
||
self,
|
||
q: torch.Tensor,
|
||
k: torch.Tensor,
|
||
v: torch.Tensor,
|
||
layer: RadixAttention,
|
||
forward_batch: ForwardBatch,
|
||
save_kv_cache=True,
|
||
q_rope: Optional[torch.Tensor] = None,
|
||
k_rope: Optional[torch.Tensor] = None,
|
||
sinks: Optional[torch.Tensor] = None,
|
||
):
|
||
if k is not None:
|
||
assert v is not None
|
||
|
||
is_cp_mode = (
|
||
forward_batch.forward_mode.is_context_parallel_extend()
|
||
and forward_batch.attn_cp_metadata is not None
|
||
and self.attn_cp_size > 1
|
||
)
|
||
|
||
if save_kv_cache and not is_cp_mode:
|
||
cache_loc = (
|
||
forward_batch.out_cache_loc
|
||
if not layer.is_cross_attention
|
||
else forward_batch.encoder_out_cache_loc
|
||
)
|
||
if not self.use_mla:
|
||
self.token_to_kv_pool.set_kv_buffer(
|
||
layer,
|
||
KVWriteLoc(cache_loc, self.forward_metadata.swa_out_cache_loc),
|
||
k,
|
||
v,
|
||
layer.k_scale,
|
||
layer.v_scale,
|
||
)
|
||
else:
|
||
self.token_to_kv_pool.set_mla_kv_buffer(
|
||
layer,
|
||
cache_loc,
|
||
k,
|
||
k_rope,
|
||
)
|
||
if is_cp_mode:
|
||
cp_allgather_and_save_kv_cache(
|
||
forward_batch,
|
||
layer,
|
||
k,
|
||
v,
|
||
self.attn_cp_size,
|
||
swa_loc=(
|
||
self.forward_metadata.swa_out_cache_loc
|
||
if self.use_sliding_window_kv_pool
|
||
else None
|
||
),
|
||
)
|
||
|
||
metadata = self.forward_metadata
|
||
|
||
is_swa_layer = (
|
||
layer.sliding_window_size is not None and layer.sliding_window_size > -1
|
||
)
|
||
window_size = (layer.sliding_window_size, 0) if is_swa_layer else (-1, -1)
|
||
k_descale, v_descale = None, None
|
||
if (
|
||
self.kv_cache_dtype_str != "auto"
|
||
and layer.head_dim <= 256
|
||
and self.fa_impl_ver != 4
|
||
):
|
||
if layer.k_scale is not None:
|
||
descale_shape = (forward_batch.batch_size, layer.tp_k_head_num)
|
||
k_descale = layer.k_scale.expand(descale_shape)
|
||
v_descale = layer.v_scale.expand(descale_shape)
|
||
q = q.to(self.kv_cache_dtype)
|
||
q_rope = q_rope.to(self.kv_cache_dtype) if q_rope is not None else None
|
||
k_rope = k_rope.to(self.kv_cache_dtype) if k_rope is not None else None
|
||
causal = True
|
||
if layer.is_cross_attention or layer.attn_type == AttentionType.ENCODER_ONLY:
|
||
causal = False
|
||
|
||
use_local_attn = (
|
||
self.has_local_attention
|
||
and self.attention_chunk_size is not None
|
||
and metadata.local_attn_metadata is not None
|
||
and (hasattr(layer, "use_irope") and layer.use_irope)
|
||
)
|
||
|
||
use_cascade_attn = (
|
||
forward_batch.forward_mode.is_target_verify()
|
||
and self.topk > 1
|
||
and not is_swa_layer
|
||
)
|
||
|
||
kwargs = {}
|
||
if sinks is not None:
|
||
kwargs["sinks"] = sinks
|
||
|
||
if use_local_attn:
|
||
local_metadata = metadata.local_attn_metadata
|
||
page_table = local_metadata.local_block_table
|
||
cu_seqlens_q = local_metadata.local_query_start_loc
|
||
cache_seqlens = local_metadata.local_seqused_k
|
||
max_seqlen_q = local_metadata.local_max_query_len
|
||
max_seqlen_k = local_metadata.local_max_seq_len
|
||
elif is_swa_layer and metadata.swa_spec_metadata is not None:
|
||
swa_spec_metadata = metadata.swa_spec_metadata
|
||
page_table = swa_spec_metadata.page_table
|
||
cu_seqlens_q = swa_spec_metadata.cu_seqlens_q
|
||
cache_seqlens = swa_spec_metadata.cache_seqlens_int32
|
||
max_seqlen_q = swa_spec_metadata.max_seq_len_q
|
||
cu_seqlens_k = swa_spec_metadata.cu_seqlens_k
|
||
max_seqlen_k = swa_spec_metadata.max_seq_len_k
|
||
else:
|
||
page_table = metadata.page_table
|
||
if is_swa_layer and self.use_sliding_window_kv_pool:
|
||
if metadata.swa_page_table is not None:
|
||
page_table = metadata.swa_page_table
|
||
else:
|
||
page_table = self.token_to_kv_pool.translate_loc_from_full_to_swa(
|
||
metadata.page_table
|
||
)
|
||
cu_seqlens_q = metadata.cu_seqlens_q
|
||
cache_seqlens = metadata.cache_seqlens_int32
|
||
max_seqlen_q = metadata.max_seq_len_q
|
||
cu_seqlens_k = metadata.cu_seqlens_k
|
||
max_seqlen_k = metadata.max_seq_len_k
|
||
|
||
# Set current state for the flash attention call
|
||
self._set_current_state(
|
||
layer=layer,
|
||
prefix="forward_extend",
|
||
max_seqlen_k=max_seqlen_k,
|
||
can_run_tbo=forward_batch.can_run_tbo,
|
||
)
|
||
if not self.use_mla:
|
||
key_cache, value_cache = self.token_to_kv_pool.get_kv_buffer(layer.layer_id)
|
||
|
||
key_cache = key_cache.view(
|
||
-1, self.page_size, layer.tp_k_head_num, layer.head_dim
|
||
)
|
||
value_cache = value_cache.view(
|
||
-1, self.page_size, layer.tp_v_head_num, layer.v_head_dim
|
||
)
|
||
if layer.is_cross_attention:
|
||
page_table = metadata.encoder_page_table
|
||
cache_seqlens = metadata.encoder_lens_int32
|
||
cu_seqlens_k = metadata.encoder_cu_seqlens_k
|
||
window_size = (-1, -1)
|
||
|
||
if (
|
||
forward_batch.forward_mode.is_context_parallel_extend()
|
||
and forward_batch.attn_cp_metadata is not None
|
||
and self.attn_cp_size > 1
|
||
):
|
||
|
||
def _fa_cp_attn(
|
||
q_chunk, cu_seqlens_q_cp, cache_seqlens_cp, max_seqlen_q_cp
|
||
):
|
||
return flash_attn_with_kvcache(
|
||
q=q_chunk,
|
||
k_cache=key_cache,
|
||
v_cache=value_cache,
|
||
page_table=page_table,
|
||
cache_seqlens=cache_seqlens_cp,
|
||
cu_seqlens_q=cu_seqlens_q_cp,
|
||
cu_seqlens_k_new=(cu_seqlens_k if not use_local_attn else None),
|
||
max_seqlen_q=max_seqlen_q_cp,
|
||
softmax_scale=layer.scaling,
|
||
causal=False if use_cascade_attn else causal,
|
||
window_size=window_size,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=use_cascade_attn,
|
||
num_splits=self.num_splits,
|
||
**kwargs,
|
||
)
|
||
|
||
result = cp_attn_forward_extend(
|
||
self,
|
||
forward_batch,
|
||
q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
self.device,
|
||
_fa_cp_attn,
|
||
)
|
||
elif (
|
||
forward_batch.extend_prefix_lens_cpu is not None
|
||
and any(forward_batch.extend_prefix_lens_cpu)
|
||
) or forward_batch.forward_mode.is_target_verify():
|
||
result = flash_attn_with_kvcache(
|
||
q=q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
k_cache=key_cache,
|
||
v_cache=value_cache,
|
||
page_table=page_table,
|
||
cache_seqlens=cache_seqlens,
|
||
cu_seqlens_q=cu_seqlens_q,
|
||
cu_seqlens_k_new=cu_seqlens_k if not use_local_attn else None,
|
||
max_seqlen_q=max_seqlen_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False if use_cascade_attn else causal,
|
||
window_size=window_size,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=use_cascade_attn,
|
||
num_splits=self.num_splits,
|
||
**kwargs,
|
||
)
|
||
else:
|
||
output = flash_attn_varlen_func(
|
||
q=q.view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
k=k.view(-1, layer.tp_k_head_num, layer.head_dim).to(q.dtype),
|
||
v=v.view(-1, layer.tp_k_head_num, layer.v_head_dim).to(q.dtype),
|
||
cu_seqlens_q=metadata.cu_seqlens_q,
|
||
cu_seqlens_k=metadata.cu_seqlens_q,
|
||
max_seqlen_q=metadata.max_seq_len_q,
|
||
max_seqlen_k=metadata.max_seq_len_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=True,
|
||
return_softmax_lse=forward_batch.mha_return_lse,
|
||
**kwargs,
|
||
)
|
||
if forward_batch.mha_return_lse:
|
||
output, lse, *rest = output
|
||
lse = torch.transpose(lse, 0, 1).contiguous()
|
||
return (
|
||
output.view(-1, layer.tp_q_head_num * layer.v_head_dim),
|
||
lse,
|
||
)
|
||
return output.view(-1, layer.tp_q_head_num * layer.v_head_dim)
|
||
|
||
if use_cascade_attn:
|
||
# Update state for the second call
|
||
self._current_prefix = "forward_extend_use_cascade_attn"
|
||
self._current_max_seqlen_k = (
|
||
self.forward_metadata_spec_decode_expand.max_seq_len_k
|
||
)
|
||
|
||
o, softmax_lse, *rest = result
|
||
o_expand, softmax_lse_expand, *rest_expand = flash_attn_with_kvcache(
|
||
q=q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
k_cache=key_cache.view(-1, 1, layer.tp_k_head_num, layer.head_dim),
|
||
v_cache=value_cache.view(
|
||
-1, 1, layer.tp_v_head_num, layer.head_dim
|
||
),
|
||
page_table=self.forward_metadata_spec_decode_expand.page_table,
|
||
cache_seqlens=self.forward_metadata_spec_decode_expand.cache_seqlens_int32,
|
||
cu_seqlens_q=self.forward_metadata_spec_decode_expand.cu_seqlens_q,
|
||
cu_seqlens_k_new=self.forward_metadata_spec_decode_expand.cu_seqlens_k,
|
||
max_seqlen_q=self.forward_metadata_spec_decode_expand.max_seq_len_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False,
|
||
window_size=window_size,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=True,
|
||
num_splits=self.num_splits,
|
||
**kwargs,
|
||
)
|
||
o, _ = merge_state_v2_wrapper(
|
||
o,
|
||
softmax_lse.T.contiguous(),
|
||
o_expand,
|
||
softmax_lse_expand.T.contiguous(),
|
||
)
|
||
else:
|
||
o = result
|
||
else:
|
||
if (
|
||
forward_batch.attn_attend_prefix_cache is not None
|
||
and not forward_batch.forward_mode.is_target_verify()
|
||
and not forward_batch.forward_mode.is_draft_extend_v2()
|
||
):
|
||
if forward_batch.attn_attend_prefix_cache:
|
||
assert not get_server_args().disable_chunked_prefix_cache
|
||
assert forward_batch.prefix_chunk_idx is not None
|
||
assert forward_batch.prefix_chunk_cu_seq_lens is not None
|
||
assert forward_batch.prefix_chunk_max_seq_lens is not None
|
||
|
||
chunk_idx = forward_batch.prefix_chunk_idx
|
||
assert chunk_idx >= 0
|
||
|
||
assert forward_batch.mha_return_lse
|
||
output = flash_attn_varlen_func(
|
||
q=q.view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
k=k.view(-1, layer.tp_k_head_num, layer.head_dim).to(q.dtype),
|
||
v=v.view(-1, layer.tp_k_head_num, layer.v_head_dim).to(q.dtype),
|
||
cu_seqlens_q=metadata.cu_seqlens_q,
|
||
cu_seqlens_k=forward_batch.prefix_chunk_cu_seq_lens[chunk_idx],
|
||
max_seqlen_q=metadata.max_seq_len_q,
|
||
max_seqlen_k=forward_batch.prefix_chunk_max_seq_lens[chunk_idx],
|
||
softmax_scale=layer.scaling,
|
||
causal=False,
|
||
return_softmax_lse=True,
|
||
**kwargs,
|
||
)
|
||
else:
|
||
cu_seqlens_k = (
|
||
metadata.cu_seqlens_q
|
||
if not forward_batch.mha_one_shot
|
||
else metadata.cu_seqlens_k
|
||
)
|
||
max_seqlen_k = (
|
||
metadata.max_seq_len_q
|
||
if not forward_batch.mha_one_shot
|
||
else metadata.max_seq_len_k
|
||
)
|
||
output = flash_attn_varlen_func(
|
||
q=q.view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
k=k.view(-1, layer.tp_k_head_num, layer.head_dim).to(q.dtype),
|
||
v=v.view(-1, layer.tp_k_head_num, layer.v_head_dim).to(q.dtype),
|
||
cu_seqlens_q=metadata.cu_seqlens_q,
|
||
cu_seqlens_k=cu_seqlens_k,
|
||
max_seqlen_q=metadata.max_seq_len_q,
|
||
max_seqlen_k=max_seqlen_k,
|
||
softmax_scale=layer.scaling,
|
||
causal=True,
|
||
return_softmax_lse=forward_batch.mha_return_lse,
|
||
**kwargs,
|
||
)
|
||
if forward_batch.mha_return_lse:
|
||
output, lse, *rest = output
|
||
lse = torch.transpose(lse, 0, 1).contiguous()
|
||
return output, lse
|
||
return output
|
||
else:
|
||
kv_cache = self.token_to_kv_pool.get_key_buffer(layer.layer_id).to(
|
||
q.dtype
|
||
)
|
||
k_rope = kv_cache[:, :, layer.v_head_dim :]
|
||
c_kv = kv_cache[:, :, : layer.v_head_dim]
|
||
k_rope_cache = k_rope.view(
|
||
-1,
|
||
self.page_size,
|
||
layer.tp_k_head_num,
|
||
layer.head_dim - layer.v_head_dim,
|
||
)
|
||
c_kv_cache = c_kv.view(
|
||
-1, self.page_size, layer.tp_v_head_num, layer.v_head_dim
|
||
)
|
||
if q_rope is not None:
|
||
q_nope = q.view(-1, layer.tp_q_head_num, layer.v_head_dim)
|
||
q_rope = q_rope.view(
|
||
-1, layer.tp_q_head_num, layer.head_dim - layer.v_head_dim
|
||
)
|
||
else:
|
||
q_all = q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim)
|
||
q_nope = q_all[:, :, : layer.v_head_dim]
|
||
q_rope = q_all[:, :, layer.v_head_dim :]
|
||
|
||
result = flash_attn_with_kvcache(
|
||
q=q_rope,
|
||
k_cache=k_rope_cache,
|
||
v_cache=c_kv_cache,
|
||
qv=q_nope,
|
||
page_table=page_table,
|
||
cache_seqlens=cache_seqlens,
|
||
cu_seqlens_q=cu_seqlens_q,
|
||
cu_seqlens_k_new=cu_seqlens_k if not use_local_attn else None,
|
||
max_seqlen_q=max_seqlen_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False if use_cascade_attn else causal,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=use_cascade_attn,
|
||
num_splits=self.num_splits,
|
||
)
|
||
if use_cascade_attn:
|
||
self._current_prefix = "forward_extend_use_cascade_attn"
|
||
self._current_max_seqlen_k = (
|
||
self.forward_metadata_spec_decode_expand.max_seq_len_k
|
||
)
|
||
|
||
o, softmax_lse, *rest = result
|
||
o_expand, softmax_lse_expand, *rest_expand = (
|
||
flash_attn_with_kvcache(
|
||
q=q_rope,
|
||
k_cache=k_rope_cache,
|
||
v_cache=c_kv_cache,
|
||
qv=q_nope,
|
||
page_table=self.forward_metadata_spec_decode_expand.page_table,
|
||
cache_seqlens=self.forward_metadata_spec_decode_expand.cache_seqlens_int32,
|
||
cu_seqlens_q=self.forward_metadata_spec_decode_expand.cu_seqlens_q,
|
||
cu_seqlens_k_new=self.forward_metadata_spec_decode_expand.cu_seqlens_k,
|
||
max_seqlen_q=self.forward_metadata_spec_decode_expand.max_seq_len_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False,
|
||
window_size=window_size,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=True,
|
||
num_splits=self.num_splits,
|
||
)
|
||
)
|
||
o, _ = merge_state_v2_wrapper(
|
||
o,
|
||
softmax_lse.T.contiguous(),
|
||
o_expand,
|
||
softmax_lse_expand.T.contiguous(),
|
||
)
|
||
else:
|
||
o = result
|
||
|
||
return o.view(-1, layer.tp_q_head_num * layer.v_head_dim)
|
||
|
||
def forward_decode(
|
||
self,
|
||
q: torch.Tensor,
|
||
k: torch.Tensor,
|
||
v: torch.Tensor,
|
||
layer: RadixAttention,
|
||
forward_batch: ForwardBatch,
|
||
save_kv_cache=True,
|
||
q_rope: Optional[torch.Tensor] = None,
|
||
k_rope: Optional[torch.Tensor] = None,
|
||
sinks: Optional[torch.Tensor] = None,
|
||
) -> torch.Tensor:
|
||
if k is not None:
|
||
assert v is not None
|
||
if save_kv_cache:
|
||
cache_loc = (
|
||
forward_batch.out_cache_loc
|
||
if not layer.is_cross_attention
|
||
else forward_batch.encoder_out_cache_loc
|
||
)
|
||
if not self.use_mla:
|
||
self.token_to_kv_pool.set_kv_buffer(
|
||
layer,
|
||
KVWriteLoc(cache_loc, self.forward_metadata.swa_out_cache_loc),
|
||
k,
|
||
v,
|
||
layer.k_scale,
|
||
layer.v_scale,
|
||
)
|
||
else:
|
||
self.token_to_kv_pool.set_mla_kv_buffer(
|
||
layer,
|
||
cache_loc,
|
||
k,
|
||
k_rope,
|
||
)
|
||
|
||
metadata = self.forward_metadata
|
||
local_attn_metadata = getattr(metadata, "local_attn_metadata", None)
|
||
use_local_attn = (
|
||
self.has_local_attention
|
||
and self.attention_chunk_size is not None
|
||
and local_attn_metadata is not None
|
||
and (hasattr(layer, "use_irope") and layer.use_irope)
|
||
)
|
||
|
||
use_cascade_attn = forward_batch.spec_info is not None and self.topk > 1
|
||
|
||
is_swa_layer = (
|
||
layer.sliding_window_size is not None and layer.sliding_window_size > -1
|
||
)
|
||
window_size = (layer.sliding_window_size, 0) if is_swa_layer else (-1, -1)
|
||
|
||
causal = True
|
||
if layer.is_cross_attention or layer.attn_type == AttentionType.ENCODER_ONLY:
|
||
causal = False
|
||
|
||
kwargs = {}
|
||
if sinks is not None:
|
||
kwargs["sinks"] = sinks
|
||
|
||
k_descale, v_descale = None, None
|
||
if self.kv_cache_dtype_str != "auto" and layer.head_dim <= 256:
|
||
if layer.k_scale is not None:
|
||
descale_shape = (forward_batch.batch_size, layer.tp_k_head_num)
|
||
k_descale = layer.k_scale.expand(descale_shape)
|
||
v_descale = layer.v_scale.expand(descale_shape)
|
||
q = q.to(self.kv_cache_dtype)
|
||
q_rope = q_rope.to(self.kv_cache_dtype) if q_rope is not None else None
|
||
k_rope = k_rope.to(self.kv_cache_dtype) if k_rope is not None else None
|
||
|
||
# Set current state for the flash attention call
|
||
self._set_current_state(
|
||
layer=layer,
|
||
prefix="forward_decode",
|
||
max_seqlen_k=metadata.max_seq_len_k,
|
||
can_run_tbo=forward_batch.can_run_tbo,
|
||
)
|
||
if not self.use_mla:
|
||
key_cache, value_cache = self.token_to_kv_pool.get_kv_buffer(layer.layer_id)
|
||
key_cache = key_cache.view(
|
||
-1, self.page_size, layer.tp_k_head_num, layer.head_dim
|
||
)
|
||
value_cache = value_cache.view(
|
||
-1, self.page_size, layer.tp_v_head_num, layer.v_head_dim
|
||
)
|
||
|
||
if layer.is_cross_attention:
|
||
o = flash_attn_with_kvcache(
|
||
q=q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
k_cache=key_cache,
|
||
v_cache=value_cache,
|
||
page_table=metadata.encoder_page_table,
|
||
cache_seqlens=metadata.encoder_lens_int32,
|
||
cu_seqlens_q=metadata.cu_seqlens_q,
|
||
cu_seqlens_k_new=metadata.encoder_cu_seqlens_k,
|
||
max_seqlen_q=1,
|
||
softmax_scale=layer.scaling,
|
||
causal=False,
|
||
window_size=(-1, -1),
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
num_splits=self.num_splits,
|
||
**kwargs,
|
||
)
|
||
elif use_local_attn:
|
||
o = flash_attn_with_kvcache(
|
||
q=q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim),
|
||
k_cache=key_cache,
|
||
v_cache=value_cache,
|
||
page_table=local_attn_metadata.local_block_table,
|
||
cache_seqlens=local_attn_metadata.local_seqused_k,
|
||
cu_seqlens_q=local_attn_metadata.local_query_start_loc,
|
||
cu_seqlens_k_new=None,
|
||
max_seqlen_q=local_attn_metadata.local_max_query_len,
|
||
softmax_scale=layer.scaling,
|
||
causal=True,
|
||
window_size=(-1, -1),
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
num_splits=self.num_splits,
|
||
**kwargs,
|
||
)
|
||
else:
|
||
page_table = metadata.page_table
|
||
if is_swa_layer and self.use_sliding_window_kv_pool:
|
||
if metadata.swa_page_table is not None:
|
||
page_table = metadata.swa_page_table
|
||
else:
|
||
page_table = (
|
||
self.token_to_kv_pool.translate_loc_from_full_to_swa(
|
||
metadata.page_table
|
||
)
|
||
)
|
||
cache_seqlens = metadata.cache_seqlens_int32
|
||
cu_seqlens_k = metadata.cu_seqlens_k
|
||
max_seqlen_q = metadata.max_seq_len_q
|
||
q_reshaped = q.contiguous().view(
|
||
-1, layer.tp_q_head_num, layer.head_dim
|
||
)
|
||
|
||
result = flash_attn_with_kvcache(
|
||
q=q_reshaped,
|
||
k_cache=key_cache,
|
||
v_cache=value_cache,
|
||
page_table=page_table,
|
||
cache_seqlens=cache_seqlens,
|
||
cu_seqlens_q=metadata.cu_seqlens_q,
|
||
max_seqlen_q=max_seqlen_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False if use_cascade_attn else causal,
|
||
window_size=window_size,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=use_cascade_attn,
|
||
num_splits=self.num_splits,
|
||
**kwargs,
|
||
)
|
||
if use_cascade_attn:
|
||
self._current_prefix = "forward_decode_use_cascade_attn"
|
||
self._current_max_seqlen_k = (
|
||
self.forward_metadata_spec_decode_expand.max_seq_len_k
|
||
)
|
||
|
||
o, softmax_lse, *rest = result
|
||
o_expand, softmax_lse_expand, *rest_expand = (
|
||
flash_attn_with_kvcache(
|
||
q=q_reshaped,
|
||
k_cache=key_cache,
|
||
v_cache=value_cache,
|
||
page_table=self.forward_metadata_spec_decode_expand.page_table,
|
||
cache_seqlens=self.forward_metadata_spec_decode_expand.cache_seqlens_int32,
|
||
cu_seqlens_q=self.forward_metadata_spec_decode_expand.cu_seqlens_q,
|
||
cu_seqlens_k_new=self.forward_metadata_spec_decode_expand.cu_seqlens_k,
|
||
max_seqlen_q=self.forward_metadata_spec_decode_expand.max_seq_len_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False,
|
||
window_size=window_size,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=True,
|
||
num_splits=self.num_splits,
|
||
**kwargs,
|
||
)
|
||
)
|
||
o, _ = merge_state_v2_wrapper(
|
||
o,
|
||
softmax_lse.T.contiguous(),
|
||
o_expand,
|
||
softmax_lse_expand.T.contiguous(),
|
||
)
|
||
else:
|
||
o = result
|
||
else:
|
||
kv_cache = self.token_to_kv_pool.get_key_buffer(layer.layer_id).to(q.dtype)
|
||
k_rope = kv_cache[:, :, layer.v_head_dim :]
|
||
c_kv = kv_cache[:, :, : layer.v_head_dim]
|
||
k_rope_cache = k_rope.view(
|
||
-1,
|
||
self.page_size,
|
||
layer.tp_k_head_num,
|
||
layer.head_dim - layer.v_head_dim,
|
||
)
|
||
c_kv_cache = c_kv.view(
|
||
-1, self.page_size, layer.tp_v_head_num, layer.v_head_dim
|
||
)
|
||
|
||
if q_rope is not None:
|
||
q_nope = q.view(-1, layer.tp_q_head_num, layer.v_head_dim)
|
||
q_rope = q_rope.view(
|
||
-1, layer.tp_q_head_num, layer.head_dim - layer.v_head_dim
|
||
)
|
||
else:
|
||
q_all = q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim)
|
||
q_nope = q_all[:, :, : layer.v_head_dim]
|
||
q_rope = q_all[:, :, layer.v_head_dim :]
|
||
max_seqlen_q = metadata.max_seq_len_q
|
||
|
||
result = flash_attn_with_kvcache(
|
||
q=q_rope,
|
||
k_cache=k_rope_cache,
|
||
v_cache=c_kv_cache,
|
||
qv=q_nope,
|
||
page_table=metadata.page_table,
|
||
cache_seqlens=metadata.cache_seqlens_int32,
|
||
cu_seqlens_q=metadata.cu_seqlens_q,
|
||
cu_seqlens_k_new=metadata.cu_seqlens_k,
|
||
max_seqlen_q=max_seqlen_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False if use_cascade_attn else causal,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=use_cascade_attn,
|
||
num_splits=self.num_splits,
|
||
)
|
||
if use_cascade_attn:
|
||
self._current_prefix = "forward_decode_use_cascade_attn"
|
||
self._current_max_seqlen_k = (
|
||
self.forward_metadata_spec_decode_expand.max_seq_len_k
|
||
)
|
||
|
||
o, softmax_lse, *rest = result
|
||
o_expand, softmax_lse_expand, *rest_expand = flash_attn_with_kvcache(
|
||
q=q_rope,
|
||
k_cache=k_rope_cache,
|
||
v_cache=c_kv_cache,
|
||
qv=q_nope,
|
||
page_table=self.forward_metadata_spec_decode_expand.page_table,
|
||
cache_seqlens=self.forward_metadata_spec_decode_expand.cache_seqlens_int32,
|
||
cu_seqlens_q=self.forward_metadata_spec_decode_expand.cu_seqlens_q,
|
||
cu_seqlens_k_new=self.forward_metadata_spec_decode_expand.cu_seqlens_k,
|
||
max_seqlen_q=self.forward_metadata_spec_decode_expand.max_seq_len_q,
|
||
softmax_scale=layer.scaling,
|
||
causal=False,
|
||
window_size=window_size,
|
||
softcap=layer.logit_cap,
|
||
k_descale=k_descale,
|
||
v_descale=v_descale,
|
||
return_softmax_lse=True,
|
||
num_splits=self.num_splits,
|
||
)
|
||
o, _ = merge_state_v2_wrapper(
|
||
o,
|
||
softmax_lse.T.contiguous(),
|
||
o_expand,
|
||
softmax_lse_expand.T.contiguous(),
|
||
)
|
||
else:
|
||
o = result
|
||
|
||
return o.view(-1, layer.tp_q_head_num * layer.v_head_dim)
|
||
|
||
|
||
class MusaFlashAttentionMultiStepBackend(FlashAttentionMultiStepBackend):
|
||
|
||
def __init__(
|
||
self,
|
||
model_runner: ModelRunner,
|
||
topk: int,
|
||
speculative_num_steps: int,
|
||
fa_impl_ver: int = 3,
|
||
):
|
||
self.model_runner = model_runner
|
||
self.topk = topk
|
||
self.speculative_num_steps = speculative_num_steps
|
||
self.attn_backends = []
|
||
for i in range(self.speculative_num_steps - 1):
|
||
self.attn_backends.append(
|
||
MusaFlashAttentionBackend(
|
||
model_runner,
|
||
speculative_step_id=i,
|
||
topk=self.topk,
|
||
speculative_num_steps=self.speculative_num_steps,
|
||
fa_impl_ver=fa_impl_ver,
|
||
)
|
||
)
|