Reland "[perf][spec decoding] Skip full-vocab softmax in EAGLE draft when topk == 1 (#26235)" (#26397)

This commit is contained in:
Qiaolin Yu
2026-05-26 14:14:48 -07:00
committed by GitHub
parent 499eecce22
commit dd6f073377
2 changed files with 37 additions and 6 deletions
@@ -30,12 +30,15 @@ from sglang.srt.model_executor.input_buffers import ForwardInputBuffers
from sglang.srt.speculative.eagle_info import EagleDraftExtendInput from sglang.srt.speculative.eagle_info import EagleDraftExtendInput
from sglang.srt.speculative.spec_utils import fast_topk from sglang.srt.speculative.spec_utils import fast_topk
from sglang.srt.utils import ( from sglang.srt.utils import (
is_hip,
require_attn_tp_gather, require_attn_tp_gather,
require_gathered_buffer, require_gathered_buffer,
require_mlp_sync, require_mlp_sync,
require_mlp_tp_gather, require_mlp_tp_gather,
) )
_is_hip = is_hip()
if TYPE_CHECKING: if TYPE_CHECKING:
from sglang.srt.speculative.eagle_worker import EAGLEWorker from sglang.srt.speculative.eagle_worker import EAGLEWorker
@@ -401,8 +404,17 @@ class EAGLEDraftExtendCudaGraphRunner:
forward_batch.positions, forward_batch.positions,
forward_batch, forward_batch,
) )
probs = torch.softmax(ret.next_token_logits, dim=-1) # ROCm's argmax tie-breaks differently from CUDA's softmax+max
ret.topk_p, ret.topk_index = fast_topk(probs, self.topk, dim=-1) # path on FP8 logits, which corrupts MTP draft selection on AMD.
# Keep the fastpath CUDA-only.
if self.topk == 1 and not _is_hip:
ret.topk_index = torch.argmax(
ret.next_token_logits, dim=-1, keepdim=True
)
ret.topk_p = torch.ones_like(ret.topk_index, dtype=torch.float32)
else:
probs = torch.softmax(ret.next_token_logits, dim=-1)
ret.topk_p, ret.topk_index = fast_topk(probs, self.topk, dim=-1)
forward_batch.out_cache_loc = output_cache_loc_backup forward_batch.out_cache_loc = output_cache_loc_backup
forward_batch.spec_info.hidden_states = hidden_states_backup forward_batch.spec_info.hidden_states = hidden_states_backup
@@ -487,8 +487,19 @@ class EagleDraftWorker(BaseDraftWorker):
).logits_output ).logits_output
maybe_detect_nan(logits_output.next_token_logits, f"draft_forward step {i}") maybe_detect_nan(logits_output.next_token_logits, f"draft_forward step {i}")
maybe_detect_inf(logits_output.next_token_logits, f"draft_forward step {i}") maybe_detect_inf(logits_output.next_token_logits, f"draft_forward step {i}")
probs = torch.softmax(logits_output.next_token_logits, dim=-1) if self.topk == 1 and not _is_hip:
topk_p, topk_index = fast_topk(probs, self.topk, dim=-1) # topk=1 → degenerate single-path tree; `topk_p` is unused
# downstream, so skip softmax and just argmax over logits.
# Gated to CUDA: on ROCm the argmax tie-break diverges from
# the softmax+max path on FP8 logits and corrupts MTP draft
# selection (DSV3.2 MTP GSM8K, see #26358).
topk_index = torch.argmax(
logits_output.next_token_logits, dim=-1, keepdim=True
)
topk_p = torch.ones_like(topk_index, dtype=torch.float32)
else:
probs = torch.softmax(logits_output.next_token_logits, dim=-1)
topk_p, topk_index = fast_topk(probs, self.topk, dim=-1)
maybe_detect_oob( maybe_detect_oob(
topk_index, topk_index,
0, 0,
@@ -660,8 +671,16 @@ class EagleDraftWorker(BaseDraftWorker):
draft_logits_output.hidden_states = draft_logits_output.hidden_states[ draft_logits_output.hidden_states = draft_logits_output.hidden_states[
select_index select_index
] ]
probs = torch.softmax(draft_logits_output.next_token_logits, dim=-1) if self.topk == 1 and not _is_hip:
ret_topk_p, ret_topk_index = fast_topk(probs, self.topk, dim=-1) # Gated to CUDA: see #26358 — ROCm's argmax tie-break corrupts
# MTP draft selection on FP8 logits.
ret_topk_index = torch.argmax(
draft_logits_output.next_token_logits, dim=-1, keepdim=True
)
ret_topk_p = torch.ones_like(ret_topk_index, dtype=torch.float32)
else:
probs = torch.softmax(draft_logits_output.next_token_logits, dim=-1)
ret_topk_p, ret_topk_index = fast_topk(probs, self.topk, dim=-1)
ret_hidden_states = draft_logits_output.hidden_states ret_hidden_states = draft_logits_output.hidden_states
# Construct the return values # Construct the return values