Prhub

#40865 [Bugfix][MoE] Only unpad routed output before shared expert add

原始 PR 作者 netanel-haber 合并时间 2026-04-26 04:50 文件变更 1 提交数 4 评论 8 代码增减 +5 / -1

执行摘要

修复无共享 expert 时 routed 输出截断过晚导致 shape 不匹配

修复 GPT-OSS(无共享 expert 的 MoE)在 b200X2 上 running GPQA 测试失败的问题。PR#40794 引入了早期截断(在 shared_output 相加前),本应在有共享 expert 时保护加法正确性(如 Nemotron-Nano-v3),但对无共享 expert 的模型(如 GPT-OSS)反而破坏了正确性。作者在 PR body 和 issue 评论中明确说明该修复源自本地复现的失败,且变更加 GPT-OSS 测试通过。

推荐精读该 PR 核心变更以理解 fused_moe runner 中 routed 输出截断的时序依赖。若不甚了解原始 padding 逻辑及 shared expert add 的交互,容易忽略条件分支的微妙影响。该 PR 本身改动极小但历史背景丰富(关联 #40794、#35949),是研究复杂 MoE 层数据流的好教材。

讨论亮点

讨论线程 1(gemini-code-assist[bot]):指出原始提交 if shared_output is not None and hidden_dim_was_padded 对有 latent MoE 但无共享 expert 的模型(如 Nemotron、DeepSeek)仍然会触发 shape crash,因为 routed_output_transform 也需要预截断。

结论:作者 netanel-haber 在后续提交中扩展为 if (shared_output is not None or self.routed_output_transform is not None) and hidden_dim_was_padded,采纳了此建议。最终 PR 版本已包含该修正。

讨论线程 2(bnellnm):“og_hidden_dim should be the same as routed_hidden_dim.”

结论:作者 netanel-haber 回应“Not in the case of latent moe, I think.” 表明两者在 latent MoE 场景下可能不同。最终 PR 未修改 og_hidden_dim 的处理,潜在问题在 review 中被说明。

最终批准:tomeras91 在确认复合条件后给出 LGTM。

实现拆解

此 PR 只修改一个文件 vllm/model_executor/layers/fused_moe/runner/moe_runner.py 中的 forward 方法,变更仅针对截断 routed 输出的条件判断。

  1. 添加注释说明意图:在记录 routed_hidden_dim 的代码前增加注释 # so routed output can be trimmed before shared+routed add / latent up proj if needed. 让后续维护更清晰。

  2. 修改截断条件:将原始条件 if hidden_dim_was_padded: 改为复合条件 if (shared_output is not None or self.routed_output_transform is not None) and hidden_dim_was_padded:。这意味着截断仅在存在共享 expert 或存在 routed 输出变换(例如 latent MoE 的 up-projection)时才提前发生;否则(无共享 expert 且无变换,如 GPT-OSS),截断延后到后续步骤,避免 shape 不匹配。

  3. 保留原有逻辑:其余部分(_maybe_pad_hidden_states_unpack、共享输出 reduce、scale 应用、最终 all-reduce 等)完全不动,确保该 PR 是一个最小化的条件修正。

测试方面,原文提及手动运行了 gpQA 测试验证,但本次 diff 不包含新增的自动化测试。

文件 模块 状态 重要度
vllm/model_executor/layers/fused_moe/runner/moe_runner.py MoE 核心 modified 5.8

关键符号

forward

关键源码片段

vllm/model_executor/layers/fused_moe/runner/moe_runner.py core-logic

该文件是 fused_moe runner 的核心实现,PR 唯一的修改文件。变更 `forward` 方法中 routed 输出截断的条件逻辑,直接影响无 shared expert MoE 层的正确性。

# 在 forward 方法中,routed_hidden_dim 记录了 padding 前的原始维度
routed_hidden_dim = hidden_states.shape[-1]
hidden_states, og_hidden_dim = self._maybe_pad_hidden_states(
    shared_experts_input,
    hidden_states,
)
hidden_dim_was_padded = hidden_states.shape[-1] > routed_hidden_dimresult = self._forward_entry(
    hidden_states,
    router_logits,
    shared_experts_input,
    self._encode_layer_name(),
)shared_output, fused_output = _unpack(result)# 关键变更:仅当有 shared expert 或需要 routed_transform 时才提前截断
# 否则延后截断以避免 shape 不匹配(如 GPT-OSS 无 shared expert)
if (
    shared_output is not None or self.routed_output_transform is not None
) and hidden_dim_was_padded:
    fused_output = fused_output[..., :routed_hidden_dim]

评论区精华

截断条件能否覆盖 latent MoE 无 shared expert 场景 正确性

gemini-code-assist[bot] 指出 `shared_output is not None` 条件在有 latent MoE 但无 shared expert 时不够,因为 routed_output_transform 也需要预截断。作者 netanel-haber 在后续提交中增加 `or self.routed_output_transform is not None` 修复。

结论:条件扩展为 `(shared_output is not None or self.routed_output_transform is not None) and hidden_dim_was_padded`,保证 latent MoE 模型也被覆盖。 · 已解决

og_hidden_dim 与 routed_hidden_dim 的等价性 question

bnellnm 询问 `og_hidden_dim` 是否应与 `routed_hidden_dim` 相同。netanel-haber 回答在 latent MoE 中可能不同(因为 input transform 可能改变维度)。

结论:确认二者在 latent MoE 场景下可能不同,但 PR 未修改相关逻辑,存留为已知状态。 · 已解决

风险与影响

  • 回归风险(低):变更只修改了一行条件逻辑,且仅在 padding 发生时生效。主流程 (hidden_dim_was_padded=False) 完全不变。已通过 GPQA 测试验证,但缺失端到端 CI 覆盖(该测试仅在特定 GPU 配置下运行)。
  • 形状不匹配(修复中):原始 shared_output is not None 条件可能漏判 latent MoE 模型(如 DeepSeek V2/R1)中无共享 expert 但需变换的场景。最终 PR 通过增加 or self.routed_output_transform is not None 修复。
  • 测试覆盖不足:PR 只依赖手动执行的 GPQA 测试,没有新的自动化测试,可能遗漏其他模型(如 DeepSeek V2/R1)的回归。建议后续补充显式测试。
  • 性能影响(微小):引入一次额外的布尔运算和属性访问,对整体推理性能无影响。
  • 用户影响:修复了 GPT-OSS(无共享 expert MoE)在特定 GPU(b200)上推理失败的问题。Nemotron-Nano-v3 (TP=1) 功能得以保留。
  • 系统影响:只影响使用 fused_moe runner 且存在 padding 的模型。无 shared expert 且无 routed_transform 的 MoE 模型沿用延迟截断;有 shared expert 或变换的模型维持早期截断。
  • 团队影响:低风险、易回溯的单行 Bug Fix,作者和 reviewer 已达成一致,快速合入。
缺少单元测试覆盖 有共享 expert 模型回归需验证

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论