Prhub

#55941 [Bugfix] Fix OpenPangu multimodal embedding merge

原始 PR 作者 taneem-ibrahim 合并时间 2026-09-09 07:54 文件变更 2 提交数 3 评论 10 代码增减 +68 / -10

执行摘要

修复 OpenPanguVL 模型多模态嵌入合并方法的过时调用签名。

PR body 明确指出,get_input_embeddings 方法传递了过时的 (input_ids, inputs_embeds, multimodal_embeddings, placeholder_token_ids) 参数形状给 SupportsMultiModal.embed_input_ids,而当前接口仅接受 input_ids、multimodal_embeddings 和关键字参数 is_multimodal。这导致直接调用多模态路径时抛出 TypeError。Issue 评论中 DarkLight1337 询问模型是否一直损坏但无人报告,作者 taneem-ibrahim 解释这是因为 V1 serving 绕过了这条直接路径,直接调用了 embed_input_ids(..., is_multimodal=...)。

此 PR 值得精读,尤其是在多模态模型如何集成嵌入到语言模型的实现模式上。它展示了如何修复一个因接口演进而导致的内部契约不一致问题。关注点包括:

  1. 新的 get_input_embeddings 实现如何构建掩码并委托给统一接口,这是一个清晰的模式。
  2. 新增的单元测试如何通过模拟和参数化高效地验证多模态嵌入合并逻辑。建议团队考虑对其他多模态模型执行类似的接口合规性审查。
讨论亮点

核心讨论集中在代码健壮性和历史问题上。DarkLight1337 提出疑问:“Does this mean the model has been broken all this time but no one reported the issue?”,这揭示了潜在的代码覆盖率或测试盲区问题。作者 taneem-ibrahim 的回复澄清了技术原因,即 V1 serving 的特定代码路径规避了此缺陷。最终结论是接受修复,但 DarkLight1337 提议后续清理可能的死代码,并 @ 了另一位维护者 Isotr0py。审查者 yewentao256 在 APPROVED 评论中询问是否应将新测试放入现有文件而非新建,这是一个关于测试组织的建议,未影响合并。

实现拆解

  1. 变更入口:修改 vllm/model_executor/models/openpangu_vl.py 中的 OpenPanguVLForConditionalGeneration.get_input_embeddings 方法。
  2. 核心逻辑改造:移除了旧的五参数调用,改为:首先构建一个包含图像和视频占位符 token ID 的张量;使用 torch.isin 创建一个布尔掩码 is_multimodal,标记 input_ids 中哪些位置是多模态占位符;最后使用关键字参数 is_multimodal 调用当前的 self.embed_input_ids 方法。同时,将 multimodal_embeddings 参数的类型注解从隐式 None 显式化为 MultiModalEmbeddings | None。
  3. 测试配套:新增独立的测试文件 tests/models/multimodal/test_openpangu_vl.py,通过模拟轻量级语言模型和构建包含图像/视频占位符的输入,验证了修复后 get_input_embeddings 能正确地将多模态嵌入合并到预期位置。测试覆盖了 CPU 和 CUDA 设备。
文件 模块 状态 重要度
vllm/model_executor/models/openpangu_vl.py 模型定义 modified 6.68
tests/models/multimodal/test_openpangu_vl.py 多模态测试 added 7.16

关键符号

get_input_embeddings embed_input_ids

关键源码片段

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

核心修复文件,修改了 `get_input_embeddings` 方法以修复过时的多模态嵌入合并调用。

# vllm/model_executor/models/openpangu_vl.py
# 修改后的 get_input_embeddings 方法,展示了修复后的实现
​
def get_input_embeddings(
    self,
    input_ids: torch.Tensor,
    multimodal_embeddings: MultiModalEmbeddings | None = None,
) -> torch.Tensor:
    # 如果没有多模态嵌入,直接返回语言模型的嵌入
    if multimodal_embeddings is None:
        return self.language_model.embed_input_ids(input_ids)
​
    # 构建图像和视频占位符 token ID 的张量
    mm_token_ids = input_ids.new_tensor(
        [self.config.image_token_id, self.config.video_token_id]
    )
    # 创建布尔掩码,标记 input_ids 中哪些位置是多模态占位符
    is_multimodal = torch.isin(input_ids, mm_token_ids)
    # 使用关键字参数调用统一的嵌入合并接口
    return self.embed_input_ids(
        input_ids,
        multimodal_embeddings,
        is_multimodal=is_multimodal,
    )
tests/models/multimodal/test_openpangu_vl.py test-coverage

新增的测试文件,通过模拟和参数化测试验证了修复后的多模态嵌入合并功能。

# tests/models/multimodal/test_openpangu_vl.py
# 测试用例,验证多模态嵌入的合并逻辑
​
@pytest.mark.parametrize("device_type", ["cpu", "cuda"])
def test_get_input_embeddings_merges_image_and_video_embeddings(
    device_type: str,
) -> None:
    # 跳过不可用的 CUDA 设备
    if device_type == "cuda" and not torch.cuda.is_available():
        pytest.skip("CUDA is not available")
​
    device = torch.device(device_type)
    hidden_size = 4
    model = _OpenPanguVL(hidden_size).to(device)
    # 构造包含图像 (41) 和视频 (42) 占位符的输入
    input_ids = torch.tensor([7, 41, 41, 8, 42, 9], device=device)
    # 模拟两个图像嵌入和一个视频嵌入
    multimodal_embeddings = (
        torch.full((2, hidden_size), -1.0, device=device),
        torch.full((1, hidden_size), -2.0, device=device),
    )
​
    # 调用被修复的方法
    actual = model.get_input_embeddings(input_ids, multimodal_embeddings)
​
    # 手动计算期望结果:先获取基础嵌入,然后替换占位符位置
    expected = model.language_model.embed_input_ids(input_ids)
    expected[1:3] = -1.0 # 图像占位符位置
    expected[4] = -2.0 # 视频占位符位置
    torch.testing.assert_close(actual, expected)

评论区精华

历史遗留问题的影响范围评估 question

DarkLight1337 询问模型是否一直损坏但无人报告,引发了对代码健壮性和测试覆盖率的讨论。作者解释了 V1 serving 路径绕过了该问题,因此生产环境未受影响。

结论:接受修复,并计划后续清理可能的死代码。 · 已解决

测试文件组织建议 测试

审查者 yewentao256 建议将新测试放入现有测试文件,而非创建新文件。

结论:该建议未被采纳或要求修改,PR 以创建新文件的方式合并。 · 已解决

风险与影响

风险较低。这是一个局部 bugfix,修复了一个之前就已损坏(但未被生产路径触发)的方法调用。核心风险在于对 embed_input_ids 接口契约的遵守,新实现正确使用了 is_multimodal 关键字参数,与当前接口定义一致。潜在回归风险是如果其他代码也依赖于旧的错误调用签名(可能性极低),但 PR 作者已通过测试验证了修复。变更范围小,仅涉及一个模型的一个方法。

直接影响 OpenPanguVL 多模态模型的功能正确性,使得通过 get_input_embeddings 方法直接传递多模态嵌入的场景(如测试或潜在的其他集成路径)能够正常工作。对通过 V1 serving 的标准推理路径无直接影响,因为该路径本就不经过此方法。对系统整体影响有限,主要提升了特定模型的代码健壮性和测试覆盖。

历史遗留缺陷

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论