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 11, 22:30 UTC
[Bugfix]: Fix `TokenizerLike` interface (#30009)
Signed-off-by: Rohan138 <rohanpotdar138@gmail.com>
Rohan Potdar committed
Dec 5, 2025 at 22:56 UTC
40a046cd82af87e65d3be9db8bd27a4be65f1b00
8 files changed
+78
-52
vllm/benchmarks/datasets.py
+32
-27
@@ -32,7 +32,6 @@ from typing import Any, cast
32
33
import numpy as np
34
from PIL import Image
35
-from transformers import PreTrainedTokenizerBase
35
from typing_extensions import deprecated
36
37
from vllm.lora.request import LoRARequest
@@ -189,7 +188,7 @@ class BenchmarkDataset(ABC):
188
@abstractmethod
189
def sample(
190
self,
192
- tokenizer: PreTrainedTokenizerBase,
191
+ tokenizer: TokenizerLike,
192
num_requests: int,
193
request_id_prefix: str = "",
194
no_oversample: bool = False,
@@ -201,7 +200,7 @@ class BenchmarkDataset(ABC):
200
for generating a list of SampleRequest objects.
201
202
Args:
204
- tokenizer (PreTrainedTokenizerBase): The tokenizer to be used
203
+ tokenizer (TokenizerLike): The tokenizer to be used
204
for processing the dataset's text.
205
num_requests (int): The number of sample requests to generate.
206
request_id_prefix (str): The prefix of request_id.
@@ -380,7 +379,7 @@ def process_video(video: Any) -> Mapping[str, Any]:
379
380
381
def gen_prompt_decode_to_target_len(
383
- tokenizer: PreTrainedTokenizerBase,
382
+ tokenizer: TokenizerLike,
383
token_sequence: list[int],
384
target_token_len: int,
385
max_retry: int = 10,
@@ -468,7 +467,7 @@ class RandomDataset(BenchmarkDataset):
467
468
def sample(
469
self,
471
- tokenizer: PreTrainedTokenizerBase,
470
+ tokenizer: TokenizerLike,
471
num_requests: int,
472
request_id_prefix: str = "",
473
no_oversample: bool = False,
@@ -580,7 +579,7 @@ class RandomDataset(BenchmarkDataset):
579
range_ratio: float,
580
input_len: int,
581
output_len: int,
583
- tokenizer: PreTrainedTokenizerBase,
582
+ tokenizer: TokenizerLike,
583
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
584
"""
585
Get the sampling parameters for the dataset.
@@ -626,7 +625,7 @@ class RandomDataset(BenchmarkDataset):
625
def generate_token_sequence(
626
self,
627
*,
629
- tokenizer: PreTrainedTokenizerBase,
628
+ tokenizer: TokenizerLike,
629
prefix_token_ids: list[int],
630
prefix_len: int,
631
vocab_size: int,
@@ -686,7 +685,7 @@ class RandomDatasetForReranking(RandomDataset):
685
686
def sample(
687
self,
689
- tokenizer: PreTrainedTokenizerBase,
688
+ tokenizer: TokenizerLike,
689
num_requests: int,
690
request_id_prefix: str = "",
691
range_ratio: float = RandomDataset.DEFAULT_RANGE_RATIO,
@@ -716,7 +715,11 @@ class RandomDatasetForReranking(RandomDataset):
715
doc_lens, _, doc_offsets = self.get_sampling_params(
716
num_requests, range_ratio, doc_len_param, 0, tokenizer
717
)
718
+
719
vocab_size = tokenizer.vocab_size
720
+ prohibited_tokens = tokenizer.all_special_ids
721
+ all_tokens = np.arange(vocab_size)
722
+ allowed_tokens = np.array(list(set(all_tokens) - set(prohibited_tokens)))
723
724
query_prompt, query_input_len, token_mismatch_total = (
725
self.generate_token_sequence(
@@ -727,6 +730,7 @@ class RandomDatasetForReranking(RandomDataset):
730
input_len=query_len,
731
offset=int(query_offsets[0]),
732
index=0,
733
+ allowed_tokens=allowed_tokens,
734
)
735
)
736
@@ -740,6 +744,7 @@ class RandomDatasetForReranking(RandomDataset):
744
input_len=int(doc_lens[i]),
745
offset=int(doc_offsets[i]),
746
index=i + 1,
747
+ allowed_tokens=allowed_tokens,
748
)
749
token_mismatch_total += token_mismatch
750
requests.append((prompt, total_input_len))
@@ -1077,7 +1082,7 @@ class RandomMultiModalDataset(RandomDataset):
1082
1083
def sample(
1084
self,
1080
- tokenizer: PreTrainedTokenizerBase,
1085
+ tokenizer: TokenizerLike,
1086
num_requests: int,
1087
request_id_prefix: str = "",
1088
no_oversample: bool = False,
@@ -1231,7 +1236,7 @@ class ShareGPTDataset(BenchmarkDataset):
1236
1237
def sample(
1238
self,
1234
- tokenizer: PreTrainedTokenizerBase,
1239
+ tokenizer: TokenizerLike,
1240
num_requests: int,
1241
lora_path: str | None = None,
1242
max_loras: int | None = None,
@@ -1633,7 +1638,7 @@ def add_dataset_parser(parser: FlexibleArgumentParser):
1638
)
1639
1640
1636
-def get_samples(args, tokenizer) -> list[SampleRequest]:
1641
+def get_samples(args, tokenizer: TokenizerLike) -> list[SampleRequest]:
1642
if not hasattr(args, "request_id_prefix"):
1643
args.request_id_prefix = ""
1644
@@ -1971,7 +1976,7 @@ class CustomDataset(BenchmarkDataset):
1976
1977
def sample(
1978
self,
1974
- tokenizer: PreTrainedTokenizerBase,
1979
+ tokenizer: TokenizerLike,
1980
num_requests: int,
1981
lora_path: str | None = None,
1982
max_loras: int | None = None,
@@ -2101,7 +2106,7 @@ class SonnetDataset(BenchmarkDataset):
2106
2107
def sample(
2108
self,
2104
- tokenizer,
2109
+ tokenizer: TokenizerLike,
2110
num_requests: int,
2111
prefix_len: int = DEFAULT_PREFIX_LEN,
2112
input_len: int = DEFAULT_INPUT_LEN,
@@ -2202,7 +2207,7 @@ class BurstGPTDataset(BenchmarkDataset):
2207
2208
def sample(
2209
self,
2205
- tokenizer: PreTrainedTokenizerBase,
2210
+ tokenizer: TokenizerLike,
2211
num_requests: int,
2212
max_loras: int | None = None,
2213
lora_path: str | None = None,
@@ -2287,7 +2292,7 @@ class ConversationDataset(HuggingFaceDataset):
2292
2293
def sample(
2294
self,
2290
- tokenizer: PreTrainedTokenizerBase,
2295
+ tokenizer: TokenizerLike,
2296
num_requests: int,
2297
output_len: int | None = None,
2298
enable_multimodal_chat: bool = False,
@@ -2347,7 +2352,7 @@ class MultiModalConversationDataset(HuggingFaceDataset):
2352
2353
def sample(
2354
self,
2350
- tokenizer: PreTrainedTokenizerBase,
2355
+ tokenizer: TokenizerLike,
2356
num_requests: int,
2357
output_len: int | None = None,
2358
enable_multimodal_chat: bool = False,
@@ -2416,7 +2421,7 @@ class VisionArenaDataset(HuggingFaceDataset):
2421
2422
def sample(
2423
self,
2419
- tokenizer: PreTrainedTokenizerBase,
2424
+ tokenizer: TokenizerLike,
2425
num_requests: int,
2426
output_len: int | None = None,
2427
enable_multimodal_chat: bool = False,
@@ -2470,7 +2475,7 @@ class MMVUDataset(HuggingFaceDataset):
2475
2476
def sample(
2477
self,
2473
- tokenizer: PreTrainedTokenizerBase,
2478
+ tokenizer: TokenizerLike,
2479
num_requests: int,
2480
output_len: int | None = None,
2481
enable_multimodal_chat: bool = False,
@@ -2531,7 +2536,7 @@ class InstructCoderDataset(HuggingFaceDataset):
2536
2537
def sample(
2538
self,
2534
- tokenizer: PreTrainedTokenizerBase,
2539
+ tokenizer: TokenizerLike,
2540
num_requests: int,
2541
output_len: int | None = None,
2542
enable_multimodal_chat: bool = False,
@@ -2595,7 +2600,7 @@ class MTBenchDataset(HuggingFaceDataset):
2600
2601
def sample(
2602
self,
2598
- tokenizer: PreTrainedTokenizerBase,
2603
+ tokenizer: TokenizerLike,
2604
num_requests: int,
2605
output_len: int | None = None,
2606
enable_multimodal_chat: bool = False,
@@ -2661,7 +2666,7 @@ class BlazeditDataset(HuggingFaceDataset):
2666
2667
def sample(
2668
self,
2664
- tokenizer: PreTrainedTokenizerBase,
2669
+ tokenizer: TokenizerLike,
2670
num_requests: int,
2671
output_len: int | None = None,
2672
skip_chat_template: bool = False,
@@ -2742,7 +2747,7 @@ class AIMODataset(HuggingFaceDataset):
2747
2748
def sample(
2749
self,
2745
- tokenizer: PreTrainedTokenizerBase,
2750
+ tokenizer: TokenizerLike,
2751
num_requests: int,
2752
output_len: int | None = None,
2753
request_id_prefix: str = "",
@@ -2852,7 +2857,7 @@ class NextEditPredictionDataset(HuggingFaceDataset):
2857
2858
def sample(
2859
self,
2855
- tokenizer: PreTrainedTokenizerBase,
2860
+ tokenizer: TokenizerLike,
2861
num_requests: int,
2862
request_id_prefix: str = "",
2863
no_oversample: bool = False,
@@ -2924,7 +2929,7 @@ class ASRDataset(HuggingFaceDataset):
2929
2930
def sample(
2931
self,
2927
- tokenizer: PreTrainedTokenizerBase,
2932
+ tokenizer: TokenizerLike,
2933
num_requests: int,
2934
output_len: int | None = None,
2935
request_id_prefix: str = "",
@@ -3002,7 +3007,7 @@ class MLPerfDataset(HuggingFaceDataset):
3007
3008
def sample(
3009
self,
3005
- tokenizer: PreTrainedTokenizerBase,
3010
+ tokenizer: TokenizerLike,
3011
num_requests: int,
3012
output_len: int | None = None,
3013
request_id_prefix: str = "",
@@ -3081,7 +3086,7 @@ class PrefixRepetitionRandomDataset(BenchmarkDataset):
3086
3087
def sample(
3088
self,
3084
- tokenizer: PreTrainedTokenizerBase,
3089
+ tokenizer: TokenizerLike,
3090
num_requests: int,
3091
prefix_len: int = DEFAULT_PREFIX_LEN,
3092
suffix_len: int = DEFAULT_SUFFIX_LEN,
@@ -3167,7 +3172,7 @@ class MMStarDataset(HuggingFaceDataset):
3172
3173
def sample(
3174
self,
3170
- tokenizer: PreTrainedTokenizerBase,
3175
+ tokenizer: TokenizerLike,
3176
num_requests: int,
3177
output_len: int | None = None,
3178
enable_multimodal_chat: bool = False,
vllm/benchmarks/serve.py
+16
-16
@@ -36,7 +36,6 @@ from typing import Any, Literal
36
import aiohttp
37
import numpy as np
38
from tqdm.asyncio import tqdm
39
-from transformers import PreTrainedTokenizerBase
39
40
from vllm.benchmarks.datasets import SampleRequest, add_dataset_parser, get_samples
41
from vllm.benchmarks.lib.endpoint_request_func import (
@@ -47,7 +46,7 @@ from vllm.benchmarks.lib.endpoint_request_func import (
46
)
47
from vllm.benchmarks.lib.ready_checker import wait_for_endpoint
48
from vllm.benchmarks.lib.utils import convert_to_pytorch_benchmark_format, write_to_json
50
-from vllm.tokenizers import get_tokenizer
49
+from vllm.tokenizers import TokenizerLike, get_tokenizer
50
from vllm.utils.gc_utils import freeze_gc_heap
51
from vllm.utils.network_utils import join_host_port
52
@@ -286,7 +285,7 @@ def calculate_metrics(
285
input_requests: list[SampleRequest],
286
outputs: list[RequestFuncOutput],
287
dur_s: float,
289
- tokenizer: PreTrainedTokenizerBase,
288
+ tokenizer: TokenizerLike,
289
selected_percentiles: list[float],
290
goodput_config_dict: dict[str, float],
291
) -> tuple[BenchmarkMetrics, list[int]]:
@@ -489,7 +488,7 @@ async def benchmark(
488
base_url: str,
489
model_id: str,
490
model_name: str,
492
- tokenizer: PreTrainedTokenizerBase,
491
+ tokenizer: TokenizerLike,
492
input_requests: list[SampleRequest],
493
logprobs: int | None,
494
request_rate: float,
@@ -1032,6 +1031,19 @@ def add_cli_args(parser: argparse.ArgumentParser):
1031
type=str,
1032
help="Name or path of the tokenizer, if not using the default tokenizer.", # noqa: E501
1033
)
1034
+ parser.add_argument(
1035
+ "--tokenizer-mode",
1036
+ type=str,
1037
+ default="auto",
1038
+ help="""Tokenizer mode:\n
1039
+ - "auto" will use the tokenizer from `mistral_common` for Mistral models
1040
+ if available, otherwise it will use the "hf" tokenizer.\n
1041
+ - "hf" will use the fast tokenizer if available.\n
1042
+ - "slow" will always use the slow tokenizer.\n
1043
+ - "mistral" will always use the tokenizer from `mistral_common`.\n
1044
+ - "deepseek_v32" will always use the tokenizer from `deepseek_v32`.\n
1045
+ - Other custom values can be supported via plugins.""",
1046
+ )
1047
parser.add_argument("--use-beam-search", action="store_true")
1048
parser.add_argument(
1049
"--logprobs",
@@ -1228,18 +1240,6 @@ def add_cli_args(parser: argparse.ArgumentParser):
1240
help="Common prefix length shared by all prompts (used by random dataset)",
1241
)
1242
1231
- parser.add_argument(
1232
- "--tokenizer-mode",
1233
- type=str,
1234
- default="auto",
1235
- choices=["auto", "slow", "mistral", "custom"],
1236
- help='The tokenizer mode.\n\n* "auto" will use the '
1237
- 'fast tokenizer if available.\n* "slow" will '
1238
- "always use the slow tokenizer. \n* "
1239
- '"mistral" will always use the `mistral_common` tokenizer. \n*'
1240
- '"custom" will use --tokenizer to select the preregistered tokenizer.',
1241
- )
1242
-
1243
parser.add_argument(
1244
"--served-model-name",
1245
type=str,
vllm/benchmarks/throughput.py
+16
-6
@@ -14,7 +14,7 @@ from typing import Any
14
import torch
15
import uvloop
16
from tqdm import tqdm
17
-from transformers import AutoModelForCausalLM, AutoTokenizer, PreTrainedTokenizerBase
17
+from transformers import AutoModelForCausalLM, PreTrainedTokenizerBase
18
19
from vllm.benchmarks.datasets import (
20
AIMODataset,
@@ -35,6 +35,7 @@ from vllm.inputs import TextPrompt, TokensPrompt
35
from vllm.lora.request import LoRARequest
36
from vllm.outputs import RequestOutput
37
from vllm.sampling_params import BeamSearchParams
38
+from vllm.tokenizers import TokenizerLike, get_tokenizer
39
from vllm.utils.async_utils import merge_async_iterators
40
41
@@ -246,12 +247,15 @@ async def run_vllm_async(
247
def run_hf(
248
requests: list[SampleRequest],
249
model: str,
249
- tokenizer: PreTrainedTokenizerBase,
250
+ tokenizer: TokenizerLike,
251
n: int,
252
max_batch_size: int,
253
trust_remote_code: bool,
254
disable_detokenize: bool = False,
255
) -> float:
256
+ assert isinstance(tokenizer, PreTrainedTokenizerBase), (
257
+ "the hf backend only supports HF tokenizers"
258
+ )
259
llm = AutoModelForCausalLM.from_pretrained(
260
model, dtype=torch.float16, trust_remote_code=trust_remote_code
261
)
@@ -692,15 +696,21 @@ def add_cli_args(parser: argparse.ArgumentParser):
696
697
698
def main(args: argparse.Namespace):
695
- if args.tokenizer is None:
696
- args.tokenizer = args.model
699
validate_args(args)
700
if args.seed is None:
701
args.seed = 0
702
random.seed(args.seed)
703
# Sample the requests.
702
- tokenizer = AutoTokenizer.from_pretrained(
703
- args.tokenizer, trust_remote_code=args.trust_remote_code
704
+ if (
705
+ args.backend == "hf" or args.backend == "mii"
706
+ ) and args.tokenizer_mode == "auto":
707
+ # mistral_common tokenizer is only supported on vllm and vllm-chat backends;
708
+ # for hf and mii backends, we use hf tokenizer
709
+ args.tokenizer_mode = "hf"
710
+ tokenizer = get_tokenizer(
711
+ args.tokenizer,
712
+ tokenizer_mode=args.tokenizer_mode,
713
+ trust_remote_code=args.trust_remote_code,
714
)
715
requests = get_requests(args, tokenizer)
716
is_multi_modal = any(request.multi_modal_data is not None for request in requests)
vllm/config/model.py
+2
-1
@@ -136,7 +136,8 @@ class ModelConfig:
136
name or path will be used."""
137
tokenizer_mode: TokenizerMode | str = "auto"
138
"""Tokenizer mode:\n
139
- - "auto" will use "hf" tokenizer if Mistral's tokenizer is not available.\n
139
+ - "auto" will use the tokenizer from `mistral_common` for Mistral models
140
+ if available, otherwise it will use the "hf" tokenizer.\n
141
- "hf" will use the fast tokenizer if available.\n
142
- "slow" will always use the slow tokenizer.\n
143
- "mistral" will always use the tokenizer from `mistral_common`.\n
vllm/tokenizers/deepseekv32.py
+3
@@ -54,6 +54,9 @@ class DeepseekV32Tokenizer(HfTokenizer):
54
prompt_str = encode_messages(messages, **encode_config) # type: ignore
55
return prompt_str
56
57
+ def num_special_tokens_to_add(self) -> int:
58
+ return len(self.encode(""))
59
+
60
@property
61
def all_special_tokens(self) -> list[str]:
62
return self.tokenizer.all_special_tokens
vllm/tokenizers/mistral.py
+5
-1
@@ -309,6 +309,9 @@ class MistralTokenizer(TokenizerLike):
309
for i in all_special_ids
310
]
311
312
+ def num_special_tokens_to_add(self) -> int:
313
+ return len(self.encode(""))
314
+
315
# the following attributes are set to fit vLLM's design and are used
316
# by the structured output backends.
317
@property
@@ -421,6 +424,7 @@ class MistralTokenizer(TokenizerLike):
424
) -> list[int]:
425
add_generation_prompt = kwargs.pop("add_generation_prompt", False)
426
continue_final_message = kwargs.get("continue_final_message", False)
427
+ tokenize = kwargs.get("tokenize", True)
428
padding = kwargs.get("padding", False)
429
truncation = kwargs.get("truncation", False)
430
max_length = kwargs.get("max_length")
@@ -433,7 +437,7 @@ class MistralTokenizer(TokenizerLike):
437
conversation=messages,
438
tools=tools,
439
continue_final_message=continue_final_message,
436
- tokenize=True,
440
+ tokenize=tokenize,
441
padding=padding,
442
truncation=truncation,
443
max_length=max_length,
vllm/tokenizers/protocol.py
+3
@@ -22,6 +22,9 @@ class TokenizerLike(Protocol):
22
) -> "TokenizerLike":
23
raise NotImplementedError
24
25
+ def num_special_tokens_to_add(self) -> int:
26
+ raise NotImplementedError
27
+
28
@property
29
def all_special_tokens(self) -> list[str]:
30
raise NotImplementedError
vllm/tokenizers/registry.py
+1
-1
@@ -183,7 +183,7 @@ def get_tokenizer(
183
"`tokenizer_mode='custom'` when initializing vLLM.",
184
tokenizer_args,
185
str(tokenizer_kwargs),
186
- tokenizer_mode,
186
+ tokenizer_name,
187
)
188
189
tokenizer_mode = str(tokenizer_name)