[VLM] Enable per-image ViT cache and avoid TP CUDA context creation for Kimi-K2.5 (#22858)

This commit is contained in:
Yuhao Yang
2026-04-16 01:14:24 +08:00
committed by GitHub
parent 7d7fdc1309
commit 8686f42acb
2 changed files with 11 additions and 64 deletions
+6 -63
View File
@@ -42,7 +42,6 @@ from sglang.srt.multimodal.mm_utils import run_dp_sharded_mrope_vision_model
from sglang.srt.server_args import get_global_server_args
from sglang.srt.utils import add_prefix, is_npu
KIMIV_VT_INFER_MAX_PATCH_NUM = 16328
logger = logging.getLogger(__name__)
from sglang.srt.layers.dp_attention import is_dp_attention_enabled
@@ -622,59 +621,6 @@ def mm_projection_auto(
return proj_out
@torch.inference_mode()
def vision_tower_forward_auto(
vision_tower: torch.nn.Module,
pixel_values: torch.Tensor,
grid_thw: torch.Tensor,
mm_projector: torch.nn.Module | None = None,
) -> list[torch.Tensor]:
"""Auto-batched vision tower forward."""
assert isinstance(
pixel_values, torch.Tensor
), "expect pixel_values to be a tensor, get {}".format(type(pixel_values))
n = grid_thw.shape[0]
n_patches_each_media = grid_thw.prod(-1)
max_infer_batch = max(n_patches_each_media.max(), KIMIV_VT_INFER_MAX_PATCH_NUM)
logger.debug(
"vt max_infer_batch: %s, KIMIV_VT_INFER_MAX_PATCH_NUM: %s",
max_infer_batch,
KIMIV_VT_INFER_MAX_PATCH_NUM,
)
tensors = []
pre_sum = 0
current_group_start = 0
current_group_patches = 0
for i in range(n):
current_media_patches = n_patches_each_media[i].item()
if current_group_patches + current_media_patches <= max_infer_batch:
current_group_patches += current_media_patches
else:
if current_group_start < i:
group_grid_thw = grid_thw[current_group_start:i]
group_n_patches = n_patches_each_media[current_group_start:i].sum()
group_input = pixel_values[pre_sum : pre_sum + group_n_patches]
group_output = vision_tower(group_input, group_grid_thw)
proj_out = mm_projection_auto(mm_projector, group_output)
tensors.extend(proj_out)
pre_sum += group_n_patches
current_group_start = i
current_group_patches = current_media_patches
# Process the last group
if current_group_start < n:
group_grid_thw = grid_thw[current_group_start:n]
group_n_patches = n_patches_each_media[current_group_start:n].sum()
group_input = pixel_values[pre_sum : pre_sum + group_n_patches]
group_output = vision_tower(group_input, group_grid_thw)
proj_out = mm_projection_auto(mm_projector, group_output)
tensors.extend(proj_out)
return tensors
class KimiK25ForConditionalGeneration(nn.Module):
# Support nvidia/Kimi-K2.5-NVFP4 naming: language_model.layers.*.
# Ref: HF config.json for nvidia/Kimi-K2.5-NVFP4
@@ -733,7 +679,9 @@ class KimiK25ForConditionalGeneration(nn.Module):
pixel_values = torch.cat([item.feature for item in items], dim=0).to(
device=device, dtype=target_dtype
)
grid_thws = torch.concat([item.grid_thws for item in items], dim=0).to(device)
grid_thws = torch.concat([item.image_grid_thw for item in items], dim=0).to(
device
)
if self.use_data_parallel:
image_embeds = run_dp_sharded_mrope_vision_model(
@@ -745,14 +693,9 @@ class KimiK25ForConditionalGeneration(nn.Module):
image_features = self.mm_projector(image_embeds)
return image_features
image_features = vision_tower_forward_auto(
self.vision_tower,
pixel_values,
grid_thws,
mm_projector=self.mm_projector,
)
image_features = torch.cat(image_features, dim=0)
return image_features
image_embeds = self.vision_tower(pixel_values, grid_thws)
proj_out = mm_projection_auto(self.mm_projector, image_embeds)
return torch.cat(proj_out, dim=0)
def pad_input_ids(self, input_ids: List[int], mm_inputs: MultimodalInputs):
pattern = MultiModalityDataPaddingPatternMultimodalTokens()
@@ -285,10 +285,14 @@ class KimiGPUProcessorWrapper:
images, resize_configs, image_mean, image_std_inv, self._patch_size
)
grid_thws = grid_thws.cpu()
return {
"input_ids": text_inputs["input_ids"],
"pixel_values": pixel_values,
"grid_thws": grid_thws,
# Use SGL-standard key so get_new_expanded_mm_items() can split
# per-image for cache granularity (it looks up 'image_grid_thw').
"image_grid_thw": grid_thws,
}
def _cpu_call(self, text, images, **kwargs):