Repository navigation
Conversation
lminer
force-pushed
the
feat/batched-logits-processor-pytorch
branch
2 times, most recently
from
October 26, 2026 18:39
b1b8ed3 to
a22ad08
Compare
…ckend LLM accepts batched_logits_processor and SamplingParams has apply_batched_logits_processor, but nothing on the PyTorch backend read either: the batched processor was never called, and the flag was dropped when the executor request was built. The engine's logits post-processor walk now collects the logits rows, token ids, request ids and client ids of every scheduled request that set the flag and hands them to the LLM's batched processor in one call per step, after each request's own processors have run. The rows are views into the step's logits tensor, viewed as [beam_width, 1, vocab] like the per-request processors see them, so in-place edits land; under beam search they are the live beams and their histories. The flag travels with the request across pipeline stages like the per-request processors do, keeps the request on the eager sampling tier, and is refused at submission when the LLM has no batched processor. Signed-off-by: Luke Miner <luke@audioshake.ai>
lminer
force-pushed
the
feat/batched-logits-processor-pytorch
branch
from
October 26, 2026 19:44
a22ad08 to
11790e7
Compare
Owner
Author
|
Opened upstream as NVIDIA#21044; this fork copy served for review. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
LLM(batched_logits_processor=...)andSamplingParams(apply_batched_logits_processor=True)are both accepted on the PyTorch backend, but neither does anything there: nothing under_torch/pyexecutorreads the LLM field, and the request flag is dropped when the executor request is built. The batched processor was a TensorRT-backend feature that was never wired into the PyTorch executor, and the docs still present it as available.This PR makes the PyTorch backend honor both, with the existing public API unchanged:
DecoderRunner._execute_logit_post_processorsalready walks the scheduled requests and hands each one's logits rows to its ownlogits_processor(s). It now also collects the rows, token ids, request ids and client ids of every request that setapply_batched_logits_processor, and hands them to the LLM's batched processor in one call per step, after the walk. Eachlogitsentry is the request's rows viewed as[beam_width, 1, vocab], the shape the per-request processors see, and a view into the step's logits tensor, so in-place edits land. Under beam search the rows are the live beams and the token ids are each beam's own history ([#19902][fix] Give logits processors each beam's hypothesis under beam search NVIDIA/TensorRT-LLM#20915). The row offsets, the context-chunk skip and the vocabulary-sharded spec-worker gather are the ones the per-request path already uses.PyExecutorregistersllm_args.batched_logits_processorwith the model engine, the same way the beam-history and in-graph sampling hooks are registered.BaseWorker, kept onLlmRequestaspy_apply_batched_logits_processor, and crosses pipeline stages with the other Python-only request attributes.LLM.generaterefuses the flag when the LLM has no batched processor, instead of silently generating without it.PyExecutorraises at construction when a processor is given but the model engine has no post-processor walk to attach it to, rather than serving requests that asked for processing nothing would run. A flagged request that still reaches a walk with nothing registered (only throughPyExecutordirectly) is left unprocessed with a one-time warning rather than failing the whole step.BatchedLogitsProcessor.__call__typesstream_ptrasOptional[int]: on the PyTorch backend it is the CUDA stream the logits live on, orNonewhen they are not on a CUDA device (CPU unit tests). The API-stability reference is updated accordingly.Two things are deliberately unchanged. Under a vocabulary-sharded spec worker the walk hands processors a gathered copy of the logits, which the per-request path already did; the worker's acceptance ran inside the forward and processors get a read-only view there (
SpecWorkerBase.target_logits), so nothing is written back, and the docs now say that such edits do not reach the sampled tokens. And the walk's row stride under speculative decoding is the per-request path's existing one; this PR does not change which rows a request's processors see. The[beam_width, 1, vocab]view of a request's rows is now built once in the walk and handed to both the per-request processors and the batched list.docs/source/features/sampling.mdgains a short section on the batched processor; theSamplingParamsandBatchedLogitsProcessordocstrings say when it is called and what it receives.Per-request processors run first and the batched one after them, so the batched processor sees their edits. Nothing changes for requests that do not set the flag, or when the LLM has no batched processor.
Test Coverage
tests/unittest/_torch/executor/test_batched_logits_processor.py(new, CPU only): one call per step in scheduling order with views into the step's logits; per-request processors before the batched one; live beam rows and beam histories; an unfinished context chunk is skipped; nothing is called without opted-in requests; a flagged request without a registered processor is skipped with a one-time warning; beam histories start for batched-only requests; the vocabulary-sharded gather runs for a batched-only request; the flag is refused without an LLM processor.tests/unittest/_torch/sampler/test_in_graph_sampling.py: a request with the flag demotes the batch to the FULL tier.tests/unittest/_torch/executor/test_request_utils.py: the flag is collected and attached like the other Python-only request attributes.tests/unittest/llmapi/test_llm_pytorch.py::test_tinyllama_batched_logits_processor(GPU): two prompts, one opted in; the opted-in one is forced to the biased token, the other is not.There is no GPU here that runs
main, so the GPU checks ran on one L4 with this change ported onto therelease:1.4.0rc1image (together with NVIDIA#20915, which that tag predates); the runner file is laid out differently there, so the port differs in placement, not in logic. Onmainitself the change is lint- and type-checked, so CI is the first GPU run of this exact code.Results on that image:
test_batched_logits_processor.pywith the changedtest_in_graph_sampling.pyandtest_request_utils.pycases: 59 passed (the vocabulary-sharded cases aremain-only and were not ported). On the stock image the 8 new cases all fail.ValueErroron an LLM without a batched processor. On the stock image the opted-in requests come back unforced and the flag is accepted silently.test_beam_search.py+test_whisper_suppress_tokens_processor.py: 322 passed, 4 skipped; the 12 errors are the same environment errors as on the stock image.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-compatibleorapi-breaking. Forapi-breaking, includeBREAKINGin 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.