[Mypy] Fix mypy typing for L models (#54177)

Signed-off-by: Taneem Ibrahim <taneem.ibrahim@gmail.com>

Taneem Ibrahim committed Sep 4, 2026 at 06:50 UTC c615b1fd67f5b149c75aea592de8e563cb0c2da9
19 files changed +255 -89
tools/pre_commit/mypy.py
-1
@@ -113,7 +113,6 @@ SEPARATE_GROUPS = [
113
114 EXCLUDE = [
115 r"vllm/model_executor/models/[kK]",
116 - r"vllm/model_executor/models/[lL]",
116 r"vllm/model_executor/models/[nN]",
117 r"vllm/model_executor/models/[oO]",
118 r"vllm/model_executor/models/[pP]",
vllm/model_executor/models/laguna.py
+1
@@ -317,6 +317,7 @@ class LagunaAttention(nn.Module):
317 # config.gating may be:
318 # - True / "per-element": one gate per (head, head_dim) channel
319 # - "per-head": one gate per head, broadcast across head_dim
320 + self.g_proj: ColumnParallelLinear | None
321 if self.gating:
322 # v5 LagunaConfig uses ``gating=True`` for per-head; older configs
323 # used ``"per-head"``. Accept both. ``"per-element"`` (or legacy
vllm/model_executor/models/laguna_dflash.py
+11 -15
@@ -69,7 +69,9 @@ class DFlashLagunaModel(DFlashQwen3Model, EagleModelMixin):
69 prefix: str = "",
70 ) -> None:
71 nn.Module.__init__(self)
72 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
72 + speculative_config = vllm_config.speculative_config
73 + assert speculative_config is not None
74 + self.config = speculative_config.draft_model_config.hf_config
75 self.vocab_size = self.config.vocab_size
76 self.quant_config = get_draft_quant_config(vllm_config)
77
@@ -216,24 +218,16 @@ class DFlashLagunaModel(DFlashQwen3Model, EagleModelMixin):
218 return all_k_normed
219
220 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
221 + if self.quant_config is not None:
222 + weights = self.quant_config.get_cache_scale_mapper().apply(weights)
223 params_dict = dict(self.named_parameters())
224 loaded_params: set[str] = set()
225 for name, loaded_weight in weights:
222 - if self.quant_config is not None and (
223 - scale_name := self.quant_config.get_cache_scale(name)
224 - ):
225 - param = params_dict[scale_name]
226 - weight_loader = getattr(param, "weight_loader", default_weight_loader)
227 - loaded_weight = (
228 - loaded_weight if loaded_weight.dim() == 0 else loaded_weight[0]
229 - )
230 - weight_loader(param, loaded_weight)
231 - loaded_params.add(scale_name)
232 - continue
226 if "scale" in name:
234 - name = maybe_remap_kv_scale_name(name, params_dict)
235 - if name is None:
227 + remapped_name = maybe_remap_kv_scale_name(name, params_dict)
228 + if remapped_name is None:
229 continue
230 + name = remapped_name
231 param = params_dict[name]
232 weight_loader = getattr(param, "weight_loader", default_weight_loader)
233 weight_loader(param, loaded_weight)
@@ -244,7 +238,9 @@ class DFlashLagunaModel(DFlashQwen3Model, EagleModelMixin):
238 class DFlashLagunaForCausalLM(nn.Module, SupportsEagle3):
239 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
240 nn.Module.__init__(self)
247 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
241 + speculative_config = vllm_config.speculative_config
242 + assert speculative_config is not None
243 + self.config = speculative_config.draft_model_config.hf_config
244 if getattr(self.config, "draft_vocab_size", None) is None:
245 raise ValueError("Laguna DFlash config requires `draft_vocab_size`.")
246 self.has_own_embed_tokens = False
vllm/model_executor/models/lfm2_vl.py
+21
@@ -3,6 +3,7 @@
3
4 import itertools
5 import math
6 +import typing
7 from collections.abc import Iterable, Mapping, Sequence
8 from typing import Annotated, Any, Literal
9
@@ -17,6 +18,7 @@ from transformers.models.lfm2_vl.image_processing_lfm2_vl_fast import (
18 find_closest_aspect_ratio,
19 round_by_factor,
20 )
21 +from typing_extensions import Buffer
22
23 from vllm.config import VllmConfig
24 from vllm.config.multimodal import BaseDummyOptions
@@ -229,6 +231,13 @@ class Lfm2VLProcessingInfo(BaseProcessingInfo):
231 "max_image_tokens", image_processor.max_image_tokens
232 )
233 tile_size = mm_kwargs.get("tile_size", image_processor.tile_size)
234 + assert isinstance(downsample_factor, int)
235 + assert isinstance(encoder_patch_size, int)
236 + assert isinstance(max_pixels_tolerance, int | float)
237 + assert isinstance(min_tiles, int)
238 + assert isinstance(max_tiles, int)
239 + assert isinstance(max_image_tokens, int)
240 + assert isinstance(tile_size, int)
241
242 do_image_splitting = not min_tiles == max_tiles == 1
243 is_image_large = self._is_image_too_large(
@@ -337,6 +346,9 @@ class Lfm2VLProcessingInfo(BaseProcessingInfo):
346 "encoder_patch_size", image_processor.encoder_patch_size
347 )
348 tile_size = mm_kwargs.get("tile_size", image_processor.tile_size)
349 + assert isinstance(downsample_factor, int)
350 + assert isinstance(encoder_patch_size, int)
351 + assert isinstance(tile_size, int)
352
353 thumbnail_height_patches = int(spatial_shapes[-1][0].item())
354 thumbnail_width_patches = int(spatial_shapes[-1][1].item())
@@ -672,6 +684,7 @@ class Lfm2VLForConditionalGeneration(
684 super().__init__()
685 config: Lfm2VlConfig = vllm_config.model_config.hf_config
686 multimodal_config = vllm_config.model_config.multimodal_config
687 + assert multimodal_config is not None
688 vision_config = config.vision_config
689 quant_config = vllm_config.quant_config
690
@@ -915,6 +928,14 @@ class Lfm2VLForConditionalGeneration(
928 "min_image_tokens",
929 getattr(self.config, "min_image_tokens", None) or 64,
930 )
931 + if not isinstance(
932 + value,
933 + (str, Buffer, typing.SupportsInt, typing.SupportsIndex),
934 + ):
935 + raise TypeError(
936 + "int() argument must be a string, a bytes-like object "
937 + f"or a real number, not '{type(value).__name__}'"
938 + )
939 return max(1, int(value))
940
941 def _get_lfm2vl_item_tile_slices(
vllm/model_executor/models/lightonocr.py
+1 -1
@@ -49,7 +49,7 @@ class LightOnOCRProcessingInfo(Mistral3ProcessingInfo):
49 return PixtralHFEncoderInfo(self.get_hf_config())
50
51
52 -class LightOnOCRMultiModalProcessor(BaseMultiModalProcessor[LightOnOCRProcessingInfo]):
52 +class LightOnOCRMultiModalProcessor(BaseMultiModalProcessor[Mistral3ProcessingInfo]):
53 def _get_hf_processor_text(self, mm_counts: Mapping[str, int]) -> str:
54 return self.dummy_inputs.get_dummy_text(mm_counts)
55
vllm/model_executor/models/llama.py
+15 -2
@@ -26,6 +26,7 @@
26
27 from collections.abc import Iterable
28 from itertools import islice
29 +from typing import TYPE_CHECKING
30
31 import torch
32 from torch import nn
@@ -544,13 +545,25 @@ class LlamaForCausalLM(
545 return loader.load_weights(weights)
546
547
547 -class LlamaBidirectionalForSequenceClassification(as_seq_cls_model(LlamaForCausalLM)):
548 +if TYPE_CHECKING:
549 + _LlamaBidirectionalForSequenceClassificationBase = LlamaForCausalLM
550 + _LlamaBidirectionalModelBase = LlamaForCausalLM
551 +else:
552 + _LlamaBidirectionalForSequenceClassificationBase = as_seq_cls_model(
553 + LlamaForCausalLM
554 + )
555 + _LlamaBidirectionalModelBase = as_embedding_model(LlamaForCausalLM)
556 +
557 +
558 +class LlamaBidirectionalForSequenceClassification(
559 + _LlamaBidirectionalForSequenceClassificationBase
560 +):
561 # This class sets the correct attention type and pooling type
562 # through LlamaBidirectionalConfig.
563 pass
564
565
553 -class LlamaBidirectionalModel(as_embedding_model(LlamaForCausalLM)):
566 +class LlamaBidirectionalModel(_LlamaBidirectionalModelBase):
567 # This class sets the correct attention type and pooling type
568 # through LlamaBidirectionalConfig.
569 pass
vllm/model_executor/models/llama4.py
+5 -3
@@ -18,7 +18,7 @@
18 # limitations under the License.
19 """Inference-only LLaMA model compatible with HuggingFace weights."""
20
21 -from collections.abc import Iterable
21 +from collections.abc import Callable, Iterable
22
23 import torch
24 from torch import nn
@@ -576,6 +576,7 @@ class Llama4Model(LlamaModel):
576 params_dict = dict(self.named_parameters())
577 # The module parameters that have been loaded.
578 loaded_params: set[str] = set()
579 + weight_loader: Callable[..., object]
580
581 # Iterate over all the weights and load them into module parameters.
582 for name, loaded_weight in weights:
@@ -612,9 +613,10 @@ class Llama4Model(LlamaModel):
613 # quant config's `get_cache_scale_mapper` does not cover
614 # (idempotent for names already renamed by the mapper).
615 if name.endswith("scale"):
615 - name = maybe_remap_kv_scale_name(name, params_dict)
616 - if name is None:
616 + remapped_name = maybe_remap_kv_scale_name(name, params_dict)
617 + if remapped_name is None:
618 continue
619 + name = remapped_name
620
621 # Load the weight into the module parameter with corresponding
622 # shard id and exit the for loop and the else block.
vllm/model_executor/models/llama4_eagle.py
+22 -4
@@ -17,6 +17,7 @@
17 # limitations under the License.
18
19 from collections.abc import Iterable
20 +from typing import TYPE_CHECKING
21
22 import torch
23 import torch.nn as nn
@@ -46,6 +47,19 @@ from .utils import (
47 logger = init_logger(__name__)
48
49
50 +if TYPE_CHECKING:
51 +
52 + class _EagleLlama4ForCausalLMBase(nn.Module):
53 + def set_moe_parameters(self) -> None: ...
54 +
55 + def permute_qk_weight_for_rotary(
56 + self, name: str, loaded_weight: torch.Tensor
57 + ) -> tuple[str, torch.Tensor]: ...
58 +
59 +else:
60 + _EagleLlama4ForCausalLMBase = Llama4ForCausalLM
61 +
62 +
63 @support_torch_compile
64 class LlamaModel(nn.Module):
65 hf_to_vllm_mapper = WeightsMapper(
@@ -68,7 +82,9 @@ class LlamaModel(nn.Module):
82 quant_config: QuantizationConfig | None = None,
83 ) -> None:
84 super().__init__()
71 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
85 + speculative_config = vllm_config.speculative_config
86 + assert speculative_config is not None
87 + self.config = speculative_config.draft_model_config.hf_config
88 self.validate_and_update_config(start_layer_id, quant_config)
89 self.vocab_size = self.config.vocab_size
90 self.embed_tokens = VocabParallelEmbedding(
@@ -152,16 +168,18 @@ class LlamaModel(nn.Module):
168 }
169
170
155 -class EagleLlama4ForCausalLM(Llama4ForCausalLM, SupportsMultiModalEmbeddings):
171 +class EagleLlama4ForCausalLM(_EagleLlama4ForCausalLMBase, SupportsMultiModalEmbeddings):
172 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
173 nn.Module.__init__(self)
158 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
174 + speculative_config = vllm_config.speculative_config
175 + assert speculative_config is not None
176 + self.config = speculative_config.draft_model_config.hf_config
177 target_layer_num = vllm_config.model_config.get_num_layers(
178 vllm_config.parallel_config
179 )
180 # draft model quantization config may differ from target model
181 quant_config = VllmConfig.get_quantization_config(
164 - vllm_config.speculative_config.draft_model_config, vllm_config.load_config
182 + speculative_config.draft_model_config, vllm_config.load_config
183 )
184 self.model = LlamaModel(
185 vllm_config=vllm_config,
vllm/model_executor/models/llama_eagle.py
+22 -5
@@ -2,6 +2,7 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from collections.abc import Iterable
5 +from typing import TYPE_CHECKING
6
7 import torch
8 import torch.nn as nn
@@ -14,7 +15,10 @@ from vllm.model_executor.layers.linear import ReplicatedLinear
15 from vllm.model_executor.layers.logits_processor import LogitsProcessor
16 from vllm.model_executor.layers.quantization.base_config import QuantizationConfig
17 from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
17 -from vllm.model_executor.models.llama import LlamaDecoderLayer, LlamaForCausalLM
18 +from vllm.model_executor.models.llama import (
19 + LlamaDecoderLayer as BaseLlamaDecoderLayer,
20 +)
21 +from vllm.model_executor.models.llama import LlamaForCausalLM
22
23 from .utils import (
24 AutoWeightsLoader,
@@ -27,7 +31,16 @@ from .utils import (
31 logger = init_logger(__name__)
32
33
30 -class LlamaDecoderLayer(LlamaDecoderLayer):
34 +if TYPE_CHECKING:
35 +
36 + class _EagleLlamaForCausalLMBase(nn.Module):
37 + pass
38 +
39 +else:
40 + _EagleLlamaForCausalLMBase = LlamaForCausalLM
41 +
42 +
43 +class LlamaDecoderLayer(BaseLlamaDecoderLayer):
44 def __init__(
45 self,
46 vllm_config: VllmConfig,
@@ -69,7 +82,9 @@ class LlamaModel(nn.Module):
82 start_layer_id: int = 0,
83 ) -> None:
84 super().__init__()
72 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
85 + speculative_config = vllm_config.speculative_config
86 + assert speculative_config is not None
87 + self.config = speculative_config.draft_model_config.hf_config
88 self.vocab_size = self.config.vocab_size
89
90 # Get drafter's quantization config
@@ -128,10 +143,12 @@ class LlamaModel(nn.Module):
143 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
144
145
131 -class EagleLlamaForCausalLM(LlamaForCausalLM):
146 +class EagleLlamaForCausalLM(_EagleLlamaForCausalLMBase):
147 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
148 nn.Module.__init__(self)
134 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
149 + speculative_config = vllm_config.speculative_config
150 + assert speculative_config is not None
151 + self.config = speculative_config.draft_model_config.hf_config
152 # Ensure draft_vocab_size is set
153 # default to the base vocab size when absent
154 if getattr(self.config, "draft_vocab_size", None) is None:
vllm/model_executor/models/llama_eagle3.py
+44 -7
@@ -2,6 +2,7 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from collections.abc import Iterable
5 +from typing import TYPE_CHECKING
6
7 import torch
8 import torch.nn as nn
@@ -18,7 +19,14 @@ from vllm.model_executor.layers.vocab_parallel_embedding import (
19 ParallelLMHead,
20 VocabParallelEmbedding,
21 )
21 -from vllm.model_executor.models.llama import LlamaDecoderLayer, LlamaForCausalLM
22 +from vllm.model_executor.models.llama import (
23 + LlamaAttention,
24 + LlamaForCausalLM,
25 + LlamaMLP,
26 +)
27 +from vllm.model_executor.models.llama import (
28 + LlamaDecoderLayer as BaseLlamaDecoderLayer,
29 +)
30 from vllm.multimodal.inputs import NestedTensors
31
32 from .utils import (
@@ -32,7 +40,31 @@ from .utils import (
40 logger = init_logger(__name__)
41
42
35 -class LlamaDecoderLayer(LlamaDecoderLayer):
43 +if TYPE_CHECKING:
44 +
45 + class _Eagle3LlamaDecoderLayerBase(nn.Module):
46 + hidden_size: int
47 + self_attn: LlamaAttention
48 + mlp: LlamaMLP
49 + input_layernorm: RMSNorm
50 + post_attention_layernorm: RMSNorm
51 +
52 + def __init__(
53 + self,
54 + vllm_config: VllmConfig,
55 + prefix: str = "",
56 + config: LlamaConfig | None = None,
57 + ) -> None: ...
58 +
59 + class _Eagle3LlamaForCausalLMBase(nn.Module):
60 + pass
61 +
62 +else:
63 + _Eagle3LlamaDecoderLayerBase = BaseLlamaDecoderLayer
64 + _Eagle3LlamaForCausalLMBase = LlamaForCausalLM
65 +
66 +
67 +class LlamaDecoderLayer(_Eagle3LlamaDecoderLayerBase):
68 def __init__(
69 self,
70 vllm_config: VllmConfig,
@@ -136,7 +168,9 @@ class LlamaModel(nn.Module):
168 prefix: str = "",
169 ) -> None:
170 super().__init__()
139 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
171 + speculative_config = vllm_config.speculative_config
172 + assert speculative_config is not None
173 + self.config = speculative_config.draft_model_config.hf_config
174 self.vocab_size = self.config.vocab_size
175
176 # Get drafter's quantization config
@@ -187,7 +221,7 @@ class LlamaModel(nn.Module):
221 self.fc_input_size = target_hidden_size * self.num_aux_hidden_states
222
223 if self.norm_before_fc:
190 - self.input_norm = RMSNorm(
224 + self.input_norm: RMSNorm | None = RMSNorm(
225 self.fc_input_size,
226 eps=self.config.rms_norm_eps,
227 )
@@ -269,10 +303,12 @@ class LlamaModel(nn.Module):
303 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
304
305
272 -class Eagle3LlamaForCausalLM(LlamaForCausalLM):
306 +class Eagle3LlamaForCausalLM(_Eagle3LlamaForCausalLMBase):
307 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
308 nn.Module.__init__(self)
275 - self.config = vllm_config.speculative_config.draft_model_config.hf_config
309 + speculative_config = vllm_config.speculative_config
310 + assert speculative_config is not None
311 + self.config = speculative_config.draft_model_config.hf_config
312 # Ensure draft_vocab_size is set
313 # default to the base vocab size when absent
314 if getattr(self.config, "draft_vocab_size", None) is None:
@@ -306,7 +342,7 @@ class Eagle3LlamaForCausalLM(LlamaForCausalLM):
342 requires_grad=False,
343 )
344
309 - self.use_parallel_drafting = vllm_config.speculative_config.parallel_drafting
345 + self.use_parallel_drafting = speculative_config.parallel_drafting
346
347 if self.use_parallel_drafting:
348 self.register_buffer(
@@ -365,6 +401,7 @@ class Eagle3LlamaForCausalLM(LlamaForCausalLM):
401 # combine multiple auxiliary hidden states returned by eagle3
402
403 if self.model.norm_before_fc:
404 + assert self.model.input_norm is not None
405 hidden_states = self.model.input_norm(hidden_states)
406
407 # `norm_before_fc` adds a single RMSNorm before the FC layer, whereas `fc_norm`
vllm/model_executor/models/llava.py
+9 -7
@@ -3,7 +3,7 @@
3
4 from abc import abstractmethod
5 from collections.abc import Iterable, Mapping, Sequence
6 -from typing import Annotated, Final, Literal, Protocol, TypeAlias, TypeVar
6 +from typing import Annotated, Literal, Protocol, TypeAlias, TypeVar
7
8 import torch
9 import torch.nn as nn
@@ -159,14 +159,14 @@ class LlavaMultiModalProjector(nn.Module):
159
160
161 class LlavaLikeConfig(Protocol):
162 - vision_config: Final[PretrainedConfig]
163 - image_token_index: Final[int]
164 - vision_feature_select_strategy: Final[str]
165 - vision_feature_layer: Final[int | list[int]]
162 + vision_config: PretrainedConfig
163 + image_token_index: int
164 + vision_feature_select_strategy: str
165 + vision_feature_layer: int | list[int]
166
167
168 class LlavaLikeProcessor(Protocol):
169 - image_token: Final[str]
169 + image_token: str
170
171
172 class BaseLlavaProcessingInfo(BaseProcessingInfo):
@@ -286,6 +286,7 @@ class BaseLlavaMultiModalProcessor(BaseMultiModalProcessor[_I]):
286 if isinstance(images, ImageEmbeddingItems):
287 num_image_tokens = images.get_feature_size(item_idx)
288 else:
289 + assert isinstance(images, ImageProcessorItems)
290 image_size = images.get_image_size(item_idx)
291 num_image_tokens = self.info.get_num_image_tokens(
292 image_width=image_size.width,
@@ -372,6 +373,7 @@ class PixtralHFMultiModalProcessor(BaseMultiModalProcessor[PixtralHFProcessingIn
373 image_end_id = vocab[processor.image_end_token]
374
375 assert isinstance(hf_config.vision_config, PixtralVisionConfig)
376 + assert isinstance(hf_config, LlavaConfig)
377 encoder_info = PixtralHFEncoderInfo(hf_config)
378
379 def get_replacement(item_idx: int):
@@ -642,7 +644,7 @@ class LlavaForConditionalGeneration(
644 self,
645 image_input: LlavaImageInputs,
646 ) -> torch.Tensor | tuple[torch.Tensor, ...]:
645 - if image_input["type"] == "image_embeds":
647 + if isinstance(image_input, LlavaImageEmbeddingInputs):
648 return image_input["data"]
649
650 image_features = self._process_image_pixels(image_input)
vllm/model_executor/models/llava_next.py
+3 -3
@@ -3,7 +3,7 @@
3
4 from abc import abstractmethod
5 from collections.abc import Iterable, Mapping
6 -from typing import Annotated, Final, Literal, Protocol, TypeAlias, TypeVar
6 +from typing import Annotated, Literal, Protocol, TypeAlias, TypeVar
7
8 import torch
9 import torch.nn as nn
@@ -88,7 +88,7 @@ LlavaNextImageInputs: TypeAlias = (
88
89
90 class LlavaNextLikeConfig(LlavaLikeConfig, Protocol):
91 - image_grid_pinpoints: Final[list[list[int]]]
91 + image_grid_pinpoints: list[list[int]]
92
93
94 class LlavaNextProcessingInfo(BaseLlavaProcessingInfo):
@@ -483,7 +483,7 @@ class LlavaNextForConditionalGeneration(
483 self,
484 image_input: LlavaNextImageInputs,
485 ) -> torch.Tensor | list[torch.Tensor]:
486 - if image_input["type"] == "image_embeds":
486 + if isinstance(image_input, LlavaNextImageEmbeddingInputs):
487 return image_input["data"]
488
489 patch_embeddings = self._process_image_pixels(image_input)
vllm/model_executor/models/llava_next_video.py
+3 -1
@@ -10,7 +10,7 @@ import torch.nn as nn
10 from transformers import BatchFeature, LlavaNextVideoConfig, LlavaNextVideoProcessor
11
12 from vllm.config import VllmConfig
13 -from vllm.config.multimodal import BaseDummyOptions
13 +from vllm.config.multimodal import BaseDummyOptions, VideoDummyOptions
14 from vllm.inputs import MultiModalDataDict
15 from vllm.model_executor.layers.activation import get_act_fn
16 from vllm.model_executor.models.clip import CLIPVisionModel
@@ -181,6 +181,7 @@ class LlavaNextVideoDummyInputsBuilder(
181 )
182
183 video_overrides = mm_options.get("video")
184 + assert video_overrides is None or isinstance(video_overrides, VideoDummyOptions)
185
186 return {
187 "video": self._get_dummy_videos(
@@ -220,6 +221,7 @@ class LlavaNextVideoMultiModalProcessor(
221 if isinstance(videos, VideoEmbeddingItems):
222 num_video_tokens = videos.get_feature_size(item_idx)
223 else:
224 + assert isinstance(videos, VideoProcessorItems)
225 image_size = videos.get_frame_size(item_idx)
226 num_video_tokens = self.info.get_num_video_tokens(
227 image_width=image_size.width,
vllm/model_executor/models/llava_onevision.py
+21 -9
@@ -3,7 +3,7 @@
3
4 import math
5 from collections.abc import Iterable, Mapping, Sequence
6 -from typing import Annotated, Final, Literal, Protocol, TypeAlias
6 +from typing import Annotated, Literal, Protocol, TypeAlias, TypedDict
7
8 import torch
9 import torch.nn as nn
@@ -14,7 +14,7 @@ from transformers.models.llava_onevision.modeling_llava_onevision import (
14 )
15
16 from vllm.config import VllmConfig
17 -from vllm.config.multimodal import BaseDummyOptions
17 +from vllm.config.multimodal import BaseDummyOptions, VideoDummyOptions
18 from vllm.inputs import MultiModalDataDict
19 from vllm.model_executor.layers.activation import get_act_fn
20 from vllm.multimodal import MULTIMODAL_REGISTRY
@@ -123,7 +123,12 @@ LlavaOnevisionMultiInputs: TypeAlias = (
123
124
125 class LlavaOnevisionLikeConfig(LlavaNextLikeConfig, Protocol):
126 - video_token_index: Final[int]
126 + video_token_index: int
127 +
128 +
129 +class LlavaOnevisionInputsByModality(TypedDict, total=False):
130 + image: LlavaOnevisionImageInputs | None
131 + video: LlavaOnevisionVideoPixelInputs | None
132
133
134 class LlavaOnevisionProcessingInfo(LlavaNextProcessingInfo):
@@ -288,6 +293,7 @@ class LlavaOnevisionDummyInputsBuilder(
293
294 image_overrides = mm_options.get("image")
295 video_overrides = mm_options.get("video")
296 + assert video_overrides is None or isinstance(video_overrides, VideoDummyOptions)
297
298 return {
299 "image": self._get_dummy_images(
@@ -417,6 +423,7 @@ class LlavaOnevisionMultiModalProcessor(
423 if isinstance(videos, VideoEmbeddingItems):
424 num_video_tokens = videos.get_feature_size(item_idx)
425 else:
426 + assert isinstance(videos, VideoProcessorItems)
427 image_size = videos.get_frame_size(item_idx)
428 num_video_tokens = self.info.get_num_video_tokens(
429 image_width=image_size.width,
@@ -570,8 +577,10 @@ class LlavaOnevisionForConditionalGeneration(nn.Module, SupportsMultiModal, Supp
577 },
578 )
579
573 - def _parse_and_validate_multimodal_inputs(self, **kwargs: object) -> dict:
574 - mm_input_by_modality = {}
580 + def _parse_and_validate_multimodal_inputs(
581 + self, **kwargs: object
582 + ) -> LlavaOnevisionInputsByModality:
583 + mm_input_by_modality = LlavaOnevisionInputsByModality()
584
585 # Preserve the order of modalities if there are multiple of them
586 # from the order of kwargs.
@@ -749,7 +758,7 @@ class LlavaOnevisionForConditionalGeneration(nn.Module, SupportsMultiModal, Supp
758 self,
759 image_input: LlavaOnevisionImageInputs,
760 ) -> torch.Tensor | list[torch.Tensor]:
752 - if image_input["type"] == "image_embeds":
761 + if isinstance(image_input, LlavaOnevisionImageEmbeddingInputs):
762 return image_input["data"]
763
764 patch_embeddings = self._process_image_pixels(image_input)
@@ -860,12 +869,15 @@ class LlavaOnevisionForConditionalGeneration(nn.Module, SupportsMultiModal, Supp
869 # NOTE: It is important to iterate over the keys in this dictionary
870 # to preserve the order of the modalities.
871 for modality in mm_input_by_modality:
863 - multimodal_input = mm_input_by_modality[modality]
872 if modality == "image":
865 - image_embeddings = self._process_image_input(multimodal_input)
873 + image_input = mm_input_by_modality["image"]
874 + assert image_input is not None
875 + image_embeddings = self._process_image_input(image_input)
876 multimodal_embeddings += tuple(image_embeddings)
877 if modality == "video":
868 - video_embeddings = self._process_video_pixels(multimodal_input)
878 + video_input = mm_input_by_modality["video"]
879 + assert video_input is not None
880 + video_embeddings = self._process_video_pixels(video_input)
881 multimodal_embeddings += tuple(video_embeddings)
882
883 return multimodal_embeddings
vllm/model_executor/models/llava_onevision2.py
+55 -18
@@ -24,12 +24,15 @@ from __future__ import annotations
24
25 import hashlib
26 import importlib
27 -from collections.abc import Callable, Iterable, Mapping, Sequence
27 +from collections.abc import Callable, Iterable, Mapping, Sequence, Sized
28 from functools import lru_cache
29 from typing import (
30 Annotated,
31 Any,
32 Literal,
33 + SupportsIndex,
34 + SupportsInt,
35 + TypedDict,
36 )
37
38 import numpy as np
@@ -45,6 +48,7 @@ from transformers.dynamic_module_utils import (
48 )
49 from transformers.models.qwen2_vl import Qwen2VLImageProcessor
50 from transformers.models.qwen2_vl.image_processing_qwen2_vl import smart_resize
51 +from typing_extensions import Buffer
52
53 from vllm.compilation.decorators import (
54 should_torch_compile_mm_encoder,
@@ -730,6 +734,11 @@ LlavaOnevision2ImageInputs = (
734 )
735
736
737 +class LlavaOnevision2InputsByModality(TypedDict, total=False):
738 + images: LlavaOnevision2ImageInputs | None
739 + videos: LlavaOnevision2VideoPixelInputs | None
740 +
741 +
742 class LlavaOnevision2VisionRotaryEmbedding(nn.Module):
743 """3-D rotary frequency constructor with 4:6:6 (T:H:W) split.
744
@@ -1468,7 +1477,7 @@ class LlavaOnevision2DummyInputsBuilder(
1477 n_img = mm_counts.get("image", 0)
1478 n_vid = mm_counts.get("video", 0)
1479 w, h = self.info.get_image_size_with_most_features()
1471 - out: MultiModalDataDict = {}
1480 + out: dict[str, object] = {}
1481 if n_img:
1482 out["image"] = self._get_dummy_images(width=w, height=h, num_images=n_img)
1483 if n_vid:
@@ -1586,6 +1595,8 @@ class LlavaOnevision2MultiModalProcessor(
1595 # array, or tensor, and ``and <array>`` would raise on the ambiguous
1596 # truth value of a multi-element array.
1597 _videos = mm_data.get("videos")
1598 + if _videos is not None and not isinstance(_videos, Sized):
1599 + raise TypeError(f"object of type '{type(_videos).__name__}' has no len()")
1600 videos_present = _videos is not None and len(_videos) > 0
1601
1602 codec_video_paths = (
@@ -1666,15 +1677,24 @@ class LlavaOnevision2MultiModalProcessor(
1677 # provided by the backend's ``compute_frames_index_to_sample``; SSRF /
1678 # local-file gating is enforced by the connector before decoding.
1679 if videos_present:
1669 - timestamp_decimals = int(
1670 - hf_processor_mm_kwargs.get(
1671 - "timestamp_decimals", _DEFAULT_TIMESTAMP_DECIMALS
1672 - )
1680 + timestamp_decimals = hf_processor_mm_kwargs.get(
1681 + "timestamp_decimals", _DEFAULT_TIMESTAMP_DECIMALS
1682 )
1683 + if not isinstance(
1684 + timestamp_decimals, (str, Buffer, SupportsInt, SupportsIndex)
1685 + ):
1686 + raise TypeError(
1687 + "int() argument must be a string, a bytes-like object "
1688 + f"or a real number, not '{type(timestamp_decimals).__name__}'"
1689 + )
1690 + timestamp_decimals = int(timestamp_decimals)
1691
1692 per_video_frames: list[list[Image.Image]] = []
1693 per_video_timestamps: list[list[float]] = []
1677 - for item in mm_data["videos"]:
1694 + videos = mm_data["videos"]
1695 + if not isinstance(videos, Iterable):
1696 + raise TypeError(f"Unsupported videos input: {type(videos)}")
1697 + for item in videos:
1698 pil_frames, timestamps = _frame_video_to_pil_and_timestamps(item)
1699 per_video_frames.append(pil_frames)
1700 per_video_timestamps.append(timestamps)
@@ -1902,18 +1922,21 @@ class LlavaOnevision2MultiModalProcessor(
1922 def get_image_replacement(item_idx: int):
1923 out_item = out_mm_kwargs["image"][item_idx]
1924 grid_thw = out_item["image_grid_thw"].data
1925 + assert isinstance(grid_thw, torch.Tensor)
1926 n = int(grid_thw.prod(-1).sum()) // merge_length
1927 return [image_pad_id] * n
1928
1929 def get_video_replacement(item_idx: int):
1930 out_item = out_mm_kwargs["video"][item_idx]
1931 grid_thw = out_item["video_grid_thw"].data
1932 + assert isinstance(grid_thw, torch.Tensor)
1933 is_codec_field = out_item.get("video_is_codec")
1912 - is_codec = (
1913 - bool(int(is_codec_field.data.item()))
1914 - if is_codec_field is not None
1915 - else False
1916 - )
1934 + if is_codec_field is not None:
1935 + is_codec_data = is_codec_field.data
1936 + assert isinstance(is_codec_data, torch.Tensor)
1937 + is_codec = bool(int(is_codec_data.item()))
1938 + else:
1939 + is_codec = False
1940 tokens: list[int] = []
1941
1942 if is_codec:
@@ -1924,6 +1947,8 @@ class LlavaOnevision2MultiModalProcessor(
1947 # run, emit ``<sec seconds><|vision_start|><pad*N><|vision_end|>\n``.
1948 patch_positions = out_item["patch_positions_videos"].data
1949 fps_t = out_item["codec_fps"].data
1950 + assert isinstance(patch_positions, torch.Tensor)
1951 + assert isinstance(fps_t, torch.Tensor)
1952 fps = float(int(fps_t.item())) / 1_000_000_000.0
1953 runs = _codec_timestamp_runs(
1954 patch_positions, fps, image_processor.merge_size
@@ -1938,6 +1963,7 @@ class LlavaOnevision2MultiModalProcessor(
1963 tokens.extend(newline_ids)
1964 else:
1965 timestamps = out_item["frame_timestamps"].data
1966 + assert isinstance(timestamps, torch.Tensor)
1967 T_total = int(grid_thw.shape[0])
1968 for t in range(T_total):
1969 sec = float(timestamps[t].item())
@@ -2121,7 +2147,7 @@ class LlavaOnevision2ForConditionalGeneration(
2147 grid_thw = image_input["image_grid_thw"]
2148 assert grid_thw.ndim == 2
2149
2124 - if image_input["type"] == "image_embeds":
2150 + if isinstance(image_input, LlavaOnevision2ImageEmbeddingInputs):
2151 image_embeds = image_input["image_embeds"]
2152 else:
2153 image_embeds = self.visual(
@@ -2166,8 +2192,13 @@ class LlavaOnevision2ForConditionalGeneration(
2192 )
2193 if isinstance(video_num_frames, list):
2194 video_num_frames = torch.cat([v.flatten() for v in video_num_frames])
2169 - else:
2195 + elif isinstance(video_num_frames, torch.Tensor):
2196 video_num_frames = video_num_frames.flatten()
2197 + else:
2198 + raise TypeError(
2199 + "video_num_frames must be a tensor or a list of tensors, "
2200 + f"got {type(video_num_frames)}"
2201 + )
2202 return LlavaOnevision2VideoPixelInputs(
2203 type="pixel_values_videos",
2204 pixel_values_videos=pixel_values_videos,
@@ -2202,8 +2233,10 @@ class LlavaOnevision2ForConditionalGeneration(
2233 cursor += n
2234 return video_embeds.split(sizes)
2235
2205 - def _parse_and_validate_multimodal_inputs(self, **kwargs: object) -> dict:
2206 - modalities = {}
2236 + def _parse_and_validate_multimodal_inputs(
2237 + self, **kwargs: object
2238 + ) -> LlavaOnevision2InputsByModality:
2239 + modalities = LlavaOnevision2InputsByModality()
2240 for key in kwargs:
2241 if key in ("pixel_values", "image_embeds") and "images" not in modalities:
2242 modalities["images"] = self._parse_and_validate_image_input(**kwargs)
@@ -2221,9 +2254,13 @@ class LlavaOnevision2ForConditionalGeneration(
2254 multimodal_embeddings: tuple[torch.Tensor, ...] = ()
2255 for modality in modalities:
2256 if modality == "images":
2224 - multimodal_embeddings += self._process_image_input(modalities["images"])
2257 + image_input = modalities["images"]
2258 + assert image_input is not None
2259 + multimodal_embeddings += self._process_image_input(image_input)
2260 elif modality == "videos":
2226 - multimodal_embeddings += self._process_video_input(modalities["videos"])
2261 + video_input = modalities["videos"]
2262 + assert video_input is not None
2263 + multimodal_embeddings += self._process_video_input(video_input)
2264 return multimodal_embeddings
2265
2266 def get_input_embeddings(
vllm/model_executor/models/longcat_flash.py
+12 -7
@@ -83,6 +83,8 @@ logger = init_logger(__name__)
83 class FlashConfig(PretrainedConfig):
84 """Flash model configuration."""
85
86 + moe_intermediate_size: int
87 +
88 model_type = "longcat_flash"
89 keys_to_ignore_at_inference = ["past_key_values"]
90
@@ -604,7 +606,7 @@ class FlashModel(nn.Module):
606 else:
607 is_expert_weight = False
608 for mapping in expert_params_mapping:
607 - param_name, weight_name, expert_id, shard_id = mapping
609 + param_name, weight_name, expert_id, expert_shard_id = mapping
610 if weight_name not in name:
611 continue
612 is_expert_weight = True
@@ -627,7 +629,7 @@ class FlashModel(nn.Module):
629 param,
630 loaded_weight,
631 name_mapped,
630 - shard_id=shard_id,
632 + shard_id=expert_shard_id,
633 expert_id=expert_id,
634 return_success=True,
635 )
@@ -664,11 +666,14 @@ class FlashModel(nn.Module):
666 if isinstance(self.layers[layer_id], PPMissingLayer):
667 continue
668 self_attn = self.layers[layer_id].self_attn[i]
667 - if hasattr(
668 - self.quant_config, "weight_block_size"
669 - ) and self_attn.kv_b_proj.weight.dtype in (
670 - torch.float8_e4m3fn,
671 - torch.float8_e4m3fnuz,
669 + if (
670 + self.quant_config is not None
671 + and hasattr(self.quant_config, "weight_block_size")
672 + and self_attn.kv_b_proj.weight.dtype
673 + in (
674 + torch.float8_e4m3fn,
675 + torch.float8_e4m3fnuz,
676 + )
677 ):
678 weight_block_size = self.quant_config.weight_block_size
679 if weight_block_size is not None:
vllm/model_executor/models/longcat_flash_mtp.py
+8 -5
@@ -266,11 +266,14 @@ class LongCatFlashMTP(nn.Module):
266 loaded_params.add(name)
267 spec_layer_id = self.config.num_hidden_layers * 2
268 self_attn = self.model.layers[str(spec_layer_id)].mtp_block.self_attn
269 - if hasattr(
270 - self.quant_config, "weight_block_size"
271 - ) and self_attn.kv_b_proj.weight.dtype in (
272 - torch.float8_e4m3fn,
273 - torch.float8_e4m3fnuz,
269 + if (
270 + self.quant_config is not None
271 + and hasattr(self.quant_config, "weight_block_size")
272 + and self_attn.kv_b_proj.weight.dtype
273 + in (
274 + torch.float8_e4m3fn,
275 + torch.float8_e4m3fnuz,
276 + )
277 ):
278 weight_block_size = self.quant_config.weight_block_size
279 if weight_block_size is not None:
vllm/model_executor/models/longcat_flash_ngram.py
+1
@@ -178,6 +178,7 @@ class FlashNgramModel(FlashModel):
178 if num_layers is not None and hf.num_hidden_layers != num_layers:
179 hf.num_hidden_layers = num_layers
180 super().__init__(vllm_config=vllm_config, prefix=prefix)
181 + self.ngram_embeddings: NgramEmbedding | None
182 if get_pp_group().is_first_rank and uses_ngram_embedding(self.config):
183 self.ngram_embeddings = NgramEmbedding(self.config, self.embed_tokens)
184 else:
vllm/model_executor/models/mistral3.py
+1 -1
@@ -217,7 +217,7 @@ class Mistral3ProcessingInfo(BaseProcessingInfo):
217 def get_vision_encoder_info(
218 self,
219 mm_processor_kwargs: Mapping[str, object] | None = None,
220 - ) -> Mistral3HFEncoderInfo:
220 + ) -> PixtralHFEncoderInfo:
221 processor = self.get_hf_processor()
222 size = processor.image_processor.size
223 merged_kwargs = self.ctx.get_merged_mm_kwargs(mm_processor_kwargs or {})