Prhub

#45868 [ModelRunnerV2] Various model/config compatibility fixes

原始 PR 作者 njhill 合并时间 2026-06-17 11:23 文件变更 4 提交数 5 评论 2 代码增减 +18 / -4

执行摘要

修复 MRV2 与多种模型和配置的兼容性问题

这些修复来源于 PR#44443 的 CI 故障分析,旨在解决 MRV2 在 CohereASR、Whisper 等模型以及 external_launcher + PP 配置下无法正常运行的问题。

建议相关开发者重点阅读 model_runner.py 中 input_ids 置 None 的条件逻辑以及 encoder_runner.py 中 is_embed 累加的修正,这是典型的边缘情况处理。整体 PR 可作为 MRV2 兼容性修复的参考模式。

讨论亮点

审核人 yewentao256 最初要求提供复现示例和错误信息,看到多个修复合并在一个 PR 后表示理解并批准。另一个讨论线程关注 CUDA 图捕获时是否需要额外处理 input_idsintermediate_tensors,作者 njhill 回应称 prepare_dummy_inputs 已处理相关逻辑。最终获得两位审核人批准。

实现拆解

  1. input_ids 在输入嵌入时置 None:在 vllm/v1/worker/gpu/model_runner.pyexecute_model 方法中,当 inputs_embeds 非 None 且模型声明 requires_raw_input_tokens 为 False 时,将 input_ids 设为 None。

  2. 补充 intermediate_tensors 默认值:在同一方法的 model_inputs 字典中始终设置 "intermediate_tensors": None,因为部分模型的前向函数期望该参数但未提供默认值。

  3. 修复多模态 is_embed 累加:在 vllm/v1/worker/gpu/mm/encoder_runner.pygather_mm_embeddings 中将一行 = 改为 |=,确保当同一条请求有多个多模态特征区域时,is_mm_embed 标记正确累积而不被覆盖。

  4. 修复 Whisper 全 CUDA 图的请求数:在 vllm/v1/worker/gpu/model_states/whisper.pyprepare_attn 中将 _get_encoder_seq_lens 调用改为传递 num_reqs(已填充后的值),而非内部从 req_ids 推导。

  5. 回退到 MRV1 对于 external_launcher + PP:在 vllm/config/vllm.py_get_v2_model_runner_unsupported_features 中新增条件,当 distributed_executor_backendexternal_launcherpipeline_parallel_size > 1 时,将该组合标记为 MRV2 不支持,并自动回退到 MRV1。

文件 模块 状态 重要度
vllm/v1/worker/gpu/model_runner.py 模型运行器 modified 5.96
vllm/config/vllm.py 配置检查 modified 5.64
vllm/v1/worker/gpu/model_states/whisper.py Whisper 状态 modified 5.6
vllm/v1/worker/gpu/mm/encoder_runner.py MM 编码器 modified 4.52

关键符号

execute_model _get_v2_model_runner_unsupported_features prepare_attn _get_encoder_seq_lens gather_mm_embeddings

关键源码片段

vllm/v1/worker/gpu/model_runner.py data-contract

核心变更:在 input_embeds 非 None 时传递 input_ids=None,并始终提供 intermediate_tensors=None 默认值,影响 MRV2 所有请求的输入组装。

# 在 execute_model 方法中,首先获取 input_ids
input_ids = input_batch.input_ids
inputs_embeds = None
if self.supports_mm_inputs and self.is_first_pp_rank:
    # 多模态嵌入处理 ...
    inputs_embeds = self.model_state.get_mm_embeddings(
        scheduler_output.scheduled_encoder_inputs, input_batch
    )
    # 如果模型不需要原始 token IDs(如输入全是嵌入),则将 input_ids 置为 None
    if inputs_embeds is not None and not self.model.requires_raw_input_tokens:
        input_ids = Nonemodel_inputs = {
    "input_ids": input_ids, # 可能是 None
    "positions": input_batch.positions,
    "inputs_embeds": inputs_embeds,
    "intermediate_tensors": None, # 始终提供默认值,避免某些模型缺少默认参数
    **self.model_state.prepare_inputs(input_batch, self.req_states),
}
# 对非首 PP rank,更新为 None 并准备 intermediate_tensors
if not self.is_first_pp_rank:
    model_inputs["input_ids"] = None
    model_inputs["inputs_embeds"] = None
    # 准备 intermediate_tensors...
vllm/v1/worker/gpu/mm/encoder_runner.py core-logic

一行修正:将 is_mm_embed 的赋值改为或赋值,避免多区域重复覆盖,修复多模态嵌入标志累积错误。

# 在 gather_mm_embeddings 方法中,累加 is_mm_embed 标志
# 修复前:直接赋值会覆盖之前的嵌入标记
# is_mm_embed[req_start_pos + start_idx : req_start_pos + end_idx] = (
# 修复后:使用或赋值,累加多个区域的嵌入标记
is_mm_embed[req_start_pos + start_idx : req_start_pos + end_idx] |= (
    True if is_embed is None else is_embed
)

评论区精华

要求描述中补充复现命令和错误信息 question

yewentao256 请求补充复现示例和原始错误信息,以便理解修复的必要性。

结论:作者未在评论中直接回复,但 PR body 已包含足够描述,随后 yewentao256 批准。 · 已解决

CUDA 图捕获时 input_ids 和 intermediate_tensors 的处理 正确性

yewentao256 询问在 CUDA 图捕获(dummy run)时是否需要额外处理 input_ids 和 intermediate_tensors,并给出了一个代码片段。

结论:njhill 回复称 `prepare_dummy_inputs` 已处理这些情况,无需额外修改。 · 已解决

风险与影响

虽然变更量少,但存在以下风险:

1) input_ids 置 None 可能影响依赖原始 ID 的下游逻辑,需确保 requires_raw_input_tokens 标志设置正确。
2) is_embed 改为 |= 若原本覆盖行为是被依赖的,则可能引入回归。
3) Whisper 的 num_reqs 改为 padded 值,若其他模式(非 full cudagraph)也需要 padded 但未使用,可能失效。
4) external_launcher + PP 回退到 MRV1 是临时方案,可能隐藏 V2 的真正限制。整体风险较低,因为变更被 CI 验证。

受益模型包括 CohereASR、Whisper 及其他需要 intermediate_tensors 默认参数的模型。受益配置为 external_launcher 与流水线并行组合。这些修复使 MRV2 能覆盖更广泛的模型和部署场景,推动 V2 模型运行器的生产就绪程度。

核心路径变更 缺少测试覆盖 多模态累加逻辑修复 回退到旧版本

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论