Skip to content

[Spec Decode] Add top-k DSpark Markov projection - #49969

Merged
benchislett merged 6 commits into
vllm-project:mainfrom
askliar:feat/add_dspark_inference_trick
Aug 4, 2026
Merged

benchislett merged 6 commits into
vllm-project:mainfrom
askliar:feat/add_dspark_inference_trick

Conversation

@askliar

@askliar askliar commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Purpose

DSpark computes the base logits for all draft positions in parallel, then applies the Markov bias sequentially over the full draft vocabulary. The repeated full-vocabulary Markov projection is on the serial drafting path.

This PR adds dspark_draft_topk for Qwen3 DSpark. It selects the top-k candidates from the base logits once, gathers the corresponding markov_w2 rows, and evaluates the sequential Markov bias only for those candidates.

The current implementation deliberately reuses the existing dense sampling path:

  • Compute dense base logits and select the top-k candidates once for all draft positions.
  • Initialize the reusable dense logits buffer to -inf.
  • At each sequential step, apply the Markov bias only to the selected candidates and scatter the corrected values into that dense row.
  • Use the existing greedy or probabilistic Gumbel/rejection sampling path unchanged.

The base LM-head output and probabilistic draft-logits storage remain dense. This optimization specifically reduces the repeated sequential Markov projection while avoiding custom proposal and rejection-sampling plumbing.

Current scope:

  • Qwen3 DSpark

Test Plan

  • Compare dense DSpark against dspark_draft_topk across lower- and higher-concurrency workloads.
  • Check GSM8K accuracy and acceptance length for greedy and probabilistic drafting.
  • Profile the decode window to confirm that savings occur in the drafter projection.
  • Run focused configuration/top-k tests and repository pre-commit hooks.

Results

End-to-end comparison

Tested with draft_sample_method: probabilistic, temperature 1, and 7 speculative tokens on GB10.

Implementation Top-k GSM8K strict / flex AIPerf tok/s/user¹ AIPerf total tok/s¹
Initial PR implementation 512 0.82 / 0.83 65.3 44.6
Initial PR implementation Off 0.80 / 0.83 53.0 40.6
Current simplified implementation 512 0.84 / 0.84 78.1 52.1
Current simplified implementation Off 0.84 / 0.85 54.0 41.3

¹ Concurrency 64, ISL 32768 / OSL 1024.

  • At concurrency 64, top-k 512 improves per-user throughput by 23% for the initial implementation (53.0 → 65.3) and 45% for the current simplified implementation (54.0 → 78.1).
  • With top-k 512, the current implementation is 20% faster per user than the initial implementation (78.1 versus 65.3). Their no-top-k baselines are equivalent.
  • These results confirm that top-k benefits higher-concurrency, GPU-bound decode.
  • GSM8K scores remain within the observed run-to-run range; there is no measured accuracy regression.

Decode GPU profile

GPU time by selected kernel category, in milliseconds, over a concurrency-1 / approximately 8K-context decode window:

Kernel category Initial / Off Initial / 512 Current / Off Current / 512
Drafter projection (cutlass / GEMV) 155 105 154 107
Elementwise / norm 28.7 34.4 28.3 28.9
Sort / top-k / select 5.5 6.2 5.5 6.7
Total GPU time 878.5 822.9 870.8 831.4

The profiles confirm that the saving occurs where expected:

  • Top-k 512 reduces the drafter projection by approximately 47–50 ms. The top-k selection itself adds only approximately 1 ms.
  • Total decode GPU time falls by 6.3% for the initial implementation and 4.5% for the current implementation.
  • The initial path adds 5.7 ms of elementwise/index work, while the current implementation adds only 0.6 ms. The profiler reports 35 additional distinct kernels for the initial path versus 14 for the current path.
  • Major target-model categories such as MoE routing/GEMMs, dense matmuls, and attention are unchanged within run-to-run variation.

The concurrency-1 profile establishes the per-step compute saving. At concurrency 64 with a 32K-token input, decode becomes GPU-bound and that saving converts into substantial throughput. The current path's advantage over the initial path at high concurrency is consistent with its lower auxiliary kernel/index overhead, although that contribution was not isolated independently.

Acceptance-length sweep

Top-k t=0 (greedy) t=1 (probabilistic)
512 3.9509 3.6582
1024 3.9448 3.6573
2048 3.9445 3.6472
4096 3.9403 3.6455
8192 3.9403 3.6556
16384 3.9648 3.6473
32768 3.9253 3.6568
65536 3.9403 3.6429
Off 3.9253 3.6413

Focused checks

  • pre-commit run --files <changed files>: passed, including Ruff and mypy.
  • pytest -q tests/v1/spec_decode/test_dspark_topk.py: 2 passed.
  • pytest -q tests/test_config.py -k 'draft_sample_method': 2 passed.
  • pytest -q tests/v1/worker/test_gpu_rejection_sampler_chunking.py -k 'preserves_request_boundaries': 1 passed.

Benchmark caveats

  • AIPerf used 5 measured requests plus 2 warmup requests, so exact throughput values have some run-to-run variance. The top-k 512 differences are substantially larger than the observed noise.
  • AIPerf and GSM8K runs used gpu-memory-utilization=0.8.
  • Nsight Systems runs used gpu-memory-utilization=0.7 because CUPTI trace buffers caused model-load OOM at 0.8 on this node. The decode kernels were unchanged, so the profiles remain representative of the code paths.

Essential Elements of an Effective PR Description Checklist
  • The purpose of the PR is described.
  • The test plan is included.
  • Test results are included.
  • Documentation changes are not required for the current model-specific scope.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@askliar
askliar marked this pull request as draft July 27, 2026 10:28
@mergify

mergify Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Documentation preview: https://vllm--49969.org.readthedocs.build/en/49969/

@mergify mergify Bot added documentation Improvements or additions to documentation qwen Related to Qwen models speculative-decoding v1 labels Jul 27, 2026
@mergify

mergify Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @askliar.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Jul 27, 2026
@askliar
askliar force-pushed the feat/add_dspark_inference_trick branch from ebd8257 to 39c1628 Compare July 29, 2026 10:37
@askliar askliar changed the title WIP: DSpark inference trick [Spec Decode] Add top-k DSpark Markov projection Jul 29, 2026
@mergify mergify Bot removed the needs-rebase label Jul 29, 2026
Signed-off-by: Andrii Skliar <askliar@nvidia.com>
@askliar
askliar force-pushed the feat/add_dspark_inference_trick branch from 39c1628 to 6bc2306 Compare July 29, 2026 10:42
@askliar
askliar marked this pull request as ready for review July 29, 2026 10:43

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@benchislett benchislett left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High level: I feel like this approach may be overly optimized.

I'm not convinced that sampling from a smaller distribution will bring efficiency here. If the savings are just coming from the sparse markov projections, then we could probably gain a lot just by having the bias module directly overwrite the logits of the backbone (with within-topk being written as calculated and outside-topk set to -inf or 0). That would eliminate the need for custom sampling code

@mergify mergify Bot added the mrv2 Model Runner V2 specific label Jul 30, 2026
that dense buffer so the normal sampler sees the truncated proposal.
"""
weight = self.markov_w2.weight[index]
bias = torch.bmm(weight, markov_embed.unsqueeze(-1)).squeeze(-1)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use addmm here?
See #50737

If it requires a layout change or something heavy, don't bother. But if it happens to be a drop-in, seems like a nice potential improvement

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with baddbmm - that should be the easiest drop-in replacement.

Comment thread vllm/config/speculative.py Outdated
self.draft_model_config.hf_config,
)
)
if (

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constraint is no longer required. Please rebase to latest main, which includes a change to replicate the markov_w2 on all gpus (TP disabled)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thank you.

Andrii Skliar added 3 commits August 3, 2026 13:29
Signed-off-by: Andrii Skliar <askliar@nvidia.com>
Signed-off-by: Andrii Skliar <askliar@nvidia.com>
Signed-off-by: Andrii Skliar <askliar@nvidia.com>
@askliar
askliar force-pushed the feat/add_dspark_inference_trick branch from b8dd547 to 3c9ea0c Compare August 3, 2026 11:32
Signed-off-by: Andrii Skliar <askliar@nvidia.com>

@benchislett benchislett left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@benchislett
benchislett enabled auto-merge (squash) August 3, 2026 14:41
@benchislett benchislett added the ready ONLY add when PR is ready to merge/full CI is needed label Aug 3, 2026
Signed-off-by: Andrii Skliar <andreyws96@gmail.com>
@benchislett
benchislett merged commit 5789897 into vllm-project:main Aug 4, 2026
133 checks passed
jasl added a commit to jasl/vllm that referenced this pull request Aug 6, 2026
Every cold boot on the nvidia DSpark path under the V2 runner dies in
profile_run: DSparkSpeculator._sample_logits calls
model.map_draft_to_target on the draft_logits-is-None branch, which is
exactly the state during profiling. vllm-project#49969 added the hooks to amd/,
xpu/, kimi_k3 and qwen3_dspark but not this class. Identity is correct
and checked, not assumed: nothing in-tree assigns _d2t_scatter_index,
0731 sets no dspark_draft_topk, and head/logits_processor/markov_w2 are
all built at config.vocab_size. compute_draft_logits mirrors amd/xpu.

Reported by alexbi29 in vllm-project#41834 with the exact fix,
verified on their SM120 TP=2+EP production cluster.

Co-authored-by: alexbi29 <alexbi29@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation mrv2 Model Runner V2 specific qwen Related to Qwen models ready ONLY add when PR is ready to merge/full CI is needed speculative-decoding v1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants