@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 671427efbf
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 11, 21:15 UTC

[Model] Move `multimodal_cpu_fields` definition to field config (#30181)

Signed-off-by: DarkLight1337 <tlleungac@connect.ust.hk>

Cyrus Leung committed Dec 6, 2025 at 21:40 UTC 671427efbf57d4e40370a336cf1d3a4d1fd8eb91
15 files changed +141 -95
tests/distributed/test_shm_storage.py
+1 -1
@@ -28,7 +28,7 @@ def _dummy_elem(modality: str, key: str, size: int):
28 modality=modality,
29 key=key,
30 data=torch.empty((size,), dtype=torch.int8),
31 - field=MultiModalSharedField(1),
31 + field=MultiModalSharedField(batch_size=1),
32 )
33
34
tests/multimodal/test_cache.py
+1 -1
@@ -51,7 +51,7 @@ def _dummy_elem(
51 modality=modality,
52 key=key,
53 data=data,
54 - field=MultiModalSharedField(1),
54 + field=MultiModalSharedField(batch_size=1),
55 )
56
57
tests/v1/test_serial_utils.py
+15 -6
@@ -104,22 +104,31 @@ class MyRequest(msgspec.Struct):
104
105 def test_multimodal_kwargs():
106 e1 = MultiModalFieldElem(
107 - "audio", "a0", torch.zeros(1000, dtype=torch.bfloat16), MultiModalBatchedField()
107 + "audio",
108 + "a0",
109 + torch.zeros(1000, dtype=torch.bfloat16),
110 + MultiModalBatchedField(),
111 )
112 e2 = MultiModalFieldElem(
113 "video",
114 "v0",
115 [torch.zeros(1000, dtype=torch.int8) for _ in range(4)],
113 - MultiModalFlatField([[slice(1, 2, 3), slice(4, 5, 6)], [slice(None, 2)]], 0),
116 + MultiModalFlatField(
117 + slices=[[slice(1, 2, 3), slice(4, 5, 6)], [slice(None, 2)]],
118 + dim=0,
119 + ),
120 )
121 e3 = MultiModalFieldElem(
116 - "image", "i0", torch.zeros(1000, dtype=torch.int32), MultiModalSharedField(4)
122 + "image",
123 + "i0",
124 + torch.zeros(1000, dtype=torch.int32),
125 + MultiModalSharedField(batch_size=4),
126 )
127 e4 = MultiModalFieldElem(
128 "image",
129 "i1",
130 torch.zeros(1000, dtype=torch.int32),
122 - MultiModalFlatField([slice(1, 2, 3), slice(4, 5, 6)], 2),
131 + MultiModalFlatField(slices=[slice(1, 2, 3), slice(4, 5, 6)], dim=2),
132 )
133 audio = MultiModalKwargsItem.from_elems([e1])
134 video = MultiModalKwargsItem.from_elems([e2])
@@ -138,8 +147,8 @@ def test_multimodal_kwargs():
147
148 total_len = sum(memoryview(x).cast("B").nbytes for x in encoded)
149
141 - # expected total encoding length, should be 14306, +-20 for minor changes
142 - assert 14275 <= total_len <= 14325
150 + # expected total encoding length, should be 14395, +-20 for minor changes
151 + assert 14375 <= total_len <= 14425
152 decoded = decoder.decode(encoded).mm[0]
153 assert isinstance(decoded, MultiModalKwargsItems)
154
vllm/model_executor/models/glm4_1v.py
+11 -18
@@ -787,10 +787,10 @@ class Glm4vVisionTransformer(nn.Module):
787 def forward(
788 self,
789 x: torch.Tensor,
790 - grid_thw: list[list[int]],
790 + grid_thw: torch.Tensor | list[list[int]],
791 ) -> torch.Tensor:
792 - # Convert grid_thw to tensor (always expecting list format now)
793 - grid_thw = torch.tensor(grid_thw, device=x.device, dtype=torch.long)
792 + if isinstance(grid_thw, list):
793 + grid_thw = torch.tensor(grid_thw, dtype=torch.int32)
794
795 # patchify
796 x = x.to(device=self.device, dtype=self.dtype)
@@ -805,7 +805,8 @@ class Glm4vVisionTransformer(nn.Module):
805 cu_seqlens = torch.repeat_interleave(
806 grid_thw[:, 1] * grid_thw[:, 2], grid_thw[:, 0]
807 ).cumsum(dim=0, dtype=torch.int32)
808 - cu_seqlens = F.pad(cu_seqlens, (1, 0), "constant", 0)
808 + cu_seqlens = torch.cat([cu_seqlens.new_zeros(1), cu_seqlens])
809 + cu_seqlens = cu_seqlens.to(self.device, non_blocking=True)
810
811 # pre-compute max_seqlen for attn mask to reduce cuMemcpy operations
812 max_seqlen = self.compute_attn_mask_seqlen(cu_seqlens)
@@ -1548,7 +1549,6 @@ class Glm4vForConditionalGeneration(
1549 ) -> tuple[torch.Tensor, ...]:
1550 grid_thw = image_input["image_grid_thw"]
1551 assert grid_thw.ndim == 2
1551 - grid_thw_list = grid_thw.tolist()
1552
1553 if image_input["type"] == "image_embeds":
1554 image_embeds = image_input["image_embeds"].type(self.visual.dtype)
@@ -1559,12 +1559,10 @@ class Glm4vForConditionalGeneration(
1559 self.visual, pixel_values, grid_thw.tolist(), rope_type="rope_3d"
1560 )
1561 else:
1562 - image_embeds = self.visual(pixel_values, grid_thw=grid_thw.tolist())
1562 + image_embeds = self.visual(pixel_values, grid_thw=grid_thw)
1563 +
1564 merge_size = self.visual.spatial_merge_size
1564 - sizes = (
1565 - torch.tensor(grid_thw_list, dtype=torch.long).prod(-1)
1566 - // (merge_size * merge_size)
1567 - ).tolist()
1565 + sizes = (grid_thw.prod(-1) // merge_size // merge_size).tolist()
1566 return image_embeds.split(sizes)
1567
1568 def _process_video_input(
@@ -1572,7 +1570,6 @@ class Glm4vForConditionalGeneration(
1570 ) -> tuple[torch.Tensor, ...]:
1571 grid_thw = video_input["video_grid_thw"]
1572 assert grid_thw.ndim == 2
1575 - grid_thw_list = grid_thw.tolist()
1573
1574 if video_input["type"] == "video_embeds":
1575 video_embeds = video_input["video_embeds"].type(self.visual.dtype)
@@ -1588,15 +1585,11 @@ class Glm4vForConditionalGeneration(
1585 rope_type="rope_3d",
1586 )
1587 else:
1591 - video_embeds = self.visual(
1592 - pixel_values_videos, grid_thw=grid_thw.tolist()
1593 - )
1588 + video_embeds = self.visual(pixel_values_videos, grid_thw=grid_thw)
1589 +
1590 # Split concatenated embeddings for each video item.
1591 merge_size = self.visual.spatial_merge_size
1596 - sizes = (
1597 - torch.tensor(grid_thw_list, dtype=torch.long).prod(-1)
1598 - // (merge_size * merge_size)
1599 - ).tolist()
1592 + sizes = (grid_thw.prod(-1) // merge_size // merge_size).tolist()
1593 return video_embeds.split(sizes)
1594
1595 def _parse_and_validate_multimodal_inputs(self, **kwargs: object) -> dict:
vllm/model_executor/models/hunyuan_vision.py
+1 -3
@@ -563,7 +563,7 @@ def _hunyuan_vl_field_config(hf_inputs: Mapping[str, torch.Tensor]):
563 return dict(
564 pixel_values=MultiModalFieldConfig.flat_from_sizes("image", image_grid_sizes),
565 image_embeds=MultiModalFieldConfig.flat_from_sizes("image", image_grid_sizes),
566 - image_grid_thw=MultiModalFieldConfig.batched("image"),
566 + image_grid_thw=MultiModalFieldConfig.batched("image", keep_on_cpu=True),
567 )
568
569
@@ -786,8 +786,6 @@ class HunYuanVLForConditionalGeneration(
786 SupportsQuant,
787 SupportsXDRoPE,
788 ):
789 - multimodal_cpu_fields = {"image_grid_thw"}
790 -
789 # To ensure correct weight loading and mapping.
790 hf_to_vllm_mapper = WeightsMapper(
791 orig_to_new_prefix={
vllm/model_executor/models/interfaces.py
+11 -2
@@ -84,9 +84,9 @@ class SupportsMultiModal(Protocol):
84 `vllm.multimodal.utils.group_mm_kwargs_by_modality` to use.
85 """
86
87 - multimodal_cpu_fields: ClassVar[Set[str]] = frozenset()
87 + multimodal_cpu_fields: ClassVar[Set[str] | None] = None
88 """
89 - A set indicating CPU-only multimodal fields.
89 + [DEPRECATED] A set indicating CPU-only multimodal fields.
90 """
91
92 _processor_factory: ClassVar[_ProcessorFactories]
@@ -279,6 +279,15 @@ def supports_multimodal(
279 "please remove the override from your model."
280 )
281
282 + multimodal_cpu_fields = getattr(model, "multimodal_cpu_fields", None)
283 + if multimodal_cpu_fields is not None:
284 + raise ValueError(
285 + "`multimodal_cpu_fields` is no longer effective, "
286 + "please set `keep_on_cpu=True` in `MultiModalFieldConfig` "
287 + "(refer to https://github.com/vllm-project/vllm/pull/30181), "
288 + "and then remove the override from your model."
289 + )
290 +
291 return res
292
293
vllm/model_executor/models/opencua.py
-2
@@ -201,8 +201,6 @@ class OpenCUADummyInputsBuilder(Qwen2VLDummyInputsBuilder):
201 dummy_inputs=OpenCUADummyInputsBuilder,
202 )
203 class OpenCUAForConditionalGeneration(Qwen2_5_VLForConditionalGeneration):
204 - multimodal_cpu_fields = {"image_grid_thw"}
205 -
204 packed_modules_mapping = {
205 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
206 "gate_up_proj": ["gate_proj", "up_proj"],
vllm/model_executor/models/qwen2_5_vl.py
-2
@@ -1039,8 +1039,6 @@ class Qwen2_5_VLForConditionalGeneration(
1039 SupportsMultiModalPruning,
1040 SupportsMRoPE,
1041 ):
1042 - multimodal_cpu_fields = {"image_grid_thw", "video_grid_thw"}
1043 -
1042 packed_modules_mapping = {
1043 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
1044 "gate_up_proj": ["gate_proj", "up_proj"],
vllm/model_executor/models/qwen2_vl.py
+6 -6
@@ -811,14 +811,14 @@ def _create_qwen2vl_field_factory(
811 image_embeds=MultiModalFieldConfig.flat_from_sizes(
812 "image", image_embed_grid_sizes
813 ),
814 - image_grid_thw=MultiModalFieldConfig.batched("image"),
814 + image_grid_thw=MultiModalFieldConfig.batched("image", keep_on_cpu=True),
815 pixel_values_videos=MultiModalFieldConfig.flat_from_sizes(
816 "video", video_grid_sizes
817 ),
818 video_embeds=MultiModalFieldConfig.flat_from_sizes(
819 "video", video_embed_grid_sizes
820 ),
821 - video_grid_thw=MultiModalFieldConfig.batched("video"),
821 + video_grid_thw=MultiModalFieldConfig.batched("video", keep_on_cpu=True),
822 )
823
824 return _qwen2vl_field_config
@@ -1131,8 +1131,6 @@ class Qwen2VLMultiModalProcessor(BaseMultiModalProcessor[Qwen2VLProcessingInfo])
1131 class Qwen2VLForConditionalGeneration(
1132 nn.Module, SupportsMultiModal, SupportsLoRA, SupportsPP, SupportsMRoPE
1133 ):
1134 - multimodal_cpu_fields = {"image_grid_thw", "video_grid_thw"}
1135 -
1134 # To ensure correct weight loading and mapping.
1135 hf_to_vllm_mapper = WeightsMapper(
1136 orig_to_new_prefix={
@@ -1393,9 +1391,11 @@ class Qwen2VLForConditionalGeneration(
1391 else:
1392 pixel_values_videos = video_input["pixel_values_videos"]
1393 if self.use_data_parallel:
1396 - grid_thw_list = grid_thw.tolist()
1394 return run_dp_sharded_mrope_vision_model(
1398 - self.visual, pixel_values_videos, grid_thw_list, rope_type="rope_3d"
1395 + self.visual,
1396 + pixel_values_videos,
1397 + grid_thw.tolist(),
1398 + rope_type="rope_3d",
1399 )
1400 else:
1401 video_embeds = self.visual(pixel_values_videos, grid_thw=grid_thw)
vllm/model_executor/models/qwen3_vl.py
+2 -4
@@ -984,14 +984,14 @@ class Qwen3VLMultiModalProcessor(BaseMultiModalProcessor[Qwen3VLProcessingInfo])
984 image_embeds=MultiModalFieldConfig.flat_from_sizes(
985 "image", image_grid_sizes
986 ),
987 - image_grid_thw=MultiModalFieldConfig.batched("image"),
987 + image_grid_thw=MultiModalFieldConfig.batched("image", keep_on_cpu=True),
988 pixel_values_videos=MultiModalFieldConfig.flat_from_sizes(
989 "video", video_grid_sizes
990 ),
991 video_embeds=MultiModalFieldConfig.flat_from_sizes(
992 "video", video_grid_sizes
993 ),
994 - video_grid_thw=MultiModalFieldConfig.batched("video"),
994 + video_grid_thw=MultiModalFieldConfig.batched("video", keep_on_cpu=True),
995 )
996
997 def _get_prompt_updates(
@@ -1190,8 +1190,6 @@ class Qwen3VLForConditionalGeneration(
1190 SupportsMRoPE,
1191 SupportsEagle3,
1192 ):
1193 - multimodal_cpu_fields = {"image_grid_thw", "video_grid_thw"}
1194 -
1193 packed_modules_mapping = {
1194 "qkv_proj": [
1195 "q_proj",
vllm/multimodal/inputs.py
+81 -35
@@ -3,7 +3,7 @@
3
4 from abc import ABC, abstractmethod
5 from collections import UserDict, defaultdict
6 -from collections.abc import Mapping, Sequence, Set
6 +from collections.abc import Mapping, Sequence
7 from dataclasses import dataclass
8 from functools import partial
9 from itertools import accumulate
@@ -223,6 +223,23 @@ def nested_tensors_equal(a: NestedTensors, b: NestedTensors) -> bool:
223 return a == b
224
225
226 +def _nested_tensors_h2d(
227 + tensors: NestedTensors,
228 + device: torch.types.Device,
229 +) -> NestedTensors:
230 + if device is None:
231 + return tensors
232 +
233 + return json_map_leaves(
234 + (
235 + lambda x: x.to(device=device, non_blocking=True)
236 + if isinstance(x, torch.Tensor)
237 + else x
238 + ),
239 + tensors,
240 + )
241 +
242 +
243 BatchedTensorInputs: TypeAlias = dict[str, NestedTensors]
244 """
245 A dictionary containing nested tensors which have been batched via
@@ -334,7 +351,7 @@ class MultiModalFieldElem:
351 ) # noqa: E721
352
353
337 -@dataclass(frozen=True)
354 +@dataclass(frozen=True, kw_only=True)
355 class BaseMultiModalField(ABC):
356 """
357 Defines how to interpret tensor data belonging to a keyword argument in
@@ -342,6 +359,12 @@ class BaseMultiModalField(ABC):
359 multi-modal items, and vice versa.
360 """
361
362 + keep_on_cpu: bool = False
363 + """
364 + If `True`, then this field is excluded from being moved to the accelerator
365 + when `MultiModalKwargsItems.get_data()` is called to batch the data.
366 + """
367 +
368 def _field_factory(self, *, modality: str, key: str):
369 f = partial(
370 MultiModalFieldElem,
@@ -386,6 +409,7 @@ class BaseMultiModalField(ABC):
409 self,
410 elems: list[MultiModalFieldElem],
411 *,
412 + device: torch.types.Device = None,
413 pin_memory: bool = False,
414 ) -> NestedTensors:
415 """
@@ -399,11 +423,17 @@ class BaseMultiModalField(ABC):
423 if len(set(field_types)) > 1:
424 raise ValueError(f"Cannot merge different {field_types=}")
425
426 + if device is not None and self.keep_on_cpu:
427 + device = "cpu"
428 + if pin_memory and self.keep_on_cpu:
429 + pin_memory = False
430 +
431 batch = [elem.data for elem in elems]
403 - return self._reduce_data(batch, pin_memory=pin_memory)
432 + out = self._reduce_data(batch, pin_memory=pin_memory)
433 + return _nested_tensors_h2d(out, device=device)
434
435
406 -@dataclass(frozen=True)
436 +@dataclass(frozen=True, kw_only=True)
437 class MultiModalBatchedField(BaseMultiModalField):
438 """
439 Info:
@@ -445,7 +475,7 @@ class MultiModalBatchedField(BaseMultiModalField):
475 return batch
476
477
448 -@dataclass(frozen=True)
478 +@dataclass(frozen=True, kw_only=True)
479 class MultiModalFlatField(BaseMultiModalField):
480 """
481 Info:
@@ -505,7 +535,7 @@ class MultiModalFlatField(BaseMultiModalField):
535 return [e for elem in batch for e in elem]
536
537
508 -@dataclass(frozen=True)
538 +@dataclass(frozen=True, kw_only=True)
539 class MultiModalSharedField(BaseMultiModalField):
540 """
541 Info:
@@ -532,9 +562,10 @@ class MultiModalSharedField(BaseMultiModalField):
562 return batch[0]
563
564
565 +@dataclass(frozen=True)
566 class MultiModalFieldConfig:
567 @staticmethod
537 - def batched(modality: str):
568 + def batched(modality: str, *, keep_on_cpu: bool = False):
569 """
570 Defines a field where an element in the batch is obtained by
571 indexing into the first dimension of the underlying data.
@@ -542,6 +573,7 @@ class MultiModalFieldConfig:
573 Args:
574 modality: The modality of the multi-modal item that uses this
575 keyword argument.
576 + keep_on_cpu: Whether to keep this field on the CPU for the model inputs.
577
578 Example:
579
@@ -558,7 +590,7 @@ class MultiModalFieldConfig:
590 ```
591 """
592 return MultiModalFieldConfig(
561 - field=MultiModalBatchedField(),
593 + field=MultiModalBatchedField(keep_on_cpu=keep_on_cpu),
594 modality=modality,
595 )
596
@@ -567,6 +599,8 @@ class MultiModalFieldConfig:
599 modality: str,
600 slices: Sequence[slice] | Sequence[Sequence[slice]],
601 dim: int = 0,
602 + *,
603 + keep_on_cpu: bool = False,
604 ):
605 """
606 Defines a field where an element in the batch is obtained by
@@ -579,6 +613,7 @@ class MultiModalFieldConfig:
613 slices (dim>0) that is used to extract the data corresponding
614 to it.
615 dim: The dimension to extract data, default to 0.
616 + keep_on_cpu: Whether to keep this field on the CPU for the model inputs.
617
618 Example:
619
@@ -613,12 +648,22 @@ class MultiModalFieldConfig:
648 ```
649 """
650 return MultiModalFieldConfig(
616 - field=MultiModalFlatField(slices=slices, dim=dim),
651 + field=MultiModalFlatField(
652 + slices=slices,
653 + dim=dim,
654 + keep_on_cpu=keep_on_cpu,
655 + ),
656 modality=modality,
657 )
658
659 @staticmethod
621 - def flat_from_sizes(modality: str, size_per_item: "torch.Tensor", dim: int = 0):
660 + def flat_from_sizes(
661 + modality: str,
662 + size_per_item: "torch.Tensor",
663 + dim: int = 0,
664 + *,
665 + keep_on_cpu: bool = False,
666 + ):
667 """
668 Defines a field where an element in the batch is obtained by
669 slicing along the first dimension of the underlying data.
@@ -629,6 +674,7 @@ class MultiModalFieldConfig:
674 size_per_item: For each multi-modal item, the size of the slice
675 that is used to extract the data corresponding to it.
676 dim: The dimension to slice, default to 0.
677 + keep_on_cpu: Whether to keep this field on the CPU for the model inputs.
678
679 Example:
680
@@ -676,10 +722,20 @@ class MultiModalFieldConfig:
722 for i in range(len(size_per_item))
723 ]
724
679 - return MultiModalFieldConfig.flat(modality, slices, dim=dim)
725 + return MultiModalFieldConfig.flat(
726 + modality,
727 + slices,
728 + dim=dim,
729 + keep_on_cpu=keep_on_cpu,
730 + )
731
732 @staticmethod
682 - def shared(modality: str, batch_size: int):
733 + def shared(
734 + modality: str,
735 + batch_size: int,
736 + *,
737 + keep_on_cpu: bool = False,
738 + ):
739 """
740 Defines a field where an element in the batch is obtained by
741 taking the entirety of the underlying data.
@@ -690,6 +746,7 @@ class MultiModalFieldConfig:
746 modality: The modality of the multi-modal item that uses this
747 keyword argument.
748 batch_size: The number of multi-modal items which share this data.
749 + keep_on_cpu: Whether to keep this field on the CPU for the model inputs.
750
751 Example:
752
@@ -708,18 +765,15 @@ class MultiModalFieldConfig:
765 ```
766 """
767 return MultiModalFieldConfig(
711 - field=MultiModalSharedField(batch_size),
768 + field=MultiModalSharedField(
769 + batch_size=batch_size,
770 + keep_on_cpu=keep_on_cpu,
771 + ),
772 modality=modality,
773 )
774
715 - def __init__(self, field: BaseMultiModalField, modality: str) -> None:
716 - super().__init__()
717 -
718 - self.field = field
719 - self.modality = modality
720 -
721 - def __repr__(self) -> str:
722 - return f"MultiModalFieldConfig(field={self.field}, modality={self.modality})"
775 + field: BaseMultiModalField
776 + modality: str
777
778 def build_elems(
779 self,
@@ -744,7 +798,7 @@ class MultiModalKwargsItem(UserDict[str, MultiModalFieldElem]):
798 modality=modality,
799 key="dummy",
800 data=torch.empty(nbytes, dtype=torch.uint8),
747 - field=MultiModalSharedField(1),
801 + field=MultiModalSharedField(batch_size=1),
802 )
803 return MultiModalKwargsItem.from_elems([mm_elem])
804
@@ -844,7 +898,6 @@ class MultiModalKwargsItems(UserDict[str, Sequence[_I]]):
898 *,
899 device: torch.types.Device = None,
900 pin_memory: bool = False,
847 - cpu_fields: Set[str] = frozenset(),
901 ) -> BatchedTensorInputs:
902 """Construct a dictionary of keyword arguments to pass to the model."""
903 elems_by_key = defaultdict[str, list[MultiModalFieldElem]](list)
@@ -859,21 +912,14 @@ class MultiModalKwargsItems(UserDict[str, Sequence[_I]]):
912 elems_by_key[key].append(elem)
913
914 data = {
862 - key: elems[0].field.reduce_data(elems, pin_memory=pin_memory)
915 + key: elems[0].field.reduce_data(
916 + elems,
917 + device=device,
918 + pin_memory=pin_memory,
919 + )
920 for key, elems in elems_by_key.items()
921 }
922
866 - if device is not None:
867 - for k in data.keys() - cpu_fields:
868 - data[k] = json_map_leaves(
869 - (
870 - lambda x: x.to(device=device, non_blocking=True)
871 - if isinstance(x, torch.Tensor)
872 - else x
873 - ),
874 - data[k],
875 - )
876 -
923 return data
924
925
vllm/multimodal/utils.py
+6 -2
@@ -413,7 +413,7 @@ def group_mm_kwargs_by_modality(
413 device: torch.types.Device = None,
414 pin_memory: bool = False,
415 merge_by_field_config: bool | None = None,
416 - multimodal_cpu_fields: Set[str] = frozenset(),
416 + multimodal_cpu_fields: Set[str] | None = None,
417 ) -> Generator[tuple[str, int, BatchedTensorInputs], None, None]:
418 """Group consecutive `MultiModalKwargsItem`s from `mm_kwargs` with the same
419 modality together into the same `MultiModalKwargs` instance.
@@ -431,6 +431,11 @@ def group_mm_kwargs_by_modality(
431 "The `merge_by_field_config` argument of `group_mm_kwargs_by_modality` "
432 "is deprecated and will be removed in v0.13."
433 )
434 + if multimodal_cpu_fields is not None:
435 + logger.warning_once(
436 + "The `multimodal_cpu_fields` argument of `group_mm_kwargs_by_modality` "
437 + "is deprecated and will be removed in v0.13."
438 + )
439
440 from vllm.multimodal.inputs import MultiModalKwargsItems
441
@@ -440,7 +445,6 @@ def group_mm_kwargs_by_modality(
445 mm_kwargs_data = mm_kwargs_items.get_data(
446 device=device,
447 pin_memory=pin_memory,
443 - cpu_fields=multimodal_cpu_fields,
448 )
449
450 yield modality, len(items_lst), mm_kwargs_data
vllm/v1/serial_utils.py
+6 -5
@@ -269,10 +269,11 @@ class MsgpackEncoder:
269 name = MMF_CLASS_TO_FACTORY.get(field.__class__)
270 if not name:
271 raise TypeError(f"Unsupported field type: {field.__class__}")
272 +
273 # We just need to copy all of the field values in order
274 # which will be then used to reconstruct the field.
274 - field_values = (getattr(field, f.name) for f in dataclasses.fields(field))
275 - return name, *field_values
275 + factory_kw = {f.name: getattr(field, f.name) for f in dataclasses.fields(field)}
276 + return name, factory_kw
277
278
279 class MsgpackDecoder:
@@ -392,15 +393,15 @@ class MsgpackDecoder:
393 obj["data"] = self._decode_nested_tensors(obj["data"])
394
395 # Reconstruct the field processor using MultiModalFieldConfig
395 - factory_meth_name, *field_args = obj["field"]
396 + factory_meth_name, factory_kw = obj["field"]
397 factory_meth = getattr(MultiModalFieldConfig, factory_meth_name)
398
399 # Special case: decode the union "slices" field of
400 # MultiModalFlatField
401 if factory_meth_name == "flat":
401 - field_args[0] = self._decode_nested_slices(field_args[0])
402 + factory_kw["slices"] = self._decode_nested_slices(factory_kw["slices"])
403
403 - obj["field"] = factory_meth(None, *field_args).field
404 + obj["field"] = factory_meth("", **factory_kw).field
405 return MultiModalFieldElem(**obj)
406
407 def _decode_nested_tensors(self, obj: Any) -> NestedTensors:
vllm/v1/worker/gpu_model_runner.py
-5
@@ -1097,7 +1097,6 @@ class GPUModelRunner(
1097 device=self.device,
1098 pin_memory=self.pin_memory,
1099 merge_by_field_config=model.merge_by_field_config,
1100 - multimodal_cpu_fields=model.multimodal_cpu_fields,
1100 ):
1101 mm_kwargs_combined.update(mm_kwargs_group)
1102
@@ -2109,7 +2108,6 @@ class GPUModelRunner(
2108 mm_kwargs,
2109 device=self.device,
2110 pin_memory=self.pin_memory,
2112 - multimodal_cpu_fields=model.multimodal_cpu_fields,
2111 ):
2112 curr_group_outputs: list[torch.Tensor] = []
2113
@@ -2135,7 +2133,6 @@ class GPUModelRunner(
2133 [video_mm_kwargs_item],
2134 device=self.device,
2135 pin_memory=self.pin_memory,
2138 - multimodal_cpu_fields=model.multimodal_cpu_fields,
2136 )
2137 )
2138
@@ -3887,14 +3884,12 @@ class GPUModelRunner(
3884 dummy_mm_item = dummy_mm_data[modality][0]
3885 dummy_mm_items = [dummy_mm_item] * max_items_per_batch
3886
3890 - model = cast(SupportsMultiModal, self.model)
3887 return next(
3888 mm_kwargs_group
3889 for _, _, mm_kwargs_group in group_mm_kwargs_by_modality(
3890 dummy_mm_items,
3891 device=self.device,
3892 pin_memory=self.pin_memory,
3897 - multimodal_cpu_fields=model.multimodal_cpu_fields,
3893 )
3894 )
3895
vllm/v1/worker/tpu_model_runner.py
-3
@@ -969,7 +969,6 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
969 mm_kwargs,
970 device=self.device,
971 pin_memory=self.pin_memory,
972 - multimodal_cpu_fields=model.multimodal_cpu_fields,
972 ):
973 # Run the encoder.
974 # `curr_group_outputs` is either of the following:
@@ -2050,14 +2049,12 @@ class TPUModelRunner(LoRAModelRunnerMixin, KVConnectorModelRunnerMixin):
2049 dummy_mm_item = dummy_mm_data[modality][0]
2050 dummy_mm_items = [dummy_mm_item] * max_items_per_batch
2051
2053 - model = cast(SupportsMultiModal, self.model)
2052 return next(
2053 grouped_mm_kwargs
2054 for _, _, grouped_mm_kwargs in group_mm_kwargs_by_modality(
2055 dummy_mm_items,
2056 device=self.device,
2057 pin_memory=self.pin_memory,
2060 - multimodal_cpu_fields=model.multimodal_cpu_fields,
2058 )
2059 )
2060