Prhub

#43727 [MoE] Remove inplace fused experts mechanism

原始 PR 作者 zyongye 合并时间 2026-05-28 11:00 文件变更 44 提交数 5 评论 3 代码增减 +11 / -237

执行摘要

移除 MoE fused experts 的 inplace 路径和 disable_inplace 机制

在 torch 2.9+ 环境下,disable_inplace() 始终返回 True,导致 inplace 路径成为死代码(参考 issue #26378)。同时,该路径曾是 torch 自定义算子中输出别名输入的隐患来源。作者有意利用代码清理的契机,提前执行已有的 TODO 注释,以简化 fused_moe 的接口和内部逻辑。

本 PR 是清理遗留技术债务的良好范例,值得对 MoE 层有维护责任的工程师精读。展示了如何在 torch 升级后安全移除已废弃的兼容代码,重点关注:版本守卫的消除、自定义算子重命名时的向下兼容策略(通过保留 outplace 别名)、以及测试覆盖的更新方式。

讨论亮点

审查者 bnellnm 建议删除一个已由 PR body 执行的 TODO 注释,并提议将 outplace_fused_experts 重命名为 fused_experts。作者采纳并完成。两个评论均得到快速闭环,未产生争议。

实现拆解

  1. 删除 FusedMoEConfig.disable_inplace 配置字段(config.py);
  2. 移除 utils.py 中的 disable_inplace() 函数和依赖的 is_torch_equal_or_newer 导入;
  3. 删除 fused_moe.py 中的 inplace_fused_experts / inplace_fused_experts_fake 自定义算子对,并将 outplace_fused_experts 重命名为 fused_experts_op;
  4. 更新 modular_kernel.py 中 FusedMoEKernelModularImpl 的构造函数,删除 inplace 参数及相关分支;
  5. 移除所有 oracle 后端、量化集成、模型文件(如 arctic、minicpm)和测试文件的 inplace 参数传递和判断逻辑;
  6. 特意保留 CPU fused_experts_cpu 算子的 inplace 参数不变,因其为独立 C++ 路径。
文件 模块 状态 重要度
vllm/model_executor/layers/fused_moe/fused_moe.py MoE 层 modified 8.83
vllm/model_executor/layers/fused_moe/modular_kernel.py MoE 层 modified 7.03
vllm/model_executor/layers/fused_moe/utils.py 工具层 modified 6.35
vllm/model_executor/layers/fused_moe/config.py 配置 modified 5.4
vllm/model_executor/layers/fused_moe/layer.py MoE 层 modified 5.51

关键符号

inplace_fused_experts inplace_fused_experts_fake outplace_fused_experts outplace_fused_experts_fake disable_inplace FusedMoEKernelModularImpl.__init__ FusedMoEKernel.inplace

关键源码片段

vllm/model_executor/layers/fused_moe/modular_kernel.py data-contract

定义 FusedMoEKernelModularImpl 和 FusedMoEKernel 类,删除 inplace 属性及相关条件判断,简化构造与 apply 方法。

# vllm/model_executor/layers/fused_moe/modular_kernel.py@final
class FusedMoEKernelModularImpl:
    def __init__(
        self,
        prepare_finalize: FusedMoEPrepareAndFinalizeModular,
        fused_experts: FusedMoEExpertsModular,
        # 注意:inplace 参数已被完全移除
    ):
        self.prepare_finalize = prepare_finalize
        self.fused_experts = fused_experts
        # 以前这里还有 self.inplace = inplace
        moe_parallel_config = fused_experts.moe_config.moe_parallel_config
        self.moe_parallel_config = moe_parallel_config
        self.is_dp_ep = (
            moe_parallel_config is not None
            and moe_parallel_config.dp_size > 1
            and moe_parallel_config.use_ep
        )
​
    def apply(self, ...):
        # 原来有 if self.inplace: output = hidden_states
        # else: output = torch.empty_like(hidden_states)
        # 现在统一使用新输出
        output = torch.empty_like(hidden_states)
        # ... 后续计算

评论区精华

删除多余的 TODO 注释 style

bnellnm 指出 PR body 中引用的 TODO 已由 PR 完成,应直接删除。

结论:作者确认删除,TODO 被移除。 · 已解决

重命名 outplace_fused_experts 为 fused_experts 设计

bnellnm 建议既然 inplace 变体已删除,原 outplace 算子应直接命名为 fused_experts,消除冗余修饰。

结论:作者接受并执行重命名,同时保留 outplace 别名为兼容性。 · 已解决

风险与影响

风险极低。移除的代码在 torch>=2.9 时已经完全不可达,且所有测试通过。保留的 CPU 路径未更改。可能的风险在于若未来有人依赖于 inplace 语义或手动配置 disable_inplace=False,但该配置字段从未被公开暴露。

对用户无行为影响;显著简化 fused_moe 内部接口(减少一个 bool 参数和若干条件分支);降低 future work 中意外依赖已废弃 inplace 路径的风险;测试文件随之更新,确保回退一致性。

死代码删除,风险低 CPU 路径保留 unchanged

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论