Prhub

#49030 [Bugfix][Multimodal] Fix video temporal padding estimates

原始 PR 作者 labAxiaoming 合并时间 2026-07-29 01:57 文件变更 7 提交数 1 评论 4 代码增减 +34 / -9

执行摘要

修复视频帧数填充公式,支持 temporal_patch_size > 2

Issue #47866 指出当 temporal_patch_size > 2 时,旧公式 num_frames + num_frames % temporal_patch_size 不能将帧数正确填充到下一个倍数,例如 17 % 4 = 18 而不是 20,导致 grid_t 和估计的视频 token 数偏小,影响 vLLM 的预算估计、dummy input 尺寸和预热步骤。PR body 也详细解释了这一问题。

建议尽快合并,作为最小修复方案。值得注意的设计决策是选择不引入共享辅助函数(如 round_up),直接在六个调用点复制修改,避免了对 math_utils 等公共模块的依赖,降低了重构风险。但长期看,可考虑未来统一抽象。

讨论亮点

审查者 Isotr0py 在 glm4_1v.py 的第 1086 行提出疑问,指出视频加载器中已经有帧填充逻辑(vllm/multimodal/video.py 中的代码)。作者 labAxiaoming 回复解释了区别:_get_vision_info 是 vLLM 侧的 token 预算估计、dummy input 尺寸和预热路径,并非实际视频预处理路径;实际输入仍由 HF/model 的图片或视频处理器处理。加载器中的填充只保证帧数为偶数,而 temporal_patch_size 可能为 4、8 等,因此仍需在估计时正确填充。审查者对解释表示认可,最终批准了 PR。

实现拆解

  1. 修复核心公式:在六个模型的 _get_vision_info 方法中,将填充公式从 num_frames + num_frames % temporal_patch_size 改为 num_frames + (-num_frames % temporal_patch_size),确保帧数总能向上取整到 temporal_patch_size 的整数倍。同时更新注释引用指向 Transformers v5.13.0 的视频处理器实现。
  2. 影响文件:修改了 vllm/model_executor/models/qwen2_vl.pyglm4_1v.pykanana_v.pykeye.pyllava_onevision2.pymimo_v2_omni.py 六个文件,每个文件只改动一行公式和一行注释(MiMo 额外涉及类型转换以适应其 effective_frames 计算)。
  3. 添加回归测试:在 tests/models/multimodal/processing/test_glm4_1v.py 中新增 test_vision_info_rounds_up_temporal_frames 测试用例,使用 Mock 对象固定 17 帧,参数化 temporal_patch_size 为 2、4、8,验证 grid_t 分别为 9、5、3,覆盖核心修复逻辑。
文件 模块 状态 重要度
tests/models/multimodal/processing/test_glm4_1v.py 测试 modified 5.98
vllm/model_executor/models/glm4_1v.py 视频处理 modified 5.28
vllm/model_executor/models/kanana_v.py 视频处理 modified 5.28
vllm/model_executor/models/qwen2_vl.py 视频处理 modified 5.28
vllm/model_executor/models/keye.py 视频处理 modified 4.7
vllm/model_executor/models/llava_onevision2.py 视频处理 modified 4.7
vllm/model_executor/models/mimo_v2_omni.py 视频处理 modified 4.7

关键符号

_get_vision_info test_vision_info_rounds_up_temporal_frames

关键源码片段

tests/models/multimodal/processing/test_glm4_1v.py test-coverage

新增回归测试,验证不同 temporal_patch_size 下的 token 估计正确性,是变更的核心验证。

@pytest.mark.parametrize(
    ("temporal_patch_size", "expected_grid_t"),
    [(2, 9), (4, 5), (8, 3)],
)
def test_vision_info_rounds_up_temporal_frames(
    temporal_patch_size: int,
    expected_grid_t: int,
):
    # 创建 Mock 对象模拟 Glm4vProcessingInfo
    info = Mock(spec=Glm4vProcessingInfo)
    vision_config = info.get_hf_config.return_value.vision_config
    vision_config.patch_size = 14
    vision_config.spatial_merge_size = 2
    vision_config.temporal_patch_size = temporal_patch_size
​
    # 调用 _get_vision_info 获取 vision token 数(传入固定 17 帧)
    _, num_vision_tokens = Glm4vProcessingInfo._get_vision_info(
        info,
        image_width=28,
        image_height=28,
        num_frames=17,
        do_resize=False,
    )
​
    # 断言 token 数与预期 grid_t 一致,确保填充正确
    assert num_vision_tokens == expected_grid_t
vllm/model_executor/models/glm4_1v.py data-contract

主要修改的模型之一,展示了公式变更和注释更新。

# 计算填充后的帧数,确保能被 temporal_patch_size 整除
# 参考 Transformers v5.13.0 视频处理器实现:
# https://github.com/huggingface/transformers/blob/v5.13.0/src/transformers/models/qwen2_vl/video_processing_qwen2_vl.py#L249-L252
padded_num_frames = num_frames + (-num_frames % temporal_patch_size)grid_t = max(padded_num_frames // temporal_patch_size, 1)
grid_h = preprocessed_size.height // patch_size
grid_w = preprocessed_size.width // patch_sizenum_patches = grid_t * grid_h * grid_w
num_vision_tokens = num_patches // (merge_size**2)return preprocessed_size, num_vision_tokens

评论区精华

视频加载器已有填充与估计路径区别 question

审查者 Isotr0py 询问视频加载器中已有帧填充逻辑(`vllm/multimodal/video.py`),为何还需在 `_get_vision_info` 中修复。作者解释 `_get_vision_info` 是 vLLM 侧的 token 预算估计路径,与实际视频预处理路径不同;加载器只保证帧数为偶数,而 temporal_patch_size 可能为 4、8 等。

结论:审查者认可解释,PR 被批准。 · 已解决

风险与影响

风险极低。仅修改了六个模型文件中的一行计算公式,且该公式只用于 vLLM 内部的 token 预算估计,不影响实际的图像/视频预处理、模型权重或推理输出。新公式与 Transformers 官方实现一致,并且测试覆盖了不同 temporal_patch_size 组合。回归风险主要可能来自其他未更新的模型(如果有类似的复制粘贴错误),但 PR 已覆盖已知的六个模型。MiMo-V2-Omni 额外需要将填充后的帧数转换为 int,但 effective_frames 本身是整数,改动安全。

影响范围限定在使用了 temporal_patch_size > 2 的视频输入场景。修复后,vLLM 的 token 预算将更准确,避免了潜在的 grid_t 低估导致的预热不足或内存分配错误。对用户透明,输出结果不变。团队通过添加回归测试确保了后续维护质量。

低风险 公式修正 复制粘贴遗留

关联 Issue

#47866 [Bug][Multi-modal]: Video frames should be paded right by temporal_patch_size
#47876 Fix video temporal padding token estimates

完整报告

参与讨论