Prhub

#41759 [MM][Perf][CG] Support ViT full CUDA graph for InternVL

原始 PR 作者 oguzhankir 合并时间 2026-06-04 10:24 文件变更 4 提交数 11 评论 18 代码增减 +183 / -2

执行摘要

为 InternVL 系列添加 ViT CUDA 图支持

ViT 编码器前向传播包含大量小 CUDA 内核,每次推理均重新启动,产生显著开销(关联 Issue #38175 跟踪此问题)。本 PR 将 CUDA 图能力扩展到 InternVL 系列,减少内核启动开销,提升多模态模型推理性能。

值得精读。PR 展示了如何为 ViT 编码器集成 CUDA 图,包括协议方法实现、测试和文档配套。特别关注接口适配 #41234 的过程,以及如何解决 MIG 环境兼容性问题。

讨论亮点

核心讨论围绕接口适配和简化:@Isotr0py 指出需要适配 #41234 引入的新接口(get_encoder_cudagraph_item_specs 等),作者及时更新。@shen-shanshan 询问 InternVL3.5 支持情况,作者确认并更新文档;建议使用更小的模型(InternVL3-1B)以减少测试资源,作者采纳;指出 supports_encoder_cudagraph 类属性和 get_max_frames_per_video 重写不必要(默认值已满足),作者移除。此外,作者在评论中报告了 MIG 环境下的 CUDA 内存分配器 NVML assert 问题,通过减少视频帧数规避。

实现拆解

  1. vllm/model_executor/models/internvl.py 中,让 InternVLChatModel 继承 SupportsEncoderCudaGraph 协议,并实现:get_encoder_cudagraph_config(定义模态和 buffer 键)、get_input_modality(从 mm_kwargs 判断模态)、get_encoder_cudagraph_budget_range(预算范围)、get_encoder_cudagraph_item_specs(项目输入/输出规格)、select_encoder_cudagraph_items(选择项目)和 prepare_encoder_cudagraph_capture_inputs(准备捕获输入)。同时移除了过时的 supports_encoder_cudagraph 类属性和 get_max_frames_per_video 重写。

  2. tests/models/multimodal/generation/test_vit_cudagraph.py 中,添加 internvl_chat_template 辅助函数和 InternVL3-1BVitCudagraphTestConfig,覆盖图像和视频模态,使用 pytest.mark.core_model 标记。

  3. examples/generate/multimodal/vision_language_offline.pyMODELS_SUPPORT_VIT_CUDA_GRAPH 列表中增加 internvl_chat 条目。

  4. docs/design/cuda_graphs_multimodal.md 的模型表格中增加 InternVLChatModel 行,注明对图像和视频均支持。

文件 模块 状态 重要度
vllm/model_executor/models/internvl.py 模型执行器 modified 8.73
tests/models/multimodal/generation/test_vit_cudagraph.py CUDA 图 modified 5.41
examples/generate/multimodal/vision_language_offline.py 示例 modified 3.78
docs/design/cuda_graphs_multimodal.md 文档 modified 1.58

关键符号

get_encoder_cudagraph_config get_input_modality get_encoder_cudagraph_budget_range _get_internvl_patches_list get_encoder_cudagraph_item_specs select_encoder_cudagraph_items prepare_encoder_cudagraph_capture_inputs internvl_chat_template

关键源码片段

vllm/model_executor/models/internvl.py data-contract

核心实现。添加 SupportsEncoderCudaGraph 继承,并实现协议方法:get_encoder_cudagraph_config, get_input_modality, get_encoder_cudagraph_budget_range, get_encoder_cudagraph_item_specs, select_encoder_cudagraph_items, prepare_encoder_cudagraph_capture_inputs。同时移除不必要的类属性和过时方法。

# vllm/model_executor/models/internvl.pyclass InternVLChatModel(
    nn.Module,
    SupportsMultiModal,
    SupportsPP,
    SupportsLoRA,
    SupportsEncoderCudaGraph, # 新加入的协议,表明支持 ViT CUDA 图
):
    supports_encoder_tp_data = True
​
    # -- SupportsEncoderCudaGraph protocol methods --
​
    def get_encoder_cudagraph_config(self):
        from vllm.v1.worker.encoder_cudagraph_defs import EncoderCudaGraphConfig
        # InternVision 使用标准 ViT attention(无 rotary embedding,
        # 无可变长度序列元数据),所以唯一需要的 graph buffer 是
        # pixel_values_flat 本身。
        return EncoderCudaGraphConfig(
            modalities=["image", "video"],
            buffer_keys=["pixel_values_flat"],
            out_hidden_size=self.config.text_config.hidden_size,
        )
​
    def get_input_modality(
        self,
        mm_kwargs: dict[str, Any],
    ) -> str:
        if "pixel_values_flat" in mm_kwargs:
            return "image"
        return "video"
​
    def get_encoder_cudagraph_budget_range(
        self,
        vllm_config: "VllmConfig",
    ) -> tuple[int, int]:
        # 最小预算:1 个 tile 对应的 num_image_token 个输出 token
        min_budget = self.num_image_token
        max_budget = min(
            vllm_config.scheduler_config.max_num_batched_tokens,
            vllm_config.model_config.max_model_len,
        )
        return (min_budget, max_budget)
​
    def get_encoder_cudagraph_item_specs(
        self,
        mm_kwargs: dict[str, Any],
    ):
        from vllm.v1.worker.encoder_cudagraph_defs import EncoderItemSpec
        return [
            EncoderItemSpec(
                input_size=n,
                output_tokens=n * self.num_image_token,
            )
            for n in self._get_internvl_patches_list(mm_kwargs)
        ]
tests/models/multimodal/generation/test_vit_cudagraph.py test-coverage

添加 InternVL 测试用例,包括 internvl_chat_template 函数和 InternVL3-1B 的 VitCudagraphTestConfig,覆盖图像和视频模态。

# tests/models/multimodal/generation/test_vit_cudagraph.pydef internvl_chat_template(content: str) -> str:
    # InternVL 使用的 chat template 与 Qwen 相同
    return f"<|im_start|>user\n{content}<|im_end|>\n<|im_start|>assistant\n"MODEL_CONFIGS: dict[str, VitCudagraphTestConfig] = {
    "internvl": VitCudagraphTestConfig(
        model="OpenGVLab/InternVL3-1B",
        num_video_frames=8,
        image_prompt=internvl_chat_template("<image>\nWhat is in this image?"),
        video_prompt=internvl_chat_template(
            "<video>\nDescribe this video in one sentence."
        ),
        needs_video_metadata=False,
        vllm_runner_kwargs={"trust_remote_code": True},
        marks=[pytest.mark.core_model],
    ),
    # 其他模型配置保持不变 ...
}

评论区精华

需要适配 #41234 新接口 设计

@Isotr0py 指出需要更新接口以适配 #41234 引入的 get_encoder_cudagraph_item_specs 等,作者回复将更新。

结论:作者在后续提交中更新了接口,替换了三个遗留方法。 · 已解决

InternVL3.5 支持确认 question

@shen-shanshan 询问 PR 是否支持 InternVL3.5,因为文档表格中未列出。

结论:作者确认 InternVL3.5 也使用 InternVLChatModel 架构,因此支持,并更新了文档表格。 · 已解决

测试使用更小模型 测试

@shen-shanshan 建议使用更小的 InternVL3-1B 模型进行 CI 测试,以节省资源。

结论:作者采纳,将测试模型从 2B 改为 1B,并相应调整视频帧数。 · 已解决

移除不必要的类属性 style

@shen-shanshan 指出 `supports_encoder_cudagraph` 类属性已由协议隐式提供,无需显式声明;`get_max_frames_per_video` 重写也是多余的(默认值已是 1)。

结论:作者移除了这些冗余代码。 · 已解决

风险与影响

主要风险包括:

1) CUDA 图捕获在部分 GPU 环境(如 MIG)下可能触发 NVML assert(已在 H200 MIG 上复现),虽然通过调小测试规模规避,但生产环境中若使用大尺寸输入或高并发可能复现;
2) 新引入的 SupportsEncoderCudaGraph 协议接口在后续版本中可能继续演进,后续维护需要同步更新;
3) InternVL 的 select_encoder_cudagraph_items 中区分了 pixel_values_flatpixel_values_flat_video 键,若未来 InternVL 的输入键发生变化,需要相应调整。

对用户:使用 InternVL3、InternVL2.5、InternVL2 的用户将自动获得 ViT 编码器 CUDA 图加速,无需额外配置,TTFT 降低 2%-17%。对系统:CUDA 图捕获会占用少量显存(根据 budget 配置),但可提升 GPU 利用率。对团队:此 PR 展示了为多模态模型添加 CUDA 图支持的标准模式(实现 SupportsEncoderCudaGraph 协议),后续其他模型(如 DeepSeek VL、Qwen3.6 等)可参照实现。

MIG 环境 NVML assert CUDA 图捕获兼容性 协议接口演进依赖

关联 Issue

#38175 [RFC]: Support ViT Full CUDA Graph (Tracker)

完整报告

参与讨论