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 7, 01:30 UTC
Increase Flexibility for OOV Multimodal Token Handling (#34858)
Signed-off-by: Alex Brooks <albrooks@redhat.com>
Alex Brooks committed
Mar 8, 2026 at 21:30 UTC
bd2659a5660a7c5ccfeb1f1579e4000ed6536250
28 files changed
+79
-77
vllm/model_executor/models/clip.py
-4
@@ -931,13 +931,11 @@ class CLIPEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
931
embed_input_ids: Callable[[torch.Tensor], torch.Tensor],
932
*,
933
is_multimodal: torch.Tensor | None,
934
- handle_oov_mm_token: bool,
934
) -> torch.Tensor:
935
inputs_embeds = super()._embed_text_input_ids(
936
input_ids,
937
embed_input_ids,
938
is_multimodal=is_multimodal,
940
- handle_oov_mm_token=handle_oov_mm_token,
939
)
940
941
# NOTE: inputs_embeds in model runner has size text_config.projection_dim
@@ -966,7 +964,6 @@ class CLIPEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
964
multimodal_embeddings: MultiModalEmbeddings | None = None,
965
*,
966
is_multimodal: torch.Tensor | None = None,
969
- handle_oov_mm_token: bool = False,
967
) -> torch.Tensor:
968
self._is_text_input = (
969
multimodal_embeddings is None or len(multimodal_embeddings) == 0
@@ -980,7 +977,6 @@ class CLIPEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
977
input_ids,
978
multimodal_embeddings=multimodal_embeddings,
979
is_multimodal=is_multimodal,
983
- handle_oov_mm_token=handle_oov_mm_token,
980
)
981
982
def embed_multimodal(self, **kwargs: object) -> MultiModalEmbeddings:
vllm/model_executor/models/eagle2_5_vl.py
-2
@@ -416,7 +416,6 @@ class Eagle2_5_VLForConditionalGeneration(
416
multimodal_embeddings: MultiModalEmbeddings | None = None,
417
*,
418
is_multimodal: torch.Tensor | None = None,
419
- handle_oov_mm_token: bool = False,
419
) -> torch.Tensor:
420
"""Embed input IDs with optional multimodal embeddings."""
421
if multimodal_embeddings is None or is_multimodal is None:
@@ -426,7 +425,6 @@ class Eagle2_5_VLForConditionalGeneration(
425
input_ids,
426
multimodal_embeddings=multimodal_embeddings,
427
is_multimodal=is_multimodal,
429
- handle_oov_mm_token=handle_oov_mm_token,
428
)
429
430
def forward(
vllm/model_executor/models/ernie45_vl.py
-2
@@ -1664,7 +1664,6 @@ class Ernie4_5_VLMoeForConditionalGeneration(
1664
multimodal_embeddings: MultiModalEmbeddings | None = None,
1665
*,
1666
is_multimodal: torch.Tensor | None = None,
1667
- handle_oov_mm_token: bool = False,
1667
) -> torch.Tensor:
1668
if multimodal_embeddings is not None and len(multimodal_embeddings) > 0:
1669
self._set_visual_token_mask(input_ids)
@@ -1677,7 +1676,6 @@ class Ernie4_5_VLMoeForConditionalGeneration(
1676
input_ids,
1677
multimodal_embeddings=multimodal_embeddings,
1678
is_multimodal=is_multimodal,
1680
- handle_oov_mm_token=handle_oov_mm_token,
1679
)
1680
1681
def forward(
vllm/model_executor/models/funasr.py
-1
@@ -975,7 +975,6 @@ class FunASRForConditionalGeneration(
975
multimodal_embeddings: MultiModalEmbeddings | None = None,
976
*,
977
is_multimodal: torch.Tensor | None = None,
978
- handle_oov_mm_token: bool = False,
978
) -> torch.Tensor:
979
inputs_embeds = self.model.decoder.embed_input_ids(input_ids)
980
vllm/model_executor/models/gemma3_mm.py
+5
-2
@@ -507,6 +507,11 @@ class Gemma3ForConditionalGeneration(
507
self.quant_config = quant_config
508
self.multimodal_config = multimodal_config
509
510
+ self.configure_mm_token_handling(
511
+ vocab_size=config.text_config.vocab_size,
512
+ mm_token_ids=[config.image_token_index],
513
+ )
514
+
515
with self._mark_tower_model(vllm_config, "image"):
516
self.vision_tower = SiglipVisionModel(
517
config.vision_config,
@@ -587,7 +592,6 @@ class Gemma3ForConditionalGeneration(
592
multimodal_embeddings: MultiModalEmbeddings | None = None,
593
*,
594
is_multimodal: torch.Tensor | None = None,
590
- handle_oov_mm_token: bool = True,
595
) -> torch.Tensor:
596
# Early return for text-only inference (no multimodal data)
597
if multimodal_embeddings is None or is_multimodal is None:
@@ -598,7 +602,6 @@ class Gemma3ForConditionalGeneration(
602
input_ids,
603
multimodal_embeddings=multimodal_embeddings,
604
is_multimodal=is_multimodal,
601
- handle_oov_mm_token=handle_oov_mm_token,
605
)
606
607
def forward(
vllm/model_executor/models/gemma3n_mm.py
-2
@@ -685,7 +685,6 @@ class Gemma3nForConditionalGeneration(
685
multimodal_embeddings: MultiModalEmbeddings | None = None,
686
*,
687
is_multimodal: torch.Tensor | None = None,
688
- handle_oov_mm_token: bool = False,
688
) -> torch.Tensor:
689
# NOTE (NickLucche) Each pass needs tokens to compute PLE so we cache
690
# them here, as the model forward has only access to the input_embeds.
@@ -710,7 +709,6 @@ class Gemma3nForConditionalGeneration(
709
input_ids,
710
multimodal_embeddings=multimodal_embeddings,
711
is_multimodal=is_multimodal,
713
- handle_oov_mm_token=handle_oov_mm_token,
712
)
713
714
def forward(
vllm/model_executor/models/granite_speech.py
+6
-3
@@ -600,6 +600,12 @@ class GraniteSpeechForConditionalGeneration(
600
self.quant_config = quant_config
601
self.cache_config = cache_config
602
603
+ # Check for OOV tokens to see if offsets need to be preserved
604
+ self.configure_mm_token_handling(
605
+ vocab_size=config.text_config.vocab_size,
606
+ mm_token_ids=[config.audio_token_index],
607
+ )
608
+
609
with self._mark_language_model(vllm_config):
610
# The language model is typically a Granite LLM
611
self.language_model = init_vllm_registered_model(
@@ -793,8 +799,6 @@ class GraniteSpeechForConditionalGeneration(
799
multimodal_embeddings: MultiModalEmbeddings | None = None,
800
*,
801
is_multimodal: torch.Tensor | None = None,
796
- # Multi-modal token ID may exceed vocab size
797
- handle_oov_mm_token: bool = True,
802
) -> torch.Tensor:
803
# This is to satisfy the type checker for each overload
804
if multimodal_embeddings is None or is_multimodal is None:
@@ -804,7 +808,6 @@ class GraniteSpeechForConditionalGeneration(
808
input_ids,
809
multimodal_embeddings=multimodal_embeddings,
810
is_multimodal=is_multimodal,
807
- handle_oov_mm_token=handle_oov_mm_token,
811
)
812
813
def forward(
vllm/model_executor/models/interfaces.py
+31
-18
@@ -130,6 +130,13 @@ class SupportsMultiModal(Protocol):
130
Set internally by `_mark_tower_model`.
131
"""
132
133
+ _has_oov_mm_tokens: bool = False
134
+ """
135
+ In general, this should be set at init time by invoking
136
+ `configure_mm_token_handling` models & passing all potentially
137
+ OOV multimodal tokens.
138
+ """
139
+
140
@classmethod
141
def get_placeholder_str(cls, modality: str, i: int) -> str | None:
142
"""
@@ -149,6 +156,17 @@ class SupportsMultiModal(Protocol):
156
"""
157
...
158
159
+ def configure_mm_token_handling(self, vocab_size: int, mm_token_ids: list[int]):
160
+ """Check if any multimodal tokens are out of vocabulary. If so, we will
161
+ explicitly mask all multimodal tokens out when computing text embeddings,
162
+ since the multimodal embeddings will be scattered over the results.
163
+ """
164
+ self._has_oov_mm_tokens = any(tok_id >= vocab_size for tok_id in mm_token_ids)
165
+ logger.info(
166
+ "Contains out of vocabulary multimodal tokens? %s",
167
+ self._has_oov_mm_tokens,
168
+ )
169
+
170
def get_language_model(self) -> VllmModel:
171
"""
172
Returns the underlying language model used for text generation.
@@ -324,7 +342,6 @@ class SupportsMultiModal(Protocol):
342
multimodal_embeddings: MultiModalEmbeddings,
343
*,
344
is_multimodal: torch.Tensor,
327
- handle_oov_mm_token: bool = False,
345
) -> Tensor: ...
346
347
def _embed_text_input_ids(
@@ -333,17 +350,14 @@ class SupportsMultiModal(Protocol):
350
embed_input_ids: Callable[[Tensor], Tensor],
351
*,
352
is_multimodal: Tensor | None,
336
- handle_oov_mm_token: bool,
353
) -> Tensor:
338
- if handle_oov_mm_token and is_multimodal is not None:
339
- is_text = ~is_multimodal
340
- text_embeds = embed_input_ids(input_ids[is_text])
341
-
342
- return torch.empty(
343
- (input_ids.shape[0], text_embeds.shape[1]),
344
- dtype=text_embeds.dtype,
345
- device=text_embeds.device,
346
- ).masked_scatter_(is_text.unsqueeze_(-1), text_embeds)
354
+ if is_multimodal is not None and self._has_oov_mm_tokens:
355
+ # Force all input IDs to be in vocab; we do this instead of squeezing
356
+ # to ensure that any external configuration requiring offset tracking,
357
+ # e.g., LoRA, are applied correctly regardless of whether or not
358
+ # we have multimodal tokens.
359
+ in_vocab_ids = input_ids.masked_fill(is_multimodal, 0)
360
+ return embed_input_ids(in_vocab_ids)
361
362
return embed_input_ids(input_ids)
363
@@ -353,7 +367,6 @@ class SupportsMultiModal(Protocol):
367
multimodal_embeddings: MultiModalEmbeddings | None = None,
368
*,
369
is_multimodal: Tensor | None = None,
356
- handle_oov_mm_token: bool = False,
370
) -> Tensor:
371
"""
372
Apply token embeddings to `input_ids`.
@@ -361,19 +374,19 @@ class SupportsMultiModal(Protocol):
374
If `multimodal_embeddings` is passed, scatter them into
375
`input_ids` according to the mask `is_multimodal`.
376
364
- In case the multi-modal token IDs exceed the vocabulary size of
365
- the language model, you can set `handle_oov_mm_token=False`
366
- to avoid calling the language model's `embed_input_ids` method
367
- on those tokens. Note however that doing so increases memory usage
368
- as an additional buffer is needed to hold the input embeddings.
377
+ NOTE: If this model has multimodal tokens that are of vocabulary
378
+ (i.e., self._has_oov_mm_tokens=True), the input_ids will be copied
379
+ and masked to 0 during the forward pass for the text embeddings.
380
"""
381
from .utils import _merge_multimodal_embeddings
382
383
+ # Get text embeddings first; multimodal embeddings will clobber
384
+ # any invalid contents in the indices of multimodal embeddings
385
+ # for the in vocabulary and out of vocabulary case.
386
inputs_embeds = self._embed_text_input_ids(
387
input_ids,
388
self.get_language_model().embed_input_ids,
389
is_multimodal=is_multimodal,
376
- handle_oov_mm_token=handle_oov_mm_token,
390
)
391
392
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
vllm/model_executor/models/interns1.py
-2
@@ -764,7 +764,6 @@ class InternS1ForConditionalGeneration(
764
multimodal_embeddings: MultiModalEmbeddings | None = None,
765
*,
766
is_multimodal: torch.Tensor | None = None,
767
- handle_oov_mm_token: bool = False,
767
) -> torch.Tensor:
768
if multimodal_embeddings is not None and len(multimodal_embeddings) > 0:
769
self._set_visual_token_mask(input_ids)
@@ -777,7 +776,6 @@ class InternS1ForConditionalGeneration(
776
input_ids,
777
multimodal_embeddings=multimodal_embeddings,
778
is_multimodal=is_multimodal,
780
- handle_oov_mm_token=handle_oov_mm_token,
779
)
780
781
def forward(
vllm/model_executor/models/internvl.py
-2
@@ -1347,7 +1347,6 @@ class InternVLChatModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA)
1347
multimodal_embeddings: MultiModalEmbeddings | None = None,
1348
*,
1349
is_multimodal: torch.Tensor | None = None,
1350
- handle_oov_mm_token: bool = False,
1350
) -> torch.Tensor:
1351
if multimodal_embeddings is not None and len(multimodal_embeddings) > 0:
1352
self._set_visual_token_mask(input_ids)
@@ -1360,7 +1359,6 @@ class InternVLChatModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA)
1359
input_ids,
1360
multimodal_embeddings=multimodal_embeddings,
1361
is_multimodal=is_multimodal,
1363
- handle_oov_mm_token=handle_oov_mm_token,
1362
)
1363
1364
def forward(
vllm/model_executor/models/llava.py
+5
@@ -544,6 +544,11 @@ class LlavaForConditionalGeneration(
544
self.config = config
545
self.multimodal_config = multimodal_config
546
547
+ self.configure_mm_token_handling(
548
+ vocab_size=config.text_config.vocab_size,
549
+ mm_token_ids=[config.image_token_index],
550
+ )
551
+
552
# NOTE: These are special cases for Pixtral-12B in the HF-format
553
# https://huggingface.co/mistral-community/pixtral-12b/blob/main/config.json # noqa
554
if (
vllm/model_executor/models/llava_next.py
+5
-3
@@ -270,6 +270,11 @@ class LlavaNextForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsP
270
self.config = config
271
self.multimodal_config = multimodal_config
272
273
+ self.configure_mm_token_handling(
274
+ vocab_size=config.text_config.vocab_size,
275
+ mm_token_ids=[config.image_token_index],
276
+ )
277
+
278
with self._mark_tower_model(vllm_config, "image"):
279
self.vision_tower = init_vision_tower_for_llava(
280
config,
@@ -497,8 +502,6 @@ class LlavaNextForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsP
502
multimodal_embeddings: MultiModalEmbeddings | None = None,
503
*,
504
is_multimodal: torch.Tensor | None = None,
500
- # Multi-modal token ID may exceed vocab size
501
- handle_oov_mm_token: bool = True,
505
) -> torch.Tensor:
506
# This is to satisfy the type checker for each overload
507
if multimodal_embeddings is None or is_multimodal is None:
@@ -508,7 +511,6 @@ class LlavaNextForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsP
511
input_ids,
512
multimodal_embeddings=multimodal_embeddings,
513
is_multimodal=is_multimodal,
511
- handle_oov_mm_token=handle_oov_mm_token,
514
)
515
516
def forward(
vllm/model_executor/models/molmo2.py
-2
@@ -2711,13 +2711,11 @@ class Molmo2ForConditionalGeneration(
2711
multimodal_embeddings: MultiModalEmbeddings | None = None,
2712
*,
2713
is_multimodal: torch.Tensor | None = None,
2714
- handle_oov_mm_token: bool = False,
2714
) -> torch.Tensor:
2715
inputs_embeds = self._embed_text_input_ids(
2716
input_ids,
2717
self.get_language_model().embed_input_ids,
2718
is_multimodal=is_multimodal,
2720
- handle_oov_mm_token=handle_oov_mm_token,
2719
)
2720
2721
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
vllm/model_executor/models/nemotron_vl.py
-2
@@ -628,7 +628,6 @@ class LlamaNemotronVLChatModel(nn.Module, SupportsMultiModal, SupportsPP, Suppor
628
multimodal_embeddings: MultiModalEmbeddings | None = None,
629
*,
630
is_multimodal: torch.Tensor | None = None,
631
- handle_oov_mm_token: bool = False,
631
) -> torch.Tensor:
632
if multimodal_embeddings is not None and len(multimodal_embeddings) > 0:
633
self._set_visual_token_mask(input_ids)
@@ -641,7 +640,6 @@ class LlamaNemotronVLChatModel(nn.Module, SupportsMultiModal, SupportsPP, Suppor
640
input_ids,
641
multimodal_embeddings=multimodal_embeddings,
642
is_multimodal=is_multimodal,
644
- handle_oov_mm_token=handle_oov_mm_token,
643
)
644
645
def forward(
vllm/model_executor/models/phi3v.py
-2
@@ -663,13 +663,11 @@ class Phi3VForCausalLM(nn.Module, SupportsMultiModal, SupportsPP, SupportsQuant)
663
multimodal_embeddings: MultiModalEmbeddings | None = None,
664
*,
665
is_multimodal: torch.Tensor | None = None,
666
- handle_oov_mm_token: bool = False,
666
) -> torch.Tensor:
667
inputs_embeds = self._embed_text_input_ids(
668
input_ids,
669
self.embed_tokens,
670
is_multimodal=is_multimodal,
672
- handle_oov_mm_token=handle_oov_mm_token,
671
)
672
673
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
vllm/model_executor/models/qwen2_5_omni_thinker.py
+9
-3
@@ -1428,11 +1428,19 @@ class Qwen2_5OmniThinkerForConditionalGeneration(
1428
multimodal_embeddings: MultiModalEmbeddings | None = None,
1429
*,
1430
is_multimodal: torch.Tensor | None = None,
1431
- handle_oov_mm_token: bool = False,
1431
) -> torch.Tensor:
1432
if multimodal_embeddings is None or is_multimodal is None:
1433
return super().embed_input_ids(input_ids)
1434
1435
+ inputs_embeds = self._embed_text_input_ids(
1436
+ input_ids,
1437
+ self.get_language_model().embed_input_ids,
1438
+ is_multimodal=is_multimodal,
1439
+ )
1440
+
1441
+ if len(multimodal_embeddings) == 0:
1442
+ return inputs_embeds
1443
+
1444
# Check for audio-in-video: interleaved video and audio tokens
1445
# in the multimodal region. Only use the interleaved path when
1446
# needed; otherwise fall back to the default parent implementation.
@@ -1450,7 +1458,6 @@ class Qwen2_5OmniThinkerForConditionalGeneration(
1458
input_ids,
1459
self.get_language_model().embed_input_ids,
1460
is_multimodal=is_multimodal,
1453
- handle_oov_mm_token=handle_oov_mm_token,
1461
)
1462
return merge_interleaved_embeddings(
1463
inputs_embeds,
@@ -1467,7 +1474,6 @@ class Qwen2_5OmniThinkerForConditionalGeneration(
1474
input_ids,
1475
multimodal_embeddings=multimodal_embeddings,
1476
is_multimodal=is_multimodal,
1470
- handle_oov_mm_token=handle_oov_mm_token,
1477
)
1478
1479
def forward(
vllm/model_executor/models/qwen3_5.py
-2
@@ -672,13 +672,11 @@ class Qwen3_5ForConditionalGeneration(Qwen3VLForConditionalGeneration, IsHybrid)
672
multimodal_embeddings: MultiModalEmbeddings | None = None,
673
*,
674
is_multimodal: torch.Tensor | None = None,
675
- handle_oov_mm_token: bool = False,
675
) -> torch.Tensor:
676
inputs_embeds = self._embed_text_input_ids(
677
input_ids,
678
self.language_model.embed_input_ids,
679
is_multimodal=is_multimodal,
681
- handle_oov_mm_token=handle_oov_mm_token,
680
)
681
682
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
vllm/model_executor/models/qwen3_5_mtp.py
-2
@@ -380,13 +380,11 @@ class Qwen3_5MTP(nn.Module, SupportsMultiModal):
380
multimodal_embeddings: MultiModalEmbeddings | None = None,
381
*,
382
is_multimodal: torch.Tensor | None = None,
383
- handle_oov_mm_token: bool = False,
383
) -> torch.Tensor:
384
inputs_embeds = self._embed_text_input_ids(
385
input_ids,
386
self.model.embed_input_ids,
387
is_multimodal=is_multimodal,
389
- handle_oov_mm_token=handle_oov_mm_token,
388
)
389
390
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
vllm/model_executor/models/qwen3_asr.py
-2
@@ -389,13 +389,11 @@ class Qwen3ASRForConditionalGeneration(
389
multimodal_embeddings: MultiModalEmbeddings | None = None,
390
*,
391
is_multimodal: torch.Tensor | None = None,
392
- handle_oov_mm_token: bool = False,
392
) -> torch.Tensor:
393
inputs_embeds = self._embed_text_input_ids(
394
input_ids,
395
self.language_model.embed_input_ids,
396
is_multimodal=is_multimodal,
398
- handle_oov_mm_token=handle_oov_mm_token,
397
)
398
399
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
vllm/model_executor/models/qwen3_omni_moe_thinker.py
-3
@@ -1851,13 +1851,11 @@ class Qwen3OmniMoeThinkerForConditionalGeneration(
1851
multimodal_embeddings: MultiModalEmbeddings | None = None,
1852
*,
1853
is_multimodal: torch.Tensor | None = None,
1854
- handle_oov_mm_token: bool = False,
1854
) -> torch.Tensor:
1855
inputs_embeds = self._embed_text_input_ids(
1856
input_ids,
1857
self.language_model.embed_input_ids,
1858
is_multimodal=is_multimodal,
1860
- handle_oov_mm_token=handle_oov_mm_token,
1859
)
1860
1861
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
@@ -1962,7 +1960,6 @@ class Qwen3OmniMoeThinkerForConditionalGeneration(
1960
input_ids,
1961
multimodal_embeddings=multimodal_embeddings,
1962
is_multimodal=is_multimodal,
1965
- handle_oov_mm_token=handle_oov_mm_token,
1963
)
1964
1965
def forward(
vllm/model_executor/models/qwen3_vl.py
-2
@@ -2301,13 +2301,11 @@ class Qwen3VLForConditionalGeneration(
2301
multimodal_embeddings: MultiModalEmbeddings | None = None,
2302
*,
2303
is_multimodal: torch.Tensor | None = None,
2304
- handle_oov_mm_token: bool = False,
2304
) -> torch.Tensor:
2305
inputs_embeds = self._embed_text_input_ids(
2306
input_ids,
2307
self.language_model.embed_input_ids,
2308
is_multimodal=is_multimodal,
2310
- handle_oov_mm_token=handle_oov_mm_token,
2309
)
2310
2311
if multimodal_embeddings is None or len(multimodal_embeddings) == 0:
vllm/model_executor/models/siglip.py
-4
@@ -1184,13 +1184,11 @@ class SiglipEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
1184
embed_input_ids: Callable[[torch.Tensor], torch.Tensor],
1185
*,
1186
is_multimodal: torch.Tensor | None,
1187
- handle_oov_mm_token: bool,
1187
) -> torch.Tensor:
1188
inputs_embeds = super()._embed_text_input_ids(
1189
input_ids,
1190
embed_input_ids,
1191
is_multimodal=is_multimodal,
1193
- handle_oov_mm_token=handle_oov_mm_token,
1192
)
1193
1194
# NOTE: inputs_embeds in model runner has size text_config.projection_size
@@ -1219,7 +1217,6 @@ class SiglipEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
1217
multimodal_embeddings: MultiModalEmbeddings | None = None,
1218
*,
1219
is_multimodal: torch.Tensor | None = None,
1222
- handle_oov_mm_token: bool = False,
1220
) -> torch.Tensor:
1221
self._is_text_input = (
1222
multimodal_embeddings is None or len(multimodal_embeddings) == 0
@@ -1232,7 +1229,6 @@ class SiglipEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
1229
input_ids,
1230
multimodal_embeddings=multimodal_embeddings,
1231
is_multimodal=is_multimodal,
1235
- handle_oov_mm_token=handle_oov_mm_token,
1232
)
1233
1234
def embed_multimodal(self, **kwargs: object) -> MultiModalEmbeddings:
vllm/model_executor/models/skyworkr1v.py
-2
@@ -877,7 +877,6 @@ class SkyworkR1VChatModel(nn.Module, SupportsMultiModal, SupportsPP):
877
multimodal_embeddings: MultiModalEmbeddings | None = None,
878
*,
879
is_multimodal: torch.Tensor | None = None,
880
- handle_oov_mm_token: bool = False,
880
) -> torch.Tensor:
881
if multimodal_embeddings is not None and len(multimodal_embeddings) > 0:
882
self._set_visual_token_mask(input_ids)
@@ -890,7 +889,6 @@ class SkyworkR1VChatModel(nn.Module, SupportsMultiModal, SupportsPP):
889
input_ids,
890
multimodal_embeddings=multimodal_embeddings,
891
is_multimodal=is_multimodal,
893
- handle_oov_mm_token=handle_oov_mm_token,
892
)
893
894
def forward(
vllm/model_executor/models/step3_vl.py
+13
-4
@@ -937,7 +937,6 @@ class Step3VLForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsPP)
937
938
def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
939
super().__init__()
940
-
940
config = vllm_config.model_config.hf_config
941
multimodal_config = vllm_config.model_config.multimodal_config
942
@@ -945,6 +944,19 @@ class Step3VLForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsPP)
944
self.multimodal_config = multimodal_config
945
self.use_data_parallel = multimodal_config.mm_encoder_tp_mode == "data"
946
947
+ # NOTE: This behavior is consistent with the previous OOV handling,
948
+ # but does not currently handle the start/stop toks around the
949
+ # image features (<patch_start> <patch_end> <im_start> <im_end>)
950
+ # See: https://huggingface.co/stepfun-ai/step3/blob/main/processing_step3v.py#L323
951
+ #
952
+ # If this becomes an issue or we refactor to handle this using the
953
+ # processor info in the future, it would probably be best to handle
954
+ # those too.
955
+ self.configure_mm_token_handling(
956
+ self.config.text_config.vocab_size,
957
+ [self.config.image_token_id],
958
+ )
959
+
960
with self._mark_tower_model(vllm_config, "image"):
961
self.vision_model = Step3VisionTransformer(
962
config.vision_config,
@@ -1080,8 +1092,6 @@ class Step3VLForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsPP)
1092
multimodal_embeddings: MultiModalEmbeddings | None = None,
1093
*,
1094
is_multimodal: torch.Tensor | None = None,
1083
- # Multi-modal token ID may exceed vocab size
1084
- handle_oov_mm_token: bool = True,
1095
) -> torch.Tensor:
1096
# This is to satisfy the type checker for each overload
1097
if multimodal_embeddings is None or is_multimodal is None:
@@ -1091,7 +1101,6 @@ class Step3VLForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsPP)
1101
input_ids,
1102
multimodal_embeddings=multimodal_embeddings,
1103
is_multimodal=is_multimodal,
1094
- handle_oov_mm_token=handle_oov_mm_token,
1104
)
1105
1106
def forward(
vllm/model_executor/models/terratorch.py
-1
@@ -265,7 +265,6 @@ class Terratorch(nn.Module, IsAttentionFree, SupportsMultiModal):
265
multimodal_embeddings: MultiModalEmbeddings | None = None,
266
*,
267
is_multimodal: torch.Tensor | None = None,
268
- handle_oov_mm_token: bool = False,
268
) -> torch.Tensor:
269
# We do not really use any input tokens and therefore no embeddings
270
# to be calculated. However, due to the mandatory token ids in
vllm/model_executor/models/ultravox.py
+5
-3
@@ -551,6 +551,11 @@ class UltravoxModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
551
self.multi_modal_config = multimodal_config
552
assert self.multi_modal_config
553
554
+ self.configure_mm_token_handling(
555
+ self.config.vocab_size,
556
+ [self.config.audio_token_index],
557
+ )
558
+
559
self.secondary_weights = []
560
if config.audio_model_id is not None:
561
# this prefix is not for initialization, but for loading weights
@@ -707,8 +712,6 @@ class UltravoxModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
712
multimodal_embeddings: MultiModalEmbeddings | None = None,
713
*,
714
is_multimodal: torch.Tensor | None = None,
710
- # Multi-modal token ID may exceed vocab size
711
- handle_oov_mm_token: bool = True,
715
) -> torch.Tensor:
716
# This is to satisfy the type checker for each overload
717
if multimodal_embeddings is None or is_multimodal is None:
@@ -718,7 +721,6 @@ class UltravoxModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
721
input_ids,
722
multimodal_embeddings=multimodal_embeddings,
723
is_multimodal=is_multimodal,
721
- handle_oov_mm_token=handle_oov_mm_token,
724
)
725
726
def forward(
vllm/model_executor/models/voxtral_realtime.py
-1
@@ -298,7 +298,6 @@ class VoxtralRealtimeGeneration(VoxtralForConditionalGeneration, SupportsRealtim
298
*,
299
is_multimodal: torch.Tensor | None = None,
300
# Multi-modal token ID may exceed vocab size
301
- handle_oov_mm_token: bool = True,
301
) -> torch.Tensor:
302
"""Pass post-conv embeddings directly as input.
303
vllm/model_executor/models/whisper.py
-1
@@ -996,7 +996,6 @@ class WhisperForConditionalGeneration(
996
multimodal_embeddings: MultiModalEmbeddings | None = None,
997
*,
998
is_multimodal: torch.Tensor | None = None,
999
- handle_oov_mm_token: bool = False,
999
) -> torch.Tensor:
1000
# This method just returns the decoder sequence embeddings since
1001
# Whisper does not have encoder text tokens.