Repository navigation
Dynamic-fork scheduling, Medusa/MTP spec decode, and InternVL resize for HPD-Parsing (based on v0.17.1) #48715
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
Open
wwwjjjj
wants to merge
18
commits into
vllm-project:main
Choose a base branch
from
wwwjjjj:HPD
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
9a474ce
[XPU] bump vllm-xpu-kernels to v0.1.3 (#35984)
jikunshang fa78ec8
[Bugfix] Fix Qwen-VL tokenizer implementation (#36140)
DarkLight1337 b7a423c
[BUGFIX]Fix Qwen-Omni models audio max_token_per_item estimation erro…
jjmiao1 e346c08
[Release] Include source distribution (sdist) in PyPI uploads (#35136)
dougbtv b31e932
Bound openai to under 2.25.0
khluu 244b922
[Bugfix] Fix passing of activation_type to trtllm fused MoE NVFP4 and…
amitz-nv f45d010
Fix/resupport nongated fused moe triton (#36412)
shaunkotek ab43e37
Fix: Re-Enable EP for trtllm MoE FP8 backend (#36494)
amirkl94 46fa044
[BUGFIX][Mamba][Qwen3.5] Zero freed SSM cache blocks on GPU (#35219)
vadiklyutiy 8e39d39
add nemotron v3 reasoning parser (#36393)
shaunkotek bc46be5
Revert "add nemotron v3 reasoning parser (#36393)"
khluu 6da1310
[Bug] Fix TRTLLM Block FP8 MoE Monolithic (#36296)
wzhao18 5bec0b0
[DSV3.2][MTP] Optimize Indexer MTP handling (#36723)
benchislett 1ff2393
[ci] Bound nvidia-cudnn-frontend version (#36719)
khluu c9b1e97
add nemotron v3 reasoning parser (#36393)
shaunkotek 95c0f92
[NemotronH] Small fix reasoning parser (#36635)
roikoren755 e7deb53
wjj modifications for HPD on vLLM v0.17.1 (baseline snapshot)
wwwjjjj 27a7adf
remove debug
wwwjjjj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # SPDX-FileCopyrightText: Copyright contributors to the vLLM project | ||
|
|
||
| from typing import TypedDict | ||
|
|
||
| import pytest | ||
| import regex as re | ||
|
|
||
| from tests.reasoning.utils import run_reasoning_extraction | ||
| from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest | ||
| from vllm.reasoning import ReasoningParser, ReasoningParserManager | ||
|
|
||
| parser_name = "nemotron_v3" | ||
|
|
||
|
|
||
| class ReasoningCase(TypedDict): | ||
| output: str | ||
| reasoning: str | None | ||
| content: str | None | ||
|
|
||
|
|
||
| class FakeNemotronTokenizer: | ||
| def __init__(self): | ||
| self._vocab = { | ||
| "<think>": 1, | ||
| "</think>": 2, | ||
| } | ||
| self._pattern = re.compile(r"(<think>|</think>)") | ||
|
|
||
| def get_vocab(self) -> dict[str, int]: | ||
| return self._vocab | ||
|
|
||
| def tokenize(self, text: str) -> list[str]: | ||
| tokens: list[str] = [] | ||
| for part in self._pattern.split(text): | ||
| if part: | ||
| tokens.append(part) | ||
| return tokens | ||
|
|
||
| def convert_tokens_to_string(self, tokens: list[str]) -> str: | ||
| return "".join(tokens) | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def tokenizer(): | ||
| return FakeNemotronTokenizer() | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "streaming,param_dict", | ||
| [ | ||
| pytest.param( | ||
| False, | ||
| { | ||
| "output": "This is a reasoning section</think>This is the rest", | ||
| "reasoning": "This is a reasoning section", | ||
| "content": "This is the rest", | ||
| }, | ||
| id="without_start_token", | ||
| ), | ||
| pytest.param( | ||
| True, | ||
| { | ||
| "output": "This is a reasoning section</think>This is the rest", | ||
| "reasoning": "This is a reasoning section", | ||
| "content": "This is the rest", | ||
| }, | ||
| id="without_start_token_streaming", | ||
| ), | ||
| pytest.param( | ||
| False, | ||
| { | ||
| "output": "<think>This is a reasoning section</think>This is the rest", | ||
| "reasoning": "This is a reasoning section", | ||
| "content": "This is the rest", | ||
| }, | ||
| id="with_start_token", | ||
| ), | ||
| pytest.param( | ||
| True, | ||
| { | ||
| "output": "<think>This is a reasoning section</think>This is the rest", | ||
| "reasoning": "This is a reasoning section", | ||
| "content": "This is the rest", | ||
| }, | ||
| id="with_start_token_streaming", | ||
| ), | ||
| ], | ||
| ) | ||
| def test_nemotron_v3_reasoning( | ||
| tokenizer: FakeNemotronTokenizer, | ||
| streaming: bool, | ||
| param_dict: ReasoningCase, | ||
| ): | ||
| output = tokenizer.tokenize(param_dict["output"]) | ||
| model_output = [tokenizer.convert_tokens_to_string([token]) for token in output] | ||
| parser: ReasoningParser = ReasoningParserManager.get_reasoning_parser(parser_name)( | ||
| tokenizer | ||
| ) | ||
|
|
||
| reasoning, content = run_reasoning_extraction( | ||
| parser, model_output, streaming=streaming | ||
| ) | ||
|
|
||
| assert reasoning == param_dict["reasoning"] | ||
| assert content == param_dict["content"] | ||
|
|
||
|
|
||
| def test_nemotron_v3_without_thinking_returns_content( | ||
| tokenizer: FakeNemotronTokenizer, | ||
| ): | ||
| parser_cls = ReasoningParserManager.get_reasoning_parser(parser_name) | ||
| parser = parser_cls(tokenizer) | ||
| request = ChatCompletionRequest( | ||
| model="test-model", | ||
| messages=[], | ||
| chat_template_kwargs={"enable_thinking": False}, | ||
| ) | ||
|
|
||
| reasoning, content = run_reasoning_extraction( | ||
| parser, | ||
| ["This is plain content"], | ||
| request=request, | ||
| streaming=False, | ||
| ) | ||
|
|
||
| assert reasoning is None | ||
| assert content == "This is plain content" | ||
|
|
||
|
|
||
| def test_nemotron_v3_force_nonempty_content_returns_content( | ||
| tokenizer: FakeNemotronTokenizer, | ||
| ): | ||
| parser_cls = ReasoningParserManager.get_reasoning_parser(parser_name) | ||
| parser = parser_cls(tokenizer) | ||
| request = ChatCompletionRequest( | ||
| model="test-model", | ||
| messages=[], | ||
| chat_template_kwargs={"force_nonempty_content": True}, | ||
| ) | ||
|
|
||
| reasoning, content = run_reasoning_extraction( | ||
| parser, | ||
| ["<think>This is plain content"], | ||
| request=request, | ||
| streaming=False, | ||
| ) | ||
|
|
||
| assert reasoning is None | ||
| assert content == "This is plain content" | ||
|
|
||
|
|
||
| def test_nemotron_v3_with_thinking_keeps_truncated_reasoning( | ||
| tokenizer: FakeNemotronTokenizer, | ||
| ): | ||
| parser_cls = ReasoningParserManager.get_reasoning_parser(parser_name) | ||
| parser = parser_cls(tokenizer) | ||
| request = ChatCompletionRequest( | ||
| model="test-model", | ||
| messages=[], | ||
| chat_template_kwargs={"enable_thinking": True}, | ||
| ) | ||
|
|
||
| reasoning, content = run_reasoning_extraction( | ||
| parser, | ||
| ["This is truncated reasoning"], | ||
| request=request, | ||
| streaming=False, | ||
| ) | ||
|
|
||
| assert reasoning == "This is truncated reasoning" | ||
| assert content is None |
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
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
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
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
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
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
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
Oops, something went wrong.
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.
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.
🟡 Severity: MEDIUM
self.method = "medusa"is placed at indentation level 8 (same as the top-levelif/elif/elsechain), so it executes unconditionally at the end of__post_init__, overriding whichever speculative decoding method was correctly detected (eagle, eagle3, mtp, mlp_speculator, etc.). This silently bypasses all method-specific validation and forces incorrect draft model execution.Helpful? Add 👍 / 👎
💡 Fix Suggestion
Suggestion: Remove the stale/misindented line
self.method = "medusa"at line 592. The medusa method is already correctly assigned conditionally at line 479 (elif self.draft_model_config.hf_config.model_type == "medusa": self.method = "medusa"). This leftover line executes unconditionally and overrides whichever speculative decoding method was correctly detected. Simply delete line 592 so that onlyreturn selfremains.