@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 30b9c67743
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 12, 19:45 UTC

Revert "[Redo] #26368 (#28771)" (#29121)

Signed-off-by: Jialin Ouyang <Jialin.Ouyang@gmail.com>

Jialin Ouyang committed Nov 20, 2025 at 21:27 UTC 30b9c6774396c168bdf019b488f2cfc133b09b35
16 files changed +99 -127
tests/v1/core/test_async_scheduler.py
+1 -2
@@ -2,7 +2,6 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 from collections import deque
4
5 -import numpy as np
5 import pytest
6
7 from vllm.v1.core.sched.output import SchedulerOutput
@@ -22,7 +21,7 @@ def _make_model_runner_output(
21 return ModelRunnerOutput(
22 req_ids=req_ids,
23 req_id_to_index={req_id: i for i, req_id in enumerate(req_ids)},
25 - sampled_token_ids=[np.array([i]) for i in range(len(req_ids))],
24 + sampled_token_ids=[[i] for i in range(len(req_ids))],
25 logprobs=None,
26 prompt_logprobs_dict={},
27 pooler_output=[],
tests/v1/core/test_priority_scheduler_random.py
+2 -4
@@ -3,7 +3,6 @@
3 import random
4 import uuid
5
6 -import numpy as np
6 import pytest
7
8 from vllm.config import VllmConfig
@@ -100,7 +99,8 @@ def _mock_execute_model(
99 random.randint(*num_output_tokens_range) for _ in range(len(request_ids))
100 ]
101 sampled_token_ids = [
103 - np.random.randint(0, 100, size=num_tokens) for num_tokens in num_output_tokens
102 + [random.randint(0, 100) for _ in range(num_tokens)]
103 + for num_tokens in num_output_tokens
104 ]
105
106 return ModelRunnerOutput(
@@ -196,8 +196,6 @@ def test_priority_scheduling_blast(
196 num_blocks: int,
197 ):
198 random.seed(42)
199 - np.random.seed(42)
200 -
199 seen_request_prompt_length = dict[str, int]()
200 seen_request_ids = set[str]()
201 seen_mm_hashes = set[str]()
tests/v1/core/test_scheduler.py
+38 -50
@@ -3,7 +3,6 @@
3 import dataclasses
4 from unittest.mock import Mock
5
6 -import numpy as np
6 import pytest
7 import torch
8
@@ -170,7 +169,7 @@ def test_schedule_partial_requests():
169 req_id_to_index=req_to_index,
170 # Only the first request has a sampled token id because
171 # the rest requests are still being prefilled.
173 - sampled_token_ids=[np.array([0]), np.array([]), np.array([])],
172 + sampled_token_ids=[[0], [], []],
173 logprobs=None,
174 prompt_logprobs_dict={},
175 pooler_output=[],
@@ -217,7 +216,7 @@ def test_no_mm_input_chunking():
216 model_runner_output = ModelRunnerOutput(
217 req_ids=[request.request_id for request in requests],
218 req_id_to_index=req_to_index,
220 - sampled_token_ids=[np.array([]) for _ in range(len(requests))],
219 + sampled_token_ids=[[] for _ in range(len(requests))],
220 logprobs=None,
221 prompt_logprobs_dict={},
222 pooler_output=[],
@@ -277,7 +276,7 @@ def test_schedule_concurrent_partial_requests(enable_prefix_caching: bool):
276 model_runner_output = ModelRunnerOutput(
277 req_ids=[request.request_id for request in requests],
278 req_id_to_index=req_to_index,
280 - sampled_token_ids=[np.array([]) for _ in range(len(requests))],
279 + sampled_token_ids=[[] for _ in range(len(requests))],
280 logprobs=None,
281 prompt_logprobs_dict={},
282 pooler_output=[],
@@ -301,8 +300,7 @@ def test_schedule_concurrent_partial_requests(enable_prefix_caching: bool):
300 model_runner_output = ModelRunnerOutput(
301 req_ids=[request.request_id for request in requests],
302 req_id_to_index=req_to_index,
304 - sampled_token_ids=[np.array([0]), np.array([0])]
305 - + [np.array([]) for _ in range(len(requests) - 2)],
303 + sampled_token_ids=[[0], [0]] + [[] for _ in range(len(requests) - 2)],
304 logprobs=None,
305 prompt_logprobs_dict={},
306 pooler_output=[],
@@ -349,8 +347,8 @@ def test_stop_via_update_from_output():
347 req_ids=[req.request_id for req in requests],
348 req_id_to_index={req.request_id: i for i, req in enumerate(requests)},
349 sampled_token_ids=[
352 - np.array([EOS_TOKEN_ID]),
353 - np.array([10, 11]),
350 + [EOS_TOKEN_ID],
351 + [10, 11],
352 ], # First request hits EOS, second continues
353 logprobs=None,
354 prompt_logprobs_dict={},
@@ -394,10 +392,7 @@ def test_stop_via_update_from_output():
392 model_output = ModelRunnerOutput(
393 req_ids=[req.request_id for req in requests],
394 req_id_to_index={req.request_id: i for i, req in enumerate(requests)},
397 - sampled_token_ids=[
398 - np.array([10, 42, 12]),
399 - np.array([13, 14]),
400 - ], # First request hits stop token
395 + sampled_token_ids=[[10, 42, 12], [13, 14]], # First request hits stop token
396 logprobs=None,
397 prompt_logprobs_dict={},
398 pooler_output=[],
@@ -441,10 +436,7 @@ def test_stop_via_update_from_output():
436 model_output = ModelRunnerOutput(
437 req_ids=[req.request_id for req in requests],
438 req_id_to_index={req.request_id: i for i, req in enumerate(requests)},
444 - sampled_token_ids=[
445 - np.array([10, 11, 12]),
446 - np.array([13]),
447 - ], # First request exceeds max_tokens
439 + sampled_token_ids=[[10, 11, 12], [13]], # First request exceeds max_tokens
440 logprobs=None,
441 prompt_logprobs_dict={},
442 pooler_output=[],
@@ -483,7 +475,7 @@ def test_stop_via_update_from_output():
475 model_output = ModelRunnerOutput(
476 req_ids=[requests[0].request_id],
477 req_id_to_index={requests[0].request_id: 0},
486 - sampled_token_ids=[np.array([EOS_TOKEN_ID, 10, 11])],
478 + sampled_token_ids=[[EOS_TOKEN_ID, 10, 11]],
479 logprobs=None,
480 prompt_logprobs_dict={},
481 pooler_output=[],
@@ -624,7 +616,7 @@ def test_schedule_concurrent_batches(
616 model_runner_output = ModelRunnerOutput(
617 req_ids=[requests[0].request_id],
618 req_id_to_index={requests[0].request_id: 0},
627 - sampled_token_ids=[np.array([0])],
619 + sampled_token_ids=[[0]],
620 logprobs=None,
621 prompt_logprobs_dict={},
622 pooler_output=[],
@@ -641,7 +633,7 @@ def test_schedule_concurrent_batches(
633 model_runner_output = ModelRunnerOutput(
634 req_ids=[requests[1].request_id],
635 req_id_to_index={requests[1].request_id: 0},
644 - sampled_token_ids=[np.array([0])],
636 + sampled_token_ids=[[0]],
637 logprobs=None,
638 prompt_logprobs_dict={},
639 pooler_output=[],
@@ -678,7 +670,7 @@ def test_preempt_during_execution():
670 model_runner_output0 = ModelRunnerOutput(
671 req_ids=[requests[0].request_id],
672 req_id_to_index={requests[0].request_id: 0},
681 - sampled_token_ids=[np.array([0])],
673 + sampled_token_ids=[[0]],
674 logprobs=None,
675 prompt_logprobs_dict={},
676 pooler_output=[],
@@ -695,7 +687,7 @@ def test_preempt_during_execution():
687 model_runner_output1 = ModelRunnerOutput(
688 req_ids=[requests[1].request_id],
689 req_id_to_index={requests[1].request_id: 0},
698 - sampled_token_ids=[np.array([42])],
690 + sampled_token_ids=[[42]],
691 logprobs=None,
692 prompt_logprobs_dict={},
693 pooler_output=[],
@@ -712,18 +704,14 @@ def test_preempt_during_execution():
704 @pytest.mark.parametrize(
705 "spec_tokens,output_tokens,expected",
706 [
715 - ([[1, 2, 3]], [np.array([1, 2, 3, 4])], (1, 3, 3, [1, 1, 1])), # perfect match
716 - ([[1, 2, 3]], [np.array([1, 5])], (1, 3, 1, [1, 0, 0])), # early mismatch
717 - (
718 - [[1, 2], [3]],
719 - [np.array([1, 2, 5]), np.array([3, 4])],
720 - (2, 3, 3, [2, 1]),
721 - ), # multiple sequences
722 - ([[1]], [np.array([1, 2])], (1, 1, 1, [1])), # single token sequence
723 - ([[]], [np.array([5])], (0, 0, 0, [0])), # empty sequence
707 + ([[1, 2, 3]], [[1, 2, 3, 4]], (1, 3, 3, [1, 1, 1])), # perfect match
708 + ([[1, 2, 3]], [[1, 5]], (1, 3, 1, [1, 0, 0])), # early mismatch
709 + ([[1, 2], [3]], [[1, 2, 5], [3, 4]], (2, 3, 3, [2, 1])), # multiple sequences
710 + ([[1]], [[1, 2]], (1, 1, 1, [1])), # single token sequence
711 + ([[]], [[5]], (0, 0, 0, [0])), # empty sequence
712 (
713 [[1, 2, 3], [4, 5, 6]],
726 - [np.array([1, 2, 7]), np.array([4, 8])],
714 + [[1, 2, 7], [4, 8]],
715 (2, 6, 3, [2, 1, 0]),
716 ), # multiple mismatches
717 ],
@@ -757,7 +745,7 @@ def test_schedule_spec_decoding_stats(spec_tokens, output_tokens, expected):
745 model_runner_output = ModelRunnerOutput(
746 req_ids=req_ids,
747 req_id_to_index=req_to_index,
760 - sampled_token_ids=[np.array([0]) for _ in range(len(requests))],
748 + sampled_token_ids=[[0] for _ in range(len(requests))],
749 logprobs=None,
750 prompt_logprobs_dict={},
751 pooler_output=[],
@@ -984,7 +972,7 @@ def test_kv_connector_basic(is_async: bool):
972 MODEL_RUNNER_OUTPUT = ModelRunnerOutput(
973 req_ids=req_ids,
974 req_id_to_index=req_to_index,
987 - sampled_token_ids=[np.array([1000])] * len(req_ids),
975 + sampled_token_ids=[[1000]] * len(req_ids),
976 logprobs=None,
977 prompt_logprobs_dict={},
978 pooler_output=[],
@@ -1037,7 +1025,7 @@ def test_kv_connector_basic(is_async: bool):
1025 MODEL_RUNNER_OUTPUT = ModelRunnerOutput(
1026 req_ids=req_ids,
1027 req_id_to_index=req_to_index,
1040 - sampled_token_ids=[np.array([1000])] * len(req_ids),
1028 + sampled_token_ids=[[1000]] * len(req_ids),
1029 logprobs=None,
1030 prompt_logprobs_dict={},
1031 pooler_output=[],
@@ -1100,7 +1088,7 @@ def test_external_prefix_cache_metrics():
1088 MODEL_RUNNER_OUTPUT = ModelRunnerOutput(
1089 req_ids=[r.request_id for r in requests],
1090 req_id_to_index={r.request_id: i for i, r in enumerate(requests)},
1103 - sampled_token_ids=[np.array([1000])] * NUM_REQUESTS,
1091 + sampled_token_ids=[[1000]] * NUM_REQUESTS,
1092 logprobs=None,
1093 prompt_logprobs_dict={},
1094 pooler_output=[],
@@ -1166,7 +1154,7 @@ def test_kv_connector_unable_to_allocate(use_ec_connector, ec_role):
1154 MODEL_RUNNER_OUTPUT = ModelRunnerOutput(
1155 req_ids=req_ids,
1156 req_id_to_index=req_to_index,
1169 - sampled_token_ids=[np.array([1000])] * len(req_ids),
1157 + sampled_token_ids=[[1000]] * len(req_ids),
1158 logprobs=None,
1159 prompt_logprobs_dict={},
1160 pooler_output=[],
@@ -1251,7 +1239,7 @@ def test_kv_connector_handles_preemption(use_ec_connector, ec_role):
1239 MODEL_RUNNER_OUTPUT = ModelRunnerOutput(
1240 req_ids=req_ids,
1241 req_id_to_index=req_to_index,
1254 - sampled_token_ids=[np.array([1000])] * len(req_ids),
1242 + sampled_token_ids=[[1000]] * len(req_ids),
1243 logprobs=None,
1244 prompt_logprobs_dict={},
1245 pooler_output=[],
@@ -1344,7 +1332,7 @@ def make_output(scheduler: Scheduler):
1332 return ModelRunnerOutput(
1333 req_ids=[req.request_id for req in scheduler.running],
1334 req_id_to_index={req.request_id: i for i, req in enumerate(scheduler.running)},
1347 - sampled_token_ids=[np.array([1000])] * len(scheduler.running),
1335 + sampled_token_ids=[[1000]] * len(scheduler.running),
1336 logprobs=None,
1337 prompt_logprobs_dict={},
1338 pooler_output=[],
@@ -1761,7 +1749,7 @@ def test_priority_scheduling_preemption():
1749 req_id_to_index={
1750 req.request_id: i for i, req in enumerate(low_priority_requests)
1751 },
1764 - sampled_token_ids=[np.array([100]) for _ in low_priority_requests],
1752 + sampled_token_ids=[[100] for _ in low_priority_requests],
1753 logprobs=None,
1754 prompt_logprobs_dict={},
1755 pooler_output=[],
@@ -1830,7 +1818,7 @@ def test_priority_scheduling_no_preemption_when_space_available():
1818 req_id_to_index={
1819 req.request_id: i for i, req in enumerate(low_priority_requests)
1820 },
1833 - sampled_token_ids=[np.array([100]) for _ in low_priority_requests],
1821 + sampled_token_ids=[[100] for _ in low_priority_requests],
1822 logprobs=None,
1823 prompt_logprobs_dict={},
1824 pooler_output=[],
@@ -2076,7 +2064,7 @@ def test_priority_scheduling_heap_property():
2064 model_output = ModelRunnerOutput(
2065 req_ids=[req.req_id],
2066 req_id_to_index={req.req_id: 0},
2079 - sampled_token_ids=[np.array([100])],
2067 + sampled_token_ids=[[100]],
2068 logprobs=None,
2069 prompt_logprobs_dict={},
2070 pooler_output=[],
@@ -2162,7 +2150,7 @@ def test_priority_scheduling_preemption_and_resumption_when_out_of_kv(
2150 model_output = ModelRunnerOutput(
2151 req_ids=[request_low.request_id],
2152 req_id_to_index={request_low.request_id: 0},
2165 - sampled_token_ids=[np.array([100])],
2153 + sampled_token_ids=[[100]],
2154 # spec_token_ids=None,
2155 logprobs=None,
2156 prompt_logprobs_dict={},
@@ -2193,7 +2181,7 @@ def test_priority_scheduling_preemption_and_resumption_when_out_of_kv(
2181 model_output = ModelRunnerOutput(
2182 req_ids=[req.request_id for req in requests],
2183 req_id_to_index={req.request_id: i for i, req in enumerate(requests)},
2196 - sampled_token_ids=[np.array([100]) for _ in requests],
2184 + sampled_token_ids=[[100] for _ in requests],
2185 # spec_token_ids=None,
2186 logprobs=None,
2187 prompt_logprobs_dict={},
@@ -2219,7 +2207,7 @@ def test_priority_scheduling_preemption_and_resumption_when_out_of_kv(
2207 model_output = ModelRunnerOutput(
2208 req_ids=[req.request_id for req in requests],
2209 req_id_to_index={req.request_id: i for i, req in enumerate(requests)},
2222 - sampled_token_ids=[np.array([]), np.array([100])],
2210 + sampled_token_ids=[[], [100]],
2211 # spec_token_ids=None,
2212 logprobs=None,
2213 prompt_logprobs_dict={},
@@ -2636,7 +2624,7 @@ def test_ec_connector_with_partial_cache_hit_multi_round(use_kv_connector):
2624 model_output = ModelRunnerOutput(
2625 req_ids=[request1.request_id],
2626 req_id_to_index={request1.request_id: 0},
2639 - sampled_token_ids=[np.array([100])],
2627 + sampled_token_ids=[[100]],
2628 # spec_token_ids=None,
2629 logprobs=None,
2630 prompt_logprobs_dict={},
@@ -2842,7 +2830,7 @@ def test_ec_connector_unable_to_allocate(use_kv_connector):
2830 MODEL_RUNNER_OUTPUT = ModelRunnerOutput(
2831 req_ids=req_ids,
2832 req_id_to_index=req_to_index,
2845 - sampled_token_ids=[np.array([1000])] * len(req_ids),
2833 + sampled_token_ids=[[1000]] * len(req_ids),
2834 logprobs=None,
2835 prompt_logprobs_dict={},
2836 pooler_output=[],
@@ -2955,7 +2943,7 @@ def test_priority_scheduling_ec_connector_preemption_and_resumption(
2943 model_output = ModelRunnerOutput(
2944 req_ids=[request_low.request_id],
2945 req_id_to_index={request_low.request_id: 0},
2958 - sampled_token_ids=[np.array([100])],
2946 + sampled_token_ids=[[100]],
2947 # spec_token_ids=None,
2948 logprobs=None,
2949 prompt_logprobs_dict={},
@@ -3006,7 +2994,7 @@ def test_priority_scheduling_ec_connector_preemption_and_resumption(
2994 model_output = ModelRunnerOutput(
2995 req_ids=[req.request_id for req in requests],
2996 req_id_to_index={req.request_id: i for i, req in enumerate(requests)},
3009 - sampled_token_ids=[np.array([100]) for _ in requests],
2997 + sampled_token_ids=[[100] for _ in requests],
2998 # spec_token_ids=None,
2999 logprobs=None,
3000 prompt_logprobs_dict={},
@@ -3041,7 +3029,7 @@ def test_priority_scheduling_ec_connector_preemption_and_resumption(
3029 model_output = ModelRunnerOutput(
3030 req_ids=[req.request_id for req in requests],
3031 req_id_to_index={req.request_id: i for i, req in enumerate(requests)},
3044 - sampled_token_ids=[np.array([100]), np.array([100, 200])],
3032 + sampled_token_ids=[[100], [100, 200]],
3033 # spec_token_ids=None,
3034 logprobs=None,
3035 prompt_logprobs_dict={},
@@ -3227,7 +3215,7 @@ def test_ec_connector_allocate_encoder_tokens_with_external_load(use_kv_connecto
3215 model_output = ModelRunnerOutput(
3216 req_ids=[request1.request_id, request2.request_id],
3217 req_id_to_index={request1.request_id: 0, request2.request_id: 1},
3230 - sampled_token_ids=[np.array([100]), np.array([121])],
3218 + sampled_token_ids=[[100], [121]],
3219 # spec_token_ids=None,
3220 logprobs=None,
3221 prompt_logprobs_dict={},
tests/v1/kv_connector/unit/test_nixl_connector.py
+3 -4
@@ -11,7 +11,6 @@ import uuid
11 from collections import defaultdict
12 from unittest.mock import patch
13
14 -import numpy as np
14 import pytest
15 import ray
16 import torch
@@ -827,7 +826,7 @@ def test_kv_connector_stats_aggregation():
826 output = ModelRunnerOutput(
827 req_ids=[f"req_{i}"],
828 req_id_to_index={f"req_{i}": 0},
830 - sampled_token_ids=[np.array([123])], # dummy token
829 + sampled_token_ids=[[123]], # dummy token
830 logprobs=None,
831 prompt_logprobs_dict={},
832 pooler_output=[None],
@@ -908,7 +907,7 @@ def test_multi_kv_connector_stats_aggregation():
907 output = ModelRunnerOutput(
908 req_ids=[f"req_{i}"],
909 req_id_to_index={f"req_{i}": 0},
911 - sampled_token_ids=[np.array([123])],
910 + sampled_token_ids=[[123]],
911 logprobs=None,
912 prompt_logprobs_dict={},
913 pooler_output=[None],
@@ -966,7 +965,7 @@ def test_scheduler_kv_connector_stats_aggregation():
965 model_output = ModelRunnerOutput(
966 req_ids=["req_0"],
967 req_id_to_index={"req_0": 0},
969 - sampled_token_ids=[np.array([123])],
968 + sampled_token_ids=[[123]],
969 logprobs=None,
970 prompt_logprobs_dict={},
971 pooler_output=[None],
tests/v1/kv_connector/unit/utils.py
+1 -2
@@ -7,7 +7,6 @@ from dataclasses import dataclass
7 from itertools import chain, count
8 from typing import Any
9
10 -import numpy as np
10 import torch
11
12 from vllm import SamplingParams
@@ -229,7 +228,7 @@ def create_model_runner_output(
228
229 # Make sampled tokens.
230 sampled_token = EOS_TOKEN_ID if use_eos else token_id
232 - sampled_token_ids = [np.array([sampled_token]) for _ in req_ids]
231 + sampled_token_ids = [[sampled_token] for _ in req_ids]
232
233 kv_connector_output = (
234 None
tests/v1/spec_decode/test_eagle.py
+1 -4
@@ -3,7 +3,6 @@
3
4 from unittest import mock
5
6 -import numpy as np
6 import pytest
7 import torch
8
@@ -113,9 +112,7 @@ def test_prepare_next_token_ids():
112 sampled_token_ids_tensor = torch.tensor(
113 sampled_token_ids, dtype=torch.int32, device=device
114 )
116 - sampled_token_ids_cpu = [
117 - np.array([i for i in seq if i != -1]) for seq in sampled_token_ids
118 - ]
115 + sampled_token_ids_cpu = [[i for i in seq if i != -1] for seq in sampled_token_ids]
116
117 expected_next_token_ids_cpu = [1, 4, 30, 40]
118 expected_next_token_ids_tensor = torch.tensor(
tests/v1/spec_decode/test_ngram.py
+9 -9
@@ -77,7 +77,7 @@ def test_ngram_proposer():
77 # No match.
78 token_ids_cpu = np.array([[1, 2, 3, 4, 5]])
79 result = get_ngram_proposer(min_n=2, max_n=2, k=2).propose(
80 - sampled_token_ids=[np.array([0])],
80 + sampled_token_ids=[[0]],
81 req_ids=["0"],
82 num_tokens_no_spec=np.array([len(c) for c in token_ids_cpu]),
83 token_ids_cpu=token_ids_cpu,
@@ -88,7 +88,7 @@ def test_ngram_proposer():
88 # No match for 4-gram.
89 token_ids_cpu = np.array([[1, 2, 3, 4, 1, 2, 3]])
90 result = get_ngram_proposer(min_n=4, max_n=4, k=2).propose(
91 - sampled_token_ids=[np.array([0])],
91 + sampled_token_ids=[[0]],
92 req_ids=["0"],
93 num_tokens_no_spec=np.array([len(c) for c in token_ids_cpu]),
94 token_ids_cpu=token_ids_cpu,
@@ -99,7 +99,7 @@ def test_ngram_proposer():
99 # No match for 4-gram but match for 3-gram.
100 token_ids_cpu = np.array([[1, 2, 3, 4, 1, 2, 3]])
101 result = get_ngram_proposer(min_n=3, max_n=4, k=2).propose(
102 - sampled_token_ids=[np.array([0])],
102 + sampled_token_ids=[[0]],
103 req_ids=["0"],
104 num_tokens_no_spec=np.array([len(c) for c in token_ids_cpu]),
105 token_ids_cpu=token_ids_cpu,
@@ -111,7 +111,7 @@ def test_ngram_proposer():
111 # In this case, the proposer should return the 4-gram match.
112 token_ids_cpu = np.array([[2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 3, 4]])
113 result = get_ngram_proposer(min_n=3, max_n=4, k=2).propose(
114 - sampled_token_ids=[np.array([0])],
114 + sampled_token_ids=[[0]],
115 req_ids=["0"],
116 num_tokens_no_spec=np.array([len(c) for c in token_ids_cpu]),
117 token_ids_cpu=token_ids_cpu,
@@ -122,7 +122,7 @@ def test_ngram_proposer():
122 # Match for 2-gram and 3-gram, but not 4-gram.
123 token_ids_cpu = np.array([[3, 4, 5, 2, 3, 4, 1, 2, 3, 4]])
124 result = get_ngram_proposer(min_n=2, max_n=4, k=2).propose(
125 - sampled_token_ids=[np.array([0])],
125 + sampled_token_ids=[[0]],
126 req_ids=["0"],
127 num_tokens_no_spec=np.array([len(c) for c in token_ids_cpu]),
128 token_ids_cpu=token_ids_cpu,
@@ -133,7 +133,7 @@ def test_ngram_proposer():
133 # Multiple 3-gram matched, but always pick the first one.
134 token_ids_cpu = np.array([[1, 2, 3, 100, 1, 2, 3, 200, 1, 2, 3, 300, 1, 2, 3]])
135 result = get_ngram_proposer(min_n=3, max_n=3, k=2).propose(
136 - sampled_token_ids=[np.array([0])],
136 + sampled_token_ids=[[0]],
137 req_ids=["0"],
138 num_tokens_no_spec=np.array([len(c) for c in token_ids_cpu]),
139 token_ids_cpu=token_ids_cpu,
@@ -144,7 +144,7 @@ def test_ngram_proposer():
144 # check empty input
145 token_ids_cpu = np.array([[]])
146 result = get_ngram_proposer(min_n=2, max_n=2, k=2).propose(
147 - sampled_token_ids=[np.array([0])],
147 + sampled_token_ids=[[0]],
148 req_ids=["0"],
149 num_tokens_no_spec=np.array([len(c) for c in token_ids_cpu]),
150 token_ids_cpu=token_ids_cpu,
@@ -157,7 +157,7 @@ def test_ngram_proposer():
157 # second request has 3 tokens and no match. Padded with -1 for max len 5
158 token_ids_cpu = np.array([[1, 2, 3, 1, 2], [4, 5, 6, -1, -1]])
159 result = get_ngram_proposer(min_n=2, max_n=2, k=2).propose(
160 - sampled_token_ids=[np.array([0]), np.array([1])],
160 + sampled_token_ids=[[0], [1]],
161 req_ids=["0", "1"],
162 num_tokens_no_spec=np.array([5, 3]),
163 token_ids_cpu=token_ids_cpu,
@@ -181,7 +181,7 @@ def test_ngram_proposer():
181 input_2[:3] = [4, 5, 6]
182 token_ids_cpu = np.array([input_1, input_2])
183 result = ngram_proposer.propose(
184 - sampled_token_ids=[np.array([0]), np.array([1])],
184 + sampled_token_ids=[[0], [1]],
185 req_ids=["0", "1"],
186 num_tokens_no_spec=np.array([len(input_1), 3]),
187 token_ids_cpu=token_ids_cpu,
vllm/utils/gc_utils.py
+8 -5
@@ -53,6 +53,7 @@ class GCDebugger:
53 self.config = config
54 # Start time in micro second of this GC cycle
55 self.start_time_ns: int = time.monotonic_ns()
56 + self.num_objects: int = 0
57 # If config.top_objects is positive,
58 # compute top collected objects by object types
59 self.gc_top_collected_objects: str = ""
@@ -68,19 +69,21 @@ class GCDebugger:
69 # Before GC started, record GC start time
70 # and top collected objects
71 self.start_time_ns = time.monotonic_ns()
71 - if (top_objects := self.config.top_objects) > 0:
72 - self.gc_top_collected_objects = _compute_top_gc_collected_objects(
73 - gc.get_objects(generation), top_objects
74 - )
72 + objects = gc.get_objects(generation)
73 + self.num_objects = len(objects)
74 + self.gc_top_collected_objects = _compute_top_gc_collected_objects(
75 + objects, self.config.top_objects
76 + )
77 elif phase == "stop":
78 # After GC finished, Record GC elapsed time and
79 # optionally top collected objects
80 elpased_ms = (time.monotonic_ns() - self.start_time_ns) / 1e6
81 logger.info(
82 "GC took %.3fms to complete. "
81 - "Collected %s objects in GC generation %d.%s",
83 + "Collected %s objects (out of %d) in GC generation %d.%s",
84 elpased_ms,
85 str(info.get("collected", "?")),
86 + self.num_objects,
87 generation,
88 (
89 f" Top collected objects: \n{self.gc_top_collected_objects}"
vllm/v1/core/sched/scheduler.py
+2 -2
@@ -1013,8 +1013,8 @@ class Scheduler(SchedulerInterface):
1013 continue
1014
1015 req_index = model_runner_output.req_id_to_index[req_id]
1016 - generated_token_ids: list[int] = (
1017 - sampled_token_ids[req_index].tolist() if sampled_token_ids else []
1016 + generated_token_ids = (
1017 + sampled_token_ids[req_index] if sampled_token_ids else []
1018 )
1019
1020 scheduled_spec_token_ids = (
vllm/v1/outputs.py
+2 -2
@@ -158,7 +158,7 @@ class ModelRunnerOutput:
158 # num_generated_tokens is the number of tokens
159 # generated in the current step. It can be different for
160 # each request due to speculative/jump decoding.
161 - sampled_token_ids: list[np.ndarray]
161 + sampled_token_ids: list[list[int]]
162
163 # [num_reqs, max_num_logprobs + 1]
164 # [num_reqs, max_num_logprobs + 1]
@@ -220,7 +220,7 @@ def make_empty_encoder_model_runner_output(
220 req_id_to_index: dict[str, int] = {rid: idx for idx, rid in enumerate(req_ids)}
221
222 # No tokens generated yet ⇒ one empty list per request
223 - sampled_token_ids: list[list[int]] = [np.array([0]) for _ in req_ids]
223 + sampled_token_ids: list[list[int]] = [[0] for _ in req_ids]
224
225 # Pooler outputs are not available yet ⇒ use None placeholders
226 pooler_output: list[torch.Tensor | None] = [None for _ in req_ids]
vllm/v1/sample/rejection_sampler.py
+5 -3
@@ -3,7 +3,6 @@
3
4 from dataclasses import replace
5
6 -import numpy as np
6 import torch
7 import torch.nn as nn
8
@@ -205,7 +204,7 @@ class RejectionSampler(nn.Module):
204 def parse_output(
205 output_token_ids: torch.Tensor,
206 vocab_size: int,
208 - ) -> list[np.ndarray]:
207 + ) -> list[list[int]]:
208 """Parse the output of the rejection sampler.
209 Args:
210 output_token_ids: The sampled token IDs in shape
@@ -221,7 +220,10 @@ class RejectionSampler(nn.Module):
220 valid_mask = (output_token_ids_np != PLACEHOLDER_TOKEN_ID) & (
221 output_token_ids_np < vocab_size
222 )
224 - return [row[valid_mask[i]] for i, row in enumerate(output_token_ids_np)]
223 + outputs = [
224 + row[valid_mask[i]].tolist() for i, row in enumerate(output_token_ids_np)
225 + ]
226 + return outputs
227
228 def apply_logits_processors(
229 self,
vllm/v1/spec_decode/eagle.py
+4 -3
@@ -496,7 +496,7 @@ class EagleProposer:
496
497 def prepare_next_token_ids_cpu(
498 self,
499 - sampled_token_ids: list[np.ndarray],
499 + sampled_token_ids: list[list[int]],
500 requests: dict[str, CachedRequestState],
501 gpu_input_batch: InputBatch,
502 num_scheduled_tokens: dict[str, int],
@@ -511,7 +511,7 @@ class EagleProposer:
511 req_ids = gpu_input_batch.req_ids
512 next_token_ids: list[int] = []
513 for i, token_ids in enumerate(sampled_token_ids):
514 - if token_ids.shape[0] > 0:
514 + if token_ids:
515 # Common case.
516 next_token_id = token_ids[-1]
517 else:
@@ -522,9 +522,10 @@ class EagleProposer:
522 seq_len = req_state.num_computed_tokens + num_scheduled_tokens[req_id]
523 next_token_id = req_state.get_token_id(seq_len)
524 next_token_ids.append(next_token_id)
525 - return torch.tensor(
525 + next_token_ids = torch.tensor(
526 next_token_ids, dtype=torch.int32, device=self.input_ids.device
527 )
528 + return next_token_ids
529
530 def prepare_next_token_ids_padded(
531 self,
vllm/v1/spec_decode/ngram_proposer.py
+3 -3
@@ -54,7 +54,7 @@ class NgramProposer:
54 # Trigger Numba JIT compilation for N-gram proposer.
55 # This usually takes less than 1 second.
56 self.propose(
57 - [np.array([])] * 1024,
57 + [[]] * 1024,
58 [""] * 1024,
59 np.zeros(1024, dtype=np.int32),
60 np.zeros((1024, self.max_model_len), dtype=np.int32),
@@ -131,7 +131,7 @@ class NgramProposer:
131
132 def propose(
133 self,
134 - sampled_token_ids: list[np.ndarray],
134 + sampled_token_ids: list[list[int]],
135 req_ids: list[str],
136 num_tokens_no_spec: np.ndarray,
137 token_ids_cpu: np.ndarray,
@@ -140,7 +140,7 @@ class NgramProposer:
140 # find which requests need ngram proposals
141 valid_ngram_requests = []
142 for i, sampled_ids in enumerate(sampled_token_ids):
143 - num_sampled_ids = sampled_ids.shape[0]
143 + num_sampled_ids = len(sampled_ids)
144 if not num_sampled_ids:
145 # Skip speculative decoding.
146 continue
vllm/v1/spec_decode/suffix_decoding.py
+4 -6
@@ -1,7 +1,5 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 -import numpy as np
4 -
3 from vllm.config import VllmConfig
4 from vllm.v1.worker.gpu_input_batch import InputBatch
5
@@ -34,16 +32,16 @@ class SuffixDecodingProposer:
32 def propose(
33 self,
34 input_batch: InputBatch,
37 - sampled_token_ids: list[np.ndarray],
35 + sampled_token_ids: list[list[int]],
36 ) -> list[list[int]]:
37 """
38 Propose speculative tokens for each request in the input batch. Suffix Decoding
39 will speculate a dynamic number of tokens for each request every decoding step,
40 so each entry in the returned list may have different lengths.
41 """
44 - draft_token_ids: list[np.ndarray] = []
42 + draft_token_ids: list[list[int]] = []
43 for i, sampled_ids in enumerate(sampled_token_ids):
46 - if sampled_ids.shape[0] == 0:
44 + if not sampled_ids:
45 # Skip speculative decoding for partial prefills.
46 draft_token_ids.append([])
47 continue
@@ -72,7 +70,7 @@ class SuffixDecodingProposer:
70 self.suffix_cache.start_request(req_id, prompt_token_ids)
71
72 # Append the newly sampled ids to the suffix cache for this request.
75 - self.suffix_cache.add_active_response(req_id, sampled_ids.tolist())
73 + self.suffix_cache.add_active_response(req_id, sampled_ids)
74
75 # Suffix decoding only uses the most recent tokens up to max_tree_depth, so
76 # we extract the pattern from the end of the input.
vllm/v1/worker/gpu_model_runner.py
+13 -23
@@ -221,16 +221,14 @@ class AsyncGPUModelRunnerOutput(AsyncModelRunnerOutput):
221 del self._sampled_token_ids
222 max_gen_len = self.sampled_token_ids_cpu.shape[-1]
223 if max_gen_len == 1:
224 - valid_sampled_token_ids: list[np.ndarray] = [
225 - row for row in self.sampled_token_ids_cpu.numpy()
226 - ]
224 + valid_sampled_token_ids = self.sampled_token_ids_cpu.tolist()
225 else:
226 valid_sampled_token_ids = RejectionSampler.parse_output(
227 self.sampled_token_ids_cpu,
228 self.vocab_size,
229 )
230 for i in self._invalid_req_indices:
233 - valid_sampled_token_ids[i] = np.array([])
231 + valid_sampled_token_ids[i].clear()
232
233 output = self._model_runner_output
234 output.sampled_token_ids = valid_sampled_token_ids
@@ -2466,7 +2464,7 @@ class GPUModelRunner(
2464 ) -> tuple[
2465 dict[str, int],
2466 LogprobsLists | None,
2469 - list[np.ndarray],
2467 + list[list[int]],
2468 dict[str, LogprobsTensors | None],
2469 list[str],
2470 dict[str, int],
@@ -2492,7 +2490,6 @@ class GPUModelRunner(
2490 num_sampled_tokens = sampler_output.sampled_token_ids.shape[0]
2491 sampled_token_ids = sampler_output.sampled_token_ids
2492 invalid_req_indices = []
2495 - valid_sampled_token_ids: list[np.ndarray]
2493 if not self.use_async_scheduling:
2494 # Get the valid generated tokens.
2495 max_gen_len = sampled_token_ids.shape[-1]
@@ -2507,7 +2504,7 @@ class GPUModelRunner(
2504 )
2505 # Mask out the sampled tokens that should not be sampled.
2506 for i in discard_sampled_tokens_req_indices:
2510 - valid_sampled_token_ids[int(i)] = np.array([])
2507 + valid_sampled_token_ids[int(i)].clear()
2508 else:
2509 valid_sampled_token_ids = []
2510 invalid_req_indices = discard_sampled_tokens_req_indices.tolist()
@@ -2537,24 +2534,19 @@ class GPUModelRunner(
2534 [0] if spec_decode_metadata and logprobs_tensors else None
2535 )
2536 for req_idx in range(num_sampled_tokens):
2540 - sampled_ids: np.ndarray | None
2537 if self.use_async_scheduling:
2542 - sampled_ids = (
2543 - np.array([-1]) if req_idx not in invalid_req_indices_set else None
2544 - )
2538 + sampled_ids = [-1] if req_idx not in invalid_req_indices_set else None
2539 else:
2540 sampled_ids = valid_sampled_token_ids[req_idx]
2541
2548 - num_sampled_ids: int = (
2549 - sampled_ids.shape[0] if sampled_ids is not None else 0
2550 - )
2542 + num_sampled_ids: int = len(sampled_ids) if sampled_ids else 0
2543
2544 if cu_num_accepted_tokens is not None:
2545 cu_num_accepted_tokens.append(
2546 cu_num_accepted_tokens[-1] + num_sampled_ids
2547 )
2548
2557 - if sampled_ids is None or num_sampled_ids == 0:
2549 + if not sampled_ids:
2550 continue
2551
2552 start_idx = self.input_batch.num_tokens_no_spec[req_idx]
@@ -2938,9 +2930,7 @@ class GPUModelRunner(
2930
2931 self.input_batch.prev_sampled_token_ids = None
2932
2941 - def propose_draft_token_ids(
2942 - sampled_token_ids: torch.Tensor | list[np.ndarray],
2943 - ) -> None:
2933 + def propose_draft_token_ids(sampled_token_ids):
2934 assert spec_decode_common_attn_metadata is not None
2935 with record_function_or_nullcontext("gpu_model_runner: draft"):
2936 self._draft_token_ids = self.propose_draft_token_ids(
@@ -3113,14 +3103,14 @@ class GPUModelRunner(
3103 def propose_draft_token_ids(
3104 self,
3105 scheduler_output: "SchedulerOutput",
3116 - sampled_token_ids: torch.Tensor | list[np.ndarray],
3106 + sampled_token_ids: torch.Tensor | list[list[int]],
3107 sampling_metadata: SamplingMetadata,
3108 hidden_states: torch.Tensor,
3109 sample_hidden_states: torch.Tensor,
3110 aux_hidden_states: list[torch.Tensor] | None,
3111 spec_decode_metadata: SpecDecodeMetadata | None,
3112 common_attn_metadata: CommonAttentionMetadata,
3123 - ) -> torch.Tensor | list[list[int]]:
3113 + ) -> list[list[int]] | torch.Tensor:
3114 num_scheduled_tokens = scheduler_output.total_num_scheduled_tokens
3115 spec_config = self.speculative_config
3116 assert spec_config is not None
@@ -3154,7 +3144,7 @@ class GPUModelRunner(
3144 for num_draft, tokens in zip(
3145 spec_decode_metadata.num_draft_tokens, sampled_token_ids
3146 ):
3157 - indices.append(offset + tokens.shape[0] - 1)
3147 + indices.append(offset + len(tokens) - 1)
3148 offset += num_draft + 1
3149 indices = torch.tensor(indices, device=self.device)
3150 hidden_states = sample_hidden_states[indices]
@@ -5150,7 +5140,7 @@ class GPUModelRunner(
5140
5141 return kv_cache_spec
5142
5153 - def _to_list(self, sampled_token_ids: torch.Tensor) -> list[np.ndarray]:
5143 + def _to_list(self, sampled_token_ids: torch.Tensor) -> list[list[int]]:
5144 # This is a short term mitigation for issue mentioned in
5145 # https://github.com/vllm-project/vllm/issues/22754.
5146 # `tolist` would trigger a cuda wise stream sync, which
@@ -5163,4 +5153,4 @@ class GPUModelRunner(
5153 pinned.copy_(sampled_token_ids, non_blocking=True)
5154 self.transfer_event.record()
5155 self.transfer_event.synchronize()
5166 - return [row for row in pinned.numpy()]
5156 + return pinned.tolist()
vllm/v1/worker/tpu_model_runner.py
+3 -5
@@ -1262,15 +1262,13 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
1262
1263 max_gen_len = selected_token_ids.shape[-1]
1264 if max_gen_len == 1:
1265 - valid_sampled_token_ids: list[np.ndarray] = [
1266 - row for row in selected_token_ids.numpy()
1267 - ]
1265 + valid_sampled_token_ids = selected_token_ids.tolist()
1266
1267 # Mask out the sampled tokens that should not be sampled.
1268 # TODO: Keep in sync with gpu_model_runner.py, in particular
1269 # the "else" case here
1270 for i in discard_sampled_tokens_req_indices:
1273 - valid_sampled_token_ids[i] = np.array([])
1271 + valid_sampled_token_ids[i].clear()
1272
1273 # Append sampled tokens
1274 for i, req_state, seq_len in request_seq_lens:
@@ -1283,7 +1281,7 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
1281 valid_mask = selected_token_ids != INVALID_TOKEN_ID
1282 gen_lens = valid_mask.sum(dim=1).tolist()
1283 valid_sampled_token_ids = [
1286 - seq.numpy() for seq in selected_token_ids[valid_mask].split(gen_lens)
1284 + seq.tolist() for seq in selected_token_ids[valid_mask].split(gen_lens)
1285 ]
1286 self.input_batch.num_tokens[:num_reqs] += gen_lens
1287 for i, req_state, seq_len in request_seq_lens: