Skip to content

[Perf][Spec Decode] Sharded greedy verification and fused vocab-parallel draft argmax - #62604

Closed
jiacao-amd wants to merge 3 commits into
vllm-project:mainfrom
jiacao-amd:minimax-m3-sharded-greedy-verify
Closed

jiacao-amd wants to merge 3 commits into
vllm-project:mainfrom
jiacao-amd:minimax-m3-sharded-greedy-verify

Conversation

@jiacao-amd

@jiacao-amd jiacao-amd commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

With a vocab-parallel LM head, greedy speculative decoding all-gathers the full-vocabulary logits across TP ranks: on the target side before rejection sampling, and (without use_local_argmax_reduction) on the draft side before the argmax. For a 200k vocabulary at TP4 that is a large gather on every decode step, although greedy verification only needs the argmax of each row.

This PR keeps the logits on each rank:

  1. Sharded greedy verification (v1/worker/gpu/spec_decode/sharded_greedy_verifier.py, opt-in via VLLM_SHARDED_GREEDY_VERIFY=1). Each rank reduces its vocabulary shard to compact per-block (max, token id) statistics, only those are all-gathered, and one kernel finishes the global argmax, acceptance (including synthetic acceptance), bonus token and sampled/rejected counts. The blocks keep the native kernels' global boundaries (8192 for draft positions, 1024 for the bonus), also across shard edges, so ties resolve exactly as on the full logits.
    • Models opt in through compute_logits_local, the hook batch-sharded sampling already uses (added here to the ROCm MiniMax-M3 model, matching the NVIDIA one). Any TP size > 1 (including non-power-of-two), vocabulary < 2^24, hidden size and number of speculative tokens; CUDA and ROCm.
    • Per step, the batch falls back to the native path, before any logits are computed, unless every request is greedy with no logits processing, logprobs, structured output, draft logits, adaptive/block verification or watermarking.
  2. Fused LogitsProcessor.get_top_tokens (model_executor/layers/vocab_parallel_argmax.py), i.e. the existing speculative_config.use_local_argmax_reduction draft path. The in-place padding mask, the torch reduction, the stack and the last-dim all-gather become two Triton kernels with a dim-0 all-gather. Same result (lowest id on ties, NaN wins, as torch.argmax); it applies to every model using LocalArgmaxMixin.

Results (MI355X, MiniMax-M3-MXFP4 TP4, EAGLE3-GQA, K=3)

Base image vllm/vllm-openai-rocm:nightly-rocm72-1b2a666391f2a24228a1436b64d547c34cc6b6ce plus the AITER gfx950 unified-attention routing fix (ROCm/aiter#6336) so an unrelated draft-attention regression does not dilute the numbers. This branch is based on the same vLLM commit; the measured image contains exactly these files. Server: VLLM_SHARDED_GREEDY_VERIFY=1, --speculative-config '{..., "use_local_argmax_reduction": true}'.

8k/1k C24 (240 requests, zero HTTP warmup, warmed compile caches, interleaved rounds vs same-round baseline):

output throughput rounds
this PR (verification + fused get_top_tokens) +1.75% +1.47 / +2.02
first, MiniMax-specific revision of this PR (same batch) +1.78% +1.68 / +1.88
verification + unfused use_local_argmax_reduction +1.25% +1.46 / +1.04
verification only +0.65% +0.65 / +0.64

Mean TPOT −3.0%, p99 E2EL −1.3%. Per decode step (profiler, 24 req × 4 tokens), NCCL in the cycle went from 385 µs to 83 µs.

AgenticX C24 (InferenceX recipe minimaxm3/vllm/mi355x-fp4-mtp/agentic.yaml, 3600 s, one run of this revision vs the same baseline): P50 interactivity +1.9%, P90 interactivity +0.7%, mean TPOT −0.5%; throughput is trace-saturated (+0.3%). TTFT regresses: mean +6.8%, P90 +8.1%. Two earlier runs that combined this change with a draft-metadata change showed the same TTFT shift (+6.3% / +5.3% mean), while other changes measured against the same baseline did not, so the TTFT cost is attributed to this PR and is being investigated before this leaves draft.

Correctness: real-acceptance greedy EAGLE3 smoke (24 concurrent ≥8k-token prompts + 4 short requests): generated text and token counts identical to the baseline (24/24, 4/4).

Test Plan

  • tests/v1/worker/test_gpu_sharded_greedy_verify.py: TP2/3/4/8 emulated in one process (per-shard statistics concatenated in rank order, as all_gather(dim=0) produces), compared with rejection_sample + get_num_sampled_and_rejected on the full logits. Covers vocab 1000/50257/200064 (including shards narrower than a block), K=1/3/5, synthetic acceptance, prefilling requests and placeholder drafts, bf16 ties and planted cross-shard ties, unaligned vocabulary padding, and NaN rows staying in-vocabulary.
  • tests/model_executor/layers/test_vocab_parallel_argmax.py: fused argmax vs torch.argmax for TP1/2/3/4/8, fp32/bf16, ties, NaN, padding, empty batch and all -inf rows.
  • 157 passed on MI355X.

Draft: E2E measured on MiniMax-M3 / ROCm only so far.

🤖 Generated with Claude Code

… fused draft argmax

Greedy EAGLE verification currently all-gathers the full-vocabulary target
logits across TP ranks before taking the argmax. Instead, each rank reduces its
own vocabulary shard to compact per-block (max, index) statistics, only those
are all-gathered, and one fused kernel finishes the global argmax, acceptance
(including synthetic acceptance), bonus token and sampled/rejected counts. The
draft side similarly takes the argmax over compact rank-major partials of the
stock BF16 LM head instead of gathering full-vocabulary logits.

Both paths are opt-in (MM3_SHARDED_GREEDY_VERIFY_EXPERIMENT,
MM3_FUSED_DRAFT_ARGMAX_EXPERIMENT) and currently limited to the measured
MiniMax-M3 TP4 greedy EAGLE3 configuration on ROCm; every other case keeps the
native path.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: jiacao-amd <jiahui.cao@amd.com>
@mergify mergify Bot added the mrv2 Model Runner V2 specific label Oct 20, 2026
@github-project-automation github-project-automation Bot moved this to Todo in AMD Oct 20, 2026
jiacao-amd and others added 2 commits October 19, 2026 20:53
Drop the MiniMax-M3/TP4/K=3 restrictions and the model-private hooks:

- Models opt in through compute_logits_local, the hook batch-sharded
  sampling already uses (added to the ROCm MiniMax-M3 model, matching the
  NVIDIA one). Any TP size > 1, vocabulary size < 2**24, hidden size and
  number of speculative tokens; CUDA and ROCm.
- Gate with VLLM_SHARDED_GREEDY_VERIFY in vllm/envs.py.
- Per step, fall back to the native path unless every request is greedy
  with no logits processing, logprobs, structured output, draft logits,
  adaptive/block verification or watermarking.
- Non-power-of-two TP sizes and shards narrower than a vocabulary block.
- Remove the fused draft argmax: the existing
  speculative_config.use_local_argmax_reduction covers the draft side
  (Eagle3 Llama drafts already implement get_top_tokens).
- Unit tests emulate TP2/3/4/8 in one process and compare against
  rejection_sample on the full logits, including synthetic acceptance,
  prefilling and placeholder drafts, bf16 and planted cross-shard ties,
  and vocabulary padding.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: jiacao-amd <jiahui.cao@amd.com>
get_top_tokens (speculative_config.use_local_argmax_reduction) masked the
padding in place, reduced with torch, stacked the (value, id) pairs and
all-gathered them along the last dim. Replace that with two Triton kernels:
per-tile (max, id) partials over the real vocabulary columns of the shard,
an all-gather along dim 0, and a merge. Ties resolve to the lowest id and
NaN wins, as with torch.argmax on the full logits. This restores the draft
side of the measured MiniMax-M3 gain that the model-specific fused draft
argmax provided.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: jiacao-amd <jiahui.cao@amd.com>
@jiacao-amd jiacao-amd changed the title [ROCm][Perf][Spec Decode][MiniMax-M3] Sharded greedy verification and fused draft argmax [Perf][Spec Decode] Sharded greedy verification and fused vocab-parallel draft argmax Oct 20, 2026
@jiacao-amd

Copy link
Copy Markdown
Contributor Author

Closing for now. The target workload for this work is the InferenceX AgenticX benchmark, which sends no sampling parameters, so requests use the model's generation_config defaults (temperature 1.0, top_p 0.95). The sharded greedy verification path therefore never triggers there, and the remaining draft-side change measured P90 interactivity +0.7% with mean TTFT +6.8% in a standalone AgenticX run. The 8k/1k greedy gain (+1.75%) stands, and the branch is kept in case greedy serving becomes a priority.

@jiacao-amd jiacao-amd closed this Oct 20, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in AMD Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minimax mrv2 Model Runner V2 specific rocm Related to AMD ROCm speculative-decoding

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant