Repository navigation
[None][feat] Call LLM(batched_logits_processor=...) on the PyTorch backend #21044
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c454552
7c7d97a
5432d1f
e7fd46d
61533c4
a112d8c
23b70e0
2385d88
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -835,6 +835,10 @@ def __init__( | |
| **kwargs): | ||
| self.py_logits_post_processors = kwargs.pop("py_logits_post_processors", | ||
| None) | ||
| # SamplingParams.apply_batched_logits_processor: the engine hands this | ||
| # request's logits to LLM(batched_logits_processor=...) each step. | ||
| self.py_apply_batched_logits_processor: bool = kwargs.pop( | ||
| "py_apply_batched_logits_processor", False) | ||
|
Comment on lines
+840
to
+841
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Copy the batched-processor flag to child requests. When
|
||
| # Owned entirely on the Python side: the TorchSampler is the only | ||
| # consumer, so the C++ request no longer carries a copy. | ||
| self.py_embedding_bias: Optional[torch.Tensor] = kwargs.pop( | ||
|
|
@@ -1384,6 +1388,8 @@ def create_child_request(self, child_id: int) -> None: | |
| py_logits_post_processors=(self.py_logits_post_processors.copy() | ||
| if self.py_logits_post_processors | ||
| is not None else None), | ||
| py_apply_batched_logits_processor=self. | ||
| py_apply_batched_logits_processor, | ||
| py_multimodal_data=deepcopy(self.py_multimodal_data), | ||
| encoder_input_features=self.py_encoder_input_features, | ||
| ) | ||
|
|
@@ -1847,6 +1853,7 @@ def executor_request_to_llm_request( | |
| exclude_input_from_output, | ||
| guided_decoding_params=executor_request.guided_decoding_params, | ||
| py_logits_post_processors=inputs.logits_post_processors, | ||
| py_apply_batched_logits_processor=inputs.apply_batched_logits_processor, | ||
| encoder_input_tokens=executor_request.encoder_input_token_ids, | ||
| encoder_input_features=encoder_input_features, | ||
| encoder_output_len=encoder_output_len, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -147,6 +147,7 @@ def greedy_tokens_usable(request: LlmRequest) -> bool: | |
| and not request.py_return_log_probs | ||
| and not request.py_return_generation_logits | ||
| and not request.py_logits_post_processors | ||
| and not request.py_apply_batched_logits_processor | ||
| and request.py_guided_decoding_params is None | ||
| and not check_stop_words_length(request) | ||
| and request_row_params(request).mode is SamplingMode.GREEDY | ||
|
|
@@ -929,14 +930,17 @@ def _request_bypasses_in_graph_sampling(request: LlmRequest) -> bool: | |
|
|
||
| The hook runs at the tail of the forward, before anything the executor | ||
| does to the logits afterwards: the guided-decoding bitmask applied by | ||
| ``guided_decoder.execute()``, and the user's own logits processors run | ||
| by ``_execute_logit_post_processors``. Both happen once | ||
| ``guided_decoder.execute()``, and the user's own logits processors | ||
| (per request, or the LLM's batched one) run by | ||
| ``_execute_logit_post_processors``. Both happen once | ||
| ``_forward_step`` has returned, so sampling in-graph would read unmasked | ||
| logits and emit a token they were meant to forbid, while their output is | ||
| discarded. Any future post-forward logits mutator belongs here too. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Heads-up for the runner.py conflict with #20306: main added
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| """ | ||
| return request.py_guided_decoding_params is not None or bool( | ||
| getattr(request, "py_logits_post_processors", None) | ||
| return ( | ||
| request.py_guided_decoding_params is not None | ||
| or bool(getattr(request, "py_logits_post_processors", None)) | ||
| or bool(getattr(request, "py_apply_batched_logits_processor", False)) | ||
| ) | ||
|
|
||
| def get_sample_type(self, requests: list[LlmRequest]) -> SampleType: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check at L1011 does not catch a non-last prefill chunk. During chunked prefill
get_tokens(0)is already the whole prompt, sopy_orig_prompt_len == len(token_ids[0]), and the request is handed over with its chunk's last-position row, which the sampler drops. Running the head walk on CPU with such a request calls the batched processor for it. The TRT backend only passedisLastContextChunk()requests, andtest_an_unfinished_context_chunk_is_not_handed_overpasses only because it setsorig_prompt_lenbelow the token count. Skipnot request.is_last_context_chunktoo?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 2ea2c72: the walk also skips
not request.is_last_context_chunk. The test now covers both reasons (middle chunk; prompt shorter than the tokens) and checks that the last chunk's row still reaches the processor at its own offset. The per-request processors share the walk, so they get the fix too.