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()