[VLM] avoid extra cuda-ipc staging for preprocessed input (#26096)

This commit is contained in:
Mick
2026-05-24 19:48:06 +08:00
committed by GitHub
parent 6447596501
commit b6f71d5850
3 changed files with 127 additions and 79 deletions
+36 -26
View File
@@ -347,18 +347,23 @@ class MultimodalDataItem:
ret.validate()
return ret
def reconstruct(self):
if not isinstance(self.feature, CudaIpcTensorTransportProxy):
return
def has_cuda_ipc_proxy(self):
return (
isinstance(self.feature, CudaIpcTensorTransportProxy)
or isinstance(self.precomputed_embeddings, CudaIpcTensorTransportProxy)
or any(
isinstance(value, CudaIpcTensorTransportProxy)
for value in self.model_specific_data.values()
)
)
reconstruct_device = torch.cuda.current_device()
def reconstruct(self, target_device: int):
"""materialize cuda ipc proxy tensors in-place on target_device"""
if isinstance(self.feature, CudaIpcTensorTransportProxy):
self.feature = self.feature.reconstruct_on_target_device(reconstruct_device)
self.feature = self.feature.reconstruct_on_target_device(target_device)
if isinstance(self.precomputed_embeddings, CudaIpcTensorTransportProxy):
self.precomputed_embeddings = (
self.precomputed_embeddings.reconstruct_on_target_device(
reconstruct_device
)
self.precomputed_embeddings.reconstruct_on_target_device(target_device)
)
for extra_key in self.model_specific_data:
if isinstance(
@@ -366,17 +371,18 @@ class MultimodalDataItem:
):
extra_data = self.model_specific_data[
extra_key
].reconstruct_on_target_device(reconstruct_device)
].reconstruct_on_target_device(target_device)
self.model_specific_data[extra_key] = extra_data
@dataclasses.dataclass
class MultimodalProcessorOutput:
"""Raw output from multimodal processors, before pad/hash computation.
"""Raw output from multimodal processors before scheduler-side preparation (pad, hash).
This is the typed replacement for the dict previously returned by
``BaseMultimodalProcessor.process_mm_data_async``. Unlike
``MultimodalInputs``, items here do NOT carry pad_value or hash yet.
``BaseMultimodalProcessor.process_mm_data_async``. Preprocessed inputs may
already carry ``pad_value`` and ``hash`` to avoid hashing the same tensor once
per scheduler TP rank.
"""
mm_items: List[MultimodalDataItem]
@@ -496,16 +502,16 @@ class MultimodalInputs:
@staticmethod
def from_processor_output(obj: "MultimodalProcessorOutput"):
mm_items = obj.mm_items
assert isinstance(mm_items, list)
mm_items = [item for item in mm_items if item.is_valid()]
# try reconstructing from cuda-ipc
reconstruct_device = None
for mm_item in mm_items:
mm_item.reconstruct()
ret = MultimodalInputs(
mm_items=mm_items,
padded_input_ids=obj.padded_input_ids,
)
assert isinstance(ret.mm_items, list)
ret.mm_items = [item for item in ret.mm_items if item.is_valid()]
if mm_item.has_cuda_ipc_proxy():
if reconstruct_device is None:
reconstruct_device = torch.cuda.current_device()
mm_item.reconstruct(reconstruct_device)
if envs.SGLANG_MM_BUFFER_SIZE_MB.get() > 0:
# Multi-modal feature hashing optimization:
@@ -522,19 +528,23 @@ class MultimodalInputs:
if not is_feature_buffer_initialized():
init_feature_buffer(device)
reset_buffer_offset()
for item in ret.mm_items:
for item in mm_items:
if item.feature is not None:
if isinstance(item.feature, torch.Tensor):
item.feature = try_add_to_buffer(item.feature)
for item in ret.mm_items:
for item in mm_items:
item.set_pad_value()
if envs.SGLANG_MM_BUFFER_SIZE_MB.get() > 0:
for item in ret.mm_items:
for item in mm_items:
if item.feature is not None:
item.feature = item.feature.to("cpu", non_blocking=True)
mm_inputs = MultimodalInputs(
mm_items=mm_items,
padded_input_ids=obj.padded_input_ids,
)
optional_args = [
"mrope_positions",
"mrope_position_delta",
@@ -554,9 +564,9 @@ class MultimodalInputs:
for arg in optional_args:
val = getattr(obj, arg, None)
if val is not None:
setattr(ret, arg, val)
setattr(mm_inputs, arg, val)
return ret
return mm_inputs
def contains_image_inputs(self) -> bool:
return any(item.is_image() for item in self.mm_items)