@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 08369289af
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 14, 05:30 UTC

[Core][MultiModalHasher] Don't convert memoryviews to bytes during hashing (#24925)

Signed-off-by: Lukas Geiger <lukas.geiger94@gmail.com>

Lukas Geiger committed Sep 16, 2025 at 16:32 UTC 08369289af49229930c61a76ec65b127ad3fba95
1 file changed +18 -29
vllm/multimodal/hasher.py
+18 -29
@@ -20,22 +20,22 @@ logger = init_logger(__name__)
20 class MultiModalHasher:
21
22 @classmethod
23 - def serialize_item(cls, obj: object) -> Union[bytes, memoryview]:
23 + def serialize_item(cls, obj: object) -> Iterable[Union[bytes, memoryview]]:
24 # Simple cases
25 - if isinstance(obj, str):
26 - return obj.encode("utf-8")
25 if isinstance(obj, (bytes, memoryview)):
28 - return obj
26 + return (obj, )
27 + if isinstance(obj, str):
28 + return (obj.encode("utf-8"), )
29 if isinstance(obj, (int, float)):
30 - return np.array(obj).tobytes()
30 + return (np.array(obj).tobytes(), )
31
32 if isinstance(obj, Image.Image):
33 exif = obj.getexif()
34 if Image.ExifTags.Base.ImageID in exif and isinstance(
35 exif[Image.ExifTags.Base.ImageID], uuid.UUID):
36 # If the image has exif ImageID tag, use that
37 - return exif[Image.ExifTags.Base.ImageID].bytes
38 - return cls.item_to_bytes(
37 + return (exif[Image.ExifTags.Base.ImageID].bytes, )
38 + return cls.iter_item_to_bytes(
39 "image", np.asarray(convert_image_mode(obj, "RGBA")))
40 if isinstance(obj, torch.Tensor):
41 tensor_obj: torch.Tensor = obj.cpu()
@@ -49,43 +49,34 @@ class MultiModalHasher:
49 tensor_obj = tensor_obj.view(
50 (tensor_obj.numel(), )).view(torch.uint8)
51
52 - return cls.item_to_bytes(
52 + return cls.iter_item_to_bytes(
53 "tensor", {
54 "original_dtype": str(tensor_dtype),
55 "original_shape": tuple(tensor_shape),
56 "data": tensor_obj.numpy(),
57 })
58 -
59 - return cls.item_to_bytes("tensor", tensor_obj.numpy())
58 + return cls.iter_item_to_bytes("tensor", tensor_obj.numpy())
59 if isinstance(obj, np.ndarray):
60 # If the array is non-contiguous, we need to copy it first
62 - arr_data = obj.data if obj.flags.c_contiguous else obj.tobytes()
63 - return cls.item_to_bytes("ndarray", {
61 + arr_data = obj.view(
62 + np.uint8).data if obj.flags.c_contiguous else obj.tobytes()
63 + return cls.iter_item_to_bytes("ndarray", {
64 "dtype": obj.dtype.str,
65 "shape": obj.shape,
66 "data": arr_data,
67 })
68 -
68 logger.warning(
69 "No serialization method found for %s. "
70 "Falling back to pickle.", type(obj))
71
73 - return pickle.dumps(obj)
74 -
75 - @classmethod
76 - def item_to_bytes(
77 - cls,
78 - key: str,
79 - obj: object,
80 - ) -> bytes:
81 - return b''.join(kb + vb for kb, vb in cls.iter_item_to_bytes(key, obj))
72 + return (pickle.dumps(obj), )
73
74 @classmethod
75 def iter_item_to_bytes(
76 cls,
77 key: str,
78 obj: object,
88 - ) -> Iterable[tuple[bytes, Union[bytes, memoryview]]]:
79 + ) -> Iterable[Union[bytes, memoryview]]:
80 # Recursive cases
81 if isinstance(obj, (list, tuple)):
82 for i, elem in enumerate(obj):
@@ -94,17 +85,15 @@ class MultiModalHasher:
85 for k, v in obj.items():
86 yield from cls.iter_item_to_bytes(f"{key}.{k}", v)
87 else:
97 - key_bytes = key.encode("utf-8")
98 - value_bytes = cls.serialize_item(obj)
99 - yield key_bytes, value_bytes
88 + yield key.encode("utf-8")
89 + yield from cls.serialize_item(obj)
90
91 @classmethod
92 def hash_kwargs(cls, **kwargs: object) -> str:
93 hasher = blake3()
94
95 for k, v in kwargs.items():
106 - for k_bytes, v_bytes in cls.iter_item_to_bytes(k, v):
107 - hasher.update(k_bytes)
108 - hasher.update(v_bytes)
96 + for bytes_ in cls.iter_item_to_bytes(k, v):
97 + hasher.update(bytes_)
98
99 return hasher.hexdigest()