Skip to content

[TRTLLM-13321][feat] Extend rejection sampling to one-model speculative decoding (MTP/DRAFT_TARGET/PARD/DFLASH)#15775

Merged
zhaoyangwang-nvidia merged 8 commits into
NVIDIA:mainfrom
zhaoyangwang-nvidia:rejection-one-model-spec
Jul 16, 2026
Merged

[TRTLLM-13321][feat] Extend rejection sampling to one-model speculative decoding (MTP/DRAFT_TARGET/PARD/DFLASH)#15775
zhaoyangwang-nvidia merged 8 commits into
NVIDIA:mainfrom
zhaoyangwang-nvidia:rejection-one-model-spec

Conversation

@zhaoyangwang-nvidia

@zhaoyangwang-nvidia zhaoyangwang-nvidia commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added broader rejection-sampling support across speculative decoding modes, including improved handling for draft/target vocab differences.
    • Draft token generation now works more consistently across one-model and multi-model speculative workflows.
  • Bug Fixes

    • Improved fallback behavior when speculative buffers are missing or invalid, reducing the chance of stale or incorrect outputs.
    • Fixed draft token handling for several speculative decoding paths.
  • Documentation

    • Added guidance for working with one-model speculative decoding workers.
  • Tests

    • Added coverage for rejection-sampling behavior across multiple speculative decoding configurations.

Description

Extends rejection sampling (previously available only for Eagle3 dynamic-tree)
to the one-model speculative-decoding workers: vanilla MTP, PARD, DFlash, and
DraftTarget one-model
. Rejection sampling makes speculative decoding
distribution-preserving under non-greedy sampling (temperature / top-k / top-p),
so accepted tokens follow the target model's distribution instead of falling back
to strict token-equality acceptance.

Alongside the feature, this PR consolidates the draft-token production and
acceptance paths that had diverged across the five one-model workers into a
single shared implementation on SpecWorkerBase, so each method now differs only
where the model architecture forces it to.

What changed

Feature: rejection sampling for one-model methods

  • Draft workers capture each proposal step's probability distribution into a
    slot-indexed draft_probs buffer (keyed by py_seq_slot), consumed by the
    rejection kernel on the next forward.
  • Fail-closed acceptance: draft_probs_valid is reset at the start of every
    draft forward and only trusted after a complete capture; _rejection_buffers_valid
    validates every dereferenced shape (CUDA-graph-safe, no host sync) and falls
    back to strict acceptance on any mismatch.
  • All-greedy batches bypass rejection (argmax acceptance is identical and cheaper).
  • Config gating in llm_args.py: rejection is opt-in per method; unsupported
    combinations (SA, relaxed-thinking, attention-DP, context-parallel, guided
    decoding, missing flashinfer) either raise on explicit opt-in or silently
    disable by default. Plain TP is supported via minimal draft-logit gather.

Refactor: unified production / acceptance

  • Production unified behind sample_draft_tokens (step form for MTP/DraftTarget,
    block form for PARD/DFlash); Eagle3 now routes through it too. d2t is cached once
    at draft-model load (self._d2t) and applied internally — no longer threaded
    through call arguments.
  • Acceptance unified behind sample_and_accept_draft_tokens -> compare_and_accept;
    workers override only the _reshape_draft_tokens_for_accept /
    _reshape_logits_for_accept hooks when their buffer/logit layout differs (only
    PARD does). MTP and Eagle3 keep full overrides for their relaxed / THOP paths.
  • Draft-logit TP policy: draft LM heads stay vocab-sharded
    (lm_head_gather_output=False); the base gathers the minimum necessary based on
    a shape check (_draft_logits_are_sharded) — light index+value gather for greedy,
    full all-gather only for a sharded non-greedy batch.

Docs & tests

  • Adds tensorrt_llm/_torch/speculative/SPEC_DEVELOPER_GUIDE.md, an
    agent-friendly module guide (so both humans and coding agents can extend the
    speculative code without re-deriving the framework). It documents the
    SpecWorkerBase inheritance framework, d2t handling, the do-not-gather
    draft-logit policy, the acceptance hooks, and the rejection-sampling contract a
    new worker must satisfy. It follows the same in-tree developer-guide convention
    as tensorrt_llm/_torch/modules/ATTENTION_DEVELOPER_GUIDE.md and
    tensorrt_llm/_torch/modules/fused_moe/MOE_DEVELOPER_GUIDE.md (and, for
    criteria-style docs, tensorrt_llm/_torch/visual_gen/ENGINEERING_CRITERIA.md) —
    these are already referenced from AGENTS.md as read-before-modifying guides.
  • One rejection e2e per method, placed next to each method's existing test
    (test_draft_target, test_pard, test_dflash, test_mtp); plus
    test_rejection_buffers_guard for the buffer-allocation and fail-closed guard
    logic. Registered in the H100 pre-merge stage.

Test Coverage

  • tests/unittest/_torch/speculative/hw_agnostic/test_{draft_target,pard,dflash,mtp}.py
    — one rejection-on non-greedy e2e per method (path-correctness).
  • tests/unittest/_torch/speculative/test_rejection_buffers_guard.py — buffer
    allocation + fail-closed guard + acceptance dispatch (parametrized).
  • All verified locally on H200; the four e2e methods and the guard suite pass.
    The draft_target / pard / dflash / eagle3 matrix (rejection on/off × cuda-graph)
    matches the pre-refactor baseline; MTP's pre-existing REJ_OFF+GRAPH_ON crash is
    an unrelated upstream issue.

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@zhaoyangwang-nvidia zhaoyangwang-nvidia force-pushed the rejection-one-model-spec branch 3 times, most recently from c8302fc to 3f93561 Compare July 3, 2026 12:29
@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57463 [ run ] triggered by Bot. Commit: 3f93561 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57463 [ run ] completed with state SUCCESS. Commit: 3f93561
/LLM/main/L0_MergeRequest_PR pipeline #46200 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@zhaoyangwang-nvidia zhaoyangwang-nvidia force-pushed the rejection-one-model-spec branch 2 times, most recently from ba30f91 to fcd785a Compare July 6, 2026 09:45
@zhaoyangwang-nvidia zhaoyangwang-nvidia marked this pull request as ready for review July 6, 2026 09:48
@zhaoyangwang-nvidia zhaoyangwang-nvidia requested review from a team as code owners July 6, 2026 09:48
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors one-model speculative decoding to add configurable LM head gather output, cache draft-to-target vocab mapping (d2t) on workers, unify draft token sampling and acceptance through new base methods, and introduce fail-closed rejection-sampling buffer validation. It also adds draft vocab size computation, updated config validation, developer documentation, and rejection-sampling tests across Eagle3, MTP, PARD, DFlash, and DraftTarget workers.

Changes

Rejection sampling and unified draft sampling refactor

Layer / File(s) Summary
LM head gather output config
tensorrt_llm/_torch/model_config.py, tensorrt_llm/_torch/models/modeling_utils.py, tensorrt_llm/_torch/models/modeling_speculative.py
Adds lm_head_gather_output field to ModelConfig, wires it into LMHead construction, and disables it for draft no-spec configs.
Rejection buffer contract and draft vocab sizing
tensorrt_llm/_torch/speculative/interface.py, tensorrt_llm/_torch/speculative/utils.py
Refactors SpecMetadata buffer allocation with slot-indexed scratch rows and conditional full_draft_probs, updates sampling scan, and computes draft_vocab_size for all metadata constructors.
Worker base d2t caching and unified sampling/acceptance
tensorrt_llm/_torch/speculative/interface.py, tensorrt_llm/_torch/models/modeling_speculative.py
Adds set_draft_model/_d2t caching, introduces _rejection_buffers_valid fail-closed guard, and rewrites sample_draft_tokens/greedy/advanced sampling paths.
Per-worker integration
tensorrt_llm/_torch/speculative/eagle3.py, eagle3_dynamic_tree.py, mtp.py, pard.py, dflash.py, draft_target.py
Wires each worker's forward loop to reset_draft_probs_valid_for_capture, sample_draft_tokens, and compare_and_accept, removing legacy TP-gather argmax helpers.
Speculative config validation
tensorrt_llm/llmapi/llm_args.py
Adds mode-aware rejection sampling compatibility checks and FlashInfer availability validation.
Developer guide and tests
tensorrt_llm/_torch/speculative/SPEC_DEVELOPER_GUIDE.md, tests/unittest/_torch/speculative/*, tests/integration/test_lists/test-db/l0_h100.yml
Adds developer documentation and rejection-sampling tests for buffers, guards, and end-to-end DFlash/DraftTarget/MTP/PARD flows.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Init as SpecDecOneEngineForCausalLM
  participant Worker as SpecWorkerBase
  participant Metadata as SpecMetadata
  participant Guard as RejectionBufferGuard

  Init->>Worker: set_draft_model(draft_model)
  Worker->>Worker: cache self._d2t
  Worker->>Metadata: sample_draft_tokens(logits, spec_metadata)
  Metadata->>Metadata: prepare_rejection_sampling_buffers()
  Worker->>Worker: greedy or advanced sample_draft, scatter draft_probs
  Worker->>Guard: validate buffers before acceptance
  Guard-->>Worker: valid or invalid
  alt buffers invalid
    Worker->>Worker: fallback to strict acceptance, clear draft_probs_valid
  else buffers valid
    Worker->>Worker: compare_and_accept via rejection sampling
  end
Loading

Possibly related PRs

  • NVIDIA/TensorRT-LLM#14745: Both PRs modify one-model speculative decoding's all-greedy fast-path plumbing around SpecMetadata.is_all_greedy_sample, used for CUDA-graph dispatch and now also for gating rejection sampling behavior.

Suggested reviewers: syuoni, mikeiovine, xinhe-nv, jieli-matrix, yuxianq

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required ticket[type] pattern and clearly summarizes the main change.
Description check ✅ Passed The description includes the required sections and gives a clear summary of the change, tests, and checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
tensorrt_llm/_torch/speculative/interface.py (1)

526-564: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add return annotations to the new helper methods.

Several newly added helpers omit return types, which lets Any leak through the central speculative-decoding path. As per coding guidelines, “Always annotate functions. Make the return type None if the function does not return anything.”

Also applies to: 1233-1366, 1368-1414, 1574-1799

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/speculative/interface.py` around lines 526 - 564, The new
helper methods in the speculative interface are missing explicit return type
annotations, which can leak Any into the decoding path. Add return annotations
of None to the relevant no-return helpers, including
prepare_rejection_sampling_buffers and prepare, and apply the same rule to the
other newly added helper methods in this area. Keep the signatures consistent
with the existing class methods in interface.py so the type checker can infer
the flow correctly.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/speculative/draft_target.py`:
- Around line 264-271: The final-cycle flag in draft token sampling is using the
configured maximum instead of the actual runtime length, which prevents
finalization when the draft length is shortened. Update the
`sample_draft_tokens()` loop in `DraftTarget` so `is_last_draft_cycle` is
computed from `runtime_draft_len` rather than `self.max_draft_len`, ensuring the
last iteration correctly marks `draft_probs_valid` when the dynamic draft length
is reached.

In `@tensorrt_llm/_torch/speculative/eagle3.py`:
- Around line 874-879: The Eagle3 draft loop in sample_draft_tokens() is using
stale draft probability state because spec_metadata.draft_probs_valid is not
reset before capturing new draft distributions. Update the drafting path around
the runtime_draft_len loop to clear spec_metadata.draft_probs_valid before the
first call to sample_draft_tokens(), matching the other one-model workers, so
each acceptance step only trusts probabilities from the current capture.

In `@tensorrt_llm/_torch/speculative/interface.py`:
- Around line 1249-1261: `maybe_gather_sharded_draft_logits()` currently avoids
gathering for attention-DP batches even when the ADP + LM-head-TP path produces
sharded draft logits, so `advanced_sample_draft()` can sample from only part of
the vocab. Update the sharded-logit detection and gather path so ADP batches
with LM-head TP are included, and make sure the TP gather logic threads
`mapping_lm_head_tp` through instead of falling back to `None`. Adjust the
relevant calls in `maybe_gather_sharded_draft_logits()`,
`advanced_sample_draft()`, and the greedy TP-gather branch to use the correct
mapping for LM-head TP logits.

In `@tensorrt_llm/_torch/speculative/mtp.py`:
- Around line 477-482: The final-draft-step check in `sample_draft_tokens` is
using the full `draft_model.mtp_layers` length, which breaks when
`runtime_draft_len` is shorter and leaves `draft_probs_valid` unset. Update the
loop in `mtp.py` so the `is_last_draft_cycle` argument is based on
`runtime_draft_len` (for example, by comparing `i` against the last captured
draft index) rather than `len(draft_model.mtp_layers) - 1`, ensuring the last
executed draft step is correctly marked for dynamic draft lengths.

In `@tensorrt_llm/_torch/speculative/pard.py`:
- Around line 334-340: The `_reshape_draft_tokens_for_accept` helper currently
reshapes the full `spec_metadata.draft_tokens` buffer to `(0, K)` when `num_gens
== 0`, which can fail for preallocated non-empty buffers. Update the `num_gens
== 0` path in `_reshape_draft_tokens_for_accept` to return an explicit empty
view/slice of `spec_metadata.draft_tokens` with shape `(0, K)` instead of
reshaping the entire buffer, while keeping the existing slicing logic for the
non-empty case.

In `@tensorrt_llm/_torch/speculative/utils.py`:
- Around line 55-68: The config parsing helper in the vocab-size lookup
currently uses a blanket exception handler, which hides unrelated bugs and
triggers the lint warning. In the function that reads config.json and returns
the vocab size, narrow the except block to only the expected failure cases from
file access, JSON parsing, and converting the value to int, while keeping the
existing fallback to target_vocab_size for those cases only.

In `@tests/unittest/_torch/speculative/hw_agnostic/test_dflash.py`:
- Around line 107-134: Add the high-memory test marker to
test_dflash_qwen3_8b_rejection so it is classified with the other CUDA-intensive
speculative rejection tests. Update the test definition in test_dflash.py by
applying the same `@pytest.mark.high_cuda_memory` decoration pattern used
elsewhere in this file or neighboring hw_agnostic speculative tests, keeping the
function name and behavior unchanged.

---

Nitpick comments:
In `@tensorrt_llm/_torch/speculative/interface.py`:
- Around line 526-564: The new helper methods in the speculative interface are
missing explicit return type annotations, which can leak Any into the decoding
path. Add return annotations of None to the relevant no-return helpers,
including prepare_rejection_sampling_buffers and prepare, and apply the same
rule to the other newly added helper methods in this area. Keep the signatures
consistent with the existing class methods in interface.py so the type checker
can infer the flow correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7e95ecf6-d6fe-4685-ba0d-0b4d766b1a5d

📥 Commits

Reviewing files that changed from the base of the PR and between 0044d5b and fcd785a.

📒 Files selected for processing (19)
  • tensorrt_llm/_torch/model_config.py
  • tensorrt_llm/_torch/models/modeling_speculative.py
  • tensorrt_llm/_torch/models/modeling_utils.py
  • tensorrt_llm/_torch/speculative/SPEC_DEVELOPER_GUIDE.md
  • tensorrt_llm/_torch/speculative/dflash.py
  • tensorrt_llm/_torch/speculative/draft_target.py
  • tensorrt_llm/_torch/speculative/eagle3.py
  • tensorrt_llm/_torch/speculative/eagle3_dynamic_tree.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tensorrt_llm/_torch/speculative/mtp.py
  • tensorrt_llm/_torch/speculative/pard.py
  • tensorrt_llm/_torch/speculative/utils.py
  • tensorrt_llm/llmapi/llm_args.py
  • tests/integration/test_lists/test-db/l0_h100.yml
  • tests/unittest/_torch/speculative/hw_agnostic/test_dflash.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_draft_target.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_mtp.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_pard.py
  • tests/unittest/_torch/speculative/test_rejection_buffers_guard.py

Comment thread tensorrt_llm/_torch/speculative/draft_target.py Outdated
Comment thread tensorrt_llm/_torch/speculative/eagle3.py Outdated
Comment thread tensorrt_llm/_torch/speculative/interface.py Outdated
Comment thread tensorrt_llm/_torch/speculative/mtp.py Outdated
Comment thread tensorrt_llm/_torch/speculative/pard.py Outdated
Comment thread tensorrt_llm/_torch/speculative/utils.py
Comment thread tests/unittest/_torch/speculative/hw_agnostic/test_dflash.py
@zhaoyangwang-nvidia zhaoyangwang-nvidia force-pushed the rejection-one-model-spec branch from fbd3d2b to 24c911e Compare July 6, 2026 12:25
@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

Hi @NVIDIA/trt-llm-llmapi-devs @NVIDIA/trt-llm-torch-devs @NVIDIA/trt-llm-torch-models-devs please help to review this PR, thanks a lot.

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57760 [ run ] triggered by Bot. Commit: 24c911e Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57760 [ run ] completed with state SUCCESS. Commit: 24c911e
/LLM/main/L0_MergeRequest_PR pipeline #46464 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Comment thread tensorrt_llm/_torch/speculative/interface.py Outdated
Comment thread tensorrt_llm/_torch/speculative/interface.py Outdated
Comment thread tensorrt_llm/_torch/speculative/eagle3.py
Comment thread tensorrt_llm/_torch/speculative/utils.py Outdated
@zhaoyangwang-nvidia zhaoyangwang-nvidia force-pushed the rejection-one-model-spec branch from 0b4b479 to cb8bac0 Compare July 9, 2026 01:53
…xt slots

Block workers (PARD/DFlash) do not draft context requests (they get a zero
placeholder token), leaving their slot-indexed draft_probs rows unwritten.
When such a request became a generation request the next iteration, rejection
acceptance would read a stale row, which was previously guarded by forcing
draft_probs_valid=False for block mixed batches.

Fill each context request's slot row with a one-hot placeholder distribution
(prob 1.0 at draft-vocab token id 0) at the worker's placeholder-assembly
point, so the row is a legal distribution: rejection rejects the placeholder
(target_prob(0) ~ 0) and resamples from the target residual, equivalent to
strict acceptance. Extracted into SpecWorkerBase.write_context_onehot_draft_probs
and shared by PARD and DFlash. This lets block mixed batches keep
draft_probs_valid=True (drop the num_contexts==0 clause).

Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
With one-model rejection sampling and dynamic draft length, runtime_draft_len
is batch-global and can toggle K->0->K as batch size fluctuates. On the 0
iteration every gen request goes through skip_drafting, producing no draft
tokens and never scattering draft_probs. The next K iteration then runs
rejection acceptance (its branch frozen in the captured CUDA graph, so a
Python flag reset cannot redirect it) reading the stale draft_probs rows
paired with padded-zero draft tokens, silently corrupting output.

Mirror the draft-token zero-padding: mark such gen requests host-side in
_handle_dynamic_draft_len (pre-pad, current_num_draft_tokens == 0), collect
their slots in _prepare_tp_inputs, and eagerly write a one-hot placeholder
distribution (draft-vocab token id 0) into their draft_probs rows after
spec_metadata.prepare(). The eager write into the stable draft_probs buffer is
read by the replayed rejection kernel, which then rejects the placeholder and
resamples from the target -- equivalent to strict acceptance. Idempotent with
the context-slot one-hot; no-op when rejection is off.

Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
The draft_probs_valid producer->consumer flag is now redundant: every slot the
rejection acceptance reads is guaranteed to hold a legal distribution written by
the request's immediately-preceding step. Context slots in block workers are
one-hot'd by write_context_onehot_draft_probs; dynamic-draft-len zero-toggle
padding slots by write_padding_onehot_draft_probs; all-greedy and pure-context
batches are already excluded by is_all_greedy_sample and the num_gens>0 guard;
CUDA-graph warmup only touches the dummy scratch row (real slots are written by
each request's own context/gen forward before any rejection reads them).

Delete the field, its term in _can_use_rejection_sampling, the fail-closed
assignment, reset_draft_probs_valid_for_capture and its five callers, the
set in sample_draft_tokens (and the now-dead is_last_draft_cycle parameter),
and _invalidate_draft_probs_after_capture. _can_use_rejection_sampling now
reduces to `use_rejection_sampling and not is_all_greedy_sample`, matching the
dynamic-tree worker's own gate. The _rejection_buffers_valid shape guard is
retained. Drop the obsolete warmup-flag test; update the dispatch tests.

Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
@zhaoyangwang-nvidia zhaoyangwang-nvidia force-pushed the rejection-one-model-spec branch from 84bee1a to 0b59abc Compare July 15, 2026 02:42
…n sampling

NGram and SA are retrieval-based drafters that emit only draft token ids
with no per-token proposal distribution q(x). Rejection sampling needs q
to form min(1, p/q) and the (p - q)+ residual, so both are gated. Document
the reason on SuffixAutomatonManager and in the validate_speculative_config
support whitelist.

Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59343 [ run ] triggered by Bot. Commit: a004f30 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59343 [ run ] completed with state SUCCESS. Commit: a004f30
/LLM/main/L0_MergeRequest_PR pipeline #47823 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59411 [ run ] triggered by Bot. Commit: a004f30 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59411 [ run ] completed with state SUCCESS. Commit: a004f30
/LLM/main/L0_MergeRequest_PR pipeline #47882 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

get_spec_worker holds the correct Mapping but never passed it to the MTP
workers: MTPEagleWorker hardcoded super().__init__(mapping=None) and
MTPWorker read the unreliable model_config.mapping (None for the MTP
worker). With the draft LM head kept vocab-sharded (lm_head_gather_output
=False), a None mapping made greedy_sample_draft_with_tp_gather skip the
TP argmax gather, so each rank argmaxed its own vocab shard, drafting
divergent tokens and desyncing the ranks into a PyExecutor hang under
plain TP + overlap scheduler (repro: DeepSeek-V3-Lite fp8 tp4 mtp_nextn=2
cuda_graph+overlap+torch_compile).

Thread mapping from get_spec_worker into MTPWorker and MTPEagleWorker,
matching every other one-model worker. Verified tp4 output is now
byte-identical to the origin/main baseline.

Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59450 [ run ] triggered by Bot. Commit: 96b73b6 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59450 [ run ] completed with state SUCCESS. Commit: 96b73b6
/LLM/main/L0_MergeRequest_PR pipeline #47918 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59566 [ run ] triggered by Bot. Commit: 96b73b6 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59566 [ run ] completed with state SUCCESS. Commit: 96b73b6
/LLM/main/L0_MergeRequest_PR pipeline #48011 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

Under attention DP each rank is data-parallel and owns a distinct set of
requests, so the draft logits must not be gathered across ranks -- a
per-rank argmax on the rank own logits is the correct proposal. The
ADP + LM-head-TP path wrongly classified its vocab-sharded draft logits
as needing the TP gather, splicing in an allgather over ranks that hold
different token counts. That desynced the ranks and crashed in the
DeepEP MoE dispatch (intranode.cu unspecified launch failure) / hung the
cuda-graph batch-padding allgather (repro: DeepSeek-V3-Lite tp4 ep4
mtp_nextn=3 attention_dp + enable_lm_head_tp_in_adp, matching CI
TestDeepSeekR1 test_nvfp4_multi_gpus[latency_adp_lmtp_tp4]).

Make _draft_logits_are_sharded return False for any attention-DP mode so
greedy takes a plain argmax and the advanced path skips the gather,
matching the pre-rework behavior. Remove the now-unreachable ADP+LM-head-TP
gather branches. Verified: ADP+LMTP tp4 ep4 and plain-TP tp4 both produce
correct output byte-matching the baseline.

Signed-off-by: ZhaoyangWang <zhaoyangw@nvidia.com>
@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59593 [ run ] triggered by Bot. Commit: f4334c9 Link to invocation

@yufeiwu-nv yufeiwu-nv removed their request for review July 16, 2026 06:46
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59593 [ run ] completed with state SUCCESS. Commit: f4334c9
/LLM/main/L0_MergeRequest_PR pipeline #48036 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59652 [ run ] triggered by Bot. Commit: f4334c9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #59652 [ run ] completed with state SUCCESS. Commit: f4334c9
/LLM/main/L0_MergeRequest_PR pipeline #48087 completed with status: 'SUCCESS'

CI Report

Link to invocation

@zhaoyangwang-nvidia zhaoyangwang-nvidia merged commit 4277d15 into NVIDIA:main Jul 16, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-compatible Accepted LLM API contract change that is backwards-compatible

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants