-
Notifications
You must be signed in to change notification settings - Fork 717
feat: share multimodal hash helpers #4704
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
d2e3866
85eec13
5bb5df6
fe5b216
499e70d
359e006
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # Copyright (c) OpenMMLab. All rights reserved. | ||
| import enum | ||
| import hashlib | ||
| from collections.abc import Mapping | ||
| from typing import Any | ||
|
|
||
| import numpy as np | ||
| import torch | ||
| from torch import Tensor | ||
|
|
||
|
|
||
| def _hash_multimodal_value(hasher: 'hashlib._Hash', value: Any): | ||
| """Update a hash with a deterministic multimodal value representation.""" | ||
| if isinstance(value, Tensor): | ||
| tensor = value.detach().cpu().contiguous() | ||
| hasher.update(f'tensor:{tensor.dtype}:{tuple(tensor.shape)}:'.encode()) | ||
| hasher.update(tensor.view(torch.uint8).numpy().tobytes()) | ||
| elif isinstance(value, np.ndarray): | ||
| array = np.ascontiguousarray(value) | ||
| hasher.update(f'ndarray:{array.dtype}:{array.shape}:'.encode()) | ||
| hasher.update(array.tobytes()) | ||
| elif isinstance(value, Mapping): | ||
| hasher.update(b'dict:{') | ||
| for key in sorted(value, key=lambda x: repr(x)): | ||
| _hash_multimodal_value(hasher, key) | ||
| hasher.update(b':') | ||
| _hash_multimodal_value(hasher, value[key]) | ||
| hasher.update(b',') | ||
| hasher.update(b'}') | ||
| elif isinstance(value, (list, tuple)): | ||
| hasher.update(f'{type(value).__name__}:['.encode()) | ||
| for item in value: | ||
| _hash_multimodal_value(hasher, item) | ||
| hasher.update(b',') | ||
| hasher.update(b']') | ||
| elif isinstance(value, enum.Enum): | ||
| _hash_multimodal_value(hasher, value.value) | ||
| else: | ||
| hasher.update(f'{type(value).__name__}:{repr(value)}'.encode()) | ||
|
|
||
|
|
||
| def make_multimodal_content_hash(data: Any, | ||
| meta: Mapping[str, Any] | None = None, | ||
| mrope_pos_ids: np.ndarray | None = None) -> str: | ||
| """Create a stable content hash for multimodal content identity.""" | ||
| hasher = hashlib.sha256() | ||
| _hash_multimodal_value(hasher, data) | ||
| _hash_multimodal_value(hasher, meta) | ||
| _hash_multimodal_value(hasher, mrope_pos_ids) | ||
| return hasher.hexdigest() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
| from lmdeploy.archs import get_model_arch | ||
| from lmdeploy.vl.constants import Modality | ||
| from lmdeploy.vl.model.preprocess_utils import ( | ||
| attach_multimodal_content_hashes, | ||
| get_expanded_input_ids, | ||
| get_expanded_mm_items, | ||
| get_mm_items_offset, | ||
|
|
@@ -233,6 +234,7 @@ def preprocess(self, | |
|
|
||
| # expand bundled hf processor outputs into per-image/video entry for lmdeploy to consume | ||
| expanded_mm_items = get_expanded_mm_items(collected_mm_items, self.mm_tokens) | ||
| attach_multimodal_content_hashes(expanded_mm_items) | ||
|
|
||
| result = dict(input_ids=input_ids.tolist(), multimodal=expanded_mm_items) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. has preprocess been override in other classes?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch. Now I have moved the hash attachment to a more general place outside the base vision model class. |
||
| return result | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is intentional. The human review guidance for this PR is to
Prefix caching is one consumer of
content_hash, but the hash is attached in the shared VL path, so it can be passed through consistently and reused by other backends later.