Skip to content

[None][feat] MTP one-model advanced_sampling_mode: skip redundant top-k / top-p filter kernels with additional config enum#16561

Open
jhaotingc wants to merge 1 commit into
NVIDIA:mainfrom
jhaotingc:qwen36-temponly
Open

[None][feat] MTP one-model advanced_sampling_mode: skip redundant top-k / top-p filter kernels with additional config enum#16561
jhaotingc wants to merge 1 commit into
NVIDIA:mainfrom
jhaotingc:qwen36-temponly

Conversation

@jhaotingc

@jhaotingc jhaotingc commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Description

For one-model speculative decoding (MTP-Eagle one-model), the advanced sampler runs
flashinfer's top-k mask (RadixTopKMaskLogits) and top-p renorm (AirTopPRenorm*)
kernels on every draft layer and the target verification — even when the
deployment's requests disable those filters (top_k=0, top_p=1). In that case the
filters are mathematical no-ops (top-k mask at k=vocab, top-p renorm at p=1), but
the kernels still launch: measured at ~290 µs (top-k mask) + ~1.34 ms (top-p
renorm) per decode step at draft_len=3 (nsys, Qwen3.6-35B-A3B-NVFP4, B200). For
fixed-config / temperature-only deployments this is pure overhead.

Add a deploy-time advanced_sampling_mode enum on DecodingBaseConfig (available
to any speculative config; default FULL) that tells the one-model sampler which
filters the deployment disables, so their flashinfer kernels are skipped:

mode top-k kernel top-p kernel
FULL (default) run run
NO_TOPK skip run
NO_TOPP run skip
NO_TOPK_NO_TOPP skip skip (pure temperature softmax)
pareto_qwen36_rejsamp_adv_modes_four_way

Design:

  • Single source of truth. AdvancedSamplingMode.skips_top_k / .skips_top_p
    properties are the only place the mode→filter mapping lives. The enum is carried
    end-to-end: pydantic parses the YAML/JSON string into the enum on the config,
    SpecMetadata stores the enum, and there are no bare-string predicates downstream.
  • Resolve once on the spec side. resolve_advanced_sampling_filters(mode, top_k, top_p) returns effective tensors with a disabled filter set to None, so the
    sampler/prob ops stay mode-agnostic.
  • Unified sampler. sample_from_logits_op(logits, temperatures, top_k, top_p, seed, offset) (mirroring compute_probs_from_logits_op) is the single one-model sampler:
    a None top_k skips the mask kernel; a None top_p samples via
    sampling_from_probs instead of top_p_sampling_from_probs. The rejection path's
    compute_probs_from_logits skips the top-k mask / top-p renorm identically.
  • Native greedy — no guard. Greedy rows carry a sentinel temperature
    (DISABLE_TEMP_VAL) set in _scan_one_model_sampling, so softmax(logits / DISABLE_TEMP_VAL) collapses to a one-hot at the argmax and sampling returns the
    argmax token. Every mode therefore supports mixed greedy + sampling batches with no
    special-case error.
  • No extra graphs. advanced_sampling_mode is a deploy-time setting and is not
    part of the CUDA-graph key.
  • Lossless. When a skipped filter is already disabled (e.g. NO_TOPK with
    top_k=0), the probs — and therefore the sampled tokens and rejection acceptance —
    are bit-for-bit identical to FULL; only the kernel launch is removed.
  • Not gated on rejection sampling. All four modes are valid with
    use_rejection_sampling on or off; the two are independent.

Benchmark

Qwen3.6-35B-A3B-NVFP4, TRT-LLM (1×TP1, MTP draft_len=3), B200, rejection sampling ON,
SPEED-Bench low-entropy (ISL≈2197, OSL=1024, temp=0.7), prefix-cache OFF. Values are
OTPS/gpu (output tok/s/gpu). Plot: plots/pareto_rejection_conc.png.

conc FULL — top_k=20, top_p=0.95, temp=0.7 FULL — temp only (top_k=0, top_p=1) NO_TOPK_NO_TOPP — temp only Speedup*
1 599.1 559.5 714.2 1.28×
2 1058.4 1052.0 1237.1 1.18×
4 1840.6 1547.9 1932.2 1.25×
8 2750.7 2874.2 3158.9 1.10×
16 4267.6 4196.3 4539.2 1.08×
32 6010.7 6014.1 6506.9 1.08×
64 8142.7 8061.2 9059.6 1.12×
128 10610.8 10599.0 11884.9 1.12×
256 13540.6 13709.0 15386.7 1.12×

* Speedup = NO_TOPK_NO_TOPP / FULL (temp only) — same sampling config
(top_k=0, top_p=1), isolating the effect of skipping the two filter kernels.
Acceptance length is unchanged across all rows, confirming identical sampling behavior.
FULL with real top_k=20 / top_p=0.95 is shown as a reference for the actual
filtered-sampling throughput.

Result: for a temperature-only deployment, NO_TOPK_NO_TOPP gives a consistent
~8–28% throughput gain (≈+12% at high concurrency) at zero accuracy cost, by
removing the two redundant per-draft-layer filter kernels.

Test coverage

tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py
(12 cases, all passing on B200):

  • Config contract — enum values {full, no_topk, no_topp, no_topk_no_topp} and the
    skips_top_k / skips_top_p properties; the field lives on DecodingBaseConfig
    (default FULL); all four modes construct with or without use_rejection_sampling
    (no gating).
  • Mode resolutionresolve_advanced_sampling_filters sets the disabled filter to
    None per mode (full→neither, no_topk→top_k, no_topp→top_p,
    no_topk_no_topp→both) and passes kept filters through unchanged.
  • Bit-for-bit equivalence (CUDA)NO_TOPK via sample_from_logits_op yields the
    exact same tokens as FULL when top_k is disabled, for the same seed/offset, across
    top_p ∈ {1.0, 0.9} (the top_k mask is a no-op at k=vocab).
  • Native greedy (CUDA) — a greedy row (sentinel temperature) in a mixed batch
    returns its argmax token under NO_TOPK and NO_TOPK_NO_TOPP, validating the
    guard-free design.
  • Spec-path acceptance — non-FULL modes construct on any spec-decoding path
    (config-time acceptance; unsupported paths fall back to FULL behavior at runtime).

Telemetry manifest / CODEOWNERS

Because this adds a new DecodingBaseConfig field, tensorrt_llm/usage/llm_args_golden_manifest.json
is regenerated via scripts/generate_llm_args_golden_manifest.py (adds
speculative_config.advanced_sampling_mode, kind: categorical). The manifest
--check CI gate passes. Touching the usage-telemetry path requires approval from
@NVIDIA/trt-llm-usage-telemetry-devs, @NVIDIA/trt-llm-oss-compliance, and
@NVIDIA/trt-llm-noncommitted-api-review-committee. The new field is additive with
default FULL (API-compatible).

Note — alternative design

Instead of a deploy-time setting that changes which sampler the single advanced CUDA
graph captures, each mode could be a separately captured CUDA graph selected at
replay by a graph key — the same mechanism is_all_greedy_sample already uses to switch
between the greedy (argmax) and advanced-sampling graphs. That would allow per-batch
mode switching, but it multiplies the number of captured decode graphs (one set per
mode) and lengthens warmup. We chose the deploy-time enum (0 extra graphs) because the
sampling config is fixed per deployment, which is the target use case.

Test Coverage

tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py
(11 cases, all passing on B200):

  • Config contract — enum values {full, no_topk, no_topp, no_topk_no_topp};
    NO_TOPK is accepted without rejection sampling; NO_TOPP and
    NO_TOPK_NO_TOPP raise a ValidationError unless use_rejection_sampling=True
    (and are accepted with it).
  • Filter-skip plumbing — for each mode, compute_probs_from_logits passes
    top_k=None and/or top_p=None into the flashinfer op (checked with a spy),
    so the right kernel is skipped: full→neither, no_topk→top_k,
    no_topp→top_p, no_topk_no_topp→both.
  • Bit-for-bit equivalence (CUDA)sampling_batch_spec_dec_one_model in
    NO_TOPK yields the exact same tokens as FULL when top_k is disabled, for the
    same seed/offset, across top_p ∈ {1.0, 0.9, 0.5} (the top_k mask is a no-op
    at k=vocab). Skipped on CPU-only CI.

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.

Summary by CodeRabbit

  • New Features

    • Added deploy-time AdvancedSamplingMode for one-model MTP speculative decoding, exposed as DecodingBaseConfig.advanced_sampling_mode (default FULL) and plumbed via SpecMetadata.
    • Modes:
      • FULL — apply both top-k and top-p filters
      • NO_TOPK — skip top-k filtering
      • NO_TOPP — skip top-p renormalization
      • NO_TOPK_NO_TOPP — skip both filters
    • Implemented CUDA-graph-friendly kernel skipping by resolving disabled filters to None:
      • resolve_advanced_sampling_filters(...) converts (advanced_sampling_mode, top_k, top_p) into effective optional tensors where disabled filters become None
      • updated sampling code to conditionally skip FlashInfer filtering kernels when the corresponding optional tensor is None
    • Added a CUDA-graph-compatible sampler sample_from_logits_op(...):
      • always computes softmax
      • applies top-k masking only if top_k is provided
      • performs top-p sampling only if top_p is provided
    • Wired mode behavior across speculative paths:
      • updated one-model speculative draft sampling (rejection and non-rejection) to resolve effective top_k/top_p from SpecMetadata.advanced_sampling_mode
      • updated dynamic-tree token sampling to use sample_from_logits_op(...) for non-greedy target token sampling
  • Tests

    • Added tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py covering:
      • enum string values and skips_top_k / skips_top_p flags
      • defaults and construction on DecodingBaseConfig / MTPDecodingConfig
      • resolve_advanced_sampling_filters(...) identity vs disabled-to-None behavior
      • CUDA-only bit-for-bit expectations (e.g., NO_TOPK matches FULL when top_k is disabled)
      • greedy-row behavior via sentinel-temperature argmax handling
      • acceptance of non-FULL modes across speculative/spec paths (including removal of the prior “one-model-only” gate)
    • Regenerated tensorrt_llm/usage/llm_args_golden_manifest.json to add speculative_config.advanced_sampling_mode as a categorical argument.
  • Docs / Config

    • Documented “Advanced sampling mode (speculative decoding)” in docs/source/features/sampling.md, including semantics, deploy-time behavior (not in CUDA-graph key), independence from rejection sampling, and a usage example.

Dev Engineer Review

  • Correctness & API consistency

    • Mode-to-filter behavior is centralized in resolve_advanced_sampling_filters(...) and consistently threaded into:
      • speculative draft probability computation (compute_probs_from_logits)
      • speculative draft/target token sampling call sites (rejection + non-rejection)
      • dynamic-tree sampling for non-greedy paths
    • Treating disabled top_k/top_p as None aligns with the stated goal: redundant FlashInfer kernels can be skipped while keeping mathematical no-op behavior when filters are disabled.
    • Greedy-row handling is designed to work via a sentinel temperature mechanism without extra special-casing guards.
  • CUDA-graph / keying

    • advanced_sampling_mode is excluded from the CUDA-graph key; functional selection is driven by resolved optional filter tensors (None vs provided tensors), matching the intended graph-stability requirement.
  • Config / manifest

    • AdvancedSamplingMode added to tensorrt_llm/llmapi/llm_args.py and defaulted to FULL on DecodingBaseConfig.
    • tensorrt_llm/usage/llm_args_golden_manifest.json updated to include speculative_config.advanced_sampling_mode with allowed values: full, no_topk, no_topp, no_topk_no_topp.

QA Engineer Review

Test changes

  • Touched: tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py
  • Added test coverage
    • Enum behavior (AdvancedSamplingMode values and skip flags)
    • Defaulting/config acceptance (DecodingBaseConfig, MTPDecodingConfig, independent of rejection sampling)
    • Filter resolution (resolve_advanced_sampling_filters maps disabled inputs to None)
    • CUDA-only sampler equivalence (bit-for-bit match when filters are mathematically no-ops)
    • Greedy-row correctness (argmax behavior for no_topk / no_topk_no_topp)
    • Speculative path acceptance (non-FULL modes allowed and stored)
  • Integration test-list coverage (tests/integration/test_lists/): not indicated in the provided context.
  • Verdict: needs follow-up

@jhaotingc jhaotingc changed the title Qwen36 temponly [None][feat] MTP one-model advanced_sampling_mode: skip redundant top-k / top-p filter kernels with additional config enum Jul 20, 2026
@jhaotingc jhaotingc added the api-compatible Accepted LLM API contract change that is backwards-compatible label Jul 20, 2026
@jhaotingc
jhaotingc marked this pull request as ready for review July 20, 2026 21:15
@jhaotingc
jhaotingc requested a review from a team as a code owner July 20, 2026 21:15
@jhaotingc
jhaotingc requested review from cascade812 and lori-ren July 20, 2026 21:15
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds deploy-time advanced sampling modes for MTP one-model speculative decoding, propagates the selected mode through metadata and sampling paths, conditionally skips top-k/top-p filtering, and adds validation tests and documentation.

Changes

Advanced sampling modes

Layer / File(s) Summary
Sampling mode configuration and metadata
tensorrt_llm/llmapi/llm_args.py, tensorrt_llm/_torch/speculative/utils.py, tensorrt_llm/usage/llm_args_golden_manifest.json
Defines four sampling modes, adds the public configuration field, and transfers the selected mode into Eagle3 one-model metadata and the args manifest.
Mode-specific probability and token sampling
tensorrt_llm/_torch/pyexecutor/sampler/sampling_utils.py
Allows disabled top-k/top-p filters to be represented by None and adds a CUDA-graph-compatible sampler.
Speculative decoding integration
tensorrt_llm/_torch/speculative/interface.py, tensorrt_llm/_torch/speculative/eagle3_dynamic_tree.py
Propagates effective filters through draft, rejection, block, batch, and dynamic-tree sampling paths.
Advanced sampling validation and documentation
tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py, docs/source/features/sampling.md
Covers mode properties, configuration, filter resolution, sampling equivalence, greedy rows, and supported modes.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MTPDecodingConfig
  participant SpecMetadata
  participant SpeculativeInterface
  participant sampling_utils
  participant FlashInfer
  MTPDecodingConfig->>SpecMetadata: configure advanced_sampling_mode
  SpecMetadata->>SpeculativeInterface: provide mode for speculative sampling
  SpeculativeInterface->>sampling_utils: resolve effective top_k and top_p
  sampling_utils-->>SpeculativeInterface: return filters or None
  SpeculativeInterface->>sampling_utils: sample draft tokens or compute rejection probabilities
  sampling_utils->>FlashInfer: apply enabled sampling kernels
  FlashInfer-->>sampling_utils: return probabilities or token IDs
  sampling_utils-->>SpeculativeInterface: return sampling results
Loading

Possibly related PRs

  • NVIDIA/TensorRT-LLM#12062: Changes the EAGLE3 dynamic-tree speculative sampling path that this PR now routes through sample_from_logits_op.

Suggested reviewers: cascade812, arysef, chang-l, qijune, lori-ren

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 94.74% which is sufficient. The required threshold is 80.00%.
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.
Title check ✅ Passed The title is specific, concise, and accurately summarizes the main feature change.
Description check ✅ Passed The description includes the required Description, Test Coverage, and PR Checklist sections with substantial detail.
✨ 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: 4

🧹 Nitpick comments (3)
tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py (2)

39-53: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exercise rejection-disabled behavior explicitly.

Lines 41 and 49 rely on the default for use_rejection_sampling; set it to False so the tests directly prove both sides of the contract.

Proposed test adjustment
-    cfg = MTPDecodingConfig(max_draft_len=1, advanced_sampling_mode="no_topk")
+    cfg = MTPDecodingConfig(
+        max_draft_len=1,
+        advanced_sampling_mode="no_topk",
+        use_rejection_sampling=False,
+    )
...
-        MTPDecodingConfig(max_draft_len=1, advanced_sampling_mode=mode)
+        MTPDecodingConfig(
+            max_draft_len=1,
+            advanced_sampling_mode=mode,
+            use_rejection_sampling=False,
+        )

As per path instructions, coverage in tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py needs direct validation of the configured behavior.

🤖 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 `@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`
around lines 39 - 53, Update both MTPDecodingConfig constructions in
test_no_topk_does_not_require_rejection and
test_topp_disabling_modes_require_rejection to explicitly pass
use_rejection_sampling=False for the rejection-disabled cases, while keeping the
existing rejection-enabled configuration unchanged.

Source: Path instructions


90-125: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover NO_TOPK rejection of greedy requests.

This only tests temperature 0.7. Add a case at or below GREEDY_TEMPERATURE_THRESHOLD that asserts the NO_TOPK request-validation path rejects it, plus a just-above-threshold success case.

Based on PR objectives, NO_TOPK disallows greedy requests. As per path instructions, coverage in tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py is insufficient for that contract.

🤖 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 `@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`
around lines 90 - 125, Extend test_no_topk_matches_full_bit_for_bit or add a
focused test covering NO_TOPK temperature validation. Use temperatures at or
below GREEDY_TEMPERATURE_THRESHOLD to assert the NO_TOPK request is rejected,
and just above the threshold to assert it succeeds. Reuse
sampling_batch_spec_dec_one_model and the existing test setup symbols, while
preserving the current bit-for-bit comparison coverage.

Source: Path instructions

tensorrt_llm/llmapi/llm_args.py (1)

2484-2504: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add the validator return annotation.

_log_advanced_sampling_mode should declare -> "MTPDecodingConfig".

🤖 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/llmapi/llm_args.py` around lines 2484 - 2504, The
_log_advanced_sampling_mode validator is missing its return annotation. Update
that method signature to declare -> "MTPDecodingConfig", preserving its existing
validation logic and return self behavior.

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/pyexecutor/sampler/sampling_utils.py`:
- Around line 890-897: Update the advanced_sampling_mode branch in the direct
sampling path to use compute_probs_from_logits with the selected mode, then
sample via sampling_from_probs_op instead of always calling
top_p_sampling_from_probs_op. Ensure both NO_TOPP and NO_TOPK_NO_TOPP bypass
top_p filtering while preserving the existing temperature, seed, and offset
behavior.

In `@tensorrt_llm/_torch/speculative/interface.py`:
- Around line 830-846: Initialize and update self.has_greedy_requests while
scanning per-request sampling parameters, ensuring it reflects any greedy row in
mixed batches. Apply the existing mixed-batch rejection to every non-FULL
advanced sampling mode, including no_topk and no_topk_no_topp, while preserving
the all-greedy and warmup-dummy exemptions.

In `@tensorrt_llm/llmapi/llm_args.py`:
- Around line 2475-2482: Validate advanced_sampling_mode after the final
spec-decoding mode is determined, accepting non-FULL values only for the
MTP-Eagle one-model branch. Reject unsupported non-FULL modes for vanilla and
two-model MTP instead of silently ignoring them, while preserving FULL as the
default and existing metadata behavior.

In
`@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`:
- Line 30: Add complete type annotations to every function in this test module,
including all test functions and the spy helper: annotate each parameter with
its precise type and use -> None for functions that do not return a value.
Update the functions represented by test_advanced_sampling_mode_enum_values and
the other referenced test/spy definitions without changing their behavior.

---

Nitpick comments:
In `@tensorrt_llm/llmapi/llm_args.py`:
- Around line 2484-2504: The _log_advanced_sampling_mode validator is missing
its return annotation. Update that method signature to declare ->
"MTPDecodingConfig", preserving its existing validation logic and return self
behavior.

In
`@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`:
- Around line 39-53: Update both MTPDecodingConfig constructions in
test_no_topk_does_not_require_rejection and
test_topp_disabling_modes_require_rejection to explicitly pass
use_rejection_sampling=False for the rejection-disabled cases, while keeping the
existing rejection-enabled configuration unchanged.
- Around line 90-125: Extend test_no_topk_matches_full_bit_for_bit or add a
focused test covering NO_TOPK temperature validation. Use temperatures at or
below GREEDY_TEMPERATURE_THRESHOLD to assert the NO_TOPK request is rejected,
and just above the threshold to assert it succeeds. Reuse
sampling_batch_spec_dec_one_model and the existing test setup symbols, while
preserving the current bit-for-bit comparison coverage.
🪄 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: 87e95728-f8e1-4129-8afa-df75e9e6ff80

📥 Commits

Reviewing files that changed from the base of the PR and between b520c6f and 6c7f810.

📒 Files selected for processing (5)
  • tensorrt_llm/_torch/pyexecutor/sampler/sampling_utils.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tensorrt_llm/_torch/speculative/utils.py
  • tensorrt_llm/llmapi/llm_args.py
  • tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py

Comment thread tensorrt_llm/_torch/pyexecutor/sampler/sampling_utils.py Outdated
Comment thread tensorrt_llm/_torch/speculative/interface.py Outdated
Comment thread tensorrt_llm/llmapi/llm_args.py Outdated
from tensorrt_llm.llmapi.llm_args import AdvancedSamplingMode, MTPDecodingConfig


def test_advanced_sampling_mode_enum_values():

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add required annotations to every function.

All test functions and spy lack parameter and return annotations. Add precise parameter types and -> None for tests.

As per coding guidelines, “Annotate every function.”

Also applies to: 39-39, 46-46, 65-67, 71-74, 90-90

🤖 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 `@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`
at line 30, Add complete type annotations to every function in this test module,
including all test functions and the spy helper: annotate each parameter with
its precise type and use -> None for functions that do not return a value.
Update the functions represented by test_advanced_sampling_mode_enum_values and
the other referenced test/spy definitions without changing their behavior.

Source: Coding guidelines

# no-op at k=vocab) so tokens match "full" bit-for-bit, avoiding any RNG discrepancy.
logits = vanilla.safely_apply_temperature_inplace(logits, temperatures)
probs = torch.softmax(logits, dim=-1)
return top_p_sampling_from_probs_op(probs, top_p, seed=seed, offset=offset)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please following compute_probs_from_logits_op, add a sample_from_logits_op; resolve advanced_sampling_mode once on the speculative side and call it directly, removing the sampling_batch_spec_dec_one_model wrapper layer.


@torch.compile(options={"max-autotune": True})
def sample_from_logits_op(
    logits: torch.Tensor,
    temperatures: torch.Tensor,
    top_k: Optional[torch.Tensor] = None,
    top_p: Optional[torch.Tensor] = None,
    seed: Optional[torch.Tensor] = None,
    offset: Optional[torch.Tensor] = None,
) -> torch.Tensor:
    if top_k is not None:
        logits = flashinfer.sampling.top_k_mask_logits(logits, top_k)
    probs = flashinfer.sampling.softmax(
        logits, temperatures, enable_pdl=get_env_enable_pdl())
    if top_p is not None:
        return flashinfer.sampling.top_p_sampling_from_probs(
            probs, top_p, seed=seed, offset=offset)
    return flashinfer.sampling.sampling_from_probs(probs, seed=seed, offset=offset)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@zhaoyangwang-nvidia I was having concern the minute diff when user turn on no_topp for non-rejection path.

In your suggestion, if user decide to turn on no_topp and pass in top_p 1.0, the kernel will be SamplingFromProbKernel instead of TopPSamplingFromProbKernel. The two kernels handle sorting differently.

Before #15775 where it removes drafter sampling for default case, the diff is more significant. So I disabled no_topp use case when rejection sampling False to make it consistent. The no_rejection sampling path is already having TopP kernel, switching to sampling from prob does not help much because 1 kernel still needs to run. The rejection path already has TopK/TopP added by you so I reused the same logic for no_topk_no_topp.

If you're ok with the behavior changes for turning on no_topp in no_rejection path, now that draft step sampling is removed, I'm ok with it as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Also, another reason of not able to discard this function is this line. This line makes ALL full path having one GREEDY result calculated and one sampled result calculated, just to make sure we take care of when temperatures <= vanilla.GREEDY_TEMPERATURE_THRESHOLD

Using this function, you suggested changes the behavior completely, and the same issue isn't considered in #15775

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

#15542 seems to add this greedy & advanced together, is this intended? should this be kept?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sorry for the late reply — timezone difference on my side.

Both behavior differences you raised are valid observations:

SamplingFromProbKernel vs TopPSamplingFromProbKernel producing different tokens for the same distribution when no_topp is enabled;
the greedy rows no longer going through an explicit argmax + torch.where selection, but instead being handled natively via the DISABLE_TEMP_VAL sentinel temperature.
That said, I'd argue both are correct behaviors that differ only by floating-point accumulation order / kernel implementation details, not accuracy bugs. In case 1, top_p=1.0 means no filtering, so any properly implemented sampling kernel is a valid realization of the same distribution. In case 2, softmax(logits / DISABLE_TEMP_VAL) collapses to a one-hot at the argmax, so sampling from it returns the argmax token — the greedy semantics are preserved.

Do you have any real cases where these differences caused an actual accuracy problem (e.g., a measurable eval-score regression, or a rejection-rate change)? If so, let's discuss further and I'm happy to reconsider. If not, I'd prefer to keep the code simple and unified — one mode-agnostic sampling op with the filters resolved once on the speculative side — rather than maintaining separate paths just for bit-for-bit token equivalence, which we don't guarantee across versions anyway.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thank you! Changed to what's suggested on comment, will click resolve before merge.

# would be sampled instead of argmax'd. All-greedy batches use the greedy graph; warmup
# dummies are exempted above.
if (self.advanced_sampling_mode != "full"
and not self.is_all_greedy_sample and self.has_greedy_requests):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please following how the rejection path handles greedy rows when computing draft/target probs (the sentinel-temperature approach — greedy rows carry DISABLE_TEMP_VAL, so softmax(logits / DISABLE_TEMP_VAL) collapses to a one-hot at the argmax and sampling from it returns the argmax token), the no_topk fast path could support greedy rows natively as well, which would eliminate this mixed-batch check and error.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+1, no need to ValueError here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

remove all constraint, now the no_topk/no_topp will apply to no rejection sampling (the target sampling only) if pre-set.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Launching sweeps to verify perf.

Comment thread tensorrt_llm/llmapi/llm_args.py Outdated
"Token ID marking end of thinking phase. Strict acceptance resumes after this."
)

advanced_sampling_mode: AdvancedSamplingMode = Field(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please update document in docs/source/features/sampling.md

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done

# Whether to use rejection sampling for one-model speculative decoding.
use_rejection_sampling: bool = False
# Advanced-sampling specialization (deploy-time; from MTPDecodingConfig.advanced_sampling_mode).
advanced_sampling_mode: str = "full"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AdvancedSamplingMode is defined as an enum in llm_args.py, but everything downstream degrades to bare strings, and the "which modes skip top_k" predicate in ("no_topk", "no_topk_no_topp") is duplicated across sampling_utils.py (twice) and this file with nothing keeping the literals in sync as the enum evolves. Consider a single source of truth — e.g. properties on the enum (mode.skips_top_k / mode.skips_top_p) or derived boolean fields on SpecMetadata — so consumers read a boolean instead of each parsing the string. (non-blocking)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Made all field to be enum instead of str, only pass in str in extra-llm-api-config.yml from user.

@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator

Hi @mikeiovine Please take a look at this PR — it adds advanced_sampling_mode to skip the top-k / top-p filter kernels for temperature-only deployments. Any comments on this implementation approach?

@mikeiovine mikeiovine left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think the optimization makes sense but I'm a bit worried about the API. As you point out in the description, we could make it more usable by capturing more graphs, but that's going to make the warmup too long and is not sustainable.

At least the default is FULL. This should be considered an optimization for advanced use cases IMO

Comment thread tensorrt_llm/llmapi/llm_args.py Outdated
"Token ID marking end of thinking phase. Strict acceptance resumes after this."
)

advanced_sampling_mode: AdvancedSamplingMode = Field(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should be part of the base config

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Moved to base config

Comment thread tensorrt_llm/llmapi/llm_args.py Outdated
Comment on lines +5247 to +5248
and not self.speculative_config.spec_dec_mode.
is_mtp_eagle_one_model()):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You can delete this. I am removing MTP one model mode

# would be sampled instead of argmax'd. All-greedy batches use the greedy graph; warmup
# dummies are exempted above.
if (self.advanced_sampling_mode != "full"
and not self.is_all_greedy_sample and self.has_greedy_requests):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

+1, no need to ValueError here

jhaotingc added a commit to jhaotingc/TensorRT-LLM that referenced this pull request Jul 21, 2026
Address PR NVIDIA#16561 reviewer feedback (zhaoyangwang-nvidia, mikeiovine):

- Add sample_from_logits_op (mirrors compute_probs_from_logits_op) and resolve
  advanced_sampling_mode once on the speculative side via
  resolve_advanced_sampling_filters; remove the sampling_batch_spec_dec_one_model
  wrapper layer. Callers pass effective (top_k/top_p) tensors, None when the mode
  disables that filter, so the ops stay mode-agnostic.
- Handle greedy rows natively via the sentinel temperature (temperature-scaled
  softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches. Remove the mixed-batch ValueError guard and the
  has_greedy_requests tracking in _scan_one_model_sampling.
- Move advanced_sampling_mode + its validator from MTPDecodingConfig to
  DecodingBaseConfig (available to any speculative config). Add
  AdvancedSamplingMode.skips_top_k / .skips_top_p as the single source of truth
  for the filter-skip predicate (replaces duplicated string literals).
- Delete the MTP-one-model spec-mode gate: non-FULL modes now construct on any
  spec path and fall back to FULL behavior where unsupported, rather than raising.
- Migrate eagle3_dynamic_tree to the unified sample_from_logits_op.
- Document advanced_sampling_mode in docs/source/features/sampling.md.
- Update unit tests: enum skip properties, resolve_advanced_sampling_filters,
  NO_TOPK == FULL bit-for-bit via the unified op, native greedy argmax on mixed
  batches, and base-config acceptance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
@jhaotingc
jhaotingc requested a review from a team as a code owner July 21, 2026 23:22
@jhaotingc
jhaotingc requested review from arysef and chang-l July 21, 2026 23:22
jhaotingc added a commit to jhaotingc/TensorRT-LLM that referenced this pull request Jul 22, 2026
Address PR NVIDIA#16561 reviewer feedback (zhaoyangwang-nvidia, mikeiovine):

- Add sample_from_logits_op (mirrors compute_probs_from_logits_op) and resolve
  advanced_sampling_mode once on the speculative side via
  resolve_advanced_sampling_filters; remove the sampling_batch_spec_dec_one_model
  wrapper layer. Callers pass effective (top_k/top_p) tensors, None when the mode
  disables that filter, so the ops stay mode-agnostic.
- Handle greedy rows natively via the sentinel temperature (temperature-scaled
  softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches. Remove the mixed-batch ValueError guard and the
  has_greedy_requests tracking in _scan_one_model_sampling.
- Move advanced_sampling_mode + its validator from MTPDecodingConfig to
  DecodingBaseConfig (available to any speculative config). Add
  AdvancedSamplingMode.skips_top_k / .skips_top_p as the single source of truth
  for the filter-skip predicate (replaces duplicated string literals).
- Delete the MTP-one-model spec-mode gate: non-FULL modes now construct on any
  spec path and fall back to FULL behavior where unsupported, rather than raising.
- Migrate eagle3_dynamic_tree to the unified sample_from_logits_op.
- Document advanced_sampling_mode in docs/source/features/sampling.md.
- Update unit tests: enum skip properties, resolve_advanced_sampling_filters,
  NO_TOPK == FULL bit-for-bit via the unified op, native greedy argmax on mixed
  batches, and base-config acceptance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator

Since this adds a new field to DecodingBaseConfig, per the repo policy for LLM args / nested-config changes, please run python3 scripts/generate_llm_args_golden_manifest.py and commit the updated tensorrt_llm/usage/llm_args_golden_manifest.json — the manifest currently doesn't include advanced_sampling_mode, which will fail CI. Also note that new config fields require approval from the telemetry/privacy CODEOWNERs.

@zhaoyangwang-nvidia

Copy link
Copy Markdown
Collaborator

@NVIDIA/trt-llm-doc-owners Please help to review this PR, thanks~

jhaotingc added a commit to jhaotingc/TensorRT-LLM that referenced this pull request Jul 22, 2026
Address PR NVIDIA#16561 reviewer feedback (zhaoyangwang-nvidia, mikeiovine):

- Add sample_from_logits_op (mirrors compute_probs_from_logits_op) and resolve
  advanced_sampling_mode once on the speculative side via
  resolve_advanced_sampling_filters; remove the sampling_batch_spec_dec_one_model
  wrapper layer. Callers pass effective (top_k/top_p) tensors, None when the mode
  disables that filter, so the ops stay mode-agnostic.
- Handle greedy rows natively via the sentinel temperature (temperature-scaled
  softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches. Remove the mixed-batch ValueError guard and the
  has_greedy_requests tracking in _scan_one_model_sampling.
- Move advanced_sampling_mode + its validator from MTPDecodingConfig to
  DecodingBaseConfig (available to any speculative config). Add
  AdvancedSamplingMode.skips_top_k / .skips_top_p as the single source of truth
  for the filter-skip predicate (replaces duplicated string literals).
- Delete the MTP-one-model spec-mode gate: non-FULL modes now construct on any
  spec path and fall back to FULL behavior where unsupported, rather than raising.
- Migrate eagle3_dynamic_tree to the unified sample_from_logits_op.
- Document advanced_sampling_mode in docs/source/features/sampling.md.
- Update unit tests: enum skip properties, resolve_advanced_sampling_filters,
  NO_TOPK == FULL bit-for-bit via the unified op, native greedy argmax on mixed
  batches, and base-config acceptance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
jhaotingc added a commit to jhaotingc/TensorRT-LLM that referenced this pull request Jul 22, 2026
Address PR NVIDIA#16561 reviewer feedback (zhaoyangwang-nvidia, mikeiovine):

- Add sample_from_logits_op (mirrors compute_probs_from_logits_op) and resolve
  advanced_sampling_mode once on the speculative side via
  resolve_advanced_sampling_filters; remove the sampling_batch_spec_dec_one_model
  wrapper layer. Callers pass effective (top_k/top_p) tensors, None when the mode
  disables that filter, so the ops stay mode-agnostic.
- Handle greedy rows natively via the sentinel temperature (temperature-scaled
  softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches. Remove the mixed-batch ValueError guard and the
  has_greedy_requests tracking in _scan_one_model_sampling.
- Move advanced_sampling_mode + its validator from MTPDecodingConfig to
  DecodingBaseConfig (available to any speculative config). Add
  AdvancedSamplingMode.skips_top_k / .skips_top_p as the single source of truth
  for the filter-skip predicate (replaces duplicated string literals).
- Delete the MTP-one-model spec-mode gate: non-FULL modes now construct on any
  spec path and fall back to FULL behavior where unsupported, rather than raising.
- Migrate eagle3_dynamic_tree to the unified sample_from_logits_op.
- Document advanced_sampling_mode in docs/source/features/sampling.md.
- Update unit tests: enum skip properties, resolve_advanced_sampling_filters,
  NO_TOPK == FULL bit-for-bit via the unified op, native greedy argmax on mixed
  batches, and base-config acceptance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
@jhaotingc

Copy link
Copy Markdown
Collaborator Author

/bot run

@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.

🧹 Nitpick comments (2)
tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py (2)

31-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a snake_case local variable.

M is a local variable; rename it to a descriptive snake_case name.

🤖 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 `@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`
at line 31, Rename the local variable M assigned to AdvancedSamplingMode to a
descriptive snake_case name, and update all references to it within the relevant
test scope.

Source: Coding guidelines


143-155: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy lift

Exercise the speculative paths claimed by this test.

This only constructs one MTPDecodingConfig; it does not invoke draft, rejection, block, batch, or dynamic-tree sampling. Add path-level coverage, or narrow the test name/docstring to config construction.

🤖 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 `@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`
around lines 143 - 155, Expand test_advanced_mode_accepted_on_all_spec_paths to
exercise each claimed speculative sampling path, including draft, rejection,
block, batch, and dynamic-tree handling, using the configured
advanced_sampling_mode. If those paths cannot be covered here, rename the test
and revise its docstring to describe only MTPDecodingConfig construction rather
than all speculative paths.
🤖 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.

Nitpick comments:
In
`@tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`:
- Line 31: Rename the local variable M assigned to AdvancedSamplingMode to a
descriptive snake_case name, and update all references to it within the relevant
test scope.
- Around line 143-155: Expand test_advanced_mode_accepted_on_all_spec_paths to
exercise each claimed speculative sampling path, including draft, rejection,
block, batch, and dynamic-tree handling, using the configured
advanced_sampling_mode. If those paths cannot be covered here, rename the test
and revise its docstring to describe only MTPDecodingConfig construction rather
than all speculative paths.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: cb0870b5-8034-46fd-bb19-e2c4118be7c3

📥 Commits

Reviewing files that changed from the base of the PR and between 07e84a7 and 3d53d8a.

📒 Files selected for processing (8)
  • docs/source/features/sampling.md
  • tensorrt_llm/_torch/pyexecutor/sampler/sampling_utils.py
  • tensorrt_llm/_torch/speculative/eagle3_dynamic_tree.py
  • tensorrt_llm/_torch/speculative/interface.py
  • tensorrt_llm/_torch/speculative/utils.py
  • tensorrt_llm/llmapi/llm_args.py
  • tensorrt_llm/usage/llm_args_golden_manifest.json
  • tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • docs/source/features/sampling.md
  • tensorrt_llm/_torch/speculative/utils.py
  • tensorrt_llm/usage/llm_args_golden_manifest.json
  • tensorrt_llm/_torch/speculative/eagle3_dynamic_tree.py
  • tensorrt_llm/llmapi/llm_args.py
  • tensorrt_llm/_torch/pyexecutor/sampler/sampling_utils.py
  • tensorrt_llm/_torch/speculative/interface.py

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61082 [ run ] triggered by Bot. Commit: 3d53d8a Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61082 [ run ] completed with state FAILURE. Commit: 3d53d8a
/LLM/main/L0_MergeRequest_PR pipeline #49336 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

jhaotingc added a commit to jhaotingc/TensorRT-LLM that referenced this pull request Jul 23, 2026
Address PR NVIDIA#16561 reviewer feedback (zhaoyangwang-nvidia, mikeiovine):

- Add sample_from_logits_op (mirrors compute_probs_from_logits_op) and resolve
  advanced_sampling_mode once on the speculative side via
  resolve_advanced_sampling_filters; remove the sampling_batch_spec_dec_one_model
  wrapper layer. Callers pass effective (top_k/top_p) tensors, None when the mode
  disables that filter, so the ops stay mode-agnostic.
- Handle greedy rows natively via the sentinel temperature (temperature-scaled
  softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches. Remove the mixed-batch ValueError guard and the
  has_greedy_requests tracking in _scan_one_model_sampling.
- Move advanced_sampling_mode + its validator from MTPDecodingConfig to
  DecodingBaseConfig (available to any speculative config). Add
  AdvancedSamplingMode.skips_top_k / .skips_top_p as the single source of truth
  for the filter-skip predicate (replaces duplicated string literals).
- Delete the MTP-one-model spec-mode gate: non-FULL modes now construct on any
  spec path and fall back to FULL behavior where unsupported, rather than raising.
- Migrate eagle3_dynamic_tree to the unified sample_from_logits_op.
- Document advanced_sampling_mode in docs/source/features/sampling.md.
- Update unit tests: enum skip properties, resolve_advanced_sampling_filters,
  NO_TOPK == FULL bit-for-bit via the unified op, native greedy argmax on mixed
  batches, and base-config acceptance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
@jhaotingc

Copy link
Copy Markdown
Collaborator Author

/bot run

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61400 [ run ] triggered by Bot. Commit: 4e1349c Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61400 [ run ] completed with state SUCCESS. Commit: 4e1349c
/LLM/main/L0_MergeRequest_PR pipeline #49626 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

jhaotingc added a commit to jhaotingc/TensorRT-LLM that referenced this pull request Jul 24, 2026
Address PR NVIDIA#16561 reviewer feedback (zhaoyangwang-nvidia, mikeiovine):

- Add sample_from_logits_op (mirrors compute_probs_from_logits_op) and resolve
  advanced_sampling_mode once on the speculative side via
  resolve_advanced_sampling_filters; remove the sampling_batch_spec_dec_one_model
  wrapper layer. Callers pass effective (top_k/top_p) tensors, None when the mode
  disables that filter, so the ops stay mode-agnostic.
- Handle greedy rows natively via the sentinel temperature (temperature-scaled
  softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches. Remove the mixed-batch ValueError guard and the
  has_greedy_requests tracking in _scan_one_model_sampling.
- Move advanced_sampling_mode + its validator from MTPDecodingConfig to
  DecodingBaseConfig (available to any speculative config). Add
  AdvancedSamplingMode.skips_top_k / .skips_top_p as the single source of truth
  for the filter-skip predicate (replaces duplicated string literals).
- Delete the MTP-one-model spec-mode gate: non-FULL modes now construct on any
  spec path and fall back to FULL behavior where unsupported, rather than raising.
- Migrate eagle3_dynamic_tree to the unified sample_from_logits_op.
- Document advanced_sampling_mode in docs/source/features/sampling.md.
- Update unit tests: enum skip properties, resolve_advanced_sampling_filters,
  NO_TOPK == FULL bit-for-bit via the unified op, native greedy argmax on mixed
  batches, and base-config acceptance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
@jhaotingc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

1 similar comment
@jhaotingc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@github-actions

Copy link
Copy Markdown

⚠️ Bot command ignored: The /bot command must appear at the very beginning of the comment (no leading blank lines or spaces). Please post a new comment with /bot as the first character.

@jhaotingc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61443 [ run ] triggered by Bot. Commit: a49a3cb Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61443 [ run ] completed with state SUCCESS. Commit: a49a3cb
/LLM/main/L0_MergeRequest_PR pipeline #49665 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

jhaotingc added a commit to jhaotingc/TensorRT-LLM that referenced this pull request Jul 24, 2026
Address PR NVIDIA#16561 reviewer feedback (zhaoyangwang-nvidia, mikeiovine):

- Add sample_from_logits_op (mirrors compute_probs_from_logits_op) and resolve
  advanced_sampling_mode once on the speculative side via
  resolve_advanced_sampling_filters; remove the sampling_batch_spec_dec_one_model
  wrapper layer. Callers pass effective (top_k/top_p) tensors, None when the mode
  disables that filter, so the ops stay mode-agnostic.
- Handle greedy rows natively via the sentinel temperature (temperature-scaled
  softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches. Remove the mixed-batch ValueError guard and the
  has_greedy_requests tracking in _scan_one_model_sampling.
- Move advanced_sampling_mode + its validator from MTPDecodingConfig to
  DecodingBaseConfig (available to any speculative config). Add
  AdvancedSamplingMode.skips_top_k / .skips_top_p as the single source of truth
  for the filter-skip predicate (replaces duplicated string literals).
- Delete the MTP-one-model spec-mode gate: non-FULL modes now construct on any
  spec path and fall back to FULL behavior where unsupported, rather than raising.
- Migrate eagle3_dynamic_tree to the unified sample_from_logits_op.
- Document advanced_sampling_mode in docs/source/features/sampling.md.
- Update unit tests: enum skip properties, resolve_advanced_sampling_filters,
  NO_TOPK == FULL bit-for-bit via the unified op, native greedy argmax on mixed
  batches, and base-config acceptance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
@jhaotingc
jhaotingc force-pushed the qwen36-temponly branch 2 times, most recently from d831d6b to 00dd072 Compare July 24, 2026 18:18
@jhaotingc

Copy link
Copy Markdown
Collaborator Author

Hi @Tabrizian @zhaoyangwang-nvidia would you mind review the sampling_util one model sampling there again? due to #16590
We're fixing the same thing.

Thank you!

@jhaotingc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61626 [ run ] triggered by Bot. Commit: 57c90ff Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61626 [ run ] completed with state SUCCESS. Commit: 57c90ff
/LLM/main/L0_MergeRequest_PR pipeline #49832 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

…els in the one-model speculative sampler

Add a deploy-time `advanced_sampling_mode` enum on `DecodingBaseConfig` (default
FULL) that lets the one-model speculative sampler skip flashinfer's top-k mask and
top-p renorm kernels when the deployment disables those filters. When a skipped
filter is already disabled the output matches FULL bit-for-bit, so this is a
lossless throughput optimization for fixed-config / temperature-only deployments
(measured ~8-28% OTPS/gpu gain on Qwen3.6-35B-A3B-NVFP4, B200, MTP draft_len=3).

- Enum end-to-end: `AdvancedSamplingMode.skips_top_k` / `.skips_top_p` are the
  single source of truth; pydantic parses the config string into the enum,
  `SpecMetadata` carries it, and `resolve_advanced_sampling_filters` resolves it
  once on the speculative side so the ops stay mode-agnostic.
- Unified sampler: `sample_from_logits_op` (top_k mask -> softmax -> top_p sample
  / plain sample) replaces the `sampling_batch_spec_dec_one_model` wrapper; a
  `None` top_k / top_p skips that filter's kernel.
- Greedy rows are handled natively via the `DISABLE_TEMP_VAL` sentinel temperature
  (softmax collapses to a one-hot argmax), so any mode supports mixed greedy +
  sampling batches with no special-case guard.
- All modes work with `use_rejection_sampling` on or off; the two are independent.
- Regenerated `tensorrt_llm/usage/llm_args_golden_manifest.json`
  (adds `speculative_config.advanced_sampling_mode`).
- Unit tests in
  `tests/unittest/_torch/speculative/hw_agnostic/test_advanced_sampling_mode.py`
  and docs in `docs/source/features/sampling.md`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jhao-Ting Chen <jhaotingc@nvidia.com>
@jhaotingc

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #61672 [ run ] triggered by Bot. Commit: 64cee60 Link to invocation

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.

4 participants