Skip to content

Commit e052b8c

Browse files
committed
[Spec Decode] Resolve both ngram methods to the GPU implementation on the V2 runner
On the V2 model runner, method="ngram" and method="ngram_gpu" now both use NgramGPUSpeculator (via a new SpeculativeConfig.use_ngram() helper); the V1 runner keeps its separate CPU and GPU proposers. Also scope the torch.compile cache disable to the V1 ngram-gpu proposer: it exists for V1's @support_torch_compile kernel, while the V2 implementation is pure Triton and does not need it. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Nick Hill <nickhill123@gmail.com>
1 parent b8a3834 commit e052b8c

7 files changed

Lines changed: 32 additions & 15 deletions

File tree

tests/v1/spec_decode/test_max_len.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@ def test_ngram_max_len(num_speculative_tokens: int, vllm_runner):
3737

3838

3939
@pytest.mark.parametrize("num_speculative_tokens", [1, 3, 10])
40-
def test_ngram_gpu_max_len(num_speculative_tokens: int, vllm_runner):
40+
@pytest.mark.parametrize("method", ["ngram", "ngram_gpu"])
41+
def test_ngram_gpu_max_len(method: str, num_speculative_tokens: int, vllm_runner):
4142
"""V2 GPU n-gram counterpart of ``test_ngram_max_len``.
4243
43-
Verifies that the V2 model runner with ``method="ngram_gpu"`` correctly
44+
Verifies that the V2 model runner (where "ngram" and "ngram_gpu" both
45+
resolve to the GPU implementation) correctly
4446
handles the ``max_model_len`` boundary across various speculative-token
4547
counts.
4648
"""
@@ -51,7 +53,7 @@ def test_ngram_gpu_max_len(num_speculative_tokens: int, vllm_runner):
5153
enable_chunked_prefill=None,
5254
enforce_eager=True, # For faster initialization.
5355
speculative_config={
54-
"method": "ngram_gpu",
56+
"method": method,
5557
"prompt_lookup_max": 5,
5658
"prompt_lookup_min": 3,
5759
"num_speculative_tokens": num_speculative_tokens,

tests/v1/spec_decode/test_ngram_gpu.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ def _make_vllm_config(
4949
k: int,
5050
max_num_seqs: int = 8,
5151
max_model_len: int = 64,
52+
method: str = "ngram_gpu",
5253
) -> VllmConfig:
5354
model_config = ModelConfig(
5455
model="facebook/opt-125m",
@@ -60,7 +61,7 @@ def _make_vllm_config(
6061
max_model_len=max_model_len,
6162
)
6263
speculative_config = SpeculativeConfig(
63-
method="ngram_gpu",
64+
method=method,
6465
prompt_lookup_min=min_n,
6566
prompt_lookup_max=max_n,
6667
num_speculative_tokens=k,
@@ -360,14 +361,23 @@ def test_propose_requires_req_states():
360361
)
361362

362363

364+
@pytest.mark.parametrize("method", ["ngram", "ngram_gpu"])
365+
def test_both_ngram_methods_resolve_to_gpu_speculator(method: str):
366+
"""On the V2 runner, "ngram" and "ngram_gpu" use the same implementation."""
367+
from vllm.v1.worker.gpu.spec_decode import init_speculator
368+
369+
cfg = _make_vllm_config(min_n=2, max_n=3, k=2, method=method)
370+
spec = init_speculator(cfg, DEVICE)
371+
assert isinstance(spec, NgramGPUSpeculator)
372+
373+
363374
def test_construction_validates_speculative_config():
364375
spec = _make_speculator(min_n=2, max_n=3, k=2)
365376
assert spec.min_n == 2
366377
assert spec.max_n == 3
367378
assert spec.num_speculative_steps == 2
368-
# No-op hooks must not raise.
369-
spec.load_model(target_model=None)
370-
spec.set_attn()
379+
# Inherited no-op hooks must not raise.
380+
spec.init_cudagraph_manager(None)
371381
spec.capture()
372382

373383

vllm/compilation/backends.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1081,10 +1081,13 @@ def __call__(self, graph: fx.GraphModule, example_inputs: Sequence[Any]) -> Any:
10811081
# Honors opt-outs such as CompilationMode.NONE or VLLM_DISABLE_COMPILE_CACHE.
10821082
disable_cache = not is_compile_cache_enabled(self.inductor_config)
10831083

1084-
# TODO(patchy): ngram gpu kernel will cause vllm torch compile cache errors.
1084+
# TODO(patchy): the V1 torch.compile ngram-gpu kernel causes vllm
1085+
# torch compile cache errors. The V2 implementation is pure Triton and
1086+
# does not need the cache disabled.
10851087
is_ngram_gpu_enabled = (
10861088
vllm_config.speculative_config is not None
10871089
and vllm_config.speculative_config.use_ngram_gpu()
1090+
and not vllm_config.use_v2_model_runner
10881091
)
10891092
disable_cache = disable_cache or is_ngram_gpu_enabled
10901093

vllm/config/speculative.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,9 @@ def uses_extract_hidden_states(self) -> bool:
14981498
def use_ngram_gpu(self) -> bool:
14991499
return self.method == "ngram_gpu"
15001500

1501+
def use_ngram(self) -> bool:
1502+
return self.method in ("ngram", "ngram_gpu")
1503+
15011504
def use_multi_module_mtp(self) -> bool:
15021505
if self.method != "mtp" or self.draft_model_config is None:
15031506
return False

vllm/config/vllm.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2395,15 +2395,15 @@ def _get_v2_model_runner_unsupported_features(self) -> list[str]:
23952395
unsupported.append("pipeline parallelism with external_launcher")
23962396

23972397
if speculative_config is not None:
2398-
# CPU ngram is not supported by the V2 model runner yet.
2399-
if speculative_config.method == "ngram":
2400-
unsupported.append("ngram speculative decoding")
2401-
elif speculative_config.method not in (
2398+
# Both ngram methods resolve to the same GPU implementation on
2399+
# the V2 model runner.
2400+
if speculative_config.method not in (
24022401
"eagle",
24032402
"eagle3",
24042403
"mtp",
24052404
"dflash",
24062405
"dspark",
2406+
"ngram",
24072407
"ngram_gpu",
24082408
):
24092409
unsupported.append(f"speculative method '{speculative_config.method}'")

vllm/v1/worker/gpu/model_runner.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,7 @@ def __init__(self, vllm_config: VllmConfig, device: torch.device):
271271

272272
# General request states.
273273
use_dense_all_token_ids = (
274-
self.speculative_config is not None
275-
and self.speculative_config.use_ngram_gpu()
274+
self.speculative_config is not None and self.speculative_config.use_ngram()
276275
)
277276
self.req_states = RequestState(
278277
max_num_reqs=self.max_num_reqs,

vllm/v1/worker/gpu/spec_decode/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def init_speculator(vllm_config: VllmConfig, device: torch.device):
4242
)
4343

4444
return EagleSpeculator(vllm_config, device)
45-
elif speculative_config.use_ngram_gpu():
45+
elif speculative_config.use_ngram():
4646
from vllm.v1.worker.gpu.spec_decode.ngram.speculator import (
4747
NgramGPUSpeculator,
4848
)

0 commit comments

Comments
 (0)