main
py 741 lines 24.9 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from abc import abstractmethod
5 from collections.abc import Iterable, Mapping, Sequence
6 from typing import Annotated, Literal, Protocol, TypeAlias, TypeVar
7
8 import torch
9 import torch.nn as nn
10 from transformers import (
11 BatchFeature,
12 CLIPVisionConfig,
13 LlavaConfig,
14 PixtralVisionConfig,
15 PreTrainedConfig,
16 SiglipVisionConfig,
17 )
18 from transformers.models.llava import LlavaProcessor
19 from transformers.models.pixtral import PixtralProcessor
20
21 from vllm.config import VllmConfig
22 from vllm.config.multimodal import MultiModalDummyOptions
23 from vllm.inputs import MultiModalDataDict
24 from vllm.model_executor.layers.activation import get_act_fn
25 from vllm.model_executor.layers.linear import ColumnParallelLinear, RowParallelLinear
26 from vllm.model_executor.layers.quantization import QuantizationConfig
27 from vllm.multimodal import MULTIMODAL_REGISTRY
28 from vllm.multimodal.inputs import (
29 MultiModalFieldConfig,
30 MultiModalKwargsItem,
31 MultiModalKwargsItems,
32 )
33 from vllm.multimodal.parse import (
34 ImageEmbeddingItems,
35 ImageProcessorItems,
36 ImageSize,
37 MultiModalDataItems,
38 )
39 from vllm.multimodal.processing import (
40 BaseDummyInputsBuilder,
41 BaseMultiModalProcessor,
42 BaseProcessingInfo,
43 InputProcessingContext,
44 PromptReplacement,
45 PromptUpdate,
46 PromptUpdateDetails,
47 )
48 from vllm.sequence import IntermediateTensors
49 from vllm.utils.tensor_schema import TensorSchema, TensorShape
50
51 from .clip import CLIPVisionModel
52 from .interfaces import (
53 MultiModalEmbeddings,
54 SupportsEagle,
55 SupportsEagle3,
56 SupportsLoRA,
57 SupportsMultiModal,
58 SupportsPP,
59 )
60 from .module_mapping import MultiModelKeys
61 from .pixtral import PixtralHFEncoderInfo, PixtralHFVisionModel
62 from .siglip import SiglipVisionModel
63 from .utils import (
64 AutoWeightsLoader,
65 WeightsMapper,
66 get_layer_index,
67 init_vllm_registered_model,
68 maybe_prefix,
69 )
70 from .vision import get_num_selected_vision_tokens, get_vision_encoder_info
71
72
73 class LlavaImagePixelInputs(TensorSchema):
74 """Dimensions:
75 - bn: Batch size * number of images
76 - c: Number of channels (3)
77 - h: Height
78 - w: Width
79
80 Note that `height` or `width` may be different per batch and image,
81 in which case the data is passed as a list instead of a batched tensor.
82 """
83
84 type: Literal["pixel_values"] = "pixel_values"
85 pixel_values: Annotated[torch.Tensor, TensorShape("bn", 3, "h", "w")]
86
87
88 class PixtralHFImagePixelInputs(TensorSchema):
89 """Dimensions:
90 - bn: Batch size * number of images
91 - c: Number of channels
92 - h: Height
93 - w: Width
94
95 Note that `height` or `width` may be different per batch and image,
96 in which case the data is passed as a list instead of a batched tensor.
97 """
98
99 type: Literal["pixel_values_pixtral"] = "pixel_values_pixtral"
100 pixel_values: Annotated[
101 torch.Tensor | list[torch.Tensor],
102 TensorShape("bn", "c", "h", "w", dynamic_dims={"h", "w"}),
103 ]
104
105
106 class LlavaImageEmbeddingInputs(TensorSchema):
107 """Dimensions:
108 - bn: Batch size * number of images
109 - ifs: Image feature size
110 - hs: Hidden size (must match language model backbone)
111 """
112
113 type: Literal["image_embeds"] = "image_embeds"
114 data: Annotated[torch.Tensor, TensorShape("bn", "ifs", "hs")]
115
116
117 LlavaImageInputs: TypeAlias = (
118 LlavaImagePixelInputs | PixtralHFImagePixelInputs | LlavaImageEmbeddingInputs
119 )
120 """Alias for supported LLaVA image input types."""
121
122
123 class LlavaMultiModalProjector(nn.Module):
124 def __init__(
125 self,
126 vision_hidden_size: int,
127 text_hidden_size: int,
128 projector_hidden_act: str,
129 multimodal_projector_bias: bool,
130 quant_config: QuantizationConfig | None = None,
131 prefix: str = "",
132 ):
133 super().__init__()
134
135 self.linear_1 = ColumnParallelLinear(
136 vision_hidden_size,
137 text_hidden_size,
138 bias=multimodal_projector_bias,
139 quant_config=quant_config,
140 prefix=f"{prefix}.linear_1",
141 )
142 self.act = get_act_fn(projector_hidden_act)
143 self.linear_2 = RowParallelLinear(
144 text_hidden_size,
145 text_hidden_size,
146 bias=multimodal_projector_bias,
147 quant_config=quant_config,
148 prefix=f"{prefix}.linear_2",
149 )
150
151 def forward(self, image_features: torch.Tensor) -> torch.Tensor:
152 hidden_states, _ = self.linear_1(image_features)
153 hidden_states = self.act(hidden_states)
154 hidden_states, _ = self.linear_2(hidden_states)
155 return hidden_states
156
157
158 class LlavaLikeConfig(Protocol):
159 vision_config: PreTrainedConfig
160 image_token_index: int
161 vision_feature_select_strategy: str
162 vision_feature_layer: int | list[int]
163
164
165 class LlavaLikeProcessor(Protocol):
166 image_token: str
167
168
169 class BaseLlavaProcessingInfo(BaseProcessingInfo):
170 def get_hf_config(self) -> LlavaLikeConfig:
171 return self.ctx.get_hf_config(LlavaConfig)
172
173 def get_vision_encoder_info(self):
174 return get_vision_encoder_info(self.get_hf_config())
175
176 @abstractmethod
177 def get_hf_processor(self, **kwargs: object) -> LlavaLikeProcessor:
178 raise NotImplementedError
179
180 def get_supported_mm_limits(self) -> Mapping[str, int | None]:
181 return {"image": None}
182
183 def get_num_image_tokens(
184 self,
185 *,
186 image_width: int,
187 image_height: int,
188 ) -> int:
189 hf_config = self.get_hf_config()
190 vision_encoder_info = self.get_vision_encoder_info()
191
192 return get_num_selected_vision_tokens(
193 vision_encoder_info.get_num_image_tokens(
194 image_width=image_width,
195 image_height=image_height,
196 ),
197 hf_config.vision_feature_select_strategy,
198 )
199
200 def get_image_size_with_most_features(self) -> ImageSize:
201 vision_encoder_info = self.get_vision_encoder_info()
202 width = height = vision_encoder_info.get_image_size()
203 return ImageSize(width=width, height=height)
204
205 def get_max_image_tokens(self) -> int:
206 target_width, target_height = self.get_image_size_with_most_features()
207
208 return self.get_num_image_tokens(
209 image_width=target_width,
210 image_height=target_height,
211 )
212
213
214 _I = TypeVar("_I", bound=BaseLlavaProcessingInfo)
215
216
217 class LlavaDummyInputsBuilder(BaseDummyInputsBuilder[_I]):
218 def get_dummy_text(self, mm_counts: Mapping[str, int]) -> str:
219 num_images = mm_counts.get("image", 0)
220
221 processor = self.info.get_hf_processor()
222 image_token = processor.image_token
223
224 return image_token * num_images
225
226 def get_dummy_mm_data(
227 self,
228 seq_len: int,
229 mm_counts: Mapping[str, int],
230 mm_options: MultiModalDummyOptions,
231 ) -> MultiModalDataDict:
232 target_width, target_height = self.info.get_image_size_with_most_features()
233
234 return {
235 "image": self._get_dummy_images(
236 width=target_width,
237 height=target_height,
238 num_images=mm_counts.get("image", 0),
239 overrides=mm_options.get("image"),
240 )
241 }
242
243
244 class LlavaProcessingInfo(BaseLlavaProcessingInfo):
245 def get_hf_processor(self, **kwargs: object):
246 hf_processor = self.ctx.get_hf_processor(LlavaProcessor, **kwargs)
247 # In case patch_size is omitted from `processor_config.json`
248 # e.g. for E5-V: https://huggingface.co/royokong/e5-v
249 if hf_processor.patch_size is None:
250 patch_size = self.get_vision_encoder_info().get_patch_size()
251 hf_processor.patch_size = patch_size
252 return hf_processor
253
254
255 class BaseLlavaMultiModalProcessor(BaseMultiModalProcessor[_I]):
256 # Copied from BaseMultiModalProcessor
257 @abstractmethod
258 def _get_mm_fields_config(
259 self,
260 hf_inputs: BatchFeature,
261 hf_processor_mm_kwargs: Mapping[str, object],
262 ) -> Mapping[str, MultiModalFieldConfig]:
263 raise NotImplementedError
264
265 def _get_prompt_updates(
266 self,
267 mm_items: MultiModalDataItems,
268 hf_processor_mm_kwargs: Mapping[str, object],
269 out_mm_kwargs: MultiModalKwargsItems,
270 ) -> Sequence[PromptUpdate]:
271 hf_config = self.info.get_hf_config()
272 image_token_id = hf_config.image_token_index
273
274 def get_replacement(item_idx: int):
275 images = mm_items.get_items(
276 "image", (ImageEmbeddingItems, ImageProcessorItems)
277 )
278
279 if isinstance(images, ImageEmbeddingItems):
280 num_image_tokens = images.get_feature_size(item_idx)
281 else:
282 assert isinstance(images, ImageProcessorItems)
283 image_size = images.get_image_size(item_idx)
284 num_image_tokens = self.info.get_num_image_tokens(
285 image_width=image_size.width,
286 image_height=image_size.height,
287 )
288
289 return [image_token_id] * num_image_tokens
290
291 return [
292 PromptReplacement(
293 modality="image",
294 target=[image_token_id],
295 replacement=get_replacement,
296 ),
297 ]
298
299
300 class LlavaMultiModalProcessor(BaseLlavaMultiModalProcessor[LlavaProcessingInfo]):
301 def _get_mm_fields_config(
302 self,
303 hf_inputs: BatchFeature,
304 hf_processor_mm_kwargs: Mapping[str, object],
305 ) -> Mapping[str, MultiModalFieldConfig]:
306 return dict(
307 pixel_values=MultiModalFieldConfig.batched("image"),
308 image_embeds=MultiModalFieldConfig.batched("image"),
309 )
310
311
312 class PixtralHFProcessingInfo(BaseLlavaProcessingInfo):
313 def get_hf_processor(self, **kwargs: object):
314 return self.ctx.get_hf_processor(PixtralProcessor, **kwargs)
315
316
317 class PixtralHFMultiModalProcessor(BaseMultiModalProcessor[PixtralHFProcessingInfo]):
318 def _get_hf_mm_text(self, mm_counts: Mapping[str, int]) -> str:
319 return self.dummy_inputs.get_dummy_text(mm_counts)
320
321 def _postprocess_hf_mm_data(
322 self,
323 mm_data: Mapping[str, object],
324 hf_processor_mm_kwargs: Mapping[str, object],
325 processed_data: BatchFeature,
326 ) -> BatchFeature:
327 if not mm_data:
328 return processed_data
329
330 pixel_values = processed_data.get("pixel_values")
331 if pixel_values is not None:
332 # Avoid padding since we need the output for each image to be
333 # independent of other images for the cache to work correctly
334 image_sizes = processed_data["image_sizes"]
335 assert len(pixel_values) == len(image_sizes)
336
337 processed_data["pixel_values"] = [
338 p[:, :h, :w] for p, (h, w) in zip(pixel_values, image_sizes)
339 ]
340
341 return processed_data
342
343 def _get_mm_fields_config(
344 self,
345 hf_inputs: BatchFeature,
346 hf_processor_mm_kwargs: Mapping[str, object],
347 ) -> Mapping[str, MultiModalFieldConfig]:
348 return dict(
349 pixel_values=MultiModalFieldConfig.batched("image"),
350 image_embeds=MultiModalFieldConfig.batched("image"),
351 )
352
353 def _get_prompt_updates(
354 self,
355 mm_items: MultiModalDataItems,
356 hf_processor_mm_kwargs: Mapping[str, object],
357 out_mm_kwargs: MultiModalKwargsItems,
358 ) -> Sequence[PromptUpdate]:
359 processor = self.info.get_hf_processor(**hf_processor_mm_kwargs)
360 hf_config = self.info.get_hf_config()
361 tokenizer = self.info.get_tokenizer()
362 vocab = tokenizer.get_vocab()
363
364 image_break_id = vocab[processor.image_break_token]
365 image_token_id = hf_config.image_token_index
366 image_end_id = vocab[processor.image_end_token]
367
368 assert isinstance(hf_config.vision_config, PixtralVisionConfig)
369 assert isinstance(hf_config, LlavaConfig)
370 encoder_info = PixtralHFEncoderInfo(hf_config)
371
372 def get_replacement(item_idx: int):
373 images = mm_items.get_items("image", ImageProcessorItems)
374 image_size = images.get_image_size(item_idx)
375
376 ncols, nrows = encoder_info.get_patch_grid_size(
377 image_width=image_size.width,
378 image_height=image_size.height,
379 )
380
381 tokens = ([image_token_id] * ncols + [image_break_id]) * nrows
382 tokens[-1] = image_end_id
383
384 return PromptUpdateDetails.select_token_id(tokens, image_token_id)
385
386 return [
387 PromptReplacement(
388 modality="image",
389 target=[image_token_id],
390 replacement=get_replacement,
391 ),
392 ]
393
394
395 def _build_llava_or_pixtral_hf_info(
396 ctx: InputProcessingContext,
397 ) -> BaseLlavaProcessingInfo:
398 hf_config = ctx.get_hf_config(LlavaConfig)
399
400 if isinstance(hf_config.vision_config, PixtralVisionConfig):
401 return PixtralHFProcessingInfo(ctx)
402
403 return LlavaProcessingInfo(ctx)
404
405
406 def _build_llava_or_pixtral_hf_processor(
407 info: _I,
408 dummy_inputs: BaseDummyInputsBuilder[_I],
409 ) -> BaseMultiModalProcessor:
410 if isinstance(info, PixtralHFProcessingInfo):
411 return PixtralHFMultiModalProcessor(
412 info,
413 dummy_inputs, # type: ignore
414 )
415
416 if isinstance(info, LlavaProcessingInfo):
417 return LlavaMultiModalProcessor(
418 info,
419 dummy_inputs, # type: ignore
420 )
421
422 raise NotImplementedError(type(info))
423
424
425 def _get_num_hidden_layers(hf_config: LlavaLikeConfig) -> int:
426 """Determine the number of hidden layers to initialize up to in the
427 visual encoder.
428
429 Args:
430 hf_config: Model config with vision feature layer(s).
431
432 """
433 feature_layers = hf_config.vision_feature_layer
434 num_hidden_layers = hf_config.vision_config.num_hidden_layers
435 # If we have one feature layer, initialize up to that layer
436 if isinstance(feature_layers, int):
437 return get_layer_index(feature_layers, num_hidden_layers)
438 # If we have multiple feature layers, initialize up to the deepest one
439 elif isinstance(feature_layers, (list, tuple)):
440 return max(get_layer_index(idx, num_hidden_layers) for idx in feature_layers)
441 raise TypeError(
442 f"vision_layer_feature type: {type(feature_layers)} is not supported"
443 )
444
445
446 def init_vision_tower_for_llava(
447 hf_config: LlavaLikeConfig,
448 quant_config: QuantizationConfig | None,
449 *,
450 require_post_norm: bool | None = None,
451 prefix: str = "",
452 ) -> CLIPVisionModel | SiglipVisionModel | PixtralHFVisionModel:
453 vision_config = hf_config.vision_config
454
455 # Initialize the vision tower only up to the deepest required feature layer
456 num_hidden_layers = _get_num_hidden_layers(hf_config)
457
458 if isinstance(vision_config, CLIPVisionConfig):
459 return CLIPVisionModel(
460 vision_config,
461 quant_config=quant_config,
462 num_hidden_layers_override=num_hidden_layers,
463 require_post_norm=require_post_norm,
464 prefix=prefix,
465 )
466 elif isinstance(vision_config, SiglipVisionConfig):
467 return SiglipVisionModel(
468 vision_config,
469 quant_config=quant_config,
470 num_hidden_layers_override=num_hidden_layers,
471 require_post_norm=require_post_norm,
472 prefix=prefix,
473 )
474 elif isinstance(vision_config, PixtralVisionConfig):
475 return PixtralHFVisionModel(
476 vision_config,
477 quant_config=quant_config,
478 num_hidden_layers_override=num_hidden_layers,
479 require_post_norm=require_post_norm,
480 prefix=prefix,
481 )
482
483 msg = f"Unsupported vision config: {type(vision_config)}"
484 raise NotImplementedError(msg)
485
486
487 @MULTIMODAL_REGISTRY.register_processor(
488 _build_llava_or_pixtral_hf_processor,
489 info=_build_llava_or_pixtral_hf_info,
490 dummy_inputs=LlavaDummyInputsBuilder,
491 )
492 class LlavaForConditionalGeneration(
493 nn.Module,
494 SupportsLoRA,
495 SupportsMultiModal,
496 SupportsPP,
497 SupportsEagle,
498 SupportsEagle3,
499 ):
500 packed_modules_mapping = {
501 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
502 "gate_up_proj": ["gate_proj", "up_proj"],
503 }
504
505 hf_to_vllm_mapper = WeightsMapper(
506 orig_to_new_prefix={
507 # mapping for new names in checkpoint saved after transformers v4.52
508 "model.language_model.": "language_model.model.",
509 "model.vision_tower.": "vision_tower.",
510 "model.multi_modal_projector.": "multi_modal_projector.",
511 "lm_head.": "language_model.lm_head.",
512 }
513 )
514
515 supports_tower_connector_lora = True
516
517 @classmethod
518 def get_placeholder_str(cls, modality: str, i: int) -> str | None:
519 if modality.startswith("image"):
520 return "<image>"
521
522 raise ValueError("Only image modality is supported")
523
524 def __init__(self, *, vllm_config: VllmConfig, prefix: str = "") -> None:
525 super().__init__()
526
527 config = vllm_config.model_config.hf_config
528 quant_config = vllm_config.quant_config
529 multimodal_config = vllm_config.model_config.multimodal_config
530
531 self.config = config
532 self.multimodal_config = multimodal_config
533
534 self.configure_mm_token_handling(
535 vocab_size=config.text_config.vocab_size,
536 mm_token_ids=[config.image_token_index],
537 )
538
539 # NOTE: These are special cases for Pixtral-12B in the HF-format
540 # https://huggingface.co/mistral-community/pixtral-12b/blob/main/config.json # noqa
541 if (
542 config.text_config.architectures is None
543 and config.text_config.model_type == "mistral"
544 ):
545 config.text_config.architectures = ["MistralForCausalLM"]
546 if (
547 config.projector_hidden_act is None
548 and config.vision_config.hidden_act == "gelu"
549 ):
550 config.projector_hidden_act = "gelu"
551
552 with self._mark_tower_model(vllm_config, "image"):
553 self.vision_tower = init_vision_tower_for_llava(
554 config,
555 quant_config=quant_config,
556 require_post_norm=False,
557 prefix=maybe_prefix(prefix, "vision_tower"),
558 )
559 self.multi_modal_projector = LlavaMultiModalProjector(
560 vision_hidden_size=config.vision_config.hidden_size,
561 text_hidden_size=config.text_config.hidden_size,
562 projector_hidden_act=config.projector_hidden_act,
563 multimodal_projector_bias=config.multimodal_projector_bias,
564 quant_config=quant_config,
565 prefix=maybe_prefix(prefix, "multi_modal_projector"),
566 )
567
568 with self._mark_language_model(vllm_config):
569 self.language_model = init_vllm_registered_model(
570 vllm_config=vllm_config,
571 hf_config=config.text_config,
572 prefix=maybe_prefix(prefix, "language_model"),
573 )
574
575 self.make_empty_intermediate_tensors = (
576 self.language_model.make_empty_intermediate_tensors
577 )
578
579 def _parse_and_validate_image_input(
580 self, **kwargs: object
581 ) -> LlavaImageInputs | None:
582 pixel_values = kwargs.pop("pixel_values", None)
583 image_embeds = kwargs.pop("image_embeds", None)
584
585 if pixel_values is None and image_embeds is None:
586 return None
587
588 if pixel_values is not None:
589 if self.config.vision_config.model_type == "pixtral":
590 return PixtralHFImagePixelInputs(
591 type="pixel_values_pixtral",
592 pixel_values=pixel_values,
593 )
594
595 expected_h = expected_w = self.config.vision_config.image_size
596 return LlavaImagePixelInputs(
597 type="pixel_values",
598 pixel_values=pixel_values,
599 resolve_bindings={"h": expected_h, "w": expected_w},
600 )
601
602 if image_embeds is not None:
603 if self.config.vision_config.model_type == "pixtral":
604 raise ValueError("Pixtral-HF does not support image_embeds.")
605
606 return LlavaImageEmbeddingInputs(
607 type="image_embeds",
608 data=image_embeds,
609 )
610
611 raise AssertionError("This line should be unreachable.")
612
613 def _image_pixels_to_features(
614 self,
615 vision_tower: CLIPVisionModel | SiglipVisionModel | PixtralHFVisionModel,
616 pixel_values: torch.Tensor | list[torch.Tensor],
617 ) -> torch.Tensor | tuple[torch.Tensor, ...]:
618 # NOTE: we skip the step to select the vision feature layer since
619 # this is already done inside the vision tower
620 return vision_tower(
621 pixel_values,
622 feature_select_strategy=self.config.vision_feature_select_strategy,
623 )
624
625 def _process_image_pixels(
626 self,
627 inputs: LlavaImagePixelInputs | PixtralHFImagePixelInputs,
628 ) -> torch.Tensor | tuple[torch.Tensor, ...]:
629 pixel_values = inputs["pixel_values"]
630
631 return self._image_pixels_to_features(self.vision_tower, pixel_values)
632
633 def _process_image_input(
634 self,
635 image_input: LlavaImageInputs,
636 ) -> torch.Tensor | tuple[torch.Tensor, ...]:
637 if isinstance(image_input, LlavaImageEmbeddingInputs):
638 return image_input["data"]
639
640 image_features = self._process_image_pixels(image_input)
641
642 if isinstance(image_features, torch.Tensor):
643 return self.multi_modal_projector(image_features)
644
645 feature_sizes = [image_feature.shape[0] for image_feature in image_features]
646
647 image_embeds = self.multi_modal_projector(torch.cat(image_features))
648 image_embeds = torch.split(image_embeds, feature_sizes)
649 return image_embeds
650
651 def embed_multimodal(self, **kwargs: object) -> MultiModalEmbeddings:
652 image_input = self._parse_and_validate_image_input(**kwargs)
653 if image_input is None:
654 return []
655
656 return self._process_image_input(image_input)
657
658 def forward(
659 self,
660 input_ids: torch.Tensor | None,
661 positions: torch.Tensor,
662 intermediate_tensors: IntermediateTensors | None = None,
663 inputs_embeds: torch.Tensor | None = None,
664 **kwargs: object,
665 ) -> torch.Tensor | IntermediateTensors:
666 """Run forward pass for LLaVA-1.5.
667
668 One key thing to understand is the `input_ids` already accounts for the
669 positions of the to-be-inserted image embeddings.
670
671 Concretely, consider a text prompt:
672 `"USER: <image>\\nWhat's the content of the image?\\nASSISTANT:"`.
673
674 Tokenizer outputs:
675 `[1, 3148, 1001, 29901, 29871, 32000, 29871, 13, 5618, 29915, 29879,
676 278, 2793, 310, 278, 1967, 29973, 13, 22933, 9047, 13566, 29901]`.
677
678 To reserve space in KV cache, we have to insert placeholder tokens
679 before they are inputted to the model, so the input processor prepends
680 additional image tokens (denoted as `32000`), resulting in:
681 `[1, 3148, 1001, 29901, 29871, 32000, ..., 32000, 29871, 13, 5618,
682 29915, 29879, 278, 2793, 310, 278, 1967, 29973, 13, 22933, 9047, 13566,
683 29901]`.
684
685 We insert 575 tokens so that including the original image token in the
686 input, there are a total of 576 (24 * 24) image tokens, which
687 corresponds to the number of image tokens inputted to the language
688 model, i.e. the number of image tokens outputted by the visual encoder.
689
690 This way, the `positions` and `attn_metadata` are consistent
691 with the `input_ids`.
692
693 Args:
694 input_ids: Flattened (concatenated) input_ids corresponding to a
695 batch.
696 positions: Position indices for the input tokens.
697 intermediate_tensors: Intermediate tensors from prior forward pass.
698 inputs_embeds: Optional tensor of input embeddings.
699 **kwargs: Multimodal inputs for this batch, forwarded to the
700 multimodal embedding path.
701
702 Info:
703 [`LlavaImageInputs`][vllm.model_executor.models.llava.LlavaImageInputs]
704
705 """
706 if intermediate_tensors is not None:
707 inputs_embeds = None
708
709 hidden_states = self.language_model.model(
710 input_ids, positions, intermediate_tensors, inputs_embeds=inputs_embeds
711 )
712
713 return hidden_states
714
715 def compute_logits(
716 self,
717 hidden_states: torch.Tensor,
718 ) -> torch.Tensor | None:
719 return self.language_model.compute_logits(hidden_states)
720
721 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
722 loader = AutoWeightsLoader(self)
723 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
724
725 def get_mm_mapping(self) -> MultiModelKeys:
726 """Get the module prefix in multimodal models."""
727 return MultiModelKeys.from_string_field(
728 language_model="language_model",
729 connector="multi_modal_projector",
730 tower_model="vision_tower",
731 )
732
733 def get_mm_lora_token_counts(
734 self,
735 *,
736 modality: str,
737 mm_kwargs: MultiModalKwargsItem | None,
738 num_mm_embeds: int,
739 ) -> tuple[int, int | None]:
740 del modality, mm_kwargs
741 return num_mm_embeds, num_mm_embeds