[Misc] Remove code paths for Transformers < 5.16.1 (#59762)
Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Harry Mellor committed
Oct 2, 2026 at 12:17 UTC
5d20979fc90a38f450e0fb89661b271926a3061a
18 files changed
+142
-757
tests/models/language/generation/test_granite.py
+7
-10
@@ -5,16 +5,15 @@ from transformers import GraniteConfig
5
6
from vllm.model_executor.models.granite import granite_layer_attn_params
7
8
-from ...utils import check_logprobs_close, check_transformers_version
8
+from ...utils import check_logprobs_close
9
10
-# model -> minimum transformers version, or None if unconstrained
11
-MODELS = {
10
+MODELS = [
11
# TODO(sang): Sliding window should be tested separately.
13
- "ibm/PowerLM-3b": None,
14
- "ibm/PowerMoE-3b": None,
15
- "ibm-granite/granite-swash-2b": "5.15.1",
16
- "ibm-granite/granite-swash-3b-a600m": "5.15.1",
17
-}
12
+ "ibm/PowerLM-3b",
13
+ "ibm/PowerMoE-3b",
14
+ "ibm-granite/granite-swash-2b",
15
+ "ibm-granite/granite-swash-3b-a600m",
16
+]
17
18
19
@pytest.mark.parametrize("model", MODELS)
@@ -31,8 +30,6 @@ def test_models(
30
max_tokens: int,
31
num_logprobs: int,
32
) -> None:
34
- check_transformers_version(model, min_transformers_version=MODELS[model])
35
-
33
with hf_runner(model, dtype=dtype) as hf_model:
34
hf_outputs = hf_model.generate_greedy_logprobs_limit(
35
example_prompts, max_tokens, num_logprobs
tests/models/multimodal/processing/test_transformers_audio.py
+13
-24
@@ -4,11 +4,8 @@ import numpy as np
4
import pytest
5
6
from vllm.config import ModelConfig
7
-from vllm.model_executor.models.transformers.multimodal import LegacyMultiModalProcessor
7
from vllm.multimodal import MULTIMODAL_REGISTRY
8
10
-from .transformers_backend import PROCESSOR_CLASSES, create_processor
11
-
9
AUDIO_MODEL_SETTINGS = {
10
"ibm-granite/granite-speech-3.3-2b": {
11
"prompt": (
@@ -56,7 +53,6 @@ AUDIO_MODEL_SETTINGS = {
53
}
54
55
59
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
56
@pytest.mark.parametrize(
57
"model_id",
58
[
@@ -78,10 +74,12 @@ AUDIO_MODEL_SETTINGS = {
74
"zai-org/GLM-ASR-Nano-2512",
75
],
76
)
81
-def test_audio_multimodal_processor(model_id, processor_cls):
77
+def test_audio_multimodal_processor(model_id):
78
settings = AUDIO_MODEL_SETTINGS[model_id]
79
84
- mm_processor = create_processor(model_id, processor_cls)
80
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
81
+ ModelConfig(model=model_id, model_impl="transformers")
82
+ )
83
84
audio = np.zeros(16000, dtype=np.float32)
85
mm_data = {"audio": (audio, 16000)}
@@ -112,13 +110,14 @@ def test_audio_multimodal_processor(model_id, processor_cls):
110
)
111
112
115
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
113
@pytest.mark.parametrize("separator", [" and ", ""])
117
-def test_audio_multiple_inputs(separator, processor_cls):
114
+def test_audio_multiple_inputs(separator):
115
"""Multiple audios per prompt are each detected as a separate placeholder
116
and multi-modal item by the Transformers modelling backend."""
117
model_id = "ibm-granite/granite-speech-3.3-2b"
121
- mm_processor = create_processor(model_id, processor_cls)
118
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
119
+ ModelConfig(model=model_id, model_impl="transformers")
120
+ )
121
122
audio_token = mm_processor.info.get_hf_processor().audio_token
123
# One token per audio; the processor expands each to its placeholder run.
@@ -128,21 +127,11 @@ def test_audio_multiple_inputs(separator, processor_cls):
127
)
128
audios = [np.zeros(16000, dtype=np.float32), np.zeros(24000, dtype=np.float32)]
129
131
- def process():
132
- return mm_processor(
133
- prompt=prompt,
134
- mm_items=mm_processor.info.parse_mm_data({"audio": audios}),
135
- hf_processor_mm_kwargs={},
136
- )
137
-
138
- # The legacy path reads placeholders off contiguous runs of the audio token, so
139
- # it cannot tell adjacent ones apart and says so instead of merging them
140
- if processor_cls is LegacyMultiModalProcessor and not separator:
141
- with pytest.raises(ValueError, match="Separate them in the prompt"):
142
- process()
143
- return
144
-
145
- result = process()
130
+ result = mm_processor(
131
+ prompt=prompt,
132
+ mm_items=mm_processor.info.parse_mm_data({"audio": audios}),
133
+ hf_processor_mm_kwargs={},
134
+ )
135
136
assert len(result["mm_placeholders"]["audio"]) == 2
137
assert len(result["mm_kwargs"]["audio"]) == 2
tests/models/multimodal/processing/test_transformers_image.py
+74
-84
@@ -5,23 +5,16 @@ from unittest.mock import patch
5
import pytest
6
7
from vllm.assets.image import ImageAsset
8
-from vllm.model_executor.models.transformers.multimodal import (
9
- LegacyMultiModalProcessor,
10
- OffsetsMultiModalProcessor,
11
-)
12
-
13
-from .transformers_backend import (
14
- PROCESSOR_CLASSES,
15
- create_cached_processor,
16
- create_processor,
17
- offsets_only,
18
-)
8
+from vllm.config import ModelConfig
9
+from vllm.multimodal import MULTIMODAL_REGISTRY
10
+from vllm.multimodal.cache import MultiModalProcessorOnlyCache
11
12
21
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
13
@pytest.mark.parametrize("model_id", ["llava-hf/llava-onevision-qwen2-0.5b-ov-hf"])
23
-def test_multimodal_processor(model_id, processor_cls):
24
- mm_processor = create_processor(model_id, processor_cls)
14
+def test_multimodal_processor(model_id):
15
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
16
+ ModelConfig(model=model_id, model_impl="transformers")
17
+ )
18
19
image_pil = ImageAsset("cherry_blossom").pil_image
20
mm_data = {"image": image_pil}
@@ -63,9 +56,11 @@ def test_multimodal_processor(model_id, processor_cls):
56
)
57
58
66
-def _process_two_images(processor_cls, separator: str):
59
+def _process_two_images(separator: str):
60
model_id = "llava-hf/llava-onevision-qwen2-0.5b-ov-hf"
68
- mm_processor = create_processor(model_id, processor_cls)
61
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
62
+ ModelConfig(model=model_id, model_impl="transformers")
63
+ )
64
65
image = ImageAsset("cherry_blossom").pil_image
66
prompt = (
@@ -80,30 +75,29 @@ def _process_two_images(processor_cls, separator: str):
75
)
76
77
83
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
84
-def test_image_multiple_inputs(processor_cls):
78
+def test_image_multiple_inputs():
79
"""Multiple images per prompt are each detected as a separate placeholder
80
and multi-modal item by the Transformers modelling backend."""
87
- result = _process_two_images(processor_cls, separator="\n and ")
81
+ result = _process_two_images(separator="\n and ")
82
83
assert len(result["mm_placeholders"]["image"]) == 2
84
assert len(result["mm_kwargs"]["image"]) == 2
85
86
93
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
94
-def test_image_adjacent_inputs(processor_cls):
87
+def test_image_adjacent_inputs():
88
"""Adjacent images stay separate placeholders rather than merging into one."""
96
- result = _process_two_images(processor_cls, separator="")
89
+ result = _process_two_images(separator="")
90
91
assert len(result["mm_placeholders"]["image"]) == 2
92
assert len(result["mm_kwargs"]["image"]) == 2
93
94
102
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
103
-def test_batch_padding_removed_from_image_items(processor_cls):
95
+def test_batch_padding_removed_from_image_items():
96
"""Emu3 pads every image up to the largest in the batch, which would leave an
97
item's data dependent on what it was processed with and so uncacheable."""
106
- mm_processor = create_processor("BAAI/Emu3-Chat-hf", processor_cls)
98
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
99
+ ModelConfig(model="BAAI/Emu3-Chat-hf", model_impl="transformers")
100
+ )
101
image_token = mm_processor.info.get_hf_processor().image_token
102
103
images = [
@@ -128,53 +122,39 @@ def test_batch_padding_removed_from_image_items(processor_cls):
122
assert len(shapes) == 2
123
124
131
-def _process_one_gemma3_image(processor_cls):
132
- mm_processor = create_processor("google/gemma-3-4b-it", processor_cls)
133
- hf_processor = mm_processor.info.get_hf_processor()
134
- result = mm_processor(
135
- prompt=f"{hf_processor.boi_token} What is this?",
125
+def _process_one_gemma3_image():
126
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
127
+ ModelConfig(model="google/gemma-3-4b-it", model_impl="transformers")
128
+ )
129
+ boi_token = mm_processor.info.get_hf_processor().boi_token
130
+ return mm_processor(
131
+ prompt=f"{boi_token} What is this?",
132
mm_items=mm_processor.info.parse_mm_data(
133
{"image": ImageAsset("cherry_blossom").pil_image}
134
),
135
hf_processor_mm_kwargs={},
136
)
141
- return hf_processor, result
137
138
144
-@offsets_only
139
def test_non_embedding_tokens_excluded_from_placeholders():
140
"""Gemma3 wraps each image in text that carries no embeddings, which must be
141
inside the placeholder range but masked out of it."""
148
- _, result = _process_one_gemma3_image(OffsetsMultiModalProcessor)
142
+ result = _process_one_gemma3_image()
143
144
(placeholder,) = result["mm_placeholders"]["image"]
145
assert placeholder.is_embed is not None
146
assert 0 < int(placeholder.is_embed.sum()) < placeholder.length
147
148
155
-def test_legacy_placeholders_hold_only_image_tokens():
156
- """The legacy path spans whatever `mm_token_type_ids` attributes to the image,
157
- which for Gemma3 excludes the text wrapping it, unlike the replacement the offsets
158
- path spans. Gemma3 is also the sharp case for the mask: its `image_token_id` is the
159
- marker in the unexpanded prompt, not the token the expansion repeats."""
160
- hf_processor, result = _process_one_gemma3_image(LegacyMultiModalProcessor)
161
-
162
- (placeholder,) = result["mm_placeholders"]["image"]
163
- assert placeholder.length == hf_processor.image_seq_length
164
- prompt_ids = result["prompt_token_ids"]
165
- covered = prompt_ids[placeholder.offset : placeholder.offset + placeholder.length]
166
- assert set(covered) == {hf_processor.tokenizer.image_token_id}
167
-
168
-
169
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
170
-def test_tokens_structuring_an_image_are_masked_not_dropped(processor_cls):
149
+def test_tokens_structuring_an_image_are_masked_not_dropped():
150
"""SmolVLM splits each image into tiles introduced by tokens carrying no
151
embeddings. Those belong inside the placeholder and masked out, because the token
152
count the processor reports is over the whole span. Idefics3 also refuses a prompt
174
- holding `<image>` when no images are passed, which is how the offsets path has to
175
- tokenize it before splicing in the expansion."""
176
- mm_processor = create_processor(
177
- "HuggingFaceTB/SmolVLM-256M-Instruct", processor_cls
153
+ holding `<image>` when no images are passed, which is how the prompt has to be
154
+ tokenized before splicing in the expansion."""
155
+ model_id = "HuggingFaceTB/SmolVLM-256M-Instruct"
156
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
157
+ ModelConfig(model=model_id, model_impl="transformers")
158
)
159
result = mm_processor(
160
prompt="<image>What is this?",
@@ -189,12 +169,13 @@ def test_tokens_structuring_an_image_are_masked_not_dropped(processor_cls):
169
assert 0 < int(placeholder.is_embed.sum()) < placeholder.length
170
171
192
-@offsets_only
172
def test_missing_replacement_offsets_names_the_processor():
173
"""A processor that reports no replacement offsets cannot be served, which must
174
be said plainly rather than surfacing later as a field config mismatch."""
175
model_id = "llava-hf/llava-onevision-qwen2-0.5b-ov-hf"
197
- mm_processor = create_processor(model_id, OffsetsMultiModalProcessor)
176
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
177
+ ModelConfig(model=model_id, model_impl="transformers")
178
+ )
179
hf_processor_cls = type(mm_processor.info.get_hf_processor())
180
hf_call = hf_processor_cls.__call__
181
@@ -216,11 +197,12 @@ def test_missing_replacement_offsets_names_the_processor():
197
)
198
199
219
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
220
-def test_text_only_prompt(processor_cls):
200
+def test_text_only_prompt():
201
"""An image model still accepts a prompt with no images."""
202
model_id = "llava-hf/llava-onevision-qwen2-0.5b-ov-hf"
223
- mm_processor = create_processor(model_id, processor_cls)
203
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
204
+ ModelConfig(model=model_id, model_impl="transformers")
205
+ )
206
207
result = mm_processor(
208
prompt="<|im_start|>user Hello!<|im_end|><|im_start|>assistant\n",
@@ -232,12 +214,14 @@ def test_text_only_prompt(processor_cls):
214
assert not result["mm_placeholders"]
215
216
235
-@offsets_only
217
def test_repeated_image_hits_the_processor_cache():
218
"""Check that mm caching is actually working."""
238
- mm_processor, cache = create_cached_processor(
239
- "llava-hf/llava-onevision-qwen2-0.5b-ov-hf", OffsetsMultiModalProcessor
219
+ model_config = ModelConfig(
220
+ model="llava-hf/llava-onevision-qwen2-0.5b-ov-hf", model_impl="transformers"
221
)
222
+ model_config.multimodal_config.mm_processor_cache_gb = 4
223
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(model_config)
224
+ cache = MultiModalProcessorOnlyCache(model_config)
225
image = ImageAsset("cherry_blossom").pil_image
226
227
def process():
@@ -255,7 +239,6 @@ def test_repeated_image_hits_the_processor_cache():
239
assert first["mm_hashes"] == second["mm_hashes"]
240
241
258
-@offsets_only
242
@pytest.mark.parametrize(
243
("model_id", "prompt"),
244
[
@@ -267,7 +250,7 @@ def test_repeated_image_hits_the_processor_cache():
250
"<image> and more text",
251
marks=pytest.mark.xfail(
252
reason="Emu3Processor prepends its BOS token only when images are "
270
- "passed, so the unexpanded prompt the offsets path tokenizes never "
253
+ "passed, so the unexpanded prompt vLLM tokenizes never "
254
"gets one. Fixed by huggingface/transformers#47924, unreleased.",
255
strict=False,
256
),
@@ -275,33 +258,40 @@ def test_repeated_image_hits_the_processor_cache():
258
],
259
)
260
def test_spliced_prompt_matches_hf_expansion(model_id, prompt):
278
- """The offsets path splices the expansion into a prompt tokenized without any
279
- multi-modal data, so its token ids have to come out the same as the ones the HF
280
- processor produces itself, which is what the legacy path returns."""
281
- prompt_ids = []
282
- for processor_cls in (LegacyMultiModalProcessor, OffsetsMultiModalProcessor):
283
- mm_processor = create_processor(model_id, processor_cls)
284
- prompt_ids.append(
285
- mm_processor(
286
- prompt=prompt,
287
- mm_items=mm_processor.info.parse_mm_data(
288
- {"image": ImageAsset("cherry_blossom").pil_image}
289
- ),
290
- hf_processor_mm_kwargs={},
291
- )["prompt_token_ids"]
292
- )
261
+ """The prompt is tokenized without any multi-modal data and the expansion spliced
262
+ in, so its token ids have to come out the same as the ones the HF processor
263
+ produces itself."""
264
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
265
+ ModelConfig(model=model_id, model_impl="transformers")
266
+ )
267
+ info = mm_processor.info
268
+ image = ImageAsset("cherry_blossom").pil_image
269
294
- legacy_ids, offsets_ids = prompt_ids
295
- assert legacy_ids == offsets_ids
270
+ hf_processor = info.get_hf_processor()
271
+ prompt_ids = info.get_tokenizer().encode(
272
+ prompt, **info.default_tok_params.get_encode_kwargs()
273
+ )
274
+ hf_ids = info.ctx.call_hf_processor(
275
+ hf_processor,
276
+ dict(text=hf_processor.decode(prompt_ids), images=[image]),
277
+ dict(truncation=False, add_special_tokens=False),
278
+ )["input_ids"][0].tolist()
279
+
280
+ result = mm_processor(
281
+ prompt=prompt,
282
+ mm_items=info.parse_mm_data({"image": image}),
283
+ hf_processor_mm_kwargs={},
284
+ )
285
+ assert result["prompt_token_ids"] == hf_ids
286
287
298
-@pytest.mark.parametrize("processor_cls", PROCESSOR_CLASSES)
299
-def test_nested_image_fields_split_per_image(processor_cls):
288
+def test_nested_image_fields_split_per_image():
289
"""Idefics3 returns image fields with a leading batch dimension, putting the rows
290
belonging to each image one dimension further in. Slicing the batch dimension
291
instead handed the first image every row and the second an empty tensor."""
303
- mm_processor = create_processor(
304
- "HuggingFaceTB/SmolVLM-256M-Instruct", processor_cls
292
+ model_id = "HuggingFaceTB/SmolVLM-256M-Instruct"
293
+ mm_processor = MULTIMODAL_REGISTRY.create_processor(
294
+ ModelConfig(model=model_id, model_impl="transformers")
295
)
296
image = ImageAsset("cherry_blossom").pil_image
297
result = mm_processor(
tests/models/multimodal/processing/transformers_backend.py
deleted
-51
@@ -1,51 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Helpers for testing both processors of the Transformers modelling backend."""
4
-
5
-import pytest
6
-
7
-from vllm.config import ModelConfig
8
-from vllm.model_executor.models.transformers.multimodal import (
9
- LegacyMultiModalProcessor,
10
- MultiModalDummyInputsBuilder,
11
- MultiModalProcessingInfo,
12
- MultiModalProcessor,
13
- OffsetsMultiModalProcessor,
14
-)
15
-from vllm.multimodal.cache import MultiModalProcessorOnlyCache
16
-from vllm.multimodal.processing import InputProcessingContext
17
-from vllm.tokenizers.registry import cached_tokenizer_from_config
18
-
19
-offsets_only = pytest.mark.skipif(
20
- MultiModalProcessor is not OffsetsMultiModalProcessor,
21
- reason="Replacement offsets are only used from transformers 5.15.0 onwards",
22
-)
23
-
24
-PROCESSOR_CLASSES = [
25
- pytest.param(LegacyMultiModalProcessor, id="legacy"),
26
- pytest.param(OffsetsMultiModalProcessor, id="offsets", marks=offsets_only),
27
-]
28
-
29
-
30
-def create_processor(model_id: str, processor_cls):
31
- """Build a processor directly, because the registry only ever builds the one the
32
- installed transformers version selects, leaving the other path untested."""
33
- model_config = ModelConfig(model=model_id, model_impl="transformers")
34
- ctx = InputProcessingContext(
35
- model_config, cached_tokenizer_from_config(model_config)
36
- )
37
- info = MultiModalProcessingInfo(ctx)
38
- return processor_cls(info, MultiModalDummyInputsBuilder(info))
39
-
40
-
41
-def create_cached_processor(model_id: str, processor_cls):
42
- """Build a processor backed by a real multi-modal processor cache, and hand the
43
- cache back so a test can check it was actually used."""
44
- model_config = ModelConfig(model=model_id, model_impl="transformers")
45
- model_config.multimodal_config.mm_processor_cache_gb = 4
46
- ctx = InputProcessingContext(
47
- model_config, cached_tokenizer_from_config(model_config)
48
- )
49
- info = MultiModalProcessingInfo(ctx)
50
- cache = MultiModalProcessorOnlyCache(model_config)
51
- return processor_cls(info, MultiModalDummyInputsBuilder(info)), cache
tests/models/registry.py
+12
-74
@@ -233,9 +233,8 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
233
"CohereLabs/North-Mini-Code",
234
trust_remote_code=True,
235
is_available_online=False,
236
- min_transformers_version="5.9.0",
236
),
238
- "CwmForCausalLM": _HfExamplesInfo("facebook/cwm", min_transformers_version="4.58"),
237
+ "CwmForCausalLM": _HfExamplesInfo("facebook/cwm"),
238
# FIXME: databricks/dbrx-instruct has been deleted
239
"DbrxForCausalLM": _HfExamplesInfo(
240
"databricks/dbrx-instruct", is_available_online=False
@@ -266,9 +265,7 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
265
"LGAI-EXAONE/EXAONE-3.0-7.8B-Instruct", trust_remote_code=True
266
),
267
"Exaone4ForCausalLM": _HfExamplesInfo("LGAI-EXAONE/EXAONE-4.0-32B"),
269
- "ExaoneMoeForCausalLM": _HfExamplesInfo(
270
- "LGAI-EXAONE/K-EXAONE-236B-A23B", min_transformers_version="5.1.0"
271
- ),
268
+ "ExaoneMoeForCausalLM": _HfExamplesInfo("LGAI-EXAONE/K-EXAONE-236B-A23B"),
269
"FalconForCausalLM": _HfExamplesInfo("tiiuae/falcon-7b"),
270
"FalconH1ForCausalLM": _HfExamplesInfo("tiiuae/Falcon-H1-0.5B-Base"),
271
"FlexOlmoForCausalLM": _HfExamplesInfo("allenai/Flex-reddit-2x7B-1T"),
@@ -279,7 +276,6 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
276
"Gemma3ForCausalLM": _HfExamplesInfo("google/gemma-3-1b-it"),
277
"Gemma4ForCausalLM": _HfExamplesInfo(
278
"google/gemma-4-E2B-it",
282
- min_transformers_version="5.0.0",
279
),
280
"Gemma3nForCausalLM": _HfExamplesInfo("google/gemma-3n-E2B-it"),
281
"GlmForCausalLM": _HfExamplesInfo("zai-org/glm-4-9b-chat-hf"),
@@ -287,11 +283,8 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
283
"Glm4MoeForCausalLM": _HfExamplesInfo("zai-org/GLM-4.5"),
284
"Glm4MoeLiteForCausalLM": _HfExamplesInfo(
285
"zai-org/GLM-4.7-Flash",
290
- min_transformers_version="5.0.0",
291
- ),
292
- "GlmMoeDsaForCausalLM": _HfExamplesInfo(
293
- "zai-org/GLM-5", min_transformers_version="5.0.1", is_available_online=False
286
),
287
+ "GlmMoeDsaForCausalLM": _HfExamplesInfo("zai-org/GLM-5", is_available_online=False),
288
"Glm5NextForCausalLM": _HfExamplesInfo("zai-org/GLM-5.3-Flash"),
289
"GPT2LMHeadModel": _HfExamplesInfo("openai-community/gpt2"),
290
"GPTBigCodeForCausalLM": _HfExamplesInfo(
@@ -316,15 +309,10 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
309
"GraniteMoeSharedForCausalLM": _HfExamplesInfo(
310
"ibm-research/moe-7b-1b-active-shared-experts"
311
),
319
- "GraniteMoeSWAForCausalLM": _HfExamplesInfo(
320
- "ibm-granite/granite-swash-3b-a600m", min_transformers_version="5.15.1"
321
- ),
322
- "GraniteSWAForCausalLM": _HfExamplesInfo(
323
- "ibm-granite/granite-swash-2b", min_transformers_version="5.15.1"
324
- ),
312
+ "GraniteMoeSWAForCausalLM": _HfExamplesInfo("ibm-granite/granite-swash-3b-a600m"),
313
+ "GraniteSWAForCausalLM": _HfExamplesInfo("ibm-granite/granite-swash-2b"),
314
"HrmTextForCausalLM": _HfExamplesInfo(
315
"sapientinc/HRM-Text-1B",
327
- min_transformers_version="5.9.0",
316
),
317
"HunYuanDenseV1ForCausalLM": _HfExamplesInfo("tencent/Hunyuan-7B-Instruct"),
318
"HunYuanMoEV1ForCausalLM": _HfExamplesInfo("tencent/Hunyuan-A13B-Instruct"),
@@ -333,7 +321,6 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
321
"HYV4ForCausalLM": _HfExamplesInfo("tencent/Hy4-preview", trust_remote_code=True),
322
"HyperCLOVAXForCausalLM": _HfExamplesInfo(
323
"naver-hyperclovax/HyperCLOVAX-SEED-Think-14B",
336
- min_transformers_version="5.9.0",
324
),
325
"InklingForCausalLM": _HfExamplesInfo(
326
"thinkingmachines/Inkling-NVFP4",
@@ -353,9 +340,7 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
340
"IQuestLoopCoderForCausalLM": _HfExamplesInfo(
341
"IQuestLab/IQuest-Coder-V1-40B-Loop-Instruct", trust_remote_code=True
342
),
356
- "Jais2ForCausalLM": _HfExamplesInfo(
357
- "inceptionai/Jais-2-8B-Chat", min_transformers_version="4.58"
358
- ),
343
+ "Jais2ForCausalLM": _HfExamplesInfo("inceptionai/Jais-2-8B-Chat"),
344
"JambaForCausalLM": _HfExamplesInfo(
345
"ai21labs/AI21-Jamba-1.5-Mini",
346
extras={
@@ -375,7 +360,6 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
360
"Lfm2ForCausalLM": _HfExamplesInfo("LiquidAI/LFM2-1.2B"),
361
"Lfm2MoeForCausalLM": _HfExamplesInfo(
362
"LiquidAI/LFM2-8B-A1B",
378
- min_transformers_version="5.0.0",
363
use_original_num_layers=True,
364
# Initialize at least one MoE layer
365
hf_overrides={"num_hidden_layers": 4},
@@ -422,7 +406,6 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
406
),
407
"MiniCPM4ForCausalLM": _HfExamplesInfo(
408
"openbmb/MiniCPM4.1-8B",
425
- min_transformers_version="4.56",
409
max_transformers_version="4.57",
410
transformers_version_reason={
411
"hf": "HF remote code imports removed `is_torch_fx_available`; "
@@ -523,7 +506,6 @@ _TEXT_GENERATION_EXAMPLE_MODELS = {
506
"Qwen3NextForCausalLM": _HfExamplesInfo(
507
"Qwen/Qwen3-Next-80B-A3B-Instruct",
508
extras={"tiny-random": "tiny-random/qwen3-next-moe"},
526
- min_transformers_version="4.56.3",
509
),
510
"Rnj1ForCausalLM": _HfExamplesInfo(
511
"EssentialAI/rnj-1-instruct",
@@ -722,7 +704,6 @@ _TOKEN_CLASSIFICATION_EXAMPLE_MODELS = {
704
),
705
"OpenAIPrivacyFilterForTokenClassification": _HfExamplesInfo(
706
"openai/privacy-filter",
725
- min_transformers_version="5.6.0.dev0",
707
),
708
"RobertaForTokenClassification": _HfExamplesInfo(
709
"Jean-Baptiste/roberta-large-ner-english"
@@ -794,7 +775,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
775
"AriaForConditionalGeneration": _HfExamplesInfo("rhymes-ai/Aria"),
776
"AudioFlamingo3ForConditionalGeneration": _HfExamplesInfo(
777
"nvidia/audio-flamingo-3-hf",
797
- min_transformers_version="5.3.0",
778
transformers_version_reason={
779
"vllm": "Needs https://github.com/huggingface/transformers/pull/43538"
780
},
@@ -823,22 +803,18 @@ _MULTIMODAL_EXAMPLE_MODELS = {
803
"Cohere2VisionForConditionalGeneration": _HfExamplesInfo(
804
"CohereLabs/command-a-vision-07-2025",
805
extras={"command-a-plus": "CohereLabs/command-a-plus-05-2026-bf16"},
826
- min_transformers_version="5.9.0",
806
),
807
"CohereCompassForConditionalGeneration": _HfExamplesInfo(
808
"CohereLabs/North-Micro-Vision-Instruct",
830
- min_transformers_version="5.16.0",
809
),
810
"Cosmos3ForConditionalGeneration": _HfExamplesInfo(
811
"nvidia/Cosmos3-Nano",
812
extras={"super": "nvidia/Cosmos3-Super"},
813
max_model_len=4096,
836
- min_transformers_version="4.57",
814
),
815
"Cosmos3EdgeForConditionalGeneration": _HfExamplesInfo(
816
"nvidia/Cosmos3-Edge",
817
max_model_len=4096,
841
- min_transformers_version="5.15",
818
use_original_num_layers=True,
819
hf_overrides={
820
"text_config": {
@@ -887,7 +863,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
863
),
864
"Exaone4_5_ForConditionalGeneration": _HfExamplesInfo(
865
"LGAI-EXAONE/EXAONE-4.5-33B",
890
- min_transformers_version="5.6.0",
866
),
867
"FireRedASR2ForConditionalGeneration": _HfExamplesInfo(
868
"allendou/FireRedASR2-LLM-vllm",
@@ -918,19 +893,14 @@ _MULTIMODAL_EXAMPLE_MODELS = {
893
),
894
"Gemma4ForConditionalGeneration": _HfExamplesInfo(
895
"google/gemma-4-E2B-it",
921
- min_transformers_version="5.5.0",
896
),
923
- # TODO: update min_transformers_version when Gemma4 Unified lands in
924
- # a stable transformers release.
897
"Gemma4UnifiedForConditionalGeneration": _HfExamplesInfo(
898
"google/gemma-4-12B-it",
927
- min_transformers_version="5.8.0",
899
is_available_online=False,
900
),
901
"Gemma3nForConditionalGeneration": _HfExamplesInfo("google/gemma-3n-E2B-it"),
902
"GlmAsrForConditionalGeneration": _HfExamplesInfo(
903
"zai-org/GLM-ASR-Nano-2512",
933
- min_transformers_version="5.0.0",
904
),
905
"Granite4VisionForConditionalGeneration": _HfExamplesInfo(
906
"ibm-granite/granite-vision-4.1-4b",
@@ -943,7 +913,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
913
),
914
"GraniteSpeechPlusForConditionalGeneration": _HfExamplesInfo(
915
"ibm-granite/granite-speech-4.1-2b-plus",
946
- min_transformers_version="5.8.0",
916
),
917
"GLM4VForCausalLM": _HfExamplesInfo(
918
"zai-org/glm-4v-9b",
@@ -957,7 +926,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
926
"Glm4vMoeForConditionalGeneration": _HfExamplesInfo("zai-org/GLM-4.5V"),
927
"GlmOcrForConditionalGeneration": _HfExamplesInfo(
928
"zai-org/GLM-OCR",
960
- min_transformers_version="5.1.0",
929
),
930
"Glm5NextForConditionalGeneration": _HfExamplesInfo("zai-org/GLM-5.3-Flash"),
931
"H2OVLChatModel": _HfExamplesInfo(
@@ -974,7 +942,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
942
),
943
"HunYuanVLForConditionalGeneration": _HfExamplesInfo(
944
"tencent/HunyuanOCR",
977
- min_transformers_version="5.13",
945
),
946
"Idefics3ForConditionalGeneration": _HfExamplesInfo(
947
"HuggingFaceM4/Idefics3-8B-Llama3",
@@ -1087,7 +1054,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
1054
),
1055
"Lfm2VlForConditionalGeneration": _HfExamplesInfo(
1056
"LiquidAI/LFM2-VL-450M",
1090
- min_transformers_version="5.0.0",
1057
),
1058
"Llama4ForConditionalGeneration": _HfExamplesInfo(
1059
"meta-llama/Llama-4-Scout-17B-16E-Instruct",
@@ -1154,7 +1120,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
1120
),
1121
"MiniCPMV4_6ForConditionalGeneration": _HfExamplesInfo(
1122
"openbmb/MiniCPM-V-4_6",
1157
- min_transformers_version="5.7.0",
1123
),
1124
"MiniMaxM3SparseForConditionalGeneration": _HfExamplesInfo(
1125
"MiniMaxAI/MiniMax-M3",
@@ -1201,7 +1166,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
1166
"Molmo2ForConditionalGeneration": _HfExamplesInfo(
1167
"allenai/Molmo2-8B",
1168
extras={"olmo": "allenai/Molmo2-O-7B"},
1204
- min_transformers_version="4.51",
1169
trust_remote_code=True,
1170
# required by current PrefixLM implementation
1171
max_num_batched_tokens=31872,
@@ -1353,7 +1317,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
1317
),
1318
"QianfanOCRForConditionalGeneration": _HfExamplesInfo(
1319
"baidu/Qianfan-OCR",
1356
- min_transformers_version="5.6.0",
1320
),
1321
"Qwen2AudioForConditionalGeneration": _HfExamplesInfo(
1322
"Qwen/Qwen2-Audio-7B-Instruct"
@@ -1368,12 +1331,10 @@ _MULTIMODAL_EXAMPLE_MODELS = {
1331
"Qwen3VLForConditionalGeneration": _HfExamplesInfo(
1332
"Qwen/Qwen3-VL-4B-Instruct",
1333
max_model_len=4096,
1371
- min_transformers_version="4.57",
1334
),
1335
"Qwen3VLMoeForConditionalGeneration": _HfExamplesInfo(
1336
"Qwen/Qwen3-VL-30B-A3B-Instruct",
1337
max_model_len=4096,
1376
- min_transformers_version="4.57",
1338
),
1339
"Qwen3_5ForConditionalGeneration": _HfExamplesInfo(
1340
"Qwen/Qwen3.5-0.8B",
@@ -1391,23 +1352,19 @@ _MULTIMODAL_EXAMPLE_MODELS = {
1352
"Qwen3OmniMoeForConditionalGeneration": _HfExamplesInfo(
1353
"Qwen/Qwen3-Omni-30B-A3B-Instruct",
1354
max_model_len=4096,
1394
- min_transformers_version="4.57",
1355
),
1356
"Qwen3ASRForConditionalGeneration": _HfExamplesInfo(
1357
"Qwen/Qwen3-ASR-0.6B",
1358
max_model_len=4096,
1399
- min_transformers_version="4.57",
1359
),
1360
"Qwen3ASRRealtimeGeneration": _HfExamplesInfo(
1361
"Qwen/Qwen3-ASR-0.6B",
1362
max_model_len=4096,
1404
- min_transformers_version="4.57",
1363
hf_overrides={"architectures": ["Qwen3ASRRealtimeGeneration"]},
1364
),
1365
"Qwen3ASRForcedAlignerForTokenClassification": _HfExamplesInfo(
1366
"Qwen/Qwen3-ForcedAligner-0.6B",
1367
max_model_len=4096,
1410
- min_transformers_version="4.57",
1368
hf_overrides={"architectures": ["Qwen3ASRForcedAlignerForTokenClassification"]},
1369
),
1370
"RForConditionalGeneration": _HfExamplesInfo("YannQi/R-4B", trust_remote_code=True),
@@ -1456,7 +1413,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
1413
),
1414
"VibeVoiceAsrForConditionalGeneration": _HfExamplesInfo(
1415
"microsoft/VibeVoice-ASR-HF",
1459
- min_transformers_version="5.13.0",
1416
),
1417
"VoxtralForConditionalGeneration": _HfExamplesInfo(
1418
"mistralai/Voxtral-Mini-3B-2507",
@@ -1530,7 +1486,6 @@ _SPECULATIVE_DECODING_EXAMPLE_MODELS = {
1486
use_original_num_layers=True, # DFlash requires all layers
1487
max_model_len=8192, # Reduce for CI
1488
max_num_seqs=32,
1533
- min_transformers_version="4.56.3", # Required for Qwen3Next
1489
),
1490
"MuseGlimmerAssistantModel": _HfExamplesInfo(
1491
"meta-models/Muse-Glimmer-30B",
@@ -1576,7 +1531,6 @@ _SPECULATIVE_DECODING_EXAMPLE_MODELS = {
1531
speculative_model="Qwen/Qwen3-Omni-30B-A3B-DSpark",
1532
is_available_online=False,
1533
use_original_num_layers=True,
1579
- min_transformers_version="4.57",
1534
),
1535
"Gemma4DSparkModel": _HfExamplesInfo(
1536
"google/gemma-4-12B-it",
@@ -1737,7 +1691,6 @@ _SPECULATIVE_DECODING_EXAMPLE_MODELS = {
1691
"google/gemma-4-E4B-it",
1692
speculative_model="google/gemma-4-E4B-it-assistant",
1693
trust_remote_code=True,
1740
- min_transformers_version="5.8.0",
1694
),
1695
"ErnieMTPModel": _HfExamplesInfo(
1696
"baidu/ERNIE-4.5-21B-A3B-PT",
@@ -1747,13 +1700,11 @@ _SPECULATIVE_DECODING_EXAMPLE_MODELS = {
1700
"ExaoneMoeMTP": _HfExamplesInfo(
1701
"LGAI-EXAONE/K-EXAONE-236B-A23B",
1702
speculative_model="LGAI-EXAONE/K-EXAONE-236B-A23B",
1750
- min_transformers_version="5.1.0",
1703
enable_prefix_caching=False,
1704
),
1705
"Exaone4_5_MTP": _HfExamplesInfo(
1706
"LGAI-EXAONE/EXAONE-4.5-33B",
1707
speculative_model="LGAI-EXAONE/EXAONE-4.5-33B",
1756
- min_transformers_version="5.6.0",
1708
),
1709
"ExtractHiddenStatesModel": _HfExamplesInfo(
1710
"Qwen/Qwen3-8B",
@@ -1766,12 +1717,10 @@ _SPECULATIVE_DECODING_EXAMPLE_MODELS = {
1717
"Glm4MoeLiteMTPModel": _HfExamplesInfo(
1718
"zai-org/GLM-4.7-Flash",
1719
speculative_model="zai-org/GLM-4.7-Flash",
1769
- min_transformers_version="5.0.0",
1720
),
1721
"GlmOcrMTPModel": _HfExamplesInfo(
1722
"zai-org/GLM-OCR",
1723
speculative_model="zai-org/GLM-OCR",
1774
- min_transformers_version="5.1.0",
1724
),
1725
"Glm5NextMTPModel": _HfExamplesInfo(
1726
"zai-org/GLM-5.3-Flash",
@@ -1842,9 +1791,7 @@ _SPECULATIVE_DECODING_EXAMPLE_MODELS = {
1791
trust_remote_code=True,
1792
is_available_online=False,
1793
),
1845
- "Qwen3NextMTP": _HfExamplesInfo(
1846
- "Qwen/Qwen3-Next-80B-A3B-Instruct", min_transformers_version="4.56.3"
1847
- ),
1794
+ "Qwen3NextMTP": _HfExamplesInfo("Qwen/Qwen3-Next-80B-A3B-Instruct"),
1795
"Qwen3_5MTP": _HfExamplesInfo(
1796
"Qwen/Qwen3.5-0.8B",
1797
speculative_model="Qwen/Qwen3.5-0.8B",
@@ -1865,29 +1812,20 @@ _SPECULATIVE_DECODING_EXAMPLE_MODELS = {
1812
}
1813
1814
_TRANSFORMERS_BACKEND_MODELS = {
1868
- "TransformersEmbeddingModel": _HfExamplesInfo(
1869
- "BAAI/bge-base-en-v1.5", min_transformers_version="5.0.0"
1870
- ),
1815
+ "TransformersEmbeddingModel": _HfExamplesInfo("BAAI/bge-base-en-v1.5"),
1816
"TransformersForSequenceClassification": _HfExamplesInfo(
1817
"papluca/xlm-roberta-base-language-detection",
1873
- min_transformers_version="5.0.0",
1818
),
1819
"TransformersForCausalLM": _HfExamplesInfo(
1820
"hmellor/Ilama-3.2-1B", trust_remote_code=True
1821
),
1822
"TransformersMultiModalForCausalLM": _HfExamplesInfo("BAAI/Emu3-Chat-hf"),
1879
- "TransformersMoEForCausalLM": _HfExamplesInfo(
1880
- "allenai/OLMoE-1B-7B-0924", min_transformers_version="5.0.0"
1881
- ),
1823
+ "TransformersMoEForCausalLM": _HfExamplesInfo("allenai/OLMoE-1B-7B-0924"),
1824
"TransformersMultiModalMoEForCausalLM": _HfExamplesInfo(
1883
- "Qwen/Qwen3-VL-30B-A3B-Instruct", min_transformers_version="5.0.0"
1884
- ),
1885
- "TransformersMoEEmbeddingModel": _HfExamplesInfo(
1886
- "Qwen/Qwen3-30B-A3B", min_transformers_version="5.0.0"
1887
- ),
1888
- "TransformersMoEForSequenceClassification": _HfExamplesInfo(
1889
- "Qwen/Qwen3-30B-A3B", min_transformers_version="5.0.0"
1825
+ "Qwen/Qwen3-VL-30B-A3B-Instruct"
1826
),
1827
+ "TransformersMoEEmbeddingModel": _HfExamplesInfo("Qwen/Qwen3-30B-A3B"),
1828
+ "TransformersMoEForSequenceClassification": _HfExamplesInfo("Qwen/Qwen3-30B-A3B"),
1829
"TransformersMultiModalEmbeddingModel": _HfExamplesInfo("google/gemma-3-4b-it"),
1830
"TransformersMultiModalForSequenceClassification": _HfExamplesInfo(
1831
"google/gemma-3-4b-it"
tests/models/transformers/test_backend.py
-11
@@ -185,17 +185,6 @@ def test_sinks(hf_runner: type[HfRunner], vllm_runner: type[VllmRunner]) -> None
185
186
187
def test_mla(vllm_runner: type[VllmRunner], example_prompts: list[str]) -> None:
188
- import transformers
189
- from packaging.version import Version
190
-
191
- installed = Version(transformers.__version__)
192
- required = Version("5.15.0.dev0")
193
- if installed < required:
194
- pytest.skip(
195
- "MLA models with the Transformers modeling backend require "
196
- f"transformers>={required}, but got {installed}"
197
- )
198
-
188
model = "hmellor/tiny-random-DeepseekV2ForCausalLM"
189
args = (example_prompts, 32, 5)
190
kwargs: dict[str, Any] = {"max_model_len": 2048, "enforce_eager": True}
tests/models/utils.py
-14
@@ -609,17 +609,3 @@ def dummy_hf_overrides(
609
)
610
611
return hf_config
612
-
613
-
614
-def check_transformers_version(
615
- model: str,
616
- min_transformers_version: str | None = None,
617
- max_transformers_version: str | None = None,
618
-):
619
- from .registry import _HfExamplesInfo
620
-
621
- return _HfExamplesInfo(
622
- model,
623
- min_transformers_version=min_transformers_version,
624
- max_transformers_version=max_transformers_version,
625
- ).check_transformers_version(on_fail="skip")
tests/tokenizers_/test_registry.py
-49
@@ -10,7 +10,6 @@ from transformers import AutoConfig
10
from transformers.models.auto.configuration_auto import CONFIG_MAPPING
11
12
from vllm.tokenizers import TokenizerLike
13
-from vllm.tokenizers.hf import CachedHfTokenizer
13
from vllm.tokenizers.registry import (
14
TokenizerRegistry,
15
cached_get_tokenizer,
@@ -93,54 +92,6 @@ def test_resolve_tokenizer_args_rejects_hf_mistral_format_true():
92
)
93
94
96
-@pytest.mark.parametrize(
97
- ("transformers_version", "model_type", "native_filename", "expect_error"),
98
- [
99
- pytest.param("5.14.0", "mistral", "tekken.json", True),
100
- pytest.param("5.15.0", "mistral", "tekken.json", False),
101
- pytest.param("5.14.0", "mistral3", "tekken.json", True),
102
- pytest.param("5.15.0", "mistral3", "tekken.json", False),
103
- pytest.param("5.14.0", "mixtral", "tokenizer.model.v1", True),
104
- pytest.param("5.15.0", "mixtral", "tokenizer.model.v1", False),
105
- pytest.param("5.14.0", "mistral", None, False),
106
- pytest.param("5.14.0", "qwen3_5_moe", "tekken.json", False),
107
- ],
108
-)
109
-def test_get_tokenizer_handles_hf_mistral_transformers_compatibility(
110
- tmp_path: Path,
111
- transformers_version: str,
112
- model_type: str,
113
- native_filename: str | None,
114
- expect_error: bool,
115
-):
116
- if native_filename is not None:
117
- (tmp_path / native_filename).touch()
118
-
119
- with (
120
- patch(
121
- "vllm.tokenizers.registry.get_config",
122
- return_value=SimpleNamespace(model_type=model_type),
123
- ),
124
- patch(
125
- "vllm.tokenizers.registry.transformers.__version__",
126
- transformers_version,
127
- ),
128
- patch.object(
129
- CachedHfTokenizer,
130
- "from_pretrained",
131
- return_value=SimpleNamespace(is_fast=True),
132
- ) as from_pretrained,
133
- ):
134
- if expect_error:
135
- with pytest.raises(ValueError, match="requires transformers>=5.15.0"):
136
- get_tokenizer(str(tmp_path), tokenizer_mode="hf")
137
- else:
138
- tokenizer = get_tokenizer(str(tmp_path), tokenizer_mode="hf")
139
- assert tokenizer.is_fast is True
140
-
141
- assert from_pretrained.called == (not expect_error)
142
-
143
-
95
def test_customized_tokenizer():
96
TokenizerRegistry.register("test_tokenizer", __name__, TestTokenizer.__name__)
97
tests/v1/e2e/spec_decode/mtp/_correctness.py
-10
@@ -48,16 +48,6 @@ def check_mtp_correctness(
48
elif "gemma-4" in model_name:
49
extra_kwargs["limit_mm_per_prompt"] = {"image": 0, "audio": 0}
50
51
- if draft_model is not None and "gemma-4" in draft_model:
52
- import transformers
53
- from packaging.version import Version
54
-
55
- if Version(transformers.__version__) < Version("5.8.0"):
56
- pytest.skip(
57
- "Gemma4 MTP assistant requires transformers>=5.8.0, "
58
- f"got {transformers.__version__}"
59
- )
60
-
51
with vllm_runner(
52
model_name,
53
block_size=None,
vllm/model_executor/models/mistral3.py
-13
@@ -7,8 +7,6 @@ from typing import Annotated, Any, Literal, cast
7
8
import torch
9
import torch.nn as nn
10
-import transformers
11
-from packaging.version import Version
10
from transformers import BatchFeature, Mistral3Config, PixtralVisionConfig
11
from transformers.models.pixtral import PixtralProcessor
12
@@ -59,10 +57,6 @@ from .utils import (
57
maybe_prefix,
58
)
59
62
-TRANSFORMERS_SUPPORTS_PIXTRAL_IMAGE_ONLY = Version(transformers.__version__) >= Version(
63
- "5.15.0"
64
-)
65
-
60
61
class Mistral3ImagePixelInputs(TensorSchema):
62
"""Dimensions:
@@ -284,13 +278,6 @@ class Mistral3DummyInputsBuilder(BaseDummyInputsBuilder):
278
279
280
class Mistral3MultiModalProcessor(BaseMultiModalProcessor[Mistral3ProcessingInfo]):
287
- def _get_hf_mm_text(self, mm_counts: Mapping[str, int]) -> str | None:
288
- # PixtralProcessor supports image-only calls starting in transformers 5.15.
289
- # Older releases need dummy text and take the slower tokenization path.
290
- if not TRANSFORMERS_SUPPORTS_PIXTRAL_IMAGE_ONLY:
291
- return self.dummy_inputs.get_dummy_text(mm_counts)
292
- return None
293
-
281
def _postprocess_hf_mm_data(
282
self,
283
mm_data: Mapping[str, object],
vllm/model_executor/models/transformers/base.py
-3
@@ -691,10 +691,8 @@ class Base(
691
# vLLM does not support encoder-decoder models, so if any encoder layer is
692
# found in a text only model, we assume the whole model is an encoder model
693
if has_encoder(self.model) and not is_multimodal(self.config):
694
- self.check_version("5.0.0", "encoder models support")
694
return EncoderOnlyAttention
695
if self.model_config.use_mla:
697
- self.check_version("5.15.0.dev0", "optimized MLA support")
696
if any(
697
isinstance(fuser, MLAFuser)
698
for fusers in self.fusers.values()
@@ -820,7 +818,6 @@ class Base(
818
)
819
820
def set_aux_hidden_state_layers(self, layers: tuple[int, ...]) -> None:
823
- self.check_version("5.2.0", "Eagle3 support")
821
from transformers.utils.output_capturing import (
822
OutputRecorder,
823
maybe_install_capturing_hooks,
vllm/model_executor/models/transformers/moe.py
-1
@@ -156,7 +156,6 @@ class MoEMixin(MixtureOfExperts, Base):
156
num_local_physical_experts: int
157
158
def __init__(self, *, vllm_config: "VllmConfig", prefix: str = ""):
159
- self.check_version("5.0.0", "MoE models support")
159
# Skip MixtureOfExperts.__init__ and call the next class in MRO
160
super(MixtureOfExperts, self).__init__(vllm_config=vllm_config, prefix=prefix)
161
vllm/model_executor/models/transformers/multimodal.py
+10
-335
@@ -23,17 +23,11 @@ from typing import TYPE_CHECKING, Any
23
24
import torch
25
import transformers
26
-from packaging.version import Version
26
from transformers.utils.generic import ModelOutput
27
28
from vllm.compilation.decorators import should_torch_compile_mm_encoder
29
from vllm.config.utils import getattr_iter
31
-from vllm.inputs import (
32
- MultiModalDataBuiltins,
33
- MultiModalDataDict,
34
- MultiModalInput,
35
- mm_input,
36
-)
30
+from vllm.inputs import MultiModalDataBuiltins, MultiModalDataDict
31
from vllm.logger import init_logger
32
from vllm.model_executor.models.interfaces import (
33
MultiModalEmbeddings,
@@ -42,26 +36,15 @@ from vllm.model_executor.models.interfaces import (
36
)
37
from vllm.model_executor.models.module_mapping import MultiModelKeys
38
from vllm.multimodal import MULTIMODAL_REGISTRY, MultiModalKwargsItems
45
-from vllm.multimodal.inputs import (
46
- MultiModalFeatureSpec,
47
- MultiModalFieldConfig,
48
- PlaceholderRange,
49
-)
50
-from vllm.multimodal.parse import (
51
- ImageProcessorItems,
52
- ImageSize,
53
- MultiModalDataItems,
54
- MultiModalDataParser,
55
-)
39
+from vllm.multimodal.inputs import MultiModalFeatureSpec, MultiModalFieldConfig
40
+from vllm.multimodal.parse import ImageSize, MultiModalDataItems, MultiModalDataParser
41
from vllm.multimodal.processing import (
42
BaseDummyInputsBuilder,
43
BaseMultiModalProcessor,
44
BaseProcessingInfo,
60
- ProcessorInputs,
45
PromptReplacement,
46
PromptUpdate,
47
PromptUpdateDetails,
64
- TimingContext,
48
cached_encode,
49
)
50
from vllm.sequence import IntermediateTensors
@@ -219,11 +202,13 @@ class MultiModalDummyInputsBuilder(BaseDummyInputsBuilder[MultiModalProcessingIn
202
return data
203
204
222
-class _MultiModalProcessorBase(BaseMultiModalProcessor[MultiModalProcessingInfo]):
223
- """Processing common to both Transformers backend processors: calling the HF
224
- processor, sizing images, and attributing its outputs to a modality.
205
+class MultiModalProcessor(BaseMultiModalProcessor[MultiModalProcessingInfo]):
206
+ """Locates placeholders from the `text_replacement_offsets` the HF processor
207
+ reports, expressing each one as a `PromptUpdate`.
208
226
- Subclasses add the strategy for locating placeholders in the prompt.
209
+ Stating the expansion as an update is what lets it be rebuilt from an
210
+ unexpanded prompt, so this processor takes the base class's processing path
211
+ and with it the multi-modal processor cache.
212
"""
213
214
def _get_modality_field_names(self, modality: str) -> set[str]:
@@ -415,301 +400,6 @@ class _MultiModalProcessorBase(BaseMultiModalProcessor[MultiModalProcessingInfo]
400
for image, (height, width) in zip(pixel_values, image_sizes.tolist())
401
]
402
418
-
419
-class LegacyMultiModalProcessor(_MultiModalProcessorBase):
420
- """Locates placeholders by searching the prompt the HF processor has already
421
- expanded for the tokens of each modality.
422
-
423
- Serves transformers versions with no `return_text_replacement_offsets`.
424
- Placeholders found this way cannot be rebuilt from an unexpanded prompt, so
425
- this processor overrides `apply` and gets no multi-modal processor cache.
426
- Remove it once `requirements/common.txt` requires `transformers>=5.15.0`.
427
- """
428
-
429
- def _get_prompt_updates(
430
- self,
431
- mm_items: MultiModalDataItems,
432
- hf_processor_mm_kwargs: Mapping[str, object],
433
- out_mm_kwargs: MultiModalKwargsItems,
434
- ) -> Sequence[PromptUpdate]:
435
- """Empty, because `apply` writes the placeholder ranges itself rather than
436
- deriving them from updates."""
437
- return []
438
-
439
- def _get_mm_token_ids(self, modality: str) -> list[int]:
440
- """Token ids marking where `modality` sits in the prompt, which for some
441
- processors differ from the placeholder written into it.
442
-
443
- The expanded prompt is all this path has to go on, so it takes the
444
- processor at its word about which tokens belong to the modality.
445
- """
446
- info = self.info
447
- processor = info.get_hf_processor()
448
- declared = getattr(processor, f"{modality}_token_ids", None) or ()
449
- if ids := [token_id for token_id in declared if token_id is not None]:
450
- return ids
451
- config = info.get_hf_config()
452
- names = (f"{modality}_token_id", f"{modality}_token_index")
453
- token_id = getattr(processor, names[0], getattr_iter(config, names))
454
- if token_id is None:
455
- token = getattr(processor, f"{modality}_token", None)
456
- if token is not None:
457
- token_id = info.get_tokenizer().get_vocab().get(token)
458
- if token_id is None:
459
- raise ValueError(
460
- f"Cannot find {modality}_token_id on processor or model config"
461
- )
462
- return [token_id]
463
-
464
- def _apply_audio(
465
- self,
466
- prompt_ids: list[int],
467
- processed_data: "BatchFeature",
468
- num_audios: int,
469
- ) -> dict[str, list[PlaceholderRange]]:
470
- """Take each contiguous run of the audio token as one item's placeholder,
471
- and record how many tokens the run holds."""
472
- audio_token_ids = self._get_mm_token_ids("audio")
473
- prompt_tensor = torch.tensor(prompt_ids)
474
- is_audio = torch.isin(prompt_tensor, torch.tensor(audio_token_ids))
475
-
476
- if not is_audio.any():
477
- raise ValueError(
478
- f"{num_audios} audio item(s) were passed but the prompt "
479
- "contains no audio token. Add one placeholder per audio item."
480
- )
481
-
482
- padded = torch.cat([torch.tensor([False]), is_audio, torch.tensor([False])])
483
- transitions = padded.int().diff()
484
- offsets = torch.where(transitions == 1)[0]
485
- lengths = torch.where(transitions == -1)[0] - offsets
486
-
487
- if len(offsets) != num_audios:
488
- raise ValueError(
489
- f"Found {len(offsets)} run(s) of the audio token in the prompt but "
490
- f"{num_audios} audio item(s) were passed. The Transformers backend "
491
- "locates audio placeholders by finding contiguous runs of the audio "
492
- "token, so placeholders with no text between them cannot yet be told "
493
- "apart. Separate them in the prompt to work around this."
494
- )
495
-
496
- ranges = [
497
- PlaceholderRange(offset=offset.item(), length=length.item())
498
- for offset, length in zip(offsets, lengths)
499
- ]
500
- processed_data["num_audio_tokens"] = lengths
501
- return {"audio": ranges}
502
-
503
- def _get_num_multimodal_tokens(
504
- self,
505
- mm_items: MultiModalDataItems,
506
- hf_processor_mm_kwargs: Mapping[str, object],
507
- ) -> Mapping[str, list[int]]:
508
- """Ask the HF processor how many tokens and patches each image expands to."""
509
- processor = self.info.get_hf_processor(**hf_processor_mm_kwargs)
510
- images = mm_items.get_items("image", ImageProcessorItems)
511
- image_sizes = [
512
- (size.height, size.width)
513
- for size in map(images.get_image_size, range(len(images)))
514
- ]
515
- return processor._get_num_multimodal_tokens(
516
- image_sizes=image_sizes,
517
- **self.info.ctx.get_merged_mm_kwargs({}),
518
- )
519
-
520
- def _apply_vision(
521
- self,
522
- prompt_ids: list[int],
523
- processed_data: "BatchFeature",
524
- mm_items: MultiModalDataItems,
525
- hf_processor_mm_kwargs: Mapping[str, object],
526
- mm_token_type_ids: torch.Tensor | None,
527
- ) -> dict[str, list[PlaceholderRange]]:
528
- """Split the positions the processor marks as image into one placeholder per
529
- item, sized by the token count it reports for each image."""
530
- hf_processor = self.info.get_hf_processor(**hf_processor_mm_kwargs)
531
- if mm_token_type_ids is None:
532
- raise ValueError(
533
- f"{type(hf_processor).__name__} returned no `mm_token_type_ids`, so "
534
- "the Transformers modeling backend cannot locate the placeholder of "
535
- "each image."
536
- )
537
-
538
- # These mark the tokens structuring an image as well as the image itself,
539
- # which is what the counts below are over
540
- mm_positions = torch.where(mm_token_type_ids[0] == 1)[0]
541
- mm_tokens_per_modality = self._get_num_multimodal_tokens(
542
- mm_items, hf_processor_mm_kwargs
543
- )
544
-
545
- mm_placeholders: dict[str, list[PlaceholderRange]] = {}
546
- split_sizes = mm_tokens_per_modality["num_image_tokens"]
547
- if sum(split_sizes) != len(mm_positions):
548
- raise ValueError(
549
- f"The expanded prompt holds {len(mm_positions)} image token(s) but "
550
- f"{type(hf_processor).__name__} accounts for {sum(split_sizes)} "
551
- f"across {mm_items.get_count('image')} image item(s)."
552
- )
553
-
554
- if split_sizes:
555
- image_token_ids = torch.tensor(self._get_mm_token_ids("image"))
556
- mm_tokens = torch.tensor(prompt_ids)[mm_positions]
557
- ranges = [
558
- PlaceholderRange(
559
- offset=positions[0].item(),
560
- length=positions.shape[0],
561
- # Only some of the span carries embeddings
562
- is_embed=torch.isin(tokens, image_token_ids),
563
- )
564
- for positions, tokens in zip(
565
- torch.split(mm_positions, split_sizes),
566
- torch.split(mm_tokens, split_sizes),
567
- )
568
- ]
569
- mm_placeholders = {"image": ranges}
570
-
571
- processed_data["num_image_patches"] = torch.tensor(
572
- mm_tokens_per_modality["num_image_patches"]
573
- )
574
- return mm_placeholders
575
-
576
- def apply(
577
- self,
578
- inputs: ProcessorInputs,
579
- timing_ctx: TimingContext,
580
- ) -> MultiModalInput:
581
- """Process the prompt and every multi-modal item in one HF processor call,
582
- then read the placeholder ranges out of the token ids it returns."""
583
- prompt = inputs.prompt
584
- mm_items = inputs.mm_data_items
585
- hf_processor_mm_kwargs = inputs.hf_processor_mm_kwargs
586
-
587
- with timing_ctx.record("apply_hf_processor"):
588
- hf_processor = self.info.get_hf_processor(**hf_processor_mm_kwargs)
589
- prompt_text = hf_processor.decode(prompt)
590
-
591
- # Bypass cached processor and always apply to the full set of mm inputs
592
- # NOTE: we can't just set caching=False because base class method
593
- # transforms outputs to `MultiModalKwargs` which is not going to
594
- # work for Transformers. The vision path has logic tied to
595
- # `mm_tokens_per_modality` in _apply_vision()
596
- hf_processor_mm_kwargs = {
597
- # vLLM needs the untruncated sequence to keep placeholder
598
- # tokens aligned. Note that the text inputs are just dummy
599
- # text, not the original prompt. The original prompt is
600
- # already tokenized by the renderer.
601
- "truncation": False,
602
- # HF processors only accept text, and the decoded string already
603
- # contains any special tokens, so don't let them be added again
604
- # (the HF processor call disables `add_special_tokens`).
605
- "add_special_tokens": False,
606
- **hf_processor_mm_kwargs,
607
- }
608
-
609
- processor_data, _, passthrough_data = self._get_hf_mm_inputs(
610
- mm_items, hf_processor_mm_kwargs
611
- )
612
-
613
- # The real prompt is fed to the processor below and the placeholder
614
- # ranges are read back out of its output, so the dummy text meant for
615
- # media-only callers is discarded here.
616
- processor_data.pop("text", None)
617
- has_mm_data = any(processor_data.values())
618
-
619
- # Ask which modality owns each token of the expanded prompt, which
620
- # is the only marking of the tokens an expansion adds around an item
621
- if has_mm_data:
622
- processor_data = {**processor_data, "return_mm_token_type_ids": True}
623
-
624
- try:
625
- processed_data = self.info.ctx.call_hf_processor(
626
- self.info.get_hf_processor(**hf_processor_mm_kwargs),
627
- dict(text=prompt_text, **processor_data),
628
- hf_processor_mm_kwargs,
629
- )
630
- except ValueError:
631
- if has_mm_data:
632
- raise
633
- # Some processors reject a prompt holding placeholders with
634
- # no data to go with them, so tokenize it without them
635
- prompt_ids = self.info.get_tokenizer().encode(prompt_text)
636
- processed_data = transformers.BatchFeature(
637
- dict(input_ids=[prompt_ids]), tensor_type="pt"
638
- )
639
- self._unpad_images(processed_data)
640
- self._unpad_audios(processed_data, processor_data, hf_processor_mm_kwargs)
641
- processed_data.update(passthrough_data)
642
-
643
- input_ids = processed_data.pop("input_ids")
644
- if not isinstance(input_ids, list):
645
- input_ids = input_ids.tolist()
646
-
647
- (prompt_ids,) = input_ids
648
-
649
- # Use overrides if provided; fallback to data-dependent hashing.
650
- with timing_ctx.record("get_mm_hashes"):
651
- mm_hashes = inputs.get_mm_hashes(
652
- self.info.model_id,
653
- self.info.ctx.get_mm_config().mm_hasher_algorithm,
654
- )
655
-
656
- # Gemma3 reports them under the key the model uses for its own token types
657
- mm_token_type_ids = processed_data.pop("token_type_ids", None)
658
- mm_token_type_ids = processed_data.pop("mm_token_type_ids", mm_token_type_ids)
659
-
660
- mm_placeholders: dict[str, list[PlaceholderRange]] = {}
661
- if num_audios := mm_items.get_count("audio", strict=False):
662
- mm_placeholders.update(
663
- self._apply_audio(prompt_ids, processed_data, num_audios)
664
- )
665
- if mm_items.get_count("image", strict=False):
666
- mm_placeholders.update(
667
- self._apply_vision(
668
- prompt_ids,
669
- processed_data,
670
- mm_items,
671
- hf_processor_mm_kwargs,
672
- mm_token_type_ids,
673
- )
674
- )
675
-
676
- mm_kwargs = MultiModalKwargsItems.from_hf_inputs(
677
- processed_data,
678
- self._get_mm_fields_config(processed_data, hf_processor_mm_kwargs),
679
- )
680
-
681
- # Bypassing `_maybe_apply_prompt_updates` also bypasses its validation.
682
- # `_validate_mm_placeholders` can't be reused because it is typed for the
683
- # `PlaceholderFeaturesInfo` the prompt update machinery produces.
684
- mm_item_counts = mm_items.get_all_counts()
685
- self._validate_mm_kwargs(mm_kwargs, mm_item_counts)
686
- for modality, item_count in mm_item_counts.items():
687
- num_placeholders = len(mm_placeholders.get(modality, []))
688
- if num_placeholders != item_count:
689
- raise RuntimeError(
690
- f"Expected there to be {item_count} prompt placeholders "
691
- f"corresponding to {item_count} {modality} items, but instead "
692
- f"found {num_placeholders} prompt placeholders! Make sure the "
693
- "prompt contains a placeholder token for each item."
694
- )
695
-
696
- return mm_input(
697
- prompt_token_ids=prompt_ids,
698
- mm_kwargs=mm_kwargs,
699
- mm_hashes=mm_hashes,
700
- mm_placeholders=mm_placeholders,
701
- )
702
-
703
-
704
-class OffsetsMultiModalProcessor(_MultiModalProcessorBase):
705
- """Locates placeholders from the `text_replacement_offsets` the HF processor
706
- reports, expressing each one as a `PromptUpdate`.
707
-
708
- Stating the expansion as an update is what lets it be rebuilt from an
709
- unexpanded prompt, so this processor takes the base class's processing path
710
- and with it the multi-modal processor cache.
711
- """
712
-
403
def _get_prompt_updates(
404
self,
405
mm_items: MultiModalDataItems,
@@ -800,9 +490,6 @@ class OffsetsMultiModalProcessor(_MultiModalProcessorBase):
490
except (AttributeError, KeyError, TypeError):
491
return None
492
803
- def _get_hf_mm_text(self, mm_counts: Mapping[str, int]) -> str:
804
- return self.dummy_inputs.get_dummy_text(mm_counts)
805
-
493
def _apply_hf_processor_main(
494
self,
495
mm_items: MultiModalDataItems,
@@ -856,8 +543,7 @@ class OffsetsMultiModalProcessor(_MultiModalProcessorBase):
543
"to reach `ProcessorMixin.get_text_with_replacements` with one "
544
"replacement per item, which usually means implementing "
545
"`replace_<modality>_token`. Please report this to transformers "
859
- "so it can be fixed, and install `transformers<5.15.0` in the "
860
- "meantime to locate placeholders in the expanded prompt instead."
546
+ "so it can be fixed."
547
)
548
hf_inputs.pop("input_ids", None)
549
return self._finalize_hf_mm_data(
@@ -896,15 +582,6 @@ class OffsetsMultiModalProcessor(_MultiModalProcessorBase):
582
)
583
584
899
-# From this version on, a processor reporting no offsets is an error rather than a
900
-# fallback to searching the expanded prompt
901
-MultiModalProcessor = (
902
- LegacyMultiModalProcessor
903
- if Version(transformers.__version__) < Version("5.15.0")
904
- else OffsetsMultiModalProcessor
905
-)
906
-
907
-
585
class MultiModalMixin(SupportsMultiModal, SupportsMRoPE, Base):
586
def __init__(self, *, vllm_config: "VllmConfig", prefix: str = ""):
587
# Skip SupportsMRoPE.__init__ and call the next class in MRO
@@ -982,7 +659,6 @@ class MultiModalMixin(SupportsMultiModal, SupportsMRoPE, Base):
659
super()._decorate_for_torch_compile()
660
# Decorate the encoder model classes to support torch compile if needed
661
if self.compilation_config.compile_mm_encoder:
985
- self.check_version("5.0.0", "multimodal encoder compilation support")
662
encoder_classes = self._pre_trained_model_classes.encoders
663
if not encoder_classes:
664
raise ValueError(
@@ -1113,7 +789,6 @@ class MultiModalMixin(SupportsMultiModal, SupportsMRoPE, Base):
789
if input_features is None:
790
return None
791
1116
- self.check_version("5.13.0", "audio models support")
792
num_audio_tokens = kwargs.pop("num_audio_tokens")
793
kwargs.pop("token_type_ids", None)
794
kwargs.pop("mm_token_type_ids", None)
vllm/reasoning/hy_v4_reasoning_parser.py
+12
-15
@@ -48,21 +48,18 @@ def detect_token_suffix(tokenizer: TokenizerLike) -> str:
48
round-trips.
49
50
"""
51
- import transformers
52
-
53
- if int(transformers.__version__.split(".")[0]) >= 5:
54
- init_kwargs = getattr(tokenizer, "init_kwargs", None) or {}
55
- think_begin_as_special = init_kwargs.get(
56
- "model_specific_special_tokens", {}
57
- ).get("think_begin_token", "")
58
- if think_begin_as_special:
59
- raise RuntimeError(
60
- "This checkpoint declares HYV4 structural tokens (think_begin_token"
61
- "/toolcalls_begin_token/argkey_begin_token) in "
62
- "tokenizer_config.json, which transformers 5 no longer supports. "
63
- "Remove those fields and keep the tokens in the tokenizer's own "
64
- "token definitions so the suffix can be read from the vocab."
65
- )
51
+ init_kwargs = getattr(tokenizer, "init_kwargs", None) or {}
52
+ think_begin_as_special = init_kwargs.get("model_specific_special_tokens", {}).get(
53
+ "think_begin_token", ""
54
+ )
55
+ if think_begin_as_special:
56
+ raise RuntimeError(
57
+ "This checkpoint declares HYV4 structural tokens (think_begin_token"
58
+ "/toolcalls_begin_token/argkey_begin_token) in "
59
+ "tokenizer_config.json, which transformers 5 no longer supports. "
60
+ "Remove those fields and keep the tokens in the tokenizer's own "
61
+ "token definitions so the suffix can be read from the vocab."
62
+ )
63
64
structural_token_re = re.compile(
65
r"<(?:think|tool_calls|tool_call|arg_key|arg_value)(:[^\s>]+)?>"
vllm/tokenizers/registry.py
-28
@@ -7,12 +7,6 @@ from pathlib import Path
7
from typing import TYPE_CHECKING
8
9
import huggingface_hub
10
-import transformers
11
-from packaging.version import Version
12
-from transformers.models.auto.tokenization_auto import (
13
- TOKENIZER_MAPPING_NAMES as _HF_TOKENIZER_MAPPING_NAMES,
14
-)
15
-from transformers.utils.import_utils import is_mistral_common_available
10
from typing_extensions import TypeVar, assert_never
11
12
from vllm import envs
@@ -32,8 +26,6 @@ if TYPE_CHECKING:
26
27
logger = init_logger(__name__)
28
35
-_MIN_TRANSFORMERS_VERSION_FOR_HF_MISTRAL = Version("5.15.0")
36
-
29
30
# Model types whose hub tokenizer_class is incorrect and should be overridden with
31
# TokenizersBackend (the generic fast tokenizer). Adding a model type here is always a
@@ -243,26 +235,6 @@ def get_tokenizer(
235
token=kwargs.get("token"),
236
)
237
246
- # TODO: delete when Transformers version dependency is bumped >= 5.15.0
247
- if (
248
- tokenizer_mode == "hf"
249
- and Version(transformers.__version__) < _MIN_TRANSFORMERS_VERSION_FOR_HF_MISTRAL
250
- and is_mistral_common_available()
251
- and _HF_TOKENIZER_MAPPING_NAMES.get(getattr(config, "model_type", None))
252
- == "MistralCommonBackend"
253
- and any_pattern_in_repo_files(
254
- model_name_or_path=str(tokenizer_name),
255
- allow_patterns=["tekken.json", "tokenizer.model.v*"],
256
- revision=revision,
257
- token=kwargs.get("token"),
258
- )
259
- ):
260
- raise ValueError(
261
- "Loading Mistral models with tokenizer_mode='hf' requires "
262
- f"transformers>={_MIN_TRANSFORMERS_VERSION_FOR_HF_MISTRAL}. "
263
- "Please upgrade transformers or delete Mistral tokenizer files."
264
- )
265
-
238
# Some models have an incorrect tokenizer_class on the hub.
239
# For these model types, bypass AutoTokenizer and use TokenizersBackend directly.
240
model_type = getattr(config, "model_type", None) if config else None
vllm/tool_parsers/hy_v4_tool_parser.py
+12
-15
@@ -104,21 +104,18 @@ def detect_token_suffix(tokenizer: TokenizerLike) -> str:
104
round-trips.
105
106
"""
107
- import transformers
108
-
109
- if int(transformers.__version__.split(".")[0]) >= 5:
110
- init_kwargs = getattr(tokenizer, "init_kwargs", None) or {}
111
- think_begin_as_special = init_kwargs.get(
112
- "model_specific_special_tokens", {}
113
- ).get("think_begin_token", "")
114
- if think_begin_as_special:
115
- raise RuntimeError(
116
- "This checkpoint declares HYV4 structural tokens (think_begin_token"
117
- "/toolcalls_begin_token/argkey_begin_token) in "
118
- "tokenizer_config.json, which transformers 5 no longer supports. "
119
- "Remove those fields and keep the tokens in the tokenizer's own "
120
- "token definitions so the suffix can be read from the vocab."
121
- )
107
+ init_kwargs = getattr(tokenizer, "init_kwargs", None) or {}
108
+ think_begin_as_special = init_kwargs.get("model_specific_special_tokens", {}).get(
109
+ "think_begin_token", ""
110
+ )
111
+ if think_begin_as_special:
112
+ raise RuntimeError(
113
+ "This checkpoint declares HYV4 structural tokens (think_begin_token"
114
+ "/toolcalls_begin_token/argkey_begin_token) in "
115
+ "tokenizer_config.json, which transformers 5 no longer supports. "
116
+ "Remove those fields and keep the tokens in the tokenizer's own "
117
+ "token definitions so the suffix can be read from the vocab."
118
+ )
119
120
structural_token_re = re.compile(
121
r"<(?:think|tool_calls|tool_call|arg_key|arg_value)(:[^\s>]+)?>"
vllm/transformers_utils/config.py
-8
@@ -7,7 +7,6 @@ from collections.abc import Callable, Iterator, Sequence
7
from contextlib import contextmanager
8
from dataclasses import asdict
9
from functools import cache, partial, wraps
10
-from importlib.metadata import version
10
from pathlib import Path
11
from typing import Any, Literal, TypeAlias
12
@@ -15,7 +14,6 @@ import huggingface_hub
14
import torch
15
import transformers.configuration_utils as hf_configuration_utils
16
from huggingface_hub import constants
18
-from packaging.version import Version
17
from safetensors.torch import _TYPES as _SAFETENSORS_TO_TORCH_DTYPE
18
from transformers import GenerationConfig, PreTrainedConfig
19
from transformers.configuration_utils import ALLOWED_LAYER_TYPES
@@ -69,12 +67,6 @@ _DENSE_MODULE_TYPES = {
67
"pylate.models.Dense.Dense",
68
}
69
72
-if Version(version("transformers")) < Version("5.0.0"):
73
- raise ImportError(
74
- "Support for Transformers v4 is deprecated and was removed in vLLM v0.24.0. "
75
- "Please upgrade to Transformers v5: pip install --upgrade transformers"
76
- )
77
-
70
71
class LazyConfigDict(dict):
72
def __getitem__(self, key):
vllm/transformers_utils/processors/voxtral.py
+2
-12
@@ -61,10 +61,8 @@ class MistralCommonFeatureExtractor(SequenceFeatureExtractor):
61
"""HF-compatible duck-typed ``fetch_audio``.
62
63
Mirrors :meth:`transformers.SequenceFeatureExtractor.fetch_audio` so
64
- :class:`transformers.ProcessorMixin.prepare_inputs_layout` (added in
65
- transformers 5.10) works on this duck-typed feature extractor. Older
66
- transformers versions never invoke this method, so the addition is a
67
- no-op there.
64
+ :class:`transformers.ProcessorMixin.prepare_inputs_layout` works on this
65
+ duck-typed feature extractor.
66
67
Accepts the same shapes as ``SequenceFeatureExtractor.fetch_audio``:
68
@@ -77,11 +75,6 @@ class MistralCommonFeatureExtractor(SequenceFeatureExtractor):
75
``ProcessorMixin.prepare_inputs_layout`` always passes already-decoded
76
audio (numpy array or torch tensor), so the str / list-of-str branches
77
exist only to keep the contract identical to the upstream method.
80
-
81
- The semantics of ``transformers.audio_utils.is_valid_audio`` differ
82
- between transformers versions (5.9 only accepts ndarray/tensor; 5.10
83
- also accepts ``list[float]``). We detect ``list[float]`` explicitly to
84
- keep behavior identical across versions.
78
"""
79
from transformers.audio_utils import is_valid_audio
80
@@ -89,9 +82,6 @@ class MistralCommonFeatureExtractor(SequenceFeatureExtractor):
82
if is_valid_audio(audio_url_or_urls):
83
return audio_url_or_urls
84
if isinstance(audio_url_or_urls, (list, tuple)):
92
- if audio_url_or_urls and isinstance(audio_url_or_urls[0], float):
93
- # A single audio represented as ``list[float]``.
94
- return audio_url_or_urls
85
return [
86
self.fetch_audio(x, sampling_rate=sampling_rate)
87
for x in audio_url_or_urls