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 14, 05:30 UTC
[Core] Remove tokenizer group in vLLM (#24078)
Signed-off-by: Zhuohan Li <zhuohan123@gmail.com>
Zhuohan Li committed
Sep 17, 2025 at 01:42 UTC
6c47f6bfa4794178035d9d941d7d40c1d71473b7
49 files changed
+276
-934
tests/detokenizer/test_stop_checker.py
+1
-7
@@ -1,10 +1,7 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
-from unittest.mock import MagicMock
5
-
4
import pytest
7
-from transformers import PreTrainedTokenizer
5
6
from vllm.engine.output_processor.stop_checker import StopChecker
7
from vllm.inputs import token_inputs
@@ -54,10 +51,7 @@ def test_stop_on_eos_token(text_wo_eos: str, eos_token: str, eos_token_id: int,
51
- When the EOS token should be ignored, and the sequence continues
52
"""
53
57
- tokenizer = MagicMock(spec=PreTrainedTokenizer)
58
- get_tokenizer_for_seq = MagicMock(return_value=tokenizer)
59
- stop_checker = StopChecker(max_model_len=1024,
60
- get_tokenizer_for_seq=get_tokenizer_for_seq)
54
+ stop_checker = StopChecker(max_model_len=1024)
55
56
seq = sequence_with_eos(
57
text=text_wo_eos,
tests/engine/test_stop_checker.py
+2
-5
@@ -58,16 +58,13 @@ def deepseek_r1_qwen_tokenizer():
58
59
@pytest.fixture
60
def stop_checker():
61
- return StopChecker(max_model_len=10,
62
- get_tokenizer_for_seq=deepseek_r1_qwen_tokenizer)
61
+ return StopChecker(max_model_len=10)
62
63
64
@pytest.fixture
65
def stop_checker_with_reasoner():
66
reasoner = MockReasoningParser(deepseek_r1_qwen_tokenizer)
68
- return StopChecker(max_model_len=10,
69
- get_tokenizer_for_seq=deepseek_r1_qwen_tokenizer,
70
- reasoner=reasoner)
67
+ return StopChecker(max_model_len=10, reasoner=reasoner)
68
69
70
def test_eos_token_stopping(stop_checker):
tests/entrypoints/conftest.py
-22
@@ -208,25 +208,3 @@ def zephyr_lora_files():
208
"""Download zephyr LoRA files once per test session."""
209
from huggingface_hub import snapshot_download
210
return snapshot_download(repo_id="typeof/zephyr-7b-beta-lora")
211
-
212
-
213
-@pytest.fixture(scope="session")
214
-def zephyr_lora_added_tokens_files(zephyr_lora_files):
215
- """Create zephyr LoRA files with added tokens once per test session."""
216
- import shutil
217
- from tempfile import TemporaryDirectory
218
-
219
- from transformers import AutoTokenizer
220
-
221
- tmp_dir = TemporaryDirectory()
222
- tmp_model_dir = f"{tmp_dir.name}/zephyr"
223
- shutil.copytree(zephyr_lora_files, tmp_model_dir)
224
- tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-beta")
225
- # Copy tokenizer to adapter and add some unique tokens
226
- # 32000, 32001, 32002
227
- added = tokenizer.add_tokens(["vllm1", "vllm2", "vllm3"],
228
- special_tokens=True)
229
- assert added == 3
230
- tokenizer.save_pretrained(tmp_model_dir)
231
- yield tmp_model_dir
232
- tmp_dir.cleanup()
tests/entrypoints/openai/test_chat.py
+2
-7
@@ -29,11 +29,7 @@ def monkeypatch_module():
29
30
31
@pytest.fixture(scope="module", params=[False, True])
32
-def server(
33
- request,
34
- monkeypatch_module,
35
- zephyr_lora_files, #noqa: F811
36
- zephyr_lora_added_tokens_files): # noqa: F811
32
+def server(request, monkeypatch_module, zephyr_lora_files): #noqa: F811
33
34
use_v1 = request.param
35
monkeypatch_module.setenv('VLLM_USE_V1', '1' if use_v1 else '0')
@@ -49,7 +45,6 @@ def server(
45
"--enable-lora",
46
"--lora-modules",
47
f"zephyr-lora={zephyr_lora_files}",
52
- f"zephyr-lora2={zephyr_lora_added_tokens_files}",
48
"--max-lora-rank",
49
"64",
50
"--max-cpu-loras",
@@ -79,7 +74,7 @@ async def client(server):
74
@pytest.mark.parametrize(
75
# first test base model, then test loras
76
"model_name",
82
- [MODEL_NAME, "zephyr-lora", "zephyr-lora2"],
77
+ [MODEL_NAME, "zephyr-lora"],
78
)
79
async def test_no_logprobs_chat(client: openai.AsyncOpenAI, model_name: str):
80
messages = [{
tests/entrypoints/openai/test_completion.py
+4
-19
@@ -27,7 +27,7 @@ GUIDED_DECODING_BACKENDS = ["outlines", "xgrammar", "guidance"]
27
28
29
@pytest.fixture(scope="module")
30
-def default_server_args(zephyr_lora_files, zephyr_lora_added_tokens_files):
30
+def default_server_args(zephyr_lora_files):
31
return [
32
# use half precision for speed and memory savings in CI environment
33
"--dtype",
@@ -41,7 +41,6 @@ def default_server_args(zephyr_lora_files, zephyr_lora_added_tokens_files):
41
"--enable-lora",
42
"--lora-modules",
43
f"zephyr-lora={zephyr_lora_files}",
44
- f"zephyr-lora2={zephyr_lora_added_tokens_files}",
44
"--max-lora-rank",
45
"64",
46
"--max-cpu-loras",
@@ -87,7 +86,7 @@ async def client(server):
86
@pytest.mark.parametrize(
87
# first test base model, then test loras
88
"model_name",
90
- [MODEL_NAME, "zephyr-lora", "zephyr-lora2"],
89
+ [MODEL_NAME, "zephyr-lora"],
90
)
91
async def test_single_completion(client: openai.AsyncOpenAI, model_name: str):
92
completion = await client.completions.create(model=model_name,
@@ -115,20 +114,6 @@ async def test_single_completion(client: openai.AsyncOpenAI, model_name: str):
114
assert completion.choices[0].prompt_logprobs is None
115
116
118
-@pytest.mark.asyncio
119
-async def test_added_lora_tokens(client: openai.AsyncOpenAI):
120
- # test using token IDs
121
- completion = await client.completions.create(
122
- model="zephyr-lora2",
123
- prompt=[0, 0, 32000, 32001, 32002],
124
- echo=True,
125
- max_tokens=5,
126
- temperature=0.0,
127
- )
128
- # Added tokens should appear in tokenized prompt
129
- assert completion.choices[0].text.startswith("<unk><unk>vllm1vllm2vllm3")
130
-
131
-
117
@pytest.mark.asyncio
118
async def test_added_lora_tokens_base_model(client: openai.AsyncOpenAI):
119
# test using token IDs
@@ -147,7 +132,7 @@ async def test_added_lora_tokens_base_model(client: openai.AsyncOpenAI):
132
@pytest.mark.parametrize(
133
# first test base model, then test loras
134
"model_name",
150
- [MODEL_NAME, "zephyr-lora", "zephyr-lora2"],
135
+ [MODEL_NAME, "zephyr-lora"],
136
)
137
async def test_no_logprobs(client: openai.AsyncOpenAI, model_name: str):
138
# test using token IDs
@@ -713,7 +698,7 @@ async def test_guided_grammar(client: openai.AsyncOpenAI,
698
@pytest.mark.parametrize(
699
# first test base model, then test loras
700
"model_name",
716
- [MODEL_NAME, "zephyr-lora", "zephyr-lora2"],
701
+ [MODEL_NAME, "zephyr-lora"],
702
)
703
@pytest.mark.parametrize("logprobs_arg", [1, 0])
704
async def test_echo_logprob_completion(client: openai.AsyncOpenAI,
tests/entrypoints/openai/test_completion_with_prompt_embeds.py
+1
-4
@@ -21,10 +21,7 @@ CONFIG = AutoConfig.from_pretrained(MODEL_NAME)
21
22
23
@pytest.fixture(scope="module")
24
-def default_server_args(
25
- zephyr_lora_files,
26
- zephyr_lora_added_tokens_files,
27
-) -> list[str]:
24
+def default_server_args() -> list[str]:
25
return [
26
# use half precision for speed and memory savings in CI environment
27
"--dtype",
tests/entrypoints/openai/test_lora_adapters.py
+1
-9
@@ -67,12 +67,6 @@ def server_with_lora_modules_json(request, monkeypatch_module,
67
"base_model_name": MODEL_NAME
68
}
69
70
- lora_module_2 = {
71
- "name": "zephyr-lora2",
72
- "path": zephyr_lora_files,
73
- "base_model_name": MODEL_NAME
74
- }
75
-
70
args = [
71
# use half precision for speed and memory savings in CI environment
72
"--dtype",
@@ -84,7 +78,6 @@ def server_with_lora_modules_json(request, monkeypatch_module,
78
"--enable-lora",
79
"--lora-modules",
80
json.dumps(lora_module_1),
87
- json.dumps(lora_module_2),
81
"--max-lora-rank",
82
"64",
83
"--max-cpu-loras",
@@ -121,7 +114,6 @@ async def test_static_lora_lineage(client: openai.AsyncOpenAI,
114
for lora_model in lora_models)
115
assert all(lora_model.parent == MODEL_NAME for lora_model in lora_models)
116
assert lora_models[0].id == "zephyr-lora"
124
- assert lora_models[1].id == "zephyr-lora2"
117
118
119
@pytest.mark.asyncio
@@ -209,7 +201,7 @@ async def test_dynamic_lora_badrequests(client: openai.AsyncOpenAI, tmp_path,
201
@pytest.mark.asyncio
202
async def test_multiple_lora_adapters(client: openai.AsyncOpenAI, tmp_path,
203
zephyr_lora_files):
212
- """Validate that many loras can be dynamically registered and inferenced
204
+ """Validate that many loras can be dynamically registered and inferenced
205
with concurrently"""
206
207
# This test file configures the server with --max-cpu-loras=2 and this test
tests/entrypoints/openai/test_models.py
-2
@@ -26,7 +26,6 @@ def server(zephyr_lora_files):
26
"--enable-lora",
27
"--lora-modules",
28
f"zephyr-lora={zephyr_lora_files}",
29
- f"zephyr-lora2={zephyr_lora_files}",
29
"--max-lora-rank",
30
"64",
31
"--max-cpu-loras",
@@ -56,4 +55,3 @@ async def test_check_models(client: openai.AsyncOpenAI, zephyr_lora_files):
55
assert all(lora_model.root == zephyr_lora_files
56
for lora_model in lora_models)
57
assert lora_models[0].id == "zephyr-lora"
59
- assert lora_models[1].id == "zephyr-lora2"
tests/entrypoints/openai/test_tokenization.py
+10
-18
@@ -14,7 +14,7 @@ MODEL_NAME = "HuggingFaceH4/zephyr-7b-beta"
14
15
16
@pytest.fixture(scope="module")
17
-def server(zephyr_lora_added_tokens_files: str): # noqa: F811
17
+def server():
18
args = [
19
# use half precision for speed and memory savings in CI environment
20
"--dtype",
@@ -24,12 +24,6 @@ def server(zephyr_lora_added_tokens_files: str): # noqa: F811
24
"--enforce-eager",
25
"--max-num-seqs",
26
"128",
27
- # lora config
28
- "--enable-lora",
29
- "--lora-modules",
30
- f"zephyr-lora2={zephyr_lora_added_tokens_files}",
31
- "--max-lora-rank",
32
- "64",
27
"--enable-tokenizer-info-endpoint",
28
]
29
@@ -38,10 +32,8 @@ def server(zephyr_lora_added_tokens_files: str): # noqa: F811
32
33
34
@pytest.fixture(scope="module")
41
-def tokenizer_name(model_name: str,
42
- zephyr_lora_added_tokens_files: str): # noqa: F811
43
- return zephyr_lora_added_tokens_files if (
44
- model_name == "zephyr-lora2") else model_name
35
+def tokenizer_name(model_name: str):
36
+ return model_name
37
38
39
@pytest_asyncio.fixture
@@ -53,7 +45,7 @@ async def client(server):
45
@pytest.mark.asyncio
46
@pytest.mark.parametrize(
47
"model_name,tokenizer_name",
56
- [(MODEL_NAME, MODEL_NAME), ("zephyr-lora2", "zephyr-lora2")],
48
+ [(MODEL_NAME, MODEL_NAME)],
49
indirect=["tokenizer_name"],
50
)
51
async def test_tokenize_completions(
@@ -86,7 +78,7 @@ async def test_tokenize_completions(
78
@pytest.mark.asyncio
79
@pytest.mark.parametrize(
80
"model_name,tokenizer_name",
89
- [(MODEL_NAME, MODEL_NAME), ("zephyr-lora2", "zephyr-lora2")],
81
+ [(MODEL_NAME, MODEL_NAME)],
82
indirect=["tokenizer_name"],
83
)
84
async def test_tokenize_chat(
@@ -148,7 +140,7 @@ async def test_tokenize_chat(
140
@pytest.mark.asyncio
141
@pytest.mark.parametrize(
142
"model_name,tokenizer_name",
151
- [(MODEL_NAME, MODEL_NAME), ("zephyr-lora2", "zephyr-lora2")],
143
+ [(MODEL_NAME, MODEL_NAME)],
144
indirect=["tokenizer_name"],
145
)
146
async def test_tokenize_chat_with_tools(
@@ -225,7 +217,7 @@ async def test_tokenize_chat_with_tools(
217
@pytest.mark.asyncio
218
@pytest.mark.parametrize(
219
"model_name, tokenizer_name",
228
- [(MODEL_NAME, MODEL_NAME), ("zephyr-lora2", "zephyr-lora2")],
220
+ [(MODEL_NAME, MODEL_NAME)],
221
indirect=["tokenizer_name"],
222
)
223
async def test_tokenize_with_return_token_strs(
@@ -260,7 +252,7 @@ async def test_tokenize_with_return_token_strs(
252
@pytest.mark.asyncio
253
@pytest.mark.parametrize(
254
"model_name,tokenizer_name",
263
- [(MODEL_NAME, MODEL_NAME), ("zephyr-lora2", "zephyr-lora2")],
255
+ [(MODEL_NAME, MODEL_NAME)],
256
indirect=["tokenizer_name"],
257
)
258
async def test_detokenize(
@@ -287,7 +279,7 @@ async def test_detokenize(
279
@pytest.mark.asyncio
280
@pytest.mark.parametrize(
281
"model_name,tokenizer_name",
290
- [(MODEL_NAME, MODEL_NAME), ("zephyr-lora2", "zephyr-lora2")],
282
+ [(MODEL_NAME, MODEL_NAME)],
283
indirect=["tokenizer_name"],
284
)
285
async def test_tokenizer_info_basic(
@@ -384,4 +376,4 @@ async def test_tokenizer_info_chat_template(server: RemoteOpenAIServer):
376
if chat_template:
377
assert isinstance(chat_template,
378
str), ("Chat template should be a string")
387
- assert chat_template.strip(), "Chat template should not be empty"
\ No newline at end of file
379
+ assert chat_template.strip(), "Chat template should not be empty"
tests/entrypoints/openai/tool_parsers/test_hermes_tool_parser.py
+2
@@ -18,6 +18,8 @@ SERVER_ARGS = [
18
"--enable-lora",
19
"--lora-modules",
20
f"{LORA_MODEL}={LORA_MODEL}",
21
+ "--tokenizer",
22
+ f"{LORA_MODEL}",
23
]
24
25
TOOLS = [{
tests/entrypoints/test_chat_utils.py
+10
-46
@@ -23,7 +23,7 @@ from vllm.entrypoints.chat_utils import (_try_extract_ast, load_chat_template,
23
from vllm.multimodal import MultiModalDataDict, MultiModalUUIDDict
24
from vllm.multimodal.utils import (encode_audio_base64, encode_image_base64,
25
encode_video_base64)
26
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
26
+from vllm.transformers_utils.tokenizer import get_tokenizer
27
from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
28
29
from ..models.registry import HF_EXAMPLE_MODELS
@@ -69,12 +69,7 @@ def phi3v_model_config_mm_interleaved():
69
70
@pytest.fixture(scope="module")
71
def phi3v_tokenizer():
72
- return TokenizerGroup(
73
- tokenizer_id=PHI3V_MODEL_ID,
74
- enable_lora=False,
75
- max_num_seqs=5,
76
- max_input_length=None,
77
- )
72
+ return get_tokenizer(PHI3V_MODEL_ID)
73
74
75
@pytest.fixture(scope="function")
@@ -91,12 +86,7 @@ def qwen2_audio_model_config():
86
87
@pytest.fixture(scope="module")
88
def qwen2_audio_tokenizer():
94
- return TokenizerGroup(
95
- tokenizer_id=QWEN2AUDIO_MODEL_ID,
96
- enable_lora=False,
97
- max_num_seqs=5,
98
- max_input_length=None,
99
- )
89
+ return get_tokenizer(QWEN2AUDIO_MODEL_ID)
90
91
92
@pytest.fixture(scope="function")
@@ -115,12 +105,7 @@ def qwen25omni_model_config_mm_interleaved():
105
106
@pytest.fixture(scope="module")
107
def qwen25omni_tokenizer():
118
- return TokenizerGroup(
119
- tokenizer_id=QWEN25OMNI_MODEL_ID,
120
- enable_lora=False,
121
- max_num_seqs=5,
122
- max_input_length=None,
123
- )
108
+ return get_tokenizer(QWEN25OMNI_MODEL_ID)
109
110
111
@pytest.fixture(scope="function")
@@ -136,12 +121,7 @@ def mistral_model_config():
121
122
@pytest.fixture(scope="module")
123
def mistral_tokenizer():
139
- return TokenizerGroup(
140
- tokenizer_id=MISTRAL_MODEL_ID,
141
- enable_lora=False,
142
- max_num_seqs=5,
143
- max_input_length=None,
144
- )
124
+ return get_tokenizer(MISTRAL_MODEL_ID)
125
126
127
@pytest.fixture(scope="module")
@@ -2250,15 +2230,11 @@ def test_resolve_hf_chat_template(sample_json_schema, model, use_tools):
2230
enforce_eager=model_info.enforce_eager,
2231
dtype=model_info.dtype)
2232
2253
- # Build the tokenizer group and grab the underlying tokenizer
2254
- tokenizer_group = TokenizerGroup(
2233
+ # Build the tokenizer
2234
+ tokenizer = get_tokenizer(
2235
model,
2256
- enable_lora=False,
2257
- max_num_seqs=5,
2258
- max_input_length=None,
2236
trust_remote_code=model_config.trust_remote_code,
2237
)
2261
- tokenizer = tokenizer_group.tokenizer
2238
2239
tools = ([{
2240
"type": "function",
@@ -2307,14 +2283,10 @@ def test_resolve_content_format_hf_defined(model, expected_format):
2283
enforce_eager=model_info.enforce_eager,
2284
dtype=model_info.dtype)
2285
2310
- tokenizer_group = TokenizerGroup(
2286
+ tokenizer = get_tokenizer(
2287
model,
2312
- enable_lora=False,
2313
- max_num_seqs=5,
2314
- max_input_length=None,
2288
trust_remote_code=model_config.trust_remote_code,
2289
)
2317
- tokenizer = tokenizer_group.tokenizer
2290
2291
# Test detecting the tokenizer's chat_template
2292
chat_template = resolve_hf_chat_template(
@@ -2368,14 +2340,10 @@ def test_resolve_content_format_fallbacks(model, expected_format):
2340
enforce_eager=model_info.enforce_eager,
2341
dtype=model_info.dtype)
2342
2371
- tokenizer_group = TokenizerGroup(
2343
+ tokenizer = get_tokenizer(
2344
model_config.tokenizer,
2373
- enable_lora=False,
2374
- max_num_seqs=5,
2375
- max_input_length=None,
2345
trust_remote_code=model_config.trust_remote_code,
2346
)
2378
- tokenizer = tokenizer_group.tokenizer
2347
2348
# Test detecting the tokenizer's chat_template
2349
chat_template = resolve_hf_chat_template(
@@ -2432,14 +2400,10 @@ def test_resolve_content_format_examples(template_path, expected_format):
2400
trust_remote_code=True,
2401
)
2402
2435
- tokenizer_group = TokenizerGroup(
2403
+ dummy_tokenizer = get_tokenizer(
2404
PHI3V_MODEL_ID, # Dummy
2437
- enable_lora=False,
2438
- max_num_seqs=5,
2439
- max_input_length=None,
2405
trust_remote_code=model_config.trust_remote_code,
2406
)
2442
- dummy_tokenizer = tokenizer_group.tokenizer
2407
dummy_tokenizer.chat_template = None
2408
2409
chat_template = load_chat_template(EXAMPLES_DIR / template_path)
tests/lora/test_llama_tp.py
+4
-24
@@ -13,14 +13,6 @@ from ..utils import VLLM_PATH, create_new_process_for_each_test, multi_gpu_test
13
14
MODEL_PATH = "meta-llama/Llama-2-7b-hf"
15
16
-EXPECTED_NO_LORA_OUTPUT = [
17
- "\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_75 (icao VARCHAR, airport VARCHAR)\n\n question: Name the ICAO for lilongwe international airport [/user] [assistant]\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_76 (icao VARCHAR, airport VARCHAR)\n\n question: Name the ICAO for lilongwe international airport [/user] [assistant]\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_77 (icao VARCHAR, airport VARCHAR)\n\n question: Name the ICAO for lilongwe international airport [/user] [assistant]\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_78 (icao VARCHAR, airport VARCHAR)\n\n question: Name the ICAO for lilongwe international airport [/user]", # noqa: E501
18
- " Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_11 (nationality VARCHAR, elector VARCHAR)\n\n question: When Anchero Pantaleone was the elector what is under nationality? ", # noqa: E501
19
- "\n\n answer: 1\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_96 (one_mora VARCHAR, gloss VARCHAR, accented_mora VARCHAR)\n\n question: What is the one mora for a high tone mora with a gloss of /˧kot/ [kòt]? [/user] [assistant]\n\n answer: 2\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_97 (one_mora VARCHAR, gloss VARCHAR, accented_mora VARCHAR)\n\n question: What is the one mora for a high tone mora with a gloss of /˧kot/ [kòt]? [/user] [assistant]\n\n answer: 2\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_98 (one_mora VARCHAR, gloss VARCHAR, accented_mora VARCHAR)\n\n question: What is the one m", # noqa: E501
20
- " Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE candidate (people_id VARCHAR, unsure_rate INTEGER); CREATE TABLE people (sex VARCHAR, people_id VARCHAR)\n\n question: which gender got the highest average uncertain ratio. ", # noqa: E501
21
- " Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_name_60 (pick INTEGER, former_wnba_team VARCHAR)\n\n question: What pick was a player that previously played for the Minnesota Lynx? ", # noqa: E501
22
- "\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_28138035_4 (womens_doubles VARCHAR, mens_singles VARCHAR)\n\n question: Name the women's doubles for werner schlager [/user] [assistant]\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_28138035_4 (womens_doubles VARCHAR, mens_singles VARCHAR)\n\n question: Name the women's doubles for werner schlager [/user] [assistant]\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE table_28138035_4 (womens_doubles VARCHAR, mens_singles VARCHAR)\n\n question: Name the women's doubles for werner schlager [/user] [assistant]\n\n [user] Write a SQL query to answer the question based on the table schema.\n\n context: CREATE TABLE", # noqa: E501
23
-]
16
EXPECTED_LORA_OUTPUT = [
17
" SELECT icao FROM table_name_74 WHERE airport = 'lilongwe international airport' ", # noqa: E501
18
" SELECT nationality FROM table_name_11 WHERE elector = 'anchero pantaleone' ", # noqa: E501
@@ -79,23 +71,12 @@ def generate_and_test(llm,
71
sql_lora_files,
72
tensorizer_config_dict: Union[dict, None] = None):
73
print("lora adapter created")
82
- assert do_sample(llm,
83
- sql_lora_files,
84
- tensorizer_config_dict=tensorizer_config_dict,
85
- lora_id=0) == EXPECTED_NO_LORA_OUTPUT
86
-
74
print("lora 1")
75
assert do_sample(llm,
76
sql_lora_files,
77
tensorizer_config_dict=tensorizer_config_dict,
78
lora_id=1) == EXPECTED_LORA_OUTPUT
79
93
- print("no lora")
94
- assert do_sample(llm,
95
- sql_lora_files,
96
- tensorizer_config_dict=tensorizer_config_dict,
97
- lora_id=0) == EXPECTED_NO_LORA_OUTPUT
98
-
80
print("lora 2")
81
assert do_sample(llm,
82
sql_lora_files,
@@ -110,6 +91,7 @@ def test_llama_lora(sql_lora_files):
91
92
llm = vllm.LLM(
93
MODEL_PATH,
94
+ tokenizer=sql_lora_files,
95
enable_lora=True,
96
# also test odd max_num_seqs
97
max_num_seqs=13,
@@ -123,6 +105,7 @@ def test_llama_lora_tp4(sql_lora_files):
105
106
llm = vllm.LLM(
107
MODEL_PATH,
108
+ tokenizer=sql_lora_files,
109
enable_lora=True,
110
max_num_seqs=16,
111
max_loras=4,
@@ -137,6 +120,7 @@ def test_llama_lora_tp4_fully_sharded_loras(sql_lora_files):
120
121
llm = vllm.LLM(
122
MODEL_PATH,
123
+ tokenizer=sql_lora_files,
124
enable_lora=True,
125
max_num_seqs=16,
126
max_loras=4,
@@ -184,6 +168,7 @@ def test_tp2_serialize_and_deserialize_lora(tmp_path, sql_lora_files,
168
tensorizer_config = TensorizerConfig(tensorizer_uri=str(model_uri))
169
170
loaded_llm = LLM(model=model_ref,
171
+ tokenizer=sql_lora_files,
172
load_format="tensorizer",
173
enable_lora=True,
174
enforce_eager=True,
@@ -195,11 +180,6 @@ def test_tp2_serialize_and_deserialize_lora(tmp_path, sql_lora_files,
180
tc_as_dict = tensorizer_config.to_serializable()
181
182
print("lora adapter created")
198
- assert do_sample(loaded_llm,
199
- sql_lora_files,
200
- tensorizer_config_dict=tc_as_dict,
201
- lora_id=0) == EXPECTED_NO_LORA_OUTPUT
202
-
183
print("lora 1")
184
assert do_sample(loaded_llm,
185
sql_lora_files,
tests/lora/test_lora_allowed_token_ids.py
deleted
-135
@@ -1,135 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-import pytest
5
-
6
-from vllm.config import CacheConfig, DeviceConfig, ModelConfig, VllmConfig
7
-from vllm.config.lora import LoRAConfig
8
-from vllm.lora.request import LoRARequest
9
-from vllm.sampling_params import SamplingParams
10
-from vllm.transformers_utils.tokenizer_group import init_tokenizer_from_configs
11
-from vllm.v1.engine.processor import Processor
12
-
13
-
14
-def test_allowed_token_ids_with_lora_vocab(llama_2_7b_base_huggingface_id,
15
- sql_lora_files):
16
- """
17
- Test that we properly resolve the range of allowed token ids for lora
18
- adapters that define additional tokens.
19
- """
20
-
21
- # Set up a base model compatible with the sql_lora_files adapter and
22
- # a known number of tokens in the base model.
23
- model_config = ModelConfig(
24
- model=llama_2_7b_base_huggingface_id,
25
- tokenizer=llama_2_7b_base_huggingface_id,
26
- tokenizer_mode="auto",
27
- )
28
-
29
- vllm_config = VllmConfig(
30
- model_config=model_config,
31
- cache_config=CacheConfig(),
32
- device_config=DeviceConfig(),
33
- lora_config=LoRAConfig(),
34
- )
35
-
36
- tokenizer = init_tokenizer_from_configs(
37
- model_config=vllm_config.model_config,
38
- scheduler_config=vllm_config.scheduler_config,
39
- lora_config=vllm_config.lora_config)
40
- processor = Processor(vllm_config, tokenizer)
41
-
42
- lora_request = LoRARequest("1", 1, str(sql_lora_files))
43
- request_id = "1"
44
- prompt = "a prompt"
45
-
46
- # tokens added in the lora adapter should not raise an error
47
- lora_token_ids = [32000, 32001, 32002, 32003]
48
- processor.process_inputs(
49
- request_id,
50
- prompt,
51
- params=SamplingParams(allowed_token_ids=lora_token_ids),
52
- lora_request=lora_request)
53
-
54
- # tokens in the base model should not raise an error
55
- base_token_ids = [1000, 1001, 1002, 1003]
56
- processor.process_inputs(
57
- request_id,
58
- prompt,
59
- params=SamplingParams(allowed_token_ids=base_token_ids),
60
- lora_request=lora_request)
61
-
62
- # tokens not in the lora adapter should raise an error
63
- invalid_token_ids = [35000, 35001, 35002, 35003]
64
- with pytest.raises(ValueError):
65
- processor.process_inputs(
66
- request_id,
67
- prompt,
68
- params=SamplingParams(allowed_token_ids=invalid_token_ids),
69
- lora_request=lora_request)
70
-
71
- # tokens in the lora adapter with no lora request should raise an error
72
- with pytest.raises(ValueError):
73
- processor.process_inputs(
74
- request_id,
75
- prompt,
76
- params=SamplingParams(allowed_token_ids=lora_token_ids),
77
- )
78
-
79
-
80
-def test_allowed_token_ids_with_lora_adapter_no_vocab(
81
- qwen25vl_base_huggingface_id, qwen25vl_lora_files):
82
- """
83
- Test that we properly resolve the range of allowed token ids for lora
84
- adapters that do not define additional tokens.
85
- """
86
-
87
- # Set up a base model compatible with the qwen25vl_lora_files adapter and
88
- # a known number of tokens in the base model.
89
- model_config = ModelConfig(
90
- model=qwen25vl_base_huggingface_id,
91
- tokenizer=qwen25vl_base_huggingface_id,
92
- tokenizer_mode="auto",
93
- )
94
-
95
- vllm_config = VllmConfig(
96
- model_config=model_config,
97
- cache_config=CacheConfig(),
98
- device_config=DeviceConfig(),
99
- lora_config=LoRAConfig(),
100
- )
101
-
102
- tokenizer = init_tokenizer_from_configs(
103
- model_config=vllm_config.model_config,
104
- scheduler_config=vllm_config.scheduler_config,
105
- lora_config=vllm_config.lora_config)
106
- processor = Processor(vllm_config, tokenizer)
107
-
108
- lora_request = LoRARequest("1", 1, str(qwen25vl_lora_files))
109
- request_id = "1"
110
- prompt = "a prompt"
111
-
112
- # tokens in the base model should not raise an error
113
- base_token_ids = [1000, 1001, 1002, 1003]
114
- processor.process_inputs(
115
- request_id,
116
- prompt,
117
- params=SamplingParams(allowed_token_ids=base_token_ids),
118
- lora_request=lora_request)
119
-
120
- # tokens in the base model with no lora request should not raise an error
121
- base_token_ids = [1000, 1001, 1002, 1003]
122
- processor.process_inputs(
123
- request_id,
124
- prompt,
125
- params=SamplingParams(allowed_token_ids=base_token_ids),
126
- )
127
-
128
- # tokens not in the base model should raise an error
129
- invalid_token_ids = [200000, 200001, 200002, 200003]
130
- with pytest.raises(ValueError):
131
- processor.process_inputs(
132
- request_id,
133
- prompt,
134
- params=SamplingParams(allowed_token_ids=invalid_token_ids),
135
- lora_request=lora_request)
tests/lora/test_quant_model.py
+2
-27
@@ -82,31 +82,20 @@ def test_quant_model_lora(tinyllama_lora_files, model):
82
gpu_memory_utilization=0.2, #avoid OOM
83
quantization=model.quantization,
84
trust_remote_code=True,
85
- enable_chunked_prefill=True)
85
+ enable_chunked_prefill=True,
86
+ tokenizer=tinyllama_lora_files)
87
88
if model.quantization is None:
88
- expected_no_lora_output = [
89
- "Here are some examples of orange-brown colors",
90
- "I'm sorry, I don't have"
91
- ]
89
expected_lora_output = [
90
"#ff8050",
91
"#ff8080",
92
]
93
elif model.quantization == "awq":
97
- expected_no_lora_output = [
98
- "I'm sorry, I don't understand",
99
- "I'm sorry, I don't understand",
100
- ]
94
expected_lora_output = [
95
"#f07700: A v",
96
"#f00000: A v",
97
]
98
elif model.quantization == "gptq":
106
- expected_no_lora_output = [
107
- "I'm sorry, I don't have",
108
- "I'm sorry, I don't have",
109
- ]
99
expected_lora_output = [
100
"#f08800: This is",
101
"#f07788 \n#",
@@ -117,7 +106,6 @@ def test_quant_model_lora(tinyllama_lora_files, model):
106
# Assert that the outputs changed.
107
if (model.quantization == "gptq"
108
and expected_output is expected_lora_output):
120
- assert output != expected_no_lora_output
109
for i, o in enumerate(output):
110
assert o.startswith(
111
'#'), f"Expected example {i} to start with # but got {o}"
@@ -127,12 +115,6 @@ def test_quant_model_lora(tinyllama_lora_files, model):
115
max_tokens = 10
116
117
print("lora adapter created")
130
- output = do_sample(llm,
131
- tinyllama_lora_files,
132
- lora_id=0,
133
- max_tokens=max_tokens)
134
- expect_match(output, expected_no_lora_output)
135
-
118
print("lora 1")
119
output = do_sample(llm,
120
tinyllama_lora_files,
@@ -140,13 +122,6 @@ def test_quant_model_lora(tinyllama_lora_files, model):
122
max_tokens=max_tokens)
123
expect_match(output, expected_lora_output)
124
143
- print("no lora")
144
- output = do_sample(llm,
145
- tinyllama_lora_files,
146
- lora_id=0,
147
- max_tokens=max_tokens)
148
- expect_match(output, expected_no_lora_output)
149
-
125
print("lora 2")
126
output = do_sample(llm,
127
tinyllama_lora_files,
tests/lora/test_tokenizer_group.py
deleted
-72
@@ -1,72 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-import pytest
5
-from transformers import AutoTokenizer, PreTrainedTokenizerBase
6
-
7
-from vllm.lora.request import LoRARequest
8
-from vllm.transformers_utils.tokenizer import get_lora_tokenizer
9
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
10
-
11
-
12
-@pytest.mark.asyncio
13
-@pytest.mark.parametrize("tokenizer_group_type", [None, "ray"])
14
-async def test_tokenizer_group_lora(sql_lora_files, tokenizer_group_type):
15
- reference_tokenizer = AutoTokenizer.from_pretrained(sql_lora_files)
16
- tokenizer_group = TokenizerGroup(
17
- tokenizer_id="gpt2",
18
- enable_lora=True,
19
- max_num_seqs=1,
20
- max_loras=1,
21
- max_input_length=None,
22
- )
23
- lora_request = LoRARequest("1", 1, sql_lora_files)
24
- assert reference_tokenizer.encode("prompt") == tokenizer_group.encode(
25
- prompt="prompt", lora_request=lora_request)
26
- assert reference_tokenizer.encode(
27
- "prompt") == await tokenizer_group.encode_async(
28
- prompt="prompt", lora_request=lora_request)
29
- assert isinstance(tokenizer_group.get_lora_tokenizer(None),
30
- PreTrainedTokenizerBase)
31
- assert tokenizer_group.get_lora_tokenizer(
32
- None) == await tokenizer_group.get_lora_tokenizer_async(None)
33
-
34
- assert isinstance(tokenizer_group.get_lora_tokenizer(lora_request),
35
- PreTrainedTokenizerBase)
36
- assert tokenizer_group.get_lora_tokenizer(
37
- lora_request) != tokenizer_group.get_lora_tokenizer(None)
38
- assert tokenizer_group.get_lora_tokenizer(
39
- lora_request) == await tokenizer_group.get_lora_tokenizer_async(
40
- lora_request)
41
-
42
-
43
-def test_get_lora_tokenizer(sql_lora_files, tmp_path):
44
- lora_request = None
45
- tokenizer = get_lora_tokenizer(lora_request)
46
- assert not tokenizer
47
-
48
- lora_request = LoRARequest("1", 1, sql_lora_files)
49
- tokenizer = get_lora_tokenizer(lora_request)
50
- assert tokenizer.get_added_vocab()
51
-
52
- lora_request = LoRARequest("1", 1, str(tmp_path))
53
- tokenizer = get_lora_tokenizer(lora_request)
54
- assert not tokenizer
55
-
56
-
57
-@pytest.mark.parametrize("enable_lora", [True, False])
58
-@pytest.mark.parametrize("max_num_seqs", [1, 2])
59
-@pytest.mark.parametrize("max_loras", [1, 2])
60
-def test_lora_tokenizers(enable_lora, max_num_seqs, max_loras):
61
- tokenizer_group = TokenizerGroup(
62
- tokenizer_id="gpt2",
63
- enable_lora=enable_lora,
64
- max_num_seqs=max_num_seqs,
65
- max_loras=max_loras,
66
- max_input_length=None,
67
- )
68
- if enable_lora:
69
- assert tokenizer_group.lora_tokenizers.capacity == max(
70
- max_num_seqs, max_loras)
71
- else:
72
- assert tokenizer_group.lora_tokenizers.capacity == 0
tests/test_cache_block_hashing.py
+3
-8
@@ -11,7 +11,7 @@ import pytest
11
from vllm.inputs import token_inputs
12
from vllm.lora.request import LoRARequest
13
from vllm.sequence import Sequence
14
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
14
+from vllm.transformers_utils.tokenizer import get_tokenizer
15
16
# Make two prefixes with different first blocks.
17
prefix_start = [("You are an expert"), ("You are a")]
@@ -47,12 +47,7 @@ def flatten_2d(li):
47
def test_auto_prefix_caching(model: str, block_size: int, max_num_seqs: int,
48
concurrent_lora_int_ids: list[Optional[int]]):
49
50
- tokenizer = TokenizerGroup(
51
- tokenizer_id="facebook/opt-125m",
52
- enable_lora=False,
53
- max_num_seqs=max_num_seqs,
54
- max_input_length=None,
55
- )
50
+ tokenizer = get_tokenizer("facebook/opt-125m")
51
52
hashes: list[list[list[int]]] = []
53
@@ -76,7 +71,7 @@ def test_auto_prefix_caching(model: str, block_size: int, max_num_seqs: int,
71
inputs=token_inputs(prompt_token_ids,
72
prompt=prompt),
73
block_size=block_size,
79
- eos_token_id=tokenizer.tokenizer.eos_token_id,
74
+ eos_token_id=tokenizer.eos_token_id,
75
lora_request=lora_request)
76
77
num_blocks = len(prompt_token_ids) // block_size
tests/tokenization/test_detokenize.py
+6
-10
@@ -11,7 +11,7 @@ from transformers import (AutoTokenizer, PreTrainedTokenizer,
11
from vllm.inputs import token_inputs
12
from vllm.sequence import Logprob, SamplingParams, Sequence, SequenceGroup
13
from vllm.transformers_utils.detokenizer import Detokenizer
14
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
14
+from vllm.transformers_utils.tokenizer import get_tokenizer
15
from vllm.transformers_utils.tokenizers.mistral import MistralTokenizer
16
from vllm.v1.engine import EngineCoreRequest
17
from vllm.v1.engine.detokenizer import (FastIncrementalDetokenizer,
@@ -221,17 +221,14 @@ def test_oov_decode(tokenizer, fast):
221
222
@pytest.fixture
223
def detokenizer(tokenizer_name: str) -> Detokenizer:
224
- tokenizer_group = TokenizerGroup(
225
- tokenizer_id=tokenizer_name,
226
- enable_lora=False,
227
- max_num_seqs=100,
228
- max_input_length=None,
224
+ tokenizer = get_tokenizer(
225
+ tokenizer_name,
226
tokenizer_mode="mistral" if "mistral" in tokenizer_name else "auto",
227
trust_remote_code=False,
228
revision=None,
229
)
230
234
- return Detokenizer(tokenizer_group)
231
+ return Detokenizer(tokenizer)
232
233
234
@pytest.fixture(name="complete_sequence_token_ids")
@@ -312,8 +309,7 @@ def test_decode_prompt_logprobs(complete_sequence: str,
309
# don't support that.
310
if complete_sequence not in SPECIAL_TOKS_TRUTH:
311
skip_special_tokens = True
315
- elif not isinstance(detokenizer.tokenizer_group.get_lora_tokenizer(None),
316
- MistralTokenizer):
312
+ elif not isinstance(detokenizer.tokenizer, MistralTokenizer):
313
skip_special_tokens = False
314
else:
315
pytest.skip("MistralTokenizers don't support "
@@ -339,7 +335,7 @@ def test_decode_prompt_logprobs(complete_sequence: str,
335
336
# decoded_prompt_logprobs doesn't contain the first token.
337
token_ids = complete_sequence_token_ids
342
- tokenizer = detokenizer.get_tokenizer_for_seq(seq)
338
+ tokenizer = detokenizer.tokenizer
339
text_full = tokenizer.decode(token_ids,
340
skip_special_tokens=skip_special_tokens)
341
text_first = tokenizer.decode(token_ids[0],
tests/tokenization/test_tokenizer_group.py
deleted
-27
@@ -1,27 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-import pytest
5
-from transformers import AutoTokenizer, PreTrainedTokenizerBase
6
-
7
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
8
-
9
-
10
-@pytest.mark.asyncio
11
-async def test_tokenizer_group():
12
- reference_tokenizer = AutoTokenizer.from_pretrained("gpt2")
13
- tokenizer_group = TokenizerGroup(
14
- tokenizer_id="gpt2",
15
- enable_lora=False,
16
- max_num_seqs=1,
17
- max_input_length=None,
18
- )
19
- assert reference_tokenizer.encode("prompt") == tokenizer_group.encode(
20
- prompt="prompt", lora_request=None)
21
- assert reference_tokenizer.encode(
22
- "prompt") == await tokenizer_group.encode_async(prompt="prompt",
23
- lora_request=None)
24
- assert isinstance(tokenizer_group.get_lora_tokenizer(None),
25
- PreTrainedTokenizerBase)
26
- assert tokenizer_group.get_lora_tokenizer(
27
- None) == await tokenizer_group.get_lora_tokenizer_async(None)
tests/tokenization/test_tokenizer_registry.py
+4
@@ -57,6 +57,10 @@ class TestTokenizer(TokenizerBase):
57
def max_token_id(self) -> int:
58
raise NotImplementedError()
59
60
+ @property
61
+ def truncation_side(self) -> str:
62
+ raise NotImplementedError()
63
+
64
def __call__(
65
self,
66
text: Union[str, list[str], list[int]],
tests/v1/engine/conftest.py
+2
-6
@@ -12,7 +12,6 @@ from tests.v1.engine.utils import (NUM_PROMPT_LOGPROBS_UNDER_TEST,
12
generate_dummy_prompt_logprobs_tensors,
13
generate_dummy_sample_logprobs)
14
from vllm.engine.arg_utils import EngineArgs
15
-from vllm.transformers_utils.tokenizer_group import init_tokenizer_from_configs
15
16
from ...distributed.conftest import publisher_config, random_port # noqa: F401
17
@@ -24,7 +23,7 @@ EngineCorePromptLogprobsType = tuple[torch.Tensor, torch.Tensor]
23
24
def _build_test_vectors_no_logprobs() -> DummyOutputProcessorTestVectors:
25
"""Generate output processor dummy test vectors, without logprobs
27
-
26
+
27
Returns:
28
DummyOutputProcessorTestVectors instance with no logprobs
29
"""
@@ -48,9 +47,6 @@ def _build_test_vectors_no_logprobs() -> DummyOutputProcessorTestVectors:
47
]
48
return DummyOutputProcessorTestVectors(
49
tokenizer=tokenizer,
51
- tokenizer_group=init_tokenizer_from_configs(
52
- vllm_config.model_config, vllm_config.scheduler_config,
53
- vllm_config.lora_config),
50
vllm_config=vllm_config,
51
full_tokens=[tokenizer(text).input_ids for text in FULL_STRINGS],
52
prompt_tokens=prompt_tokens,
@@ -68,7 +64,7 @@ def _build_test_vectors_no_logprobs() -> DummyOutputProcessorTestVectors:
64
@pytest.fixture
65
def dummy_test_vectors() -> DummyOutputProcessorTestVectors:
66
"""Generate output processor dummy test vectors, with logprobs
71
-
67
+
68
Returns:
69
DummyOutputProcessorTestVectors instance with logprobs
70
"""
tests/v1/engine/test_output_processor.py
+5
-5
@@ -43,7 +43,7 @@ def _ref_convert_id_to_token(
43
[RequestOutputKind.DELTA, RequestOutputKind.FINAL_ONLY])
44
def test_incremental_detokenization(request_output_kind: RequestOutputKind,
45
dummy_test_vectors):
46
- output_processor = OutputProcessor(dummy_test_vectors.tokenizer_group,
46
+ output_processor = OutputProcessor(dummy_test_vectors.tokenizer,
47
log_stats=False)
48
engine_core = MockEngineCore(
49
tokens_list=dummy_test_vectors.generation_tokens)
@@ -382,7 +382,7 @@ def test_logprobs_processor(request_output_kind: RequestOutputKind,
382
num_sample_logprobs: Optional[int],
383
num_prompt_logprobs: Optional[int],
384
dummy_test_vectors):
385
- output_processor = OutputProcessor(dummy_test_vectors.tokenizer_group,
385
+ output_processor = OutputProcessor(dummy_test_vectors.tokenizer,
386
log_stats=False)
387
engine_core = MockEngineCore(
388
tokens_list=dummy_test_vectors.generation_tokens,
@@ -535,7 +535,7 @@ def test_stop_token(include_stop_str_in_output: bool,
535
) # '<|end_of_text|>'
536
stop_token_ids = [128009] if not is_eos_test else None # '<|eot_id|>'
537
538
- output_processor = OutputProcessor(dummy_test_vectors.tokenizer_group,
538
+ output_processor = OutputProcessor(dummy_test_vectors.tokenizer,
539
log_stats=False)
540
# Dummy engine core outputs, with control tokens suffixed to test stops
541
suffix_token = ([eos_token_id] if is_eos_test else stop_token_ids)
@@ -642,7 +642,7 @@ def test_stop_token(include_stop_str_in_output: bool,
642
[None, NUM_SAMPLE_LOGPROBS_UNDER_TEST])
643
def test_stop_string(include_stop_str_in_output: bool,
644
num_sample_logprobs: Optional[int], dummy_test_vectors):
645
- output_processor = OutputProcessor(dummy_test_vectors.tokenizer_group,
645
+ output_processor = OutputProcessor(dummy_test_vectors.tokenizer,
646
log_stats=False)
647
engine_core = MockEngineCore(
648
tokens_list=dummy_test_vectors.generation_tokens,
@@ -763,7 +763,7 @@ def test_stop_string(include_stop_str_in_output: bool,
763
764
765
def test_iteration_stats(dummy_test_vectors):
766
- output_processor = OutputProcessor(dummy_test_vectors.tokenizer_group,
766
+ output_processor = OutputProcessor(dummy_test_vectors.tokenizer,
767
log_stats=True)
768
engine_core = MockEngineCore(dummy_test_vectors.generation_tokens)
769
engine_core_timestamp = time.monotonic()
tests/v1/engine/utils.py
+2
-4
@@ -9,7 +9,6 @@ import torch
9
from transformers import PreTrainedTokenizer, PreTrainedTokenizerFast
10
11
from vllm.engine.arg_utils import EngineArgs
12
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
12
from vllm.v1.engine import EngineCoreOutput, FinishReason
13
from vllm.v1.outputs import LogprobsLists, LogprobsTensors
14
@@ -39,7 +38,7 @@ def _create_random_top_logprob_test_vector(
38
upper: float,
39
) -> torch.Tensor:
40
"""Create a random vector of top logprob float values.
42
-
41
+
42
Use to create fake sample logprobs for testing.
43
44
Note that a real production scenario would require
@@ -63,7 +62,7 @@ def _create_random_top_logprob_test_matrix(
62
upper: float,
63
) -> torch.Tensor:
64
"""Create a random matrix of top logprob float values.
66
-
65
+
66
Use to create fake prompt logprobs for testing.
67
68
Note that a real production scenario would require
@@ -296,7 +295,6 @@ def generate_dummy_prompt_logprobs_tensors(
295
class DummyOutputProcessorTestVectors:
296
"""Dummy test vectors for output processor tests"""
297
tokenizer: GeneralTokenizerType
299
- tokenizer_group: TokenizerGroup
298
vllm_config: EngineArgs
299
full_tokens: list[list[int]] # Prompt + generated tokens
300
prompt_tokens: list[list[int]]
tests/v1/entrypoints/llm/test_struct_output_generate.py
+1
-1
@@ -582,7 +582,7 @@ def test_structured_output_with_reasoning_matrices(
582
reasoning_parser=reasoning_parser,
583
speculative_config=speculative_config,
584
)
585
- tokenizer = llm.get_tokenizer(None)
585
+ tokenizer = llm.get_tokenizer()
586
reasoner = ReasoningParserManager.get_reasoning_parser(reasoning_parser)(
587
tokenizer=tokenizer)
588
vllm/benchmarks/datasets.py
+80
-93
@@ -37,7 +37,7 @@ from vllm.lora.request import LoRARequest
37
from vllm.lora.utils import get_adapter_absolute_path
38
from vllm.multimodal import MultiModalDataDict
39
from vllm.multimodal.image import convert_image_mode
40
-from vllm.transformers_utils.tokenizer import AnyTokenizer, get_lora_tokenizer
40
+from vllm.transformers_utils.tokenizer import AnyTokenizer
41
from vllm.utils import PlaceholderModule
42
43
try:
@@ -100,8 +100,8 @@ class BenchmarkDataset(ABC):
100
) -> None:
101
"""
102
Initialize the BenchmarkDataset with an optional dataset path and random
103
- seed.
104
-
103
+ seed.
104
+
105
Args:
106
dataset_path (Optional[str]): Path to the dataset. If None, it
107
indicates that a default or random dataset might be used.
@@ -133,10 +133,10 @@ class BenchmarkDataset(ABC):
133
elif isinstance(mm_content, dict):
134
content.append(mm_content)
135
else:
136
- raise TypeError(
136
+ raise TypeError(
137
"Could not process multimodal content of type: " +
138
- f"{type(mm_content)}"
139
- )
138
+ f"{type(mm_content)}"
139
+ )
140
return [{"role": "user", "content": content}]
141
142
def load_data(self) -> None:
@@ -155,34 +155,26 @@ class BenchmarkDataset(ABC):
155
156
def get_random_lora_request(
157
self,
158
- tokenizer: PreTrainedTokenizerBase,
158
max_loras: Optional[int] = None,
159
lora_path: Optional[str] = None,
161
- ) -> tuple[Optional[LoRARequest], AnyTokenizer]:
160
+ ) -> Optional[LoRARequest]:
161
"""
163
- Optionally select a random LoRA request and return its associated
164
- tokenizer.
162
+ Optionally select a random LoRA request.
163
164
This method is used when LoRA parameters are provided. It randomly
167
- selects a LoRA based on max_loras and retrieves a cached tokenizer for
168
- that LoRA if available. Otherwise, it returns the base tokenizer.
165
+ selects a LoRA based on max_loras.
166
167
Args:
171
- tokenizer (PreTrainedTokenizerBase): The base tokenizer to use if no
172
- LoRA is selected.
168
max_loras (Optional[int]): The maximum number of LoRAs available.
169
If `None`, LoRA is not used.
170
lora_path (Optional[str]): Path to the LoRA parameters on disk.
171
If `None`, LoRA is not used.
172
173
Returns:
179
- A tuple with the following elements:
180
- - A new [LoRARequest][] (or `None` if not applicable).
181
- - The tokenizer associated with the LoRA request
182
- (or the base tokenizer).
174
+ A new [LoRARequest][] (or `None` if not applicable).
175
"""
176
if max_loras is None or lora_path is None:
185
- return None, tokenizer
177
+ return None
178
179
# Generate a random LoRA ID in the range [1, max_loras].
180
lora_id = random.randint(1, max_loras)
@@ -191,11 +183,7 @@ class BenchmarkDataset(ABC):
183
lora_int_id=lora_id,
184
lora_path=lora_path_on_disk(lora_path),
185
)
194
- if lora_id not in lora_tokenizer_cache:
195
- lora_tokenizer_cache[lora_id] = get_lora_tokenizer(lora_request)
196
- # Return lora_request and the cached tokenizer if available; otherwise,
197
- # return the base tokenizer
198
- return lora_request, lora_tokenizer_cache[lora_id] or tokenizer
186
+ return lora_request
187
188
@abstractmethod
189
def sample(self, tokenizer: PreTrainedTokenizerBase,
@@ -213,7 +201,7 @@ class BenchmarkDataset(ABC):
201
for processing the dataset's text.
202
num_requests (int): The number of sample requests to generate.
203
request_id_prefix (str) The prefix of request_id.
216
-
204
+
205
206
Returns:
207
list[SampleRequest]: A list of sample requests generated from the
@@ -527,7 +515,7 @@ class RandomDataset(BenchmarkDataset):
515
size=num_requests)
516
output_lens = self._rng.integers(output_low, output_high + 1,
517
size=num_requests)
530
- offsets = self._rng.integers(0, tokenizer.vocab_size,
518
+ offsets = self._rng.integers(0, tokenizer.vocab_size,
519
size=num_requests)
520
return input_lens, output_lens, offsets
521
@@ -555,7 +543,7 @@ class RandomDataset(BenchmarkDataset):
543
the encoded sequence is truncated before being decoded again.
544
"""
545
# Build the inner sequence by sampling sequentially from the vocab
558
- inner_seq = ((offset + index + np.arange(input_len))
546
+ inner_seq = ((offset + index + np.arange(input_len))
547
% vocab_size).tolist()
548
token_sequence = prefix_token_ids + inner_seq
549
@@ -590,9 +578,9 @@ class RandomMultiModalDataset(RandomDataset):
578
`num_mm_items_range_ratio` in [0, 1]. r=0 keeps it fixed; r=1 allows 0.
579
The maximum is further clamped to the sum of per-modality limits.
580
2) Each item’s modality and shape is sampled from `bucket_config`, a dict
593
- mapping (height, width, num_frames) → probability. We treat
594
- `num_frames`=1 as image and and `num_frames` > 1 as video.
595
- Entries with zero probability are removed and the rest are renormalized
581
+ mapping (height, width, num_frames) → probability. We treat
582
+ `num_frames`=1 as image and and `num_frames` > 1 as video.
583
+ Entries with zero probability are removed and the rest are renormalized
584
to sum to 1.
585
3) Per-modality hard caps are enforced via `limit_mm_per_prompt`.
586
When a modality reaches its cap, all of its buckets are excluded and the
@@ -600,8 +588,8 @@ class RandomMultiModalDataset(RandomDataset):
588
589
Example bucket configuration:
590
{(256, 256, 1): 0.5, (720, 1280, 1): 0.4, (720, 1280, 16): 0.1}
603
- - Two image buckets (`num_frames`=1) and one video bucket
604
- (`num_frames`=16).
591
+ - Two image buckets (`num_frames`=1) and one video bucket
592
+ (`num_frames`=16).
593
OBS.: Only image sampling is supported for now.
594
"""
595
@@ -624,9 +612,9 @@ class RandomMultiModalDataset(RandomDataset):
612
613
def generate_synthetic_image(self, width: int, height: int) -> Image.Image:
614
"""Generate synthetic PIL image with random RGB values.
627
-
628
- NOTE: iid pixel sampling results in worst-case compression
629
- (good for stressing I/O), but very unlike real photos.
615
+
616
+ NOTE: iid pixel sampling results in worst-case compression
617
+ (good for stressing I/O), but very unlike real photos.
618
We could consider a “low-freq” mode (e.g., noise blur)
619
to emulate network realism instead of max stress.
620
"""
@@ -638,11 +626,11 @@ class RandomMultiModalDataset(RandomDataset):
626
)
627
return Image.fromarray(random_pixels)
628
641
- def generate_synthetic_video(self, width: int,
642
- height: int,
629
+ def generate_synthetic_video(self, width: int,
630
+ height: int,
631
num_frames: int) -> Any:
632
"""Generate synthetic video with random values.
645
-
633
+
634
TODO: Finish this method.
635
"""
636
raise NotImplementedError("Video sampling is WIP.")
@@ -656,7 +644,7 @@ class RandomMultiModalDataset(RandomDataset):
644
else:
645
raise ValueError(f"Invalid multimodal item configuration: {config}")
646
659
- def normalize_bucket_config(self, bucket_config: dict[tuple[int, int, int],
647
+ def normalize_bucket_config(self, bucket_config: dict[tuple[int, int, int],
648
float]) -> dict[tuple[int, int, int], float]:
649
"""
650
Remove zero probability entries
@@ -676,24 +664,24 @@ class RandomMultiModalDataset(RandomDataset):
664
return {k: v / total for k, v in bucket_config.items()}
665
666
679
- def generate_mm_item(self,
667
+ def generate_mm_item(self,
668
mm_item_config: tuple[int, int, int],
669
) -> Mapping[str, Any]:
670
"""
683
- Create synthetic images and videos and
671
+ Create synthetic images and videos and
672
apply process_image/process_video respectively.
673
This follows the OpenAI API chat completions
674
https://github.com/openai/openai-python
675
"""
688
-
676
+
677
if self.map_config_to_modality(mm_item_config) == "image":
678
return process_image(self.generate_synthetic_image(
679
mm_item_config[1],
680
mm_item_config[0]))
681
elif self.map_config_to_modality(mm_item_config) == "video":
682
return process_video(self.generate_synthetic_video(
695
- mm_item_config[1],
696
- mm_item_config[0],
683
+ mm_item_config[1],
684
+ mm_item_config[0],
685
mm_item_config[2]))
686
else:
687
raise ValueError(f"Invalid multimodal item configuration: "
@@ -723,17 +711,17 @@ class RandomMultiModalDataset(RandomDataset):
711
f"limit_mm_per_prompt: "
712
f"{limit_mm_per_prompt.keys()}")
713
726
- # Remove zero probability entries
714
+ # Remove zero probability entries
715
# and normalize bucket config to sum to 1
716
bucket_config = self.normalize_bucket_config(bucket_config)
717
logger.info(
718
"Normalized bucket config: %s", bucket_config,
719
)
720
# Only consider limit per prompt for modalities in bucket config
733
- allowed_modalities = {self.map_config_to_modality(cfg)
721
+ allowed_modalities = {self.map_config_to_modality(cfg)
722
for cfg in bucket_config}
723
limit_mm_per_prompt = {
736
- k: v for k, v in limit_mm_per_prompt.items()
724
+ k: v for k, v in limit_mm_per_prompt.items()
725
if k in allowed_modalities}
726
if not limit_mm_per_prompt:
727
raise ValueError("No valid limits for modalities present in "
@@ -746,19 +734,19 @@ class RandomMultiModalDataset(RandomDataset):
734
# Get max and min num mm items and ensure
735
# it is at most the sum of limit_mm_per_prompt for all modalities
736
max_num_mm_items = min(
749
- sum(limit_mm_per_prompt.values()),
737
+ sum(limit_mm_per_prompt.values()),
738
math.ceil(base_items_per_request * (1 + num_mm_items_range_ratio))
739
)
740
# Ensure min num mm items is at least 0
741
min_num_mm_items = max(
754
- 0,
742
+ 0,
743
math.floor(base_items_per_request * (1 - num_mm_items_range_ratio))
744
)
745
# Raise error if min num mm items is greater than max num mm items
746
if min_num_mm_items > max_num_mm_items:
747
raise ValueError(f"Min num mm items is greater than max mm items: "
748
f"{min_num_mm_items} > {max_num_mm_items}")
761
-
749
+
750
logger.info(
751
"Sampling number of multimodal items from [%s, %s]",
752
min_num_mm_items, max_num_mm_items,
@@ -783,8 +771,8 @@ class RandomMultiModalDataset(RandomDataset):
771
whose size is between min_num_mm_items and max_num_mm_items.
772
773
Loop over the bucket config and sample a multimodal item.
786
- Loop until the number of multimodal items sampled is equal to
787
- request_num_mm_items or limit of multimodal items per prompt
774
+ Loop until the number of multimodal items sampled is equal to
775
+ request_num_mm_items or limit of multimodal items per prompt
776
for all modalities is reached.
777
778
Note:
@@ -796,19 +784,19 @@ class RandomMultiModalDataset(RandomDataset):
784
# Get the number of multimodal items to sample
785
request_num_mm_items = int(
786
self._rng.integers(min_num_mm_items, max_num_mm_items + 1)
799
- )
787
+ )
788
# If request_num_mm_items is 0, yield an empty iterator
789
if request_num_mm_items == 0:
790
return
791
# Initialize modality counters
804
- modality_counter = {self.map_config_to_modality(k): 0
792
+ modality_counter = {self.map_config_to_modality(k): 0
793
for k in bucket_config}
794
# Copy the bucket config to avoid modifying the original
795
bucket_config_copy = bucket_config.copy()
796
# Loop over the number of multimodal items to sample
797
while sum(modality_counter.values()) < request_num_mm_items:
798
# Sample a multimodal item config
811
- mm_item_config = self._rng.choice(list(bucket_config_copy.keys()),
799
+ mm_item_config = self._rng.choice(list(bucket_config_copy.keys()),
800
p=list(bucket_config_copy.values()))
801
modality = self.map_config_to_modality(mm_item_config)
802
# Check that modality count is less than limit per prompt
@@ -849,7 +837,7 @@ class RandomMultiModalDataset(RandomDataset):
837
limit_mm_per_prompt: dict[str, int] = DEFAULT_LIMIT_MM_PER_PROMPT,
838
base_items_per_request: int = DEFAULT_BASE_ITEMS_PER_REQUEST,
839
num_mm_items_range_ratio: float = DEFAULT_NUM_MM_ITEMS_RANGE_RATIO,
852
- bucket_config: dict[tuple[int, int, int], float] =
840
+ bucket_config: dict[tuple[int, int, int], float] =
841
DEFAULT_MM_ITEM_BUCKET_CONFIG,
842
enable_multimodal_chat: bool = DEFAULT_ENABLE_MULTIMODAL_CHAT,
843
**kwargs,
@@ -857,7 +845,7 @@ class RandomMultiModalDataset(RandomDataset):
845
846
# NOTE: Video sampling is WIP. Raise error if video is in bucket config
847
# and probability is non-zero.
860
- if any(self.map_config_to_modality(cfg) == "video" and p > 0
848
+ if any(self.map_config_to_modality(cfg) == "video" and p > 0
849
for cfg, p in bucket_config.items()):
850
raise NotImplementedError("Video sampling not implemented; "
851
"set its probability to 0.")
@@ -908,7 +896,7 @@ class RandomMultiModalDataset(RandomDataset):
896
])
897
898
if enable_multimodal_chat:
911
- # NOTE: For now this option is only provided for completeness
899
+ # NOTE: For now this option is only provided for completeness
900
# given that the serve.py benchmark currently does not use it.
901
mm_chat_prompt: Any = prompt
902
mm_chat_prompt = self.apply_multimodal_chat_transformation(
@@ -982,8 +970,8 @@ class ShareGPTDataset(BenchmarkDataset):
970
entry["conversations"][1]["value"],
971
)
972
985
- lora_request, tokenizer = self.get_random_lora_request(
986
- tokenizer=tokenizer, max_loras=max_loras, lora_path=lora_path)
973
+ lora_request = self.get_random_lora_request(
974
+ max_loras=max_loras, lora_path=lora_path)
975
prompt_ids = tokenizer(prompt).input_ids
976
completion_ids = tokenizer(completion).input_ids
977
prompt_len = len(prompt_ids)
@@ -994,11 +982,11 @@ class ShareGPTDataset(BenchmarkDataset):
982
skip_min_output_len_check=output_len
983
is not None):
984
continue
997
- if image_path := entry.get("image"):
998
- mm_content = process_image(image_path)
999
- elif video_path := entry.get("video"):
985
+ if image_path := entry.get("image"):
986
+ mm_content = process_image(image_path)
987
+ elif video_path := entry.get("video"):
988
mm_content = process_video(video_path)
1001
- else:
989
+ else:
990
mm_content = None
991
if enable_multimodal_chat:
992
prompt = self.apply_multimodal_chat_transformation(
@@ -1013,9 +1001,9 @@ class ShareGPTDataset(BenchmarkDataset):
1001
request_id=request_id_prefix + str(ind),
1002
))
1003
ind += 1
1016
- self.maybe_oversample_requests(samples,
1017
- num_requests,
1018
- request_id_prefix,
1004
+ self.maybe_oversample_requests(samples,
1005
+ num_requests,
1006
+ request_id_prefix,
1007
no_oversample)
1008
return samples
1009
@@ -1024,11 +1012,11 @@ class _ValidateDatasetArgs(argparse.Action):
1012
"""Argparse action to validate dataset name and path compatibility."""
1013
def __call__(self, parser, namespace, values, option_string=None):
1014
setattr(namespace, self.dest, values)
1027
-
1015
+
1016
# Get current values of both dataset_name and dataset_path
1017
dataset_name = getattr(namespace, 'dataset_name', 'random')
1018
dataset_path = getattr(namespace, 'dataset_path', None)
1031
-
1019
+
1020
# Validate the combination
1021
if dataset_name == "random" and dataset_path is not None:
1022
parser.error(
@@ -1053,7 +1041,7 @@ def add_dataset_parser(parser: FlexibleArgumentParser):
1041
default="random",
1042
action=_ValidateDatasetArgs,
1043
choices=[
1056
- "sharegpt", "burstgpt", "sonnet", "random", "random-mm", "hf",
1044
+ "sharegpt", "burstgpt", "sonnet", "random", "random-mm", "hf",
1045
"custom", "prefix_repetition", "spec_bench"
1046
],
1047
help="Name of the dataset to benchmark on.",
@@ -1502,7 +1490,7 @@ def get_samples(args, tokenizer) -> list[SampleRequest]:
1490
# For datasets that follow a similar structure, use a mapping.
1491
dataset_mapping = {
1492
"spec_bench":
1505
- lambda: SpecBench(dataset_path=args.dataset_path,
1493
+ lambda: SpecBench(dataset_path=args.dataset_path,
1494
category=args.spec_bench_category).sample(
1495
num_requests=args.num_prompts,
1496
tokenizer=tokenizer,
@@ -1660,7 +1648,7 @@ class CustomDataset(BenchmarkDataset):
1648
logger.info("num_requests is set to 0 or negative, "
1649
"so using all available samples: %d",
1650
num_requests)
1663
-
1651
+
1652
sampled_requests = []
1653
for i, item in enumerate(self.data):
1654
if len(sampled_requests) >= num_requests:
@@ -1686,7 +1674,7 @@ class CustomDataset(BenchmarkDataset):
1674
expected_output_len=output_len,
1675
request_id=request_id_prefix + str(i),
1676
))
1689
- self.maybe_oversample_requests(sampled_requests, num_requests,
1677
+ self.maybe_oversample_requests(sampled_requests, num_requests,
1678
request_id_prefix, no_oversample)
1679
1680
return sampled_requests
@@ -1700,7 +1688,7 @@ class CustomDataset(BenchmarkDataset):
1688
class SpecBench(CustomDataset):
1689
"""
1690
Implements the SpecBench dataset: https://github.com/hemingkx/Spec-Bench
1703
- Download the dataset using:
1691
+ Download the dataset using:
1692
wget https://raw.githubusercontent.com/hemingkx/Spec-Bench/refs/heads/main/data/spec_bench/question.jsonl
1693
""" # noqa: E501
1694
@@ -1736,8 +1724,8 @@ class SpecBench(CustomDataset):
1724
# leverage CustomDataset sample
1725
kwargs["skip_chat_template"] = False
1726
return super().sample(**kwargs)
1739
-
1740
-
1727
+
1728
+
1729
# -----------------------------------------------------------------------------
1730
# Sonnet Dataset Implementation
1731
# -----------------------------------------------------------------------------
@@ -1882,8 +1870,8 @@ class BurstGPTDataset(BenchmarkDataset):
1870
for i in range(num_requests):
1871
input_len = int(data[i][2])
1872
output_len = int(data[i][3])
1885
- lora_req, tokenizer = self.get_random_lora_request(
1886
- tokenizer=tokenizer, max_loras=max_loras, lora_path=lora_path)
1873
+ lora_req = self.get_random_lora_request(
1874
+ max_loras=max_loras, lora_path=lora_path)
1875
vocab_size = tokenizer.vocab_size
1876
# Generate a synthetic prompt: a list of token IDs computed as (i +
1877
# j) modulo vocab_size.
@@ -1995,7 +1983,7 @@ class ConversationDataset(HuggingFaceDataset):
1983
request_id=request_id_prefix + str(ind),
1984
))
1985
ind += 1
1998
- self.maybe_oversample_requests(sampled_requests, num_requests,
1986
+ self.maybe_oversample_requests(sampled_requests, num_requests,
1987
request_id_prefix, no_oversample)
1988
return sampled_requests
1989
@@ -2055,7 +2043,7 @@ class VisionArenaDataset(HuggingFaceDataset):
2043
multi_modal_data=mm_content,
2044
request_id=request_id_prefix + str(i),
2045
))
2058
- self.maybe_oversample_requests(sampled_requests, num_requests,
2046
+ self.maybe_oversample_requests(sampled_requests, num_requests,
2047
request_id_prefix, no_oversample)
2048
return sampled_requests
2049
@@ -2172,7 +2160,7 @@ class InstructCoderDataset(HuggingFaceDataset):
2160
expected_output_len=output_len,
2161
request_id=request_id_prefix + str(i),
2162
))
2175
- self.maybe_oversample_requests(sampled_requests, num_requests,
2163
+ self.maybe_oversample_requests(sampled_requests, num_requests,
2164
request_id_prefix, no_oversample)
2165
return sampled_requests
2166
@@ -2234,7 +2222,7 @@ class MTBenchDataset(HuggingFaceDataset):
2222
expected_output_len=output_len,
2223
request_id=request_id_prefix + str(i),
2224
))
2237
- self.maybe_oversample_requests(sampled_requests, num_requests,
2225
+ self.maybe_oversample_requests(sampled_requests, num_requests,
2226
request_id_prefix, no_oversample)
2227
return sampled_requests
2228
@@ -2288,8 +2276,8 @@ class BlazeditDataset(HuggingFaceDataset):
2276
# compare the levenshtein distance normalized by code length
2277
if norm_distance < min_distance or norm_distance > max_distance:
2278
continue
2291
-
2292
- # template copied from
2279
+
2280
+ # template copied from
2281
# https://github.com/ise-uiuc/blazedit/blob/7765137e656fd62de877422d2e4cf8de51228054/dataset/create_refined_dataset.py#L94-L105 # noqa: E501
2282
instruction = f"""Given a code file, please apply the change requests and generate the new file.
2283
@@ -2322,9 +2310,9 @@ Please generate the new code file in the "New file" section below.""" # noqa: E5
2310
expected_output_len=output_len,
2311
request_id=request_id_prefix + str(i),
2312
))
2325
- self.maybe_oversample_requests(sampled_requests, num_requests,
2313
+ self.maybe_oversample_requests(sampled_requests, num_requests,
2314
request_id_prefix, no_oversample)
2327
-
2315
+
2316
return sampled_requests
2317
2318
@@ -2376,7 +2364,6 @@ class AIMODataset(HuggingFaceDataset):
2364
expected_output_len=output_len,
2365
multi_modal_data=None,
2366
request_id=request_id_prefix + str(ind),
2379
-
2367
))
2368
ind += 1
2369
self.maybe_oversample_requests(sampled_requests, num_requests,
@@ -2470,9 +2457,9 @@ class NextEditPredictionDataset(HuggingFaceDataset):
2457
))
2458
if len(samples) >= num_requests:
2459
break
2473
- self.maybe_oversample_requests(samples,
2474
- num_requests,
2475
- request_id_prefix,
2460
+ self.maybe_oversample_requests(samples,
2461
+ num_requests,
2462
+ request_id_prefix,
2463
no_oversample)
2464
return samples
2465
@@ -2562,7 +2549,7 @@ class ASRDataset(HuggingFaceDataset):
2549
" what Whisper supports.",
2550
skipped,
2551
)
2565
- self.maybe_oversample_requests(sampled_requests, num_requests,
2552
+ self.maybe_oversample_requests(sampled_requests, num_requests,
2553
request_id_prefix, no_oversample)
2554
return sampled_requests
2555
@@ -2647,7 +2634,7 @@ class MLPerfDataset(HuggingFaceDataset):
2634
)
2635
ind += 1
2636
2650
- self.maybe_oversample_requests(sampled_requests, num_requests,
2637
+ self.maybe_oversample_requests(sampled_requests, num_requests,
2638
request_id_prefix, no_oversample)
2639
return sampled_requests
2640
@@ -2658,7 +2645,7 @@ class MLPerfDataset(HuggingFaceDataset):
2645
2646
2647
class PrefixRepetitionRandomDataset(BenchmarkDataset):
2661
- # Default values copied from benchmark_serving.py for the repeated prefix
2648
+ # Default values copied from benchmark_serving.py for the repeated prefix
2649
# dataset.
2650
DEFAULT_PREFIX_LEN = 256
2651
DEFAULT_SUFFIX_LEN = 256
vllm/engine/async_llm_engine.py
+4
-11
@@ -390,11 +390,8 @@ class _AsyncLLMEngine(LLMEngine):
390
"""Stop the remote worker execution loop."""
391
await self.model_executor.stop_remote_worker_execution_loop_async()
392
393
- async def get_tokenizer_async(self,
394
- lora_request: Optional[LoRARequest] = None
395
- ) -> AnyTokenizer:
396
- return await (
397
- self.get_tokenizer_group().get_lora_tokenizer_async(lora_request))
393
+ async def get_tokenizer_async(self) -> AnyTokenizer:
394
+ return self.get_tokenizer()
395
396
async def add_request_async(
397
self,
@@ -435,7 +432,6 @@ class _AsyncLLMEngine(LLMEngine):
432
433
processed_inputs = await self.input_preprocessor.preprocess_async(
434
prompt,
438
- lora_request=lora_request,
435
tokenization_kwargs=tokenization_kwargs,
436
)
437
@@ -614,11 +610,8 @@ class AsyncLLMEngine(EngineClient):
610
async def get_input_preprocessor(self) -> InputPreprocessor:
611
return self.engine.input_preprocessor
612
617
- async def get_tokenizer(
618
- self,
619
- lora_request: Optional[LoRARequest] = None,
620
- ) -> AnyTokenizer:
621
- return await self.engine.get_tokenizer_async(lora_request)
613
+ async def get_tokenizer(self) -> AnyTokenizer:
614
+ return self.engine.get_tokenizer()
615
616
def start_background_loop(self) -> None:
617
"""Start the background loop."""
vllm/engine/llm_engine.py
+14
-43
@@ -49,9 +49,8 @@ from vllm.sequence import (ExecuteModelRequest, ParallelSampleSequenceGroup,
49
from vllm.tracing import (SpanAttributes, SpanKind, extract_trace_context,
50
init_tracer)
51
from vllm.transformers_utils.detokenizer import Detokenizer
52
-from vllm.transformers_utils.tokenizer import AnyTokenizer
53
-from vllm.transformers_utils.tokenizer_group import (
54
- TokenizerGroup, init_tokenizer_from_configs)
52
+from vllm.transformers_utils.tokenizer import (AnyTokenizer,
53
+ init_tokenizer_from_configs)
54
from vllm.usage.usage_lib import (UsageContext, is_usage_stats_enabled,
55
usage_message)
56
from vllm.utils import Counter, Device, resolve_obj_by_qualname, weak_bind
@@ -186,7 +185,7 @@ class LLMEngine:
185
186
return outputs_
187
189
- tokenizer: Optional[TokenizerGroup]
188
+ tokenizer: Optional[AnyTokenizer]
189
190
def __init__(
191
self,
@@ -233,18 +232,9 @@ class LLMEngine:
232
if self.model_config.skip_tokenizer_init:
233
self.tokenizer = None
234
self.detokenizer = None
236
- tokenizer_group = None
235
else:
236
self.tokenizer = self._init_tokenizer()
237
self.detokenizer = Detokenizer(self.tokenizer)
240
- tokenizer_group = self.get_tokenizer_group()
241
-
242
- # Ensure that the function doesn't contain a reference to self,
243
- # to avoid engine GC issues
244
- def get_tokenizer_for_seq(sequence: Sequence) -> AnyTokenizer:
245
- assert tokenizer_group, ("tokenizer_group cannot be None, "
246
- "make sure skip_tokenizer_init is False")
247
- return tokenizer_group.get_lora_tokenizer(sequence.lora_request)
238
239
self.seq_counter = Counter()
240
self.generation_config_fields = (
@@ -389,10 +379,8 @@ class LLMEngine:
379
self.detokenizer,
380
self.scheduler,
381
self.seq_counter,
392
- get_tokenizer_for_seq,
382
stop_checker=StopChecker(
383
self.scheduler_config.max_model_len,
395
- get_tokenizer_for_seq,
384
self.reasoner if self.decoding_config.reasoning_backend
385
and self.tokenizer else None,
386
),
@@ -521,24 +509,15 @@ class LLMEngine:
509
if model_executor := getattr(self, "model_executor", None):
510
model_executor.shutdown()
511
524
- def get_tokenizer_group(self) -> TokenizerGroup:
512
+ def get_tokenizer(self) -> AnyTokenizer:
513
if self.tokenizer is None:
514
raise ValueError("Unable to get tokenizer because "
515
"skip_tokenizer_init is True")
516
517
return self.tokenizer
518
531
- def get_tokenizer(
532
- self,
533
- lora_request: Optional[LoRARequest] = None,
534
- ) -> AnyTokenizer:
535
- return self.get_tokenizer_group().get_lora_tokenizer(lora_request)
536
-
537
- def _init_tokenizer(self) -> TokenizerGroup:
538
- return init_tokenizer_from_configs(
539
- model_config=self.model_config,
540
- scheduler_config=self.scheduler_config,
541
- lora_config=self.lora_config)
519
+ def _init_tokenizer(self) -> AnyTokenizer:
520
+ return init_tokenizer_from_configs(model_config=self.model_config)
521
522
def _verify_args(self) -> None:
523
self.model_config.verify_with_parallel_config(self.parallel_config)
@@ -574,11 +553,11 @@ class LLMEngine:
553
)
554
return None
555
577
- self._validate_model_inputs(processed_inputs, lora_request)
556
+ self._validate_model_inputs(processed_inputs)
557
# Create the sequences.
558
block_size = self.cache_config.block_size
559
seq_id = next(self.seq_counter)
581
- eos_token_id = self.input_preprocessor.get_eos_token_id(lora_request)
560
+ eos_token_id = self.input_preprocessor.get_eos_token_id()
561
562
encoder_inputs, decoder_inputs = split_enc_dec_inputs(processed_inputs)
563
@@ -700,7 +679,6 @@ class LLMEngine:
679
processed_inputs = self.input_preprocessor.preprocess(
680
prompt,
681
tokenization_kwargs=tokenization_kwargs,
703
- lora_request=lora_request,
682
)
683
684
self._add_processed_request(
@@ -1739,29 +1717,22 @@ class LLMEngine:
1717
SpanAttributes.GEN_AI_LATENCY_TIME_IN_MODEL_EXECUTE,
1718
metrics.model_execute_time)
1719
1742
- def _validate_model_inputs(self, inputs: ProcessorInputs,
1743
- lora_request: Optional[LoRARequest]):
1720
+ def _validate_model_inputs(self, inputs: ProcessorInputs):
1721
encoder_inputs, decoder_inputs = split_enc_dec_inputs(inputs)
1722
1723
if encoder_inputs is not None:
1747
- self._validate_model_input(encoder_inputs,
1748
- lora_request,
1749
- prompt_type="encoder")
1724
+ self._validate_model_input(encoder_inputs, prompt_type="encoder")
1725
1751
- self._validate_model_input(decoder_inputs,
1752
- lora_request,
1753
- prompt_type="decoder")
1726
+ self._validate_model_input(decoder_inputs, prompt_type="decoder")
1727
1728
def _validate_model_input(
1729
self,
1730
prompt_inputs: SingletonInputs,
1758
- lora_request: Optional[LoRARequest],
1731
*,
1732
prompt_type: Literal["encoder", "decoder"],
1733
):
1734
model_config = self.model_config
1763
- tokenizer = (None if self.tokenizer is None else
1764
- self.tokenizer.get_lora_tokenizer(lora_request))
1735
+ tokenizer = self.tokenizer
1736
1737
prompt_ids = prompt_inputs.get("prompt_token_ids", [])
1738
if not prompt_ids:
@@ -1822,7 +1793,7 @@ class LLMEngine:
1793
logits_processors = []
1794
1795
if (sampling_params.logit_bias or sampling_params.allowed_token_ids):
1825
- tokenizer = self.get_tokenizer(lora_request=lora_request)
1796
+ tokenizer = self.get_tokenizer()
1797
1798
processors = get_openai_logits_processors(
1799
logit_bias=sampling_params.logit_bias,
@@ -1835,7 +1806,7 @@ class LLMEngine:
1806
sampling_params.allowed_token_ids = None
1807
1808
if len(sampling_params.bad_words) > 0:
1838
- tokenizer = self.get_tokenizer(lora_request)
1809
+ tokenizer = self.get_tokenizer()
1810
processors = get_bad_words_logits_processors(
1811
bad_words=sampling_params.bad_words, tokenizer=tokenizer)
1812
logits_processors.extend(processors)
vllm/engine/output_processor/interfaces.py
+2
-4
@@ -2,14 +2,13 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
from abc import ABC, abstractmethod
5
-from typing import Callable, List
5
+from typing import List
6
7
from vllm.config import SchedulerConfig
8
from vllm.core.scheduler import Scheduler
9
from vllm.engine.output_processor.stop_checker import StopChecker
10
-from vllm.sequence import Sequence, SequenceGroup, SequenceGroupOutput
10
+from vllm.sequence import SequenceGroup, SequenceGroupOutput
11
from vllm.transformers_utils.detokenizer import Detokenizer
12
-from vllm.transformers_utils.tokenizer import AnyTokenizer
12
from vllm.utils import Counter
13
14
@@ -31,7 +30,6 @@ class SequenceGroupOutputProcessor(ABC):
30
detokenizer: Detokenizer,
31
scheduler: List[Scheduler],
32
seq_counter: Counter,
34
- get_tokenizer_for_seq: Callable[[Sequence], AnyTokenizer],
33
stop_checker: "StopChecker",
34
):
35
"""Create an output processor.
vllm/engine/output_processor/stop_checker.py
+1
-4
@@ -1,13 +1,12 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
-from typing import Callable, List, Optional, Tuple
4
+from typing import List, Optional, Tuple
5
6
from vllm.lora.request import LoRARequest
7
from vllm.reasoning import ReasoningParser
8
from vllm.sampling_params import SamplingParams
9
from vllm.sequence import Sequence, SequenceStatus
10
-from vllm.transformers_utils.tokenizer import AnyTokenizer
10
11
12
class StopChecker:
@@ -20,12 +19,10 @@ class StopChecker:
19
def __init__(
20
self,
21
max_model_len: int,
23
- get_tokenizer_for_seq: Callable[[Sequence], AnyTokenizer],
22
reasoner: Optional[ReasoningParser] = None,
23
):
24
# Do not use it directly, but use `self._get_max_model_len`.
25
self._max_model_len = max_model_len
28
- self.get_tokenizer_for_seq = get_tokenizer_for_seq
26
self.reasoner = reasoner
27
28
def _get_max_model_len(self, lora_req: Optional[LoRARequest]):
vllm/engine/protocol.py
+3
-7
@@ -76,8 +76,7 @@ class EngineClient(ABC):
76
include_stop_str_in_output = params.include_stop_str_in_output
77
78
preprocessor = await self.get_input_preprocessor()
79
- tokenizer_group = preprocessor.get_tokenizer_group()
80
- tokenizer = await tokenizer_group.get_lora_tokenizer_async()
79
+ tokenizer = preprocessor.get_tokenizer()
80
eos_token_id = tokenizer.eos_token_id
81
82
if is_explicit_encoder_decoder_prompt(prompt):
@@ -260,11 +259,8 @@ class EngineClient(ABC):
259
...
260
261
@abstractmethod
263
- async def get_tokenizer(
264
- self,
265
- lora_request: Optional[LoRARequest] = None,
266
- ) -> AnyTokenizer:
267
- """Get the appropriate tokenizer for the request"""
262
+ async def get_tokenizer(self) -> AnyTokenizer:
263
+ """Get the tokenizer"""
264
...
265
266
async def get_io_processor(self) -> IOProcessor:
vllm/entrypoints/llm.py
+6
-14
@@ -301,23 +301,17 @@ class LLM:
301
self.io_processor = get_io_processor(self.llm_engine.vllm_config,
302
io_processor_plugin)
303
304
- def get_tokenizer(
305
- self,
306
- lora_request: Optional[LoRARequest] = None,
307
- ) -> AnyTokenizer:
308
- return self.llm_engine.get_tokenizer_group().get_lora_tokenizer(
309
- lora_request)
304
+ def get_tokenizer(self) -> AnyTokenizer:
305
+ return self.llm_engine.get_tokenizer()
306
307
def set_tokenizer(self, tokenizer: AnyTokenizer) -> None:
312
- tokenizer_group = self.llm_engine.get_tokenizer_group()
313
-
308
# While CachedTokenizer is dynamic, have no choice but
309
# compare class name. Misjudgment will arise from
310
# user-defined tokenizer started with 'Cached'
311
if tokenizer.__class__.__name__.startswith("Cached"):
318
- tokenizer_group.tokenizer = tokenizer
312
+ self.llm_engine.tokenizer = tokenizer
313
else:
320
- tokenizer_group.tokenizer = get_cached_tokenizer(tokenizer)
314
+ self.llm_engine.tokenizer = get_cached_tokenizer(tokenizer)
315
316
def get_default_sampling_params(self) -> SamplingParams:
317
if self.default_sampling_params is None:
@@ -707,7 +701,6 @@ class LLM:
701
self,
702
messages: Union[list[ChatCompletionMessageParam],
703
list[list[ChatCompletionMessageParam]]],
710
- lora_request: Optional[LoRARequest] = None,
704
chat_template: Optional[str] = None,
705
chat_template_content_format: ChatTemplateContentFormatOption = "auto",
706
add_generation_prompt: bool = True,
@@ -739,7 +732,7 @@ class LLM:
732
cast(list[ChatCompletionMessageParam], messages)
733
]
734
742
- tokenizer = self.get_tokenizer(lora_request)
735
+ tokenizer = self.get_tokenizer()
736
model_config = self.llm_engine.get_model_config()
737
resolved_content_format = resolve_chat_template_content_format(
738
chat_template,
@@ -872,7 +865,6 @@ class LLM:
865
866
prompts = self.preprocess_chat(
867
messages=messages,
875
- lora_request=lora_request,
868
chat_template=chat_template,
869
chat_template_content_format=chat_template_content_format,
870
add_generation_prompt=add_generation_prompt,
@@ -1519,7 +1511,7 @@ class LLM:
1511
):
1512
"""
1513
Validate that if any multi-modal data is skipped (i.e. None),
1522
- then its corresponding UUID must be set.
1514
+ then its corresponding UUID must be set.
1515
"""
1516
if multi_modal_data is None:
1517
return
vllm/entrypoints/openai/serving_chat.py
+1
-1
@@ -188,7 +188,7 @@ class OpenAIServingChat(OpenAIServing):
188
189
model_name = self.models.model_name(lora_request)
190
191
- tokenizer = await self.engine_client.get_tokenizer(lora_request)
191
+ tokenizer = await self.engine_client.get_tokenizer()
192
193
tool_parser = self.tool_parser
194
vllm/entrypoints/openai/serving_classification.py
+1
-4
@@ -50,10 +50,7 @@ class ClassificationMixin(OpenAIServing):
50
return None
51
52
try:
53
- ctx.lora_request = self._maybe_get_adapters(ctx.request)
54
-
55
- ctx.tokenizer = await self.engine_client.get_tokenizer(
56
- ctx.lora_request)
53
+ ctx.tokenizer = await self.engine_client.get_tokenizer()
54
55
renderer = self._get_renderer(ctx.tokenizer)
56
ctx.engine_prompts = await renderer.render_prompt(
vllm/entrypoints/openai/serving_completion.py
+1
-2
@@ -127,8 +127,7 @@ class OpenAIServingCompletion(OpenAIServing):
127
if self.model_config.skip_tokenizer_init:
128
tokenizer = None
129
else:
130
- tokenizer = await self.engine_client.get_tokenizer(lora_request
131
- )
130
+ tokenizer = await self.engine_client.get_tokenizer()
131
renderer = self._get_renderer(tokenizer)
132
133
engine_prompts = await renderer.render_prompt_and_embeds(
vllm/entrypoints/openai/serving_embedding.py
+3
-4
@@ -76,8 +76,7 @@ class EmbeddingMixin(OpenAIServing):
76
try:
77
ctx.lora_request = self._maybe_get_adapters(ctx.request)
78
79
- tokenizer = await self.engine_client.get_tokenizer(ctx.lora_request
80
- )
79
+ tokenizer = await self.engine_client.get_tokenizer()
80
renderer = self._get_renderer(tokenizer)
81
82
if isinstance(ctx.request, EmbeddingChatRequest):
@@ -394,8 +393,8 @@ class EmbeddingMixin(OpenAIServing):
393
) -> Optional[ErrorResponse]:
394
"""Collect and aggregate batch results
395
with support for chunked processing.
397
-
398
- For chunked requests, performs online aggregation to
396
+
397
+ For chunked requests, performs online aggregation to
398
minimize memory usage.
399
For regular requests, collects results normally.
400
"""
vllm/entrypoints/openai/serving_pooling.py
+1
-2
@@ -103,8 +103,7 @@ class OpenAIServingPooling(OpenAIServing):
103
if self.model_config.skip_tokenizer_init:
104
tokenizer = None
105
else:
106
- tokenizer = await self.engine_client.get_tokenizer(lora_request
107
- )
106
+ tokenizer = await self.engine_client.get_tokenizer()
107
renderer = self._get_renderer(tokenizer)
108
109
if getattr(request, "dimensions", None) is not None:
vllm/entrypoints/openai/serving_responses.py
+1
-1
@@ -240,7 +240,7 @@ class OpenAIServingResponses(OpenAIServing):
240
try:
241
lora_request = self._maybe_get_adapters(request)
242
model_name = self.models.model_name(lora_request)
243
- tokenizer = await self.engine_client.get_tokenizer(lora_request)
243
+ tokenizer = await self.engine_client.get_tokenizer()
244
245
if self.use_harmony:
246
messages, request_prompts, engine_prompts = (
vllm/entrypoints/openai/serving_score.py
+1
-1
@@ -269,7 +269,7 @@ class ServingScores(OpenAIServing):
269
) -> Union[list[PoolingRequestOutput], ErrorResponse]:
270
lora_request = self._maybe_get_adapters(request)
271
272
- tokenizer = await self.engine_client.get_tokenizer(lora_request)
272
+ tokenizer = await self.engine_client.get_tokenizer()
273
274
truncate_prompt_tokens = getattr(request, "truncate_prompt_tokens",
275
None)
vllm/entrypoints/openai/serving_tokenization.py
+2
-2
@@ -65,7 +65,7 @@ class OpenAIServingTokenization(OpenAIServing):
65
try:
66
lora_request = self._maybe_get_adapters(request)
67
68
- tokenizer = await self.engine_client.get_tokenizer(lora_request)
68
+ tokenizer = await self.engine_client.get_tokenizer()
69
renderer = self._get_renderer(tokenizer)
70
71
if isinstance(request, TokenizeChatRequest):
@@ -130,7 +130,7 @@ class OpenAIServingTokenization(OpenAIServing):
130
131
lora_request = self._maybe_get_adapters(request)
132
133
- tokenizer = await self.engine_client.get_tokenizer(lora_request)
133
+ tokenizer = await self.engine_client.get_tokenizer()
134
135
self._log_inputs(request_id,
136
request.tokens,
vllm/inputs/preprocess.py
+18
-66
@@ -9,13 +9,11 @@ from typing_extensions import assert_never
9
10
from vllm.config import ModelConfig
11
from vllm.logger import init_logger
12
-from vllm.lora.request import LoRARequest
12
from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalRegistry
13
from vllm.multimodal.cache import BaseMultiModalProcessorCache
14
from vllm.multimodal.inputs import (MultiModalDataDict, MultiModalEncDecInputs,
15
MultiModalInputs, MultiModalUUIDDict)
16
from vllm.transformers_utils.tokenizer import AnyTokenizer
18
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
17
18
from .data import (DecoderOnlyInputs, EmbedsInputs, EmbedsPrompt,
19
EncoderDecoderInputs, ProcessorInputs, PromptType,
@@ -31,7 +29,7 @@ class InputPreprocessor:
29
def __init__(
30
self,
31
model_config: ModelConfig,
34
- tokenizer: Optional[TokenizerGroup],
32
+ tokenizer: Optional[AnyTokenizer],
33
mm_registry: MultiModalRegistry = MULTIMODAL_REGISTRY,
34
mm_processor_cache: Optional[BaseMultiModalProcessorCache] = None,
35
) -> None:
@@ -42,32 +40,28 @@ class InputPreprocessor:
40
self.mm_registry = mm_registry
41
self.mm_processor_cache = mm_processor_cache
42
45
- def get_tokenizer_group(self) -> TokenizerGroup:
43
+ def get_tokenizer(self) -> AnyTokenizer:
44
if self.tokenizer is None:
45
raise ValueError("You cannot pass text prompts when "
46
"`skip_tokenizer_init` is True")
47
48
return self.tokenizer
49
52
- def get_bos_token_id(self,
53
- lora_request: Optional[LoRARequest] = None
54
- ) -> Optional[int]:
50
+ def get_bos_token_id(self) -> Optional[int]:
51
if self.tokenizer is None:
52
logger.warning("Using None for BOS token id because tokenizer "
53
"is not initialized")
54
return None
55
60
- return self.tokenizer.get_lora_tokenizer(lora_request).bos_token_id
56
+ return self.tokenizer.bos_token_id
57
62
- def get_eos_token_id(self,
63
- lora_request: Optional[LoRARequest] = None
64
- ) -> Optional[int]:
58
+ def get_eos_token_id(self) -> Optional[int]:
59
if self.tokenizer is None:
60
logger.warning("Using None for EOS token id because tokenizer "
61
"is not initialized")
62
return None
63
70
- return self.tokenizer.get_lora_tokenizer(lora_request).eos_token_id
64
+ return self.tokenizer.eos_token_id
65
66
def get_decoder_start_token_id(self) -> Optional[int]:
67
"""
@@ -190,14 +184,13 @@ class InputPreprocessor:
184
def _tokenize_prompt(
185
self,
186
prompt: str,
193
- lora_request: Optional[LoRARequest],
187
tokenization_kwargs: Optional[dict[str, Any]] = None,
188
) -> list[int]:
189
"""
190
Apply the model's tokenizer to a text prompt, returning the
191
corresponding token IDs.
192
"""
200
- tokenizer = self.get_tokenizer_group()
193
+ tokenizer = self.get_tokenizer()
194
tokenization_kwargs = self._get_tokenization_kw(tokenization_kwargs)
195
196
encoder_config = self.model_config.encoder_config
@@ -205,50 +198,39 @@ class InputPreprocessor:
198
if encoder_config and encoder_config.get("do_lower_case", False):
199
prompt = prompt.lower()
200
208
- return tokenizer.encode(prompt=prompt,
209
- lora_request=lora_request,
210
- **tokenization_kwargs)
201
+ return tokenizer.encode(prompt, **tokenization_kwargs)
202
203
async def _tokenize_prompt_async(
204
self,
205
prompt: str,
215
- lora_request: Optional[LoRARequest],
206
tokenization_kwargs: Optional[dict[str, Any]] = None,
207
) -> list[int]:
208
"""
209
Async version of
210
[`_tokenize_prompt`][vllm.inputs.preprocess.InputPreprocessor._tokenize_prompt].
211
"""
222
- tokenizer = self.get_tokenizer_group()
212
+ tokenizer = self.get_tokenizer()
213
tokenization_kwargs = self._get_tokenization_kw(tokenization_kwargs)
214
225
- return await tokenizer.encode_async(prompt=prompt,
226
- lora_request=lora_request,
227
- **tokenization_kwargs)
215
+ return tokenizer.encode(prompt, **tokenization_kwargs)
216
229
- def _get_mm_tokenizer(
230
- self,
231
- lora_request: Optional[LoRARequest],
232
- ) -> AnyTokenizer:
217
+ def _get_mm_tokenizer(self) -> AnyTokenizer:
218
# PrithviGeoSpatialMAE needs to be initialized without a tokenizer
219
# while using also multi-modal input
220
if not self.tokenizer:
221
return cast(AnyTokenizer, object()) # Dummy
222
238
- tokenizer_group = self.get_tokenizer_group()
239
- return tokenizer_group.get_lora_tokenizer(lora_request)
223
+ tokenizer = self.get_tokenizer()
224
+ return tokenizer
225
241
- async def _get_mm_tokenizer_async(
242
- self,
243
- lora_request: Optional[LoRARequest],
244
- ) -> AnyTokenizer:
226
+ async def _get_mm_tokenizer_async(self) -> AnyTokenizer:
227
# PrithviGeoSpatialMAE needs to be initialized without a tokenizer
228
# while using also multi-modal input
229
if not self.tokenizer:
230
return cast(AnyTokenizer, object()) # Dummy
231
250
- tokenizer_group = self.get_tokenizer_group()
251
- return await tokenizer_group.get_lora_tokenizer_async(lora_request)
232
+ tokenizer = self.get_tokenizer()
233
+ return tokenizer
234
235
def _process_multimodal(
236
self,
@@ -256,7 +238,6 @@ class InputPreprocessor:
238
mm_data: MultiModalDataDict,
239
mm_processor_kwargs: Optional[Mapping[str, object]],
240
tokenization_kwargs: Optional[dict[str, Any]] = None,
259
- lora_request: Optional[LoRARequest] = None,
241
*,
242
mm_uuids: Optional[MultiModalUUIDDict] = None,
243
) -> MultiModalInputs:
@@ -264,7 +245,7 @@ class InputPreprocessor:
245
Apply the model's multi-modal processor to a multi-modal prompt,
246
returning the corresponding token IDs and metadata.
247
"""
267
- tokenizer = self._get_mm_tokenizer(lora_request)
248
+ tokenizer = self._get_mm_tokenizer()
249
250
mm_processor = self.mm_registry.create_processor(
251
self.model_config,
@@ -299,7 +280,6 @@ class InputPreprocessor:
280
mm_data: MultiModalDataDict,
281
mm_processor_kwargs: Optional[Mapping[str, object]],
282
tokenization_kwargs: Optional[dict[str, Any]] = None,
302
- lora_request: Optional[LoRARequest] = None,
283
*,
284
mm_uuids: Optional[MultiModalUUIDDict] = None,
285
) -> MultiModalInputs:
@@ -307,7 +287,7 @@ class InputPreprocessor:
287
Async version of
288
[`_process_multimodal`][vllm.inputs.preprocess.InputPreprocessor._process_multimodal].
289
"""
310
- tokenizer = await self._get_mm_tokenizer_async(lora_request)
290
+ tokenizer = await self._get_mm_tokenizer_async()
291
292
mm_processor = self.mm_registry.create_processor(
293
self.model_config,
@@ -386,7 +366,6 @@ class InputPreprocessor:
366
self,
367
parsed_content: TokensPrompt,
368
tokenization_kwargs: Optional[dict[str, Any]] = None,
389
- lora_request: Optional[LoRARequest] = None,
369
*,
370
mm_uuids: Optional[MultiModalUUIDDict] = None,
371
) -> Union[TokenInputs, MultiModalInputs]:
@@ -400,7 +379,6 @@ class InputPreprocessor:
379
multi_modal_data,
380
parsed_content.get("mm_processor_kwargs"),
381
tokenization_kwargs=tokenization_kwargs,
403
- lora_request=lora_request,
382
mm_uuids=mm_uuids,
383
)
384
else:
@@ -415,7 +393,6 @@ class InputPreprocessor:
393
self,
394
parsed_content: TokensPrompt,
395
tokenization_kwargs: Optional[dict[str, Any]] = None,
418
- lora_request: Optional[LoRARequest] = None,
396
*,
397
mm_uuids: Optional[MultiModalUUIDDict] = None,
398
) -> Union[TokenInputs, MultiModalInputs]:
@@ -429,7 +406,6 @@ class InputPreprocessor:
406
multi_modal_data,
407
parsed_content.get("mm_processor_kwargs"),
408
tokenization_kwargs=tokenization_kwargs,
432
- lora_request=lora_request,
409
mm_uuids=mm_uuids,
410
)
411
else:
@@ -444,7 +420,6 @@ class InputPreprocessor:
420
self,
421
parsed_content: TextPrompt,
422
tokenization_kwargs: Optional[dict[str, Any]] = None,
447
- lora_request: Optional[LoRARequest] = None,
423
*,
424
mm_uuids: Optional[MultiModalUUIDDict] = None,
425
) -> Union[TokenInputs, MultiModalInputs]:
@@ -457,13 +432,11 @@ class InputPreprocessor:
432
multi_modal_data,
433
parsed_content.get("mm_processor_kwargs"),
434
tokenization_kwargs=tokenization_kwargs,
460
- lora_request=lora_request,
435
mm_uuids=mm_uuids,
436
)
437
else:
438
prompt_token_ids = self._tokenize_prompt(
439
prompt_text,
466
- lora_request=lora_request,
440
tokenization_kwargs=tokenization_kwargs,
441
)
442
inputs = token_inputs(
@@ -480,7 +453,6 @@ class InputPreprocessor:
453
self,
454
parsed_content: TextPrompt,
455
tokenization_kwargs: Optional[dict[str, Any]] = None,
483
- lora_request: Optional[LoRARequest] = None,
456
*,
457
mm_uuids: Optional[MultiModalUUIDDict] = None,
458
) -> Union[TokenInputs, MultiModalInputs]:
@@ -493,13 +465,11 @@ class InputPreprocessor:
465
multi_modal_data,
466
parsed_content.get("mm_processor_kwargs"),
467
tokenization_kwargs=tokenization_kwargs,
496
- lora_request=lora_request,
468
mm_uuids=mm_uuids,
469
)
470
else:
471
prompt_token_ids = await self._tokenize_prompt_async(
472
prompt_text,
502
- lora_request=lora_request,
473
tokenization_kwargs=tokenization_kwargs,
474
)
475
inputs = token_inputs(
@@ -516,7 +486,6 @@ class InputPreprocessor:
486
self,
487
prompt: SingletonPrompt,
488
tokenization_kwargs: Optional[dict[str, Any]] = None,
519
- lora_request: Optional[LoRARequest] = None,
489
*,
490
mm_uuids: Optional[MultiModalUUIDDict] = None,
491
) -> SingletonInputs:
@@ -526,7 +495,6 @@ class InputPreprocessor:
495
Arguments:
496
497
* prompt: single encoder or decoder input prompt
529
- * lora_request: this is only valid for decoder prompts
498
499
Returns:
500
@@ -539,21 +507,18 @@ class InputPreprocessor:
507
if parsed["type"] == "tokens":
508
return self._process_tokens(
509
parsed["content"],
542
- lora_request=lora_request,
510
mm_uuids=mm_uuids,
511
)
512
if parsed["type"] == "text":
513
return self._process_text(
514
parsed["content"],
515
tokenization_kwargs=tokenization_kwargs,
549
- lora_request=lora_request,
516
mm_uuids=mm_uuids,
517
)
518
if parsed["type"] == "str":
519
return self._process_text(
520
TextPrompt(prompt=parsed["content"]),
521
tokenization_kwargs=tokenization_kwargs,
556
- lora_request=lora_request,
522
mm_uuids=mm_uuids,
523
)
524
@@ -563,7 +528,6 @@ class InputPreprocessor:
528
self,
529
prompt: SingletonPrompt,
530
tokenization_kwargs: Optional[dict[str, Any]] = None,
566
- lora_request: Optional[LoRARequest] = None,
531
*,
532
mm_uuids: Optional[MultiModalUUIDDict] = None,
533
) -> SingletonInputs:
@@ -578,21 +542,18 @@ class InputPreprocessor:
542
if parsed["type"] == "tokens":
543
return await self._process_tokens_async(
544
parsed["content"],
581
- lora_request=lora_request,
545
mm_uuids=mm_uuids,
546
)
547
if parsed["type"] == "text":
548
return await self._process_text_async(
549
parsed["content"],
550
tokenization_kwargs=tokenization_kwargs,
588
- lora_request=lora_request,
551
mm_uuids=mm_uuids,
552
)
553
if parsed["type"] == "str":
554
return await self._process_text_async(
555
TextPrompt(prompt=parsed["content"]),
556
tokenization_kwargs=tokenization_kwargs,
595
- lora_request=lora_request,
557
mm_uuids=mm_uuids,
558
)
559
@@ -844,7 +805,6 @@ class InputPreprocessor:
805
self,
806
prompt: SingletonPrompt,
807
tokenization_kwargs: Optional[dict[str, Any]] = None,
847
- lora_request: Optional[LoRARequest] = None,
808
*,
809
mm_uuids: Optional[MultiModalUUIDDict] = None,
810
) -> DecoderOnlyInputs:
@@ -856,7 +816,6 @@ class InputPreprocessor:
816
Arguments:
817
818
* prompt: input prompt
859
- * lora_request
819
820
Returns:
821
@@ -866,7 +825,6 @@ class InputPreprocessor:
825
prompt_comps = self._prompt_to_llm_inputs(
826
prompt,
827
tokenization_kwargs=tokenization_kwargs,
869
- lora_request=lora_request,
828
mm_uuids=mm_uuids,
829
)
830
@@ -876,7 +834,6 @@ class InputPreprocessor:
834
self,
835
prompt: SingletonPrompt,
836
tokenization_kwargs: Optional[dict[str, Any]] = None,
879
- lora_request: Optional[LoRARequest] = None,
837
*,
838
mm_uuids: Optional[MultiModalUUIDDict] = None,
839
) -> DecoderOnlyInputs:
@@ -887,7 +844,6 @@ class InputPreprocessor:
844
prompt_comps = await self._prompt_to_llm_inputs_async(
845
prompt,
846
tokenization_kwargs=tokenization_kwargs,
890
- lora_request=lora_request,
847
mm_uuids=mm_uuids,
848
)
849
@@ -897,7 +853,6 @@ class InputPreprocessor:
853
self,
854
prompt: PromptType,
855
tokenization_kwargs: Optional[dict[str, Any]] = None,
900
- lora_request: Optional[LoRARequest] = None,
856
*,
857
mm_uuids: Optional[MultiModalUUIDDict] = None,
858
) -> ProcessorInputs:
@@ -919,7 +874,6 @@ class InputPreprocessor:
874
return self._process_decoder_only_prompt(
875
prompt,
876
tokenization_kwargs=tokenization_kwargs,
922
- lora_request=lora_request,
877
mm_uuids=mm_uuids,
878
)
879
@@ -927,7 +881,6 @@ class InputPreprocessor:
881
self,
882
prompt: PromptType,
883
tokenization_kwargs: Optional[dict[str, Any]] = None,
930
- lora_request: Optional[LoRARequest] = None,
884
*,
885
mm_uuids: Optional[MultiModalUUIDDict] = None,
886
) -> ProcessorInputs:
@@ -952,7 +905,6 @@ class InputPreprocessor:
905
return await self._process_decoder_only_prompt_async(
906
prompt,
907
tokenization_kwargs=tokenization_kwargs,
955
- lora_request=lora_request,
908
mm_uuids=mm_uuids,
909
)
910
vllm/transformers_utils/detokenizer.py
+8
-15
@@ -10,18 +10,13 @@ from vllm.sequence import (VLLM_INVALID_TOKEN_ID, SamplingParams, Sequence,
10
from .detokenizer_utils import (convert_prompt_ids_to_tokens,
11
detokenize_incrementally)
12
from .tokenizer import AnyTokenizer
13
-from .tokenizer_group import TokenizerGroup
13
14
15
class Detokenizer:
16
"""Provides methods to decode the output of a model into text."""
17
19
- def __init__(self, tokenizer_group: TokenizerGroup):
20
- self.tokenizer_group = tokenizer_group
21
-
22
- def get_tokenizer_for_seq(self, sequence: Sequence) -> AnyTokenizer:
23
- """Returns the HF tokenizer to use for a given sequence."""
24
- return self.tokenizer_group.get_lora_tokenizer(sequence.lora_request)
18
+ def __init__(self, tokenizer: AnyTokenizer):
19
+ self.tokenizer = tokenizer
20
21
def decode_prompt_logprobs_inplace(self, seq_group: SequenceGroup,
22
prompt_logprobs: list[Optional[dict[
@@ -32,9 +27,9 @@ class Detokenizer:
27
Args:
28
seq_group: The sequence group to decode.
29
prompt_logprobs: The logprobs to decode.
35
- position_offset: Offset of the first index of the logprobs
30
+ position_offset: Offset of the first index of the logprobs
31
relative to the start of the sequence (for chunked prefill).
37
-
32
+
33
Returns:
34
The prompt logprobs with the decoded tokens.
35
"""
@@ -46,7 +41,6 @@ class Detokenizer:
41
# Only prompt, without the generated token.
42
all_token_ids = seq.get_token_ids()
43
prompt_token_ids = all_token_ids[:-1]
49
- tokenizer = self.get_tokenizer_for_seq(seq)
44
prefix_offset = 0
45
read_offset = 0
46
next_iter_prefix_offset = 0
@@ -70,7 +64,7 @@ class Detokenizer:
64
prompt_token_ids[:token_position] + [token_id])
65
(new_tokens, new_text, new_prefix_offset,
66
new_read_offset) = detokenize_incrementally(
73
- tokenizer=tokenizer,
67
+ tokenizer=self.tokenizer,
68
all_input_ids=prompt_token_ids_with_token,
69
prev_tokens=prev_tokens,
70
prefix_offset=prefix_offset,
@@ -111,7 +105,6 @@ class Detokenizer:
105
"""
106
all_input_ids = seq.get_token_ids()
107
token_id_generated_this_iteration = all_input_ids[-1]
114
- tokenizer = self.get_tokenizer_for_seq(seq)
108
109
# Convert prompt token IDs to tokens if necessary.
110
# Do it here so that we don't have to repeat this
@@ -119,14 +112,14 @@ class Detokenizer:
112
if seq.tokens is None:
113
(seq.tokens, seq.prefix_offset,
114
seq.read_offset) = convert_prompt_ids_to_tokens(
122
- tokenizer=tokenizer,
115
+ tokenizer=self.tokenizer,
116
prompt_ids=all_input_ids[:-1],
117
skip_special_tokens=prms.skip_special_tokens,
118
)
119
120
(new_tokens, new_decoded_token_text, prefix_offset,
121
read_offset) = detokenize_incrementally(
129
- tokenizer=tokenizer,
122
+ tokenizer=self.tokenizer,
123
all_input_ids=all_input_ids,
124
prev_tokens=seq.tokens,
125
prefix_offset=seq.prefix_offset,
@@ -150,7 +143,7 @@ class Detokenizer:
143
and token_id != VLLM_INVALID_TOKEN_ID):
144
all_input_ids_with_logprob = previous_tokens + [token_id]
145
(_, new_text, _, _) = detokenize_incrementally(
153
- tokenizer=tokenizer,
146
+ tokenizer=self.tokenizer,
147
all_input_ids=all_input_ids_with_logprob,
148
prev_tokens=seq.tokens,
149
prefix_offset=seq.prefix_offset,
vllm/transformers_utils/tokenizer.py
+16
-17
@@ -12,6 +12,7 @@ from typing import TYPE_CHECKING, Any, Optional, Union
12
import huggingface_hub
13
from transformers import (AutoTokenizer, PreTrainedTokenizer,
14
PreTrainedTokenizerFast)
15
+from typing_extensions import assert_never
16
17
from vllm import envs
18
from vllm.logger import init_logger
@@ -19,7 +20,6 @@ from vllm.transformers_utils.config import (
20
get_sentence_transformer_tokenizer_config)
21
from vllm.transformers_utils.tokenizers import MistralTokenizer
22
from vllm.transformers_utils.utils import check_gguf_file
22
-from vllm.utils import make_async
23
24
if TYPE_CHECKING:
25
from vllm.config import ModelConfig
@@ -274,20 +274,19 @@ def cached_tokenizer_from_config(
274
)
275
276
277
-def get_lora_tokenizer(lora_request: LoRARequest, *args,
278
- **kwargs) -> Optional[AnyTokenizer]:
279
- if lora_request is None:
280
- return None
281
- try:
282
- tokenizer = get_tokenizer(lora_request.lora_path, *args, **kwargs)
283
- except Exception as e:
284
- # No tokenizer was found in the LoRA folder,
285
- # use base model tokenizer
286
- logger.warning(
287
- "No tokenizer found in %s, using base model tokenizer instead. "
288
- "(Exception: %s)", lora_request.lora_path, e)
289
- tokenizer = None
290
- return tokenizer
291
-
277
+def init_tokenizer_from_configs(model_config: ModelConfig):
278
+ runner_type = model_config.runner_type
279
+ if runner_type == "generate" or runner_type == "draft":
280
+ truncation_side = "left"
281
+ elif runner_type == "pooling":
282
+ truncation_side = "right"
283
+ else:
284
+ assert_never(runner_type)
285
293
-get_lora_tokenizer_async = make_async(get_lora_tokenizer)
286
+ return get_tokenizer(
287
+ model_config.tokenizer,
288
+ tokenizer_mode=model_config.tokenizer_mode,
289
+ trust_remote_code=model_config.trust_remote_code,
290
+ revision=model_config.tokenizer_revision,
291
+ truncation_side=truncation_side,
292
+ )
vllm/transformers_utils/tokenizer_base.py
+5
@@ -61,6 +61,11 @@ class TokenizerBase(ABC):
61
def max_token_id(self) -> int:
62
raise NotImplementedError()
63
64
+ @property
65
+ @abstractmethod
66
+ def truncation_side(self) -> str:
67
+ raise NotImplementedError()
68
+
69
def __len__(self) -> int:
70
return self.vocab_size
71
vllm/transformers_utils/tokenizer_group.py
deleted
-132
@@ -1,132 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-from typing import Optional
5
-
6
-from typing_extensions import assert_never
7
-
8
-from vllm.config import ModelConfig, SchedulerConfig
9
-from vllm.config.lora import LoRAConfig
10
-from vllm.lora.request import LoRARequest
11
-from vllm.transformers_utils.tokenizer import (AnyTokenizer, encode_tokens,
12
- get_lora_tokenizer,
13
- get_lora_tokenizer_async,
14
- get_tokenizer)
15
-from vllm.utils import LRUCache
16
-
17
-
18
-class TokenizerGroup:
19
- """A group of tokenizers that can be used for LoRA adapters."""
20
-
21
- def __init__(self, tokenizer_id: str, enable_lora: bool, max_num_seqs: int,
22
- max_input_length: Optional[int], **tokenizer_config):
23
- self.tokenizer_id = tokenizer_id
24
- self.tokenizer_config = tokenizer_config
25
- self.enable_lora = enable_lora
26
- self.max_input_length = max_input_length
27
- self.truncation_side = tokenizer_config.get("truncation_side", "left")
28
- self.tokenizer = get_tokenizer(self.tokenizer_id, **tokenizer_config)
29
- max_loras = tokenizer_config.get("max_loras", 0)
30
- self.lora_tokenizers = LRUCache[int, AnyTokenizer](
31
- capacity=max(max_loras, max_num_seqs) if enable_lora else 0)
32
-
33
- def get_max_input_len(self,
34
- lora_request: Optional[LoRARequest] = None
35
- ) -> Optional[int]:
36
- """Get the maximum input length for the LoRA request."""
37
- return self.max_input_length
38
-
39
- def _raise_if_input_too_long(self,
40
- encoded_tokens: list[int],
41
- lora_request: Optional[LoRARequest] = None):
42
- input_length = len(encoded_tokens)
43
- if lora_request:
44
- max_input_length = (lora_request.long_lora_max_len
45
- or self.max_input_length)
46
- else:
47
- max_input_length = self.max_input_length
48
- if max_input_length is not None and input_length > max_input_length:
49
- raise ValueError("Input too long.", input_length, max_input_length)
50
-
51
- def encode(self,
52
- prompt: str,
53
- max_length: Optional[int] = None,
54
- truncation: Optional[bool] = None,
55
- lora_request: Optional[LoRARequest] = None,
56
- add_special_tokens: Optional[bool] = None) -> list[int]:
57
-
58
- tokenizer = self.get_lora_tokenizer(lora_request)
59
- ret = encode_tokens(tokenizer,
60
- prompt,
61
- max_length=max_length,
62
- truncation=truncation,
63
- add_special_tokens=add_special_tokens)
64
- self._raise_if_input_too_long(ret, lora_request)
65
- return ret
66
-
67
- async def encode_async(
68
- self,
69
- prompt: str,
70
- max_length: Optional[int] = None,
71
- truncation: Optional[bool] = None,
72
- lora_request: Optional[LoRARequest] = None,
73
- add_special_tokens: Optional[bool] = None) -> list[int]:
74
- tokenizer = await self.get_lora_tokenizer_async(lora_request)
75
- ret = encode_tokens(tokenizer,
76
- prompt,
77
- max_length=max_length,
78
- truncation=truncation,
79
- add_special_tokens=add_special_tokens)
80
- self._raise_if_input_too_long(ret, lora_request)
81
- return ret
82
-
83
- def get_lora_tokenizer(
84
- self,
85
- lora_request: Optional[LoRARequest] = None,
86
- ) -> AnyTokenizer:
87
- if not lora_request or not self.enable_lora:
88
- return self.tokenizer
89
- if lora_request.lora_int_id not in self.lora_tokenizers:
90
- tokenizer = (get_lora_tokenizer(
91
- lora_request, **self.tokenizer_config) or self.tokenizer)
92
- self.lora_tokenizers.put(lora_request.lora_int_id, tokenizer)
93
- return tokenizer
94
- else:
95
- return self.lora_tokenizers[lora_request.lora_int_id]
96
-
97
- async def get_lora_tokenizer_async(
98
- self,
99
- lora_request: Optional[LoRARequest] = None,
100
- ) -> AnyTokenizer:
101
- if not lora_request or not self.enable_lora:
102
- return self.tokenizer
103
- if lora_request.lora_int_id not in self.lora_tokenizers:
104
- tokenizer = (await get_lora_tokenizer_async(
105
- lora_request, **self.tokenizer_config) or self.tokenizer)
106
- self.lora_tokenizers.put(lora_request.lora_int_id, tokenizer)
107
- return tokenizer
108
- else:
109
- return self.lora_tokenizers[lora_request.lora_int_id]
110
-
111
-
112
-def init_tokenizer_from_configs(model_config: ModelConfig,
113
- scheduler_config: SchedulerConfig,
114
- lora_config: Optional[LoRAConfig]):
115
- runner_type = model_config.runner_type
116
- if runner_type == "generate" or runner_type == "draft":
117
- truncation_side = "left"
118
- elif runner_type == "pooling":
119
- truncation_side = "right"
120
- else:
121
- assert_never(runner_type)
122
-
123
- return TokenizerGroup(
124
- tokenizer_id=model_config.tokenizer,
125
- enable_lora=bool(lora_config),
126
- max_num_seqs=scheduler_config.max_num_seqs,
127
- max_loras=lora_config.max_loras if lora_config else 0,
128
- max_input_length=None,
129
- tokenizer_mode=model_config.tokenizer_mode,
130
- trust_remote_code=model_config.trust_remote_code,
131
- revision=model_config.tokenizer_revision,
132
- truncation_side=truncation_side)
vllm/transformers_utils/tokenizers/mistral.py
+4
@@ -327,6 +327,10 @@ class MistralTokenizer(TokenizerBase):
327
def max_token_id(self) -> int:
328
return self._max_token_id
329
330
+ @property
331
+ def truncation_side(self) -> str:
332
+ raise NotImplementedError()
333
+
334
def __len__(self) -> int:
335
return self.vocab_size
336
vllm/v1/engine/async_llm.py
+5
-10
@@ -29,8 +29,8 @@ from vllm.tasks import SupportedTask
29
from vllm.tracing import init_tracer
30
from vllm.transformers_utils.config import (
31
maybe_register_config_serialize_by_value)
32
-from vllm.transformers_utils.tokenizer import AnyTokenizer
33
-from vllm.transformers_utils.tokenizer_group import init_tokenizer_from_configs
32
+from vllm.transformers_utils.tokenizer import (AnyTokenizer,
33
+ init_tokenizer_from_configs)
34
from vllm.usage.usage_lib import UsageContext
35
from vllm.utils import (Device, as_list, cancel_task_threadsafe, cdiv,
36
deprecate_kwargs)
@@ -112,9 +112,7 @@ class AsyncLLM(EngineClient):
112
else:
113
# Tokenizer (+ ensure liveness if running in another process).
114
self.tokenizer = init_tokenizer_from_configs(
115
- model_config=vllm_config.model_config,
116
- scheduler_config=vllm_config.scheduler_config,
117
- lora_config=vllm_config.lora_config)
115
+ model_config=vllm_config.model_config)
116
117
# Processor (converts Inputs --> EngineCoreRequests).
118
self.processor = Processor(
@@ -596,15 +594,12 @@ class AsyncLLM(EngineClient):
594
async def get_input_preprocessor(self) -> InputPreprocessor:
595
return self.processor.input_preprocessor
596
599
- async def get_tokenizer(
600
- self,
601
- lora_request: Optional[LoRARequest] = None,
602
- ) -> AnyTokenizer:
597
+ async def get_tokenizer(self) -> AnyTokenizer:
598
if self.tokenizer is None:
599
raise ValueError("Unable to get tokenizer because "
600
"skip_tokenizer_init is True")
601
607
- return self.tokenizer.get_lora_tokenizer(lora_request)
602
+ return self.tokenizer
603
604
async def is_tracing_enabled(self) -> bool:
605
return self.observability_config.otlp_traces_endpoint is not None
vllm/v1/engine/llm_engine.py
+4
-6
@@ -20,8 +20,8 @@ from vllm.pooling_params import PoolingParams
20
from vllm.sampling_params import SamplingParams
21
from vllm.tasks import SupportedTask
22
from vllm.tracing import init_tracer
23
-from vllm.transformers_utils.tokenizer_group import (
24
- TokenizerGroup, init_tokenizer_from_configs)
23
+from vllm.transformers_utils.tokenizer import (AnyTokenizer,
24
+ init_tokenizer_from_configs)
25
from vllm.usage.usage_lib import UsageContext
26
from vllm.utils import Device
27
from vllm.v1.engine.core_client import EngineCoreClient
@@ -89,9 +89,7 @@ class LLMEngine:
89
else:
90
# Tokenizer (+ ensure liveness if running in another process).
91
self.tokenizer = init_tokenizer_from_configs(
92
- model_config=vllm_config.model_config,
93
- scheduler_config=vllm_config.scheduler_config,
94
- lora_config=vllm_config.lora_config)
92
+ model_config=vllm_config.model_config)
93
94
# Processor (convert Inputs --> EngineCoreRequests)
95
self.processor = Processor(vllm_config=vllm_config,
@@ -297,7 +295,7 @@ class LLMEngine:
295
assert self.log_stats, "Stat logging disabled"
296
return get_metrics_snapshot()
297
300
- def get_tokenizer_group(self) -> TokenizerGroup:
298
+ def get_tokenizer(self) -> AnyTokenizer:
299
if self.tokenizer is None:
300
raise ValueError("Unable to get tokenizer because "
301
"skip_tokenizer_init is True")
vllm/v1/engine/output_processor.py
+2
-6
@@ -14,7 +14,6 @@ from vllm.sampling_params import RequestOutputKind
14
from vllm.tracing import (SpanAttributes, SpanKind, Tracer,
15
extract_trace_context)
16
from vllm.transformers_utils.tokenizer import AnyTokenizer
17
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
17
from vllm.v1.engine import EngineCoreOutput, EngineCoreRequest, FinishReason
18
from vllm.v1.engine.detokenizer import IncrementalDetokenizer
19
from vllm.v1.engine.logprobs import LogprobsProcessor
@@ -290,7 +289,7 @@ class RequestState:
289
class OutputProcessor:
290
"""Process EngineCoreOutputs into RequestOutputs."""
291
293
- def __init__(self, tokenizer: TokenizerGroup, log_stats: bool):
292
+ def __init__(self, tokenizer: AnyTokenizer, log_stats: bool):
293
self.log_stats = log_stats
294
self.tokenizer = tokenizer
295
self.request_states: dict[str, RequestState] = {}
@@ -347,10 +346,7 @@ class OutputProcessor:
346
if request_id in self.request_states:
347
raise ValueError(f"Request id {request_id} already running.")
348
350
- tokenizer = None if not self.tokenizer else \
351
- self.tokenizer.get_lora_tokenizer(request.lora_request)
352
-
353
- req_state = RequestState.from_new_request(tokenizer=tokenizer,
349
+ req_state = RequestState.from_new_request(tokenizer=self.tokenizer,
350
request=request,
351
prompt=prompt,
352
parent_req=parent_req,
vllm/v1/engine/processor.py
+29
-26
@@ -9,6 +9,7 @@ from vllm.config import VllmConfig
9
from vllm.inputs import ProcessorInputs, PromptType, SingletonInputs
10
from vllm.inputs.parse import split_enc_dec_inputs
11
from vllm.inputs.preprocess import InputPreprocessor
12
+from vllm.logger import init_logger
13
from vllm.lora.request import LoRARequest
14
from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalRegistry
15
from vllm.multimodal.cache import processor_cache_from_config
@@ -17,7 +18,7 @@ from vllm.multimodal.processing import EncDecMultiModalProcessor
18
from vllm.multimodal.utils import argsort_mm_positions
19
from vllm.pooling_params import PoolingParams
20
from vllm.sampling_params import SamplingParams
20
-from vllm.transformers_utils.tokenizer_group import TokenizerGroup
21
+from vllm.transformers_utils.tokenizer import AnyTokenizer
22
from vllm.v1.engine import EngineCoreRequest
23
from vllm.v1.structured_output.backend_guidance import (
24
validate_guidance_grammar)
@@ -28,13 +29,15 @@ from vllm.v1.structured_output.backend_outlines import (
29
from vllm.v1.structured_output.backend_xgrammar import (
30
validate_xgrammar_grammar)
31
32
+logger = init_logger(__name__)
33
+
34
35
class Processor:
36
37
def __init__(
38
self,
39
vllm_config: VllmConfig,
37
- tokenizer: TokenizerGroup,
40
+ tokenizer: AnyTokenizer,
41
mm_registry: MultiModalRegistry = MULTIMODAL_REGISTRY,
42
):
43
@@ -90,7 +93,6 @@ class Processor:
93
def _validate_sampling_params(
94
self,
95
params: SamplingParams,
93
- lora_request: Optional[LoRARequest],
96
) -> None:
97
self._validate_structured_output(params)
98
self._validate_logit_bias(params)
@@ -103,8 +105,7 @@ class Processor:
105
# When skip_tokenizer_init=True, we can't validate token IDs
106
# Skip validation and let the model handle invalid tokens
107
return
106
- tokenizer = self.tokenizer.get_lora_tokenizer(lora_request)
107
- vocab_size = len(tokenizer)
108
+ vocab_size = len(self.tokenizer)
109
if not all(0 <= tid < vocab_size for tid in params.allowed_token_ids):
110
raise ValueError(
111
"allowed_token_ids contains out-of-vocab token id!")
@@ -144,7 +145,6 @@ class Processor:
145
def _validate_params(
146
self,
147
params: Union[SamplingParams, PoolingParams],
147
- lora_request: Optional[LoRARequest],
148
):
149
"""
150
Validate supported SamplingParam.
@@ -155,14 +155,14 @@ class Processor:
155
return
156
157
self._validate_logprobs(params)
158
- self._validate_sampling_params(params, lora_request)
158
+ self._validate_sampling_params(params)
159
self._validate_supported_sampling_params(params)
160
161
def _validate_multi_modal_uuids(self, prompt: PromptType) -> None:
162
"""
163
Validate that user-provided multi_modal_uuids align with
164
multi_modal_data in the incoming request prompt(s).
165
- Only checks lengths; `None` entries are allowed and will be
165
+ Only checks lengths; `None` entries are allowed and will be
166
auto-hashed downstream.
167
"""
168
@@ -202,10 +202,22 @@ class Processor:
202
_validate_single_prompt(prompt) # type: ignore[arg-type]
203
204
def _validate_lora(self, lora_request: Optional[LoRARequest]) -> None:
205
- if lora_request is not None and not self.lora_config:
205
+ if lora_request is None:
206
+ return
207
+
208
+ # LoRA request passed in while LoRA is not enabled
209
+ if not self.lora_config:
210
raise ValueError(f"Got lora_request {lora_request} but LoRA is "
211
"not enabled!")
212
213
+ if self.tokenizer is not None:
214
+ logger.warning_once(
215
+ "vLLM has deprecated support for supporting different "
216
+ "tokenizers for different LoRAs. By default, vLLM uses base "
217
+ "model's tokenizer. If you are using a LoRA "
218
+ "with its own tokenizer, consider specifying `--tokenizer "
219
+ "[lora_path]` to use the LoRA tokenizer.")
220
+
221
def _validate_structured_output(self, params: SamplingParams) -> None:
222
if not params.guided_decoding or not self.decoding_config:
223
return
@@ -326,7 +338,7 @@ class Processor:
338
339
# TODO(woosuk): Support pooling models.
340
self._validate_lora(lora_request)
329
- self._validate_params(params, lora_request)
341
+ self._validate_params(params)
342
343
data_parallel_size = self.vllm_config.parallel_config.data_parallel_size
344
if data_parallel_rank is not None and not (0 <= data_parallel_rank <
@@ -365,7 +377,6 @@ class Processor:
377
processed_inputs: ProcessorInputs = self.input_preprocessor.preprocess(
378
prompt,
379
tokenization_kwargs=tokenization_kwargs,
368
- lora_request=lora_request,
380
mm_uuids=mm_uuids,
381
)
382
from vllm.platforms import current_platform
@@ -375,9 +386,9 @@ class Processor:
386
processed_inputs=processed_inputs,
387
)
388
378
- eos_token_id = self.input_preprocessor.get_eos_token_id(lora_request)
389
+ eos_token_id = self.input_preprocessor.get_eos_token_id()
390
380
- self._validate_model_inputs(processed_inputs, lora_request)
391
+ self._validate_model_inputs(processed_inputs)
392
393
encoder_inputs, decoder_inputs = split_enc_dec_inputs(processed_inputs)
394
@@ -394,8 +405,7 @@ class Processor:
405
sampling_params.update_from_generation_config(
406
self.generation_config_fields, eos_token_id)
407
if self.tokenizer is not None:
397
- sampling_params.update_from_tokenizer(
398
- self.tokenizer.get_lora_tokenizer(lora_request))
408
+ sampling_params.update_from_tokenizer(self.tokenizer)
409
else:
410
pooling_params = params.clone()
411
@@ -436,24 +446,17 @@ class Processor:
446
trace_headers=trace_headers,
447
)
448
439
- def _validate_model_inputs(self,
440
- inputs: ProcessorInputs,
441
- lora_request: Optional[LoRARequest] = None):
449
+ def _validate_model_inputs(self, inputs: ProcessorInputs):
450
encoder_inputs, decoder_inputs = split_enc_dec_inputs(inputs)
451
452
if encoder_inputs is not None:
445
- self._validate_model_input(encoder_inputs,
446
- lora_request,
447
- prompt_type="encoder")
453
+ self._validate_model_input(encoder_inputs, prompt_type="encoder")
454
449
- self._validate_model_input(decoder_inputs,
450
- lora_request,
451
- prompt_type="decoder")
455
+ self._validate_model_input(decoder_inputs, prompt_type="decoder")
456
457
def _validate_model_input(
458
self,
459
prompt_inputs: SingletonInputs,
456
- lora_request: Optional[LoRARequest],
460
*,
461
prompt_type: Literal["encoder", "decoder"],
462
):
@@ -469,7 +472,7 @@ class Processor:
472
if self.model_config.skip_tokenizer_init:
473
tokenizer = None
474
else:
472
- tokenizer = self.tokenizer.get_lora_tokenizer(lora_request)
475
+ tokenizer = self.tokenizer
476
max_input_id = max(prompt_ids, default=0)
477
478
# NOTE: tokenizer.max_token_id is the tokenizer’s vocab size while
vllm/v1/structured_output/__init__.py
+2
-5
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, Optional
9
from vllm.config import VllmConfig
10
from vllm.logger import init_logger
11
from vllm.reasoning import ReasoningParserManager
12
-from vllm.transformers_utils.tokenizer_group import init_tokenizer_from_configs
12
+from vllm.transformers_utils.tokenizer import init_tokenizer_from_configs
13
from vllm.utils import LazyLoader
14
from vllm.v1.structured_output.backend_guidance import GuidanceBackend
15
from vllm.v1.structured_output.backend_types import (StructuredOutputBackend,
@@ -60,10 +60,7 @@ class StructuredOutputManager:
60
max_workers = max(1, (multiprocessing.cpu_count() + 1) // 2)
61
self.executor = ThreadPoolExecutor(max_workers=max_workers)
62
self.tokenizer = init_tokenizer_from_configs(
63
- model_config=self.vllm_config.model_config,
64
- scheduler_config=self.vllm_config.scheduler_config,
65
- lora_config=self.vllm_config.lora_config,
66
- ).get_lora_tokenizer(None)
63
+ model_config=self.vllm_config.model_config)
64
reasoning_backend = \
65
self.vllm_config.decoding_config.reasoning_backend
66
if reasoning_backend: