[RL] DSV4: dispatch indexer topk_transform_512 through DSATopKBackend (#31087)
Signed-off-by: zhihaow6 <zhihaow6@illinois.edu>
This commit is contained in:
@@ -40,6 +40,7 @@ from sglang.kernels.ops.speculative.dspark.dspark_attn_metadata import (
|
|||||||
)
|
)
|
||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
from sglang.srt.layers.attention.base_attn_backend import AttentionBackend
|
from sglang.srt.layers.attention.base_attn_backend import AttentionBackend
|
||||||
|
from sglang.srt.layers.attention.dsa.dsa_topk_backend import DSATopKBackend
|
||||||
from sglang.srt.layers.attention.dsv4.compressor_v2 import (
|
from sglang.srt.layers.attention.dsv4.compressor_v2 import (
|
||||||
CompressorBackendMixin,
|
CompressorBackendMixin,
|
||||||
FusedCompressMetadata,
|
FusedCompressMetadata,
|
||||||
@@ -528,6 +529,9 @@ class DeepseekV4AttnBackend(
|
|||||||
self.enable_deepseek_v4_fp4_indexer: bool = (
|
self.enable_deepseek_v4_fp4_indexer: bool = (
|
||||||
model_runner.server_args.enable_deepseek_v4_fp4_indexer
|
model_runner.server_args.enable_deepseek_v4_fp4_indexer
|
||||||
)
|
)
|
||||||
|
self.dsa_topk_backend: DSATopKBackend = DSATopKBackend(
|
||||||
|
model_runner.server_args.dsa_topk_backend
|
||||||
|
)
|
||||||
self.topk = model_runner.server_args.speculative_eagle_topk or 0
|
self.topk = model_runner.server_args.speculative_eagle_topk or 0
|
||||||
assert self.topk in [0, 1], "MTP Topk > 1 not supported for DeepSeek V4"
|
assert self.topk in [0, 1], "MTP Topk > 1 not supported for DeepSeek V4"
|
||||||
self.mtp_enabled = self.topk > 0
|
self.mtp_enabled = self.topk > 0
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Any, List, Optional, Tuple, TypeAlias, Union
|
from typing import (
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
TypeAlias,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
@@ -15,6 +25,7 @@ from sglang.kernels.ops.attention.dsv4 import (
|
|||||||
from sglang.kernels.ops.quantization.fp8_kernel import is_fp8_fnuz
|
from sglang.kernels.ops.quantization.fp8_kernel import is_fp8_fnuz
|
||||||
from sglang.srt.configs.deepseek_v4 import DeepSeekV4Config
|
from sglang.srt.configs.deepseek_v4 import DeepSeekV4Config
|
||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
|
from sglang.srt.layers.attention.dsa.dsa_topk_backend import DSATopKBackend
|
||||||
from sglang.srt.layers.attention.dsv4.compressor import Compressor
|
from sglang.srt.layers.attention.dsv4.compressor import Compressor
|
||||||
from sglang.srt.layers.attention.dsv4.metadata import (
|
from sglang.srt.layers.attention.dsv4.metadata import (
|
||||||
NonPagedIndexerPlan,
|
NonPagedIndexerPlan,
|
||||||
@@ -245,18 +256,17 @@ def fp8_paged_mqa_logits_torch_sm120(
|
|||||||
return logits
|
return logits
|
||||||
|
|
||||||
|
|
||||||
def topk_transform_512_pytorch_vectorized(
|
def _topk_transform_512_vectorized(
|
||||||
scores: torch.Tensor,
|
scores: torch.Tensor,
|
||||||
seq_lens: torch.Tensor,
|
seq_lens: torch.Tensor,
|
||||||
page_tables: torch.Tensor,
|
page_tables: torch.Tensor,
|
||||||
out_page_indices: torch.Tensor,
|
out_page_indices: torch.Tensor,
|
||||||
page_size: int,
|
page_size: int,
|
||||||
out_raw_indices: Optional[torch.Tensor] = None,
|
out_raw_indices: Optional[torch.Tensor] = None,
|
||||||
|
topk_op: Callable[..., Tuple[torch.Tensor, torch.Tensor]] = torch.topk,
|
||||||
|
topk_op_kwargs: Optional[Dict[str, object]] = None,
|
||||||
|
contiguous_topk_input: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Vectorized PyTorch fallback for topk_transform_512.
|
|
||||||
All helper tensors (arange, zeros) are cached to avoid device-tensor
|
|
||||||
creation during HIP/CUDA graph capture."""
|
|
||||||
|
|
||||||
TOPK = out_page_indices.shape[1]
|
TOPK = out_page_indices.shape[1]
|
||||||
batch_size = scores.shape[0]
|
batch_size = scores.shape[0]
|
||||||
max_seq_len = scores.shape[1]
|
max_seq_len = scores.shape[1]
|
||||||
@@ -283,9 +293,13 @@ def topk_transform_512_pytorch_vectorized(
|
|||||||
masked_scores.masked_fill_(~valid_mask, float("-inf"))
|
masked_scores.masked_fill_(~valid_mask, float("-inf"))
|
||||||
|
|
||||||
actual_k = min(TOPK, max_seq_len)
|
actual_k = min(TOPK, max_seq_len)
|
||||||
_, raw_indices = torch.topk(
|
topk_kwargs = (
|
||||||
masked_scores, k=actual_k, dim=1, largest=True, sorted=False
|
{"dim": 1, "largest": True, "sorted": False}
|
||||||
|
if topk_op_kwargs is None
|
||||||
|
else topk_op_kwargs
|
||||||
)
|
)
|
||||||
|
topk_input = masked_scores.contiguous() if contiguous_topk_input else masked_scores
|
||||||
|
_, raw_indices = topk_op(topk_input, actual_k, **topk_kwargs)
|
||||||
raw_indices = raw_indices.to(torch.int32)
|
raw_indices = raw_indices.to(torch.int32)
|
||||||
|
|
||||||
if actual_k < TOPK:
|
if actual_k < TOPK:
|
||||||
@@ -330,10 +344,67 @@ def topk_transform_512_pytorch_vectorized(
|
|||||||
out_raw_indices.copy_(raw_indices)
|
out_raw_indices.copy_(raw_indices)
|
||||||
|
|
||||||
|
|
||||||
|
def topk_transform_512_pytorch_vectorized(
|
||||||
|
scores: torch.Tensor,
|
||||||
|
seq_lens: torch.Tensor,
|
||||||
|
page_tables: torch.Tensor,
|
||||||
|
out_page_indices: torch.Tensor,
|
||||||
|
page_size: int,
|
||||||
|
out_raw_indices: Optional[torch.Tensor] = None,
|
||||||
|
) -> None:
|
||||||
|
"""Vectorized PyTorch fallback for topk_transform_512.
|
||||||
|
All helper tensors (arange, zeros) are cached to avoid device-tensor
|
||||||
|
creation during HIP/CUDA graph capture."""
|
||||||
|
|
||||||
|
_topk_transform_512_vectorized(
|
||||||
|
scores,
|
||||||
|
seq_lens,
|
||||||
|
page_tables,
|
||||||
|
out_page_indices,
|
||||||
|
page_size,
|
||||||
|
out_raw_indices,
|
||||||
|
topk_op=torch.topk,
|
||||||
|
topk_op_kwargs={"dim": 1, "largest": True, "sorted": False},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def topk_transform_512_flashinfer_unfused(
|
||||||
|
scores: torch.Tensor,
|
||||||
|
seq_lens: torch.Tensor,
|
||||||
|
page_tables: torch.Tensor,
|
||||||
|
out_page_indices: torch.Tensor,
|
||||||
|
page_size: int,
|
||||||
|
out_raw_indices: Optional[torch.Tensor] = None,
|
||||||
|
) -> None:
|
||||||
|
import flashinfer
|
||||||
|
|
||||||
|
from sglang.srt.layers.attention.dsa.dsa_topk_backend import (
|
||||||
|
_flashinfer_tie_break_value,
|
||||||
|
)
|
||||||
|
|
||||||
|
_topk_transform_512_vectorized(
|
||||||
|
scores,
|
||||||
|
seq_lens,
|
||||||
|
page_tables,
|
||||||
|
out_page_indices,
|
||||||
|
page_size,
|
||||||
|
out_raw_indices,
|
||||||
|
topk_op=flashinfer.top_k,
|
||||||
|
topk_op_kwargs={
|
||||||
|
"sorted": False,
|
||||||
|
"deterministic": envs.SGLANG_DSA_TOPK_FLASHINFER_DETERMINISTIC.get(),
|
||||||
|
"tie_break": _flashinfer_tie_break_value(),
|
||||||
|
"dsa_graph_safe": True,
|
||||||
|
},
|
||||||
|
contiguous_topk_input=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class C4IndexerBackendMixin:
|
class C4IndexerBackendMixin:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.debug_use_external_c4_sparse_indices: bool = False
|
self.debug_use_external_c4_sparse_indices: bool = False
|
||||||
|
self.dsa_topk_backend: DSATopKBackend = DSATopKBackend.SGL_KERNEL
|
||||||
|
|
||||||
def _forward_prepare_multi_stream(
|
def _forward_prepare_multi_stream(
|
||||||
self,
|
self,
|
||||||
@@ -732,7 +803,10 @@ class C4IndexerBackendMixin:
|
|||||||
elif core_metadata.c4_sparse_raw_indices is not None:
|
elif core_metadata.c4_sparse_raw_indices is not None:
|
||||||
raw_indices = core_metadata.c4_sparse_raw_indices
|
raw_indices = core_metadata.c4_sparse_raw_indices
|
||||||
|
|
||||||
if envs.SGLANG_TOPK_TRANSFORM_512_TORCH.get():
|
if (
|
||||||
|
envs.SGLANG_TOPK_TRANSFORM_512_TORCH.get()
|
||||||
|
or self.dsa_topk_backend.is_torch()
|
||||||
|
):
|
||||||
topk_transform_512_pytorch_vectorized(
|
topk_transform_512_pytorch_vectorized(
|
||||||
logits,
|
logits,
|
||||||
c4_seq_lens,
|
c4_seq_lens,
|
||||||
@@ -741,6 +815,15 @@ class C4IndexerBackendMixin:
|
|||||||
indexer_metadata.c4_page_size,
|
indexer_metadata.c4_page_size,
|
||||||
raw_indices,
|
raw_indices,
|
||||||
)
|
)
|
||||||
|
elif self.dsa_topk_backend.is_flashinfer():
|
||||||
|
topk_transform_512_flashinfer_unfused(
|
||||||
|
logits,
|
||||||
|
c4_seq_lens,
|
||||||
|
page_table,
|
||||||
|
c4_sparse_page_indices,
|
||||||
|
indexer_metadata.c4_page_size,
|
||||||
|
raw_indices,
|
||||||
|
)
|
||||||
elif envs.SGLANG_OPT_USE_TOPK_V2.get() and raw_indices is None:
|
elif envs.SGLANG_OPT_USE_TOPK_V2.get() and raw_indices is None:
|
||||||
topk_transform_512_v2(
|
topk_transform_512_v2(
|
||||||
logits,
|
logits,
|
||||||
|
|||||||
Reference in New Issue
Block a user