[dsv4] fix multi-step draft on non-cuda-graph path (#26239)

This commit is contained in:
Liangsheng Yin
2026-05-24 17:04:18 -07:00
committed by GitHub
parent d7e3e54148
commit ed179bf9b2
3 changed files with 47 additions and 7 deletions
@@ -53,6 +53,7 @@ from sglang.srt.layers.dp_attention import (
)
from sglang.srt.mem_cache.deepseek_v4_memory_pool import DeepSeekV4TokenToKVPool
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, ForwardMode
from sglang.srt.speculative.eagle_utils import per_step_draft_out_cache_loc
from sglang.srt.speculative.spec_info import SpecInput
from sglang.srt.utils import ceil_align
@@ -676,11 +677,22 @@ class DeepseekV4AttnBackend(
max_seq_len = int(seq_lens_cpu.max().item())
if forward_batch.forward_mode.is_decode_or_idle():
# DSv4 bakes this step's KV write target (c4/c128) into metadata,
# so slice the shared multi-step out_cache_loc now rather than at
# forward time.
out_cache_loc = forward_batch.out_cache_loc
if self.topk > 0 and self.speculative_num_steps > 1:
out_cache_loc = per_step_draft_out_cache_loc(
out_cache_loc,
forward_batch.batch_size,
self.topk,
self.speculative_num_steps,
)[self.speculative_step_id]
metadata = self.init_forward_metadata_decode(
max_seq_len=max_seq_len,
req_pool_indices=req_pool_indices,
seq_lens=seq_lens,
out_cache_loc=forward_batch.out_cache_loc,
out_cache_loc=out_cache_loc,
)
elif forward_batch.forward_mode.is_target_verify():
metadata = self.init_forward_metadata_target_verify(
@@ -23,6 +23,30 @@ if _is_cuda or _is_hip or _is_musa:
)
def per_step_draft_out_cache_loc(
out_cache_loc: torch.Tensor,
batch_size: int,
topk: int,
num_steps: int,
) -> torch.Tensor:
"""Per-step slice of the multi-step EAGLE draft out_cache_loc buffer.
Single source of truth for the layout shared by EagleWorkerV2.draft_forward
(per-step write target) and DeepseekV4AttnBackend (per-step compression
write target baked into metadata).
"""
expected = batch_size * topk * num_steps
assert out_cache_loc.shape[0] == expected, (
f"out_cache_loc.shape[0]={out_cache_loc.shape[0]} != "
f"batch_size * topk * num_steps = {batch_size}*{topk}*{num_steps}={expected}"
)
return (
out_cache_loc.view(batch_size, topk, num_steps)
.permute(2, 0, 1)
.reshape(num_steps, -1)
)
def apply_eagle_prefill_input_rotation(
batch: ScheduleBatch, next_token_ids: torch.Tensor
) -> None:
@@ -53,7 +53,11 @@ from sglang.srt.speculative.eagle_info_v2 import (
fill_accepted_out_cache_loc,
fill_bonus_tokens,
)
from sglang.srt.speculative.eagle_utils import TreeMaskMode, build_tree_kernel_efficient
from sglang.srt.speculative.eagle_utils import (
TreeMaskMode,
build_tree_kernel_efficient,
per_step_draft_out_cache_loc,
)
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
from sglang.srt.speculative.spec_utils import (
draft_tp_context,
@@ -438,11 +442,11 @@ class EagleDraftWorker(BaseDraftWorker):
if self.hot_token_id is not None:
topk_index = self.hot_token_id[topk_index]
out_cache_loc = out_cache_loc.reshape(
forward_batch.batch_size, self.topk, self.speculative_num_steps
)
out_cache_loc = out_cache_loc.permute((2, 0, 1)).reshape(
self.speculative_num_steps, -1
out_cache_loc = per_step_draft_out_cache_loc(
out_cache_loc,
forward_batch.batch_size,
self.topk,
self.speculative_num_steps,
)
# Return values