Hybrid kv cache for LLaMA4 (#6563)
Co-authored-by: Cheng Wan <54331508+ch-wan@users.noreply.github.com> Co-authored-by: tarinkk <rt572@physics.rutger.edu> Co-authored-by: tarinkk <rt572@rutgers.physics.edu> Co-authored-by: Hanming Lu <69857889+hanming-lu@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import torch
|
||||
from sglang.srt.configs.model_config import AttentionArch
|
||||
from sglang.srt.layers.attention.base_attn_backend import AttentionBackend
|
||||
from sglang.srt.managers.schedule_batch import global_server_args_dict
|
||||
from sglang.srt.mem_cache.memory_pool import SWAKVPool
|
||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, ForwardMode
|
||||
from sglang.srt.speculative.eagle_utils import EagleDraftInput, EagleVerifyInput
|
||||
|
||||
@@ -320,6 +321,11 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
self.page_size = model_runner.page_size
|
||||
self.use_mla = model_runner.model_config.attention_arch == AttentionArch.MLA
|
||||
self.skip_prefill = skip_prefill
|
||||
self.is_hybrid = model_runner.is_hybrid
|
||||
if self.is_hybrid:
|
||||
self.full_to_swa_index_mapping = (
|
||||
model_runner.token_to_kv_pool.full_to_swa_index_mapping
|
||||
)
|
||||
self.topk = model_runner.server_args.speculative_eagle_topk or 0
|
||||
self.speculative_num_steps = speculative_num_steps
|
||||
self.speculative_num_draft_tokens = (
|
||||
@@ -428,7 +434,7 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
forward_batch.req_pool_indices, : metadata.max_seq_len_k
|
||||
]
|
||||
# TODO: we need to test this part for llama 4 eagle case
|
||||
self._init_local_attn_metadata(metadata, device)
|
||||
self._init_local_attn_metadata(forward_batch, metadata, device)
|
||||
elif forward_batch.forward_mode.is_target_verify():
|
||||
if self.topk <= 1:
|
||||
metadata.cache_seqlens_int32 = (
|
||||
@@ -456,7 +462,7 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
forward_batch.req_pool_indices, : metadata.max_seq_len_k
|
||||
]
|
||||
|
||||
self._init_local_attn_metadata(metadata, device)
|
||||
self._init_local_attn_metadata(forward_batch, metadata, device)
|
||||
else:
|
||||
metadata.cache_seqlens_int32 = forward_batch.seq_lens.to(torch.int32)
|
||||
metadata.max_seq_len_q = self.speculative_num_draft_tokens
|
||||
@@ -575,7 +581,7 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
|
||||
# Setup local attention if enabled
|
||||
if forward_batch.forward_mode == ForwardMode.EXTEND:
|
||||
self._init_local_attn_metadata(metadata, device)
|
||||
self._init_local_attn_metadata(forward_batch, metadata, device)
|
||||
|
||||
# Encoder metadata for cross attention
|
||||
if forward_batch.encoder_lens is not None:
|
||||
@@ -1588,7 +1594,7 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
forward_mode: ForwardMode,
|
||||
spec_info: Optional[Union[EagleDraftInput, EagleVerifyInput]],
|
||||
seq_lens_cpu: Optional[torch.Tensor],
|
||||
out_cache_loc: torch.Tensor = None,
|
||||
out_cache_loc: Optional[torch.Tensor] = None,
|
||||
):
|
||||
"""Initialize forward metadata for replaying CUDA graph."""
|
||||
seq_lens = seq_lens[:bs]
|
||||
@@ -1673,7 +1679,10 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
self.page_size,
|
||||
)
|
||||
|
||||
self._update_local_attn_metadata_for_replay(metadata, bs)
|
||||
self._update_local_attn_metadata_for_replay(
|
||||
metadata,
|
||||
bs,
|
||||
)
|
||||
elif forward_mode.is_target_verify():
|
||||
if self.topk <= 1:
|
||||
metadata = self.target_verify_metadata[bs]
|
||||
@@ -1829,7 +1838,9 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
"""Get the fill value for sequence length in CUDA graph."""
|
||||
return 1
|
||||
|
||||
def _init_local_attn_metadata(self, metadata: FlashAttentionMetadata, device):
|
||||
def _init_local_attn_metadata(
|
||||
self, forwardbatch: ForwardBatch, metadata: FlashAttentionMetadata, device
|
||||
):
|
||||
"""Centralized utility to initialize local_attn_metadata if chunked attention is enabled."""
|
||||
if self.attention_chunk_size is None:
|
||||
metadata.local_attn_metadata = None
|
||||
@@ -1837,7 +1848,12 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
|
||||
cu_seqlens_q = metadata.cu_seqlens_q
|
||||
cache_seqlens_int32 = metadata.cache_seqlens_int32
|
||||
page_table = metadata.page_table
|
||||
if self.is_hybrid:
|
||||
page_table = self.full_to_swa_index_mapping[metadata.page_table].to(
|
||||
torch.int32
|
||||
)
|
||||
else:
|
||||
page_table = metadata.page_table
|
||||
if cu_seqlens_q is None or cache_seqlens_int32 is None or page_table is None:
|
||||
metadata.local_attn_metadata = None
|
||||
return
|
||||
@@ -1923,7 +1939,9 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
)
|
||||
|
||||
def _update_local_attn_metadata_for_replay(
|
||||
self, metadata: FlashAttentionMetadata, bs: int
|
||||
self,
|
||||
metadata: FlashAttentionMetadata,
|
||||
bs: int,
|
||||
):
|
||||
"""Update preallocated local attention metadata in-place before CUDA graph replay."""
|
||||
if self.attention_chunk_size is None:
|
||||
@@ -1954,7 +1972,12 @@ class FlashAttentionBackend(AttentionBackend):
|
||||
# Without this slicing, the pre-allocated page_table may contain zeros or invalid indices
|
||||
# beyond the actual sequence length, leading to incorrect attention calculations
|
||||
max_seq_len = int(seqlens.max().item())
|
||||
sliced_page_table = metadata.page_table[:bs, :max_seq_len]
|
||||
if self.is_hybrid:
|
||||
sliced_page_table = self.full_to_swa_index_mapping[
|
||||
metadata.page_table[:bs, :max_seq_len]
|
||||
].to(torch.int32)
|
||||
else:
|
||||
sliced_page_table = metadata.page_table[:bs, :max_seq_len]
|
||||
|
||||
cu_seqlens_q_np = cu_seqlens_q.cpu().numpy()
|
||||
seqlens_np = seqlens.cpu().numpy()
|
||||
|
||||
Reference in New Issue
Block a user