Prhub

#42027 [Kernel][MoE] Add GELU_TANH to CPU, CUTLASS, and WNA16 MoE backends

原始 PR 作者 lesj0610 合并时间 2026-06-03 05:12 文件变更 7 提交数 4 评论 5 代码增减 +119 / -7

执行摘要

为 CPU/CUTLASS/WNA16 MoE 后端添加 GELU_TANH 激活支持

核心GELU_TANH MoE激活已在主路径支持,但CPU fused MoE、CUTLASS FP8/FP4和WNA16后端仍拒绝该激活:CPU fused MoE在激活映射中缺少GELU_TANH条目会引发KeyError;CUTLASS未在_supports_activation中列出导致不必要的fallback;WNA16 MoE硬断言仅支持SiLU,遇到非SiLU模型会崩溃。

值得精读,尤其是 WNA16 中从硬编码断言到动态传递 activation 的设计决策,以及 CPU C++ 中添加新激活的完整流程——枚举、解析、kernel 实现、分发函数。可作为后续扩展其他激活的参考模板。

讨论亮点
  • 测试平台兼容性:审查者 AndreasKaratzas 指出 WNA16 测试应添加 CUDA-only 跳过的 pytest mark,因为 WNA16 是 CUDA 特定的量化路径。作者 lesj0610 响应并添加了 @pytest.mark.skipif(not current_platform.is_cuda())

实现拆解

  1. CPU C++ 核心:在 csrc/cpu/cpu_fused_moe.cppFusedMOEAct 枚举中添加 GeluTanhAndMul,并在 get_act_type 中增加 "gelu_tanh" 到该枚举的映射。实现向量化 gelu_tanh_and_mul 模板函数,使用 tanh 近似计算 GELU_TANH 激活。在 apply_gated_act 中增加对应的 case 分支。

  2. CPU Python 层:在 vllm/model_executor/layers/fused_moe/cpu_fused_moe.py_CPU_MOE_ACT_FN 字典中添加 MoEActivation.GELU_TANH 条目,使用 F.gelu(approximate="tanh") 实现。

  3. CUTLASS 后端:在 vllm/model_executor/layers/fused_moe/experts/cutlass_moe.py_supports_activation 静态方法中(针对 FP8 和 FP4 两个类)添加 MoEActivation.GELU_TANHMoEActivation.GELU_TANH_NO_MUL

  4. WNA16 量化层:在 vllm/model_executor/layers/quantization/moe_wna16.pyMoeWNA16Method.apply 中移除 assert layer.activation == MoEActivation.SILU 的硬限制,并在调用 fused_experts 时新增 activation=layer.activation 参数传递。

  5. 测试配套:新增 tests/quantization/test_moe_wna16.py 测试 WNA16 方法能正确传递 GELU_TANH 激活;在 tests/kernels/moe/test_cutlass_moe.py 添加 test_cutlass_moe_supports_gelu_tanh_activation_metadata 验证 CUTLASS 后端的元数据支持;在 tests/kernels/moe/test_cpu_fused_moe.py 扩展 CPU 后端的测试覆盖。

文件 模块 状态 重要度
csrc/cpu/cpu_fused_moe.cpp CPU 内核 modified 7.24
tests/quantization/test_moe_wna16.py WNA16 量化 added 6.68
vllm/model_executor/layers/quantization/moe_wna16.py 量化层 modified 5.94
vllm/model_executor/layers/fused_moe/cpu_fused_moe.py MoE 层 modified 5.46
vllm/model_executor/layers/fused_moe/experts/cutlass_moe.py CUTLASS 专家 modified 5.05
tests/kernels/moe/test_cutlass_moe.py CUTLASS 测试 modified 4.65
tests/kernels/moe/test_cpu_fused_moe.py CPU 测试 modified 4.27

关键符号

gelu_tanh_and_mul (C++ template) get_act_type (C++) apply_gated_act (C++) MoeWNA16Method.apply (Python) _CPU_MOE_ACT_FN (Python dict) _supports_activation (CUTLASS method) test_moe_wna16_apply_passes_layer_activation test_cutlass_moe_supports_gelu_tanh_activation_metadata

关键源码片段

csrc/cpu/cpu_fused_moe.cpp core-logic

核心 C++ 实现,新增 GELU_TANH 枚举、名称解析和向量化计算函数。

// 扩展枚举,添加 GeluTanhAndMul
enum class FusedMOEAct {
  SiluAndMul,
  SwigluOAIAndMul,
  GeluAndMul,
  GeluTanhAndMul, // 新增 : GELU_TANH 激活
};// 在 get_act_type 中添加 "gelu_tanh" 分支
FusedMOEAct get_act_type(const std::string& act) {
  if (act == "silu") return FusedMOEAct::SiluAndMul;
  if (act == "swigluoai") return FusedMOEAct::SwigluOAIAndMul;
  if (act == "gelu") return FusedMOEAct::GeluAndMul;
  if (act == "gelu_tanh") return FusedMOEAct::GeluTanhAndMul; // 新增分支
  TORCH_CHECK(false, "Invalid act type: " + act);
}// apply_gated_act 中新增 case
FORCE_INLINE void apply_gated_act(const FusedMOEAct act,
                                  float* __restrict__ input,
                                  scalar_t* __restrict__ output,
                                  const int32_t m, const int32_t n,
                                  const int32_t input_stride,
                                  const int32_t output_stride) {
  switch (act) {
    // ... 其他 case ...
    case FusedMOEAct::GeluTanhAndMul:
      gelu_tanh_and_mul(input, output, m, n, input_stride, output_stride);
      return;
    default:
      TORCH_CHECK(false, "Unsupported act type.");
  }
}
vllm/model_executor/layers/quantization/moe_wna16.py data-contract

移除 SiLU-only 断言,改为传递 layer.activation,使 WNA16 支持任何激活。

def apply(
    self,
    layer: RoutedExperts,
    x: torch.Tensor,
    topk_weights: torch.Tensor,
    topk_ids: torch.Tensor,
    shared_experts: SharedExperts | None,
    shared_experts_input: torch.Tensor | None,
) -> torch.Tensor:
    from vllm.model_executor.layers.fused_moe import fused_experts
​
    # 移除了 assert layer.activation == MoEActivation.SILU 的限制
    return fused_experts(
        x,
        layer.w13_qweight,
        layer.w2_qweight,
        topk_weights=topk_weights,
        topk_ids=topk_ids,
        activation=layer.activation, # 新增:传递层配置的激活类型
        apply_router_weight_on_input=layer.apply_router_weight_on_input,
        global_num_experts=layer.global_num_experts,
        expert_map=layer.expert_map,
        quant_config=self.moe_quant_config,
    )
vllm/model_executor/layers/fused_moe/cpu_fused_moe.py data-contract

在激活映射中添加 GELU_TANH 的 PyTorch 实现。

# 激活名称到原生前向函数的映射
_CPU_MOE_ACT_FN: dict[MoEActivation, Callable[[torch.Tensor], torch.Tensor]] = {
    MoEActivation.SILU: lambda x: SiluAndMul(compile_native=False).forward_native(x),
    MoEActivation.SWIGLUOAI: _swigluoai_forward_native,
    MoEActivation.GELU: _gelu_and_mul,
    MoEActivation.GELU_TANH: ( # 新增:GELU_TANH 支持
        lambda x: F.gelu(x[..., : x.shape[-1] // 2], approximate="tanh")
        * x[..., x.shape[-1] // 2 :]
    ),
}

评论区精华

WNA16 测试应添加 CUDA-only 跳过标记 测试

AndreasKaratzas 指出 WNA16 是 CUDA 特定的量化路径,测试应添加 `pytest.mark.skipif(not current_platform.is_cuda())` 以避免在非 CUDA 平台上失败。

结论:作者 lesj0610 采纳建议,在测试函数上添加了 CUDA-only 跳过装饰器。 · 已解决

风险与影响

  • WNA16 断言移除:移除 SiLU 硬断言后,若 fused_experts 不支持的激活被传入,运行时错误将替代早期报错,可能使故障定位更困难。但当前 fused_experts 已具备完整的激活路由能力。
  • C++ kernel 新实现gelu_tanh_and_mul 使用标量 tanh 回退循环,在未充分测试的平台上可能有性能隐忧,但与现有 gelu_and_mul 模式一致。
  • CUTLASS 元数据扩展:FP8/FP4 路径新增激活元数据后,若底层 kernel 实际不支持,将静默选择 fallback 路径,不影响正确性但可能改变性能特征。
  • 用户:使用 GELU_TANH 激活的模型(如 Gemma 4)现在可以在 CPU、CUTLASS (FP8/FP4) 和 WNA16 量化后端上正常推理,不再报错或 crash。
  • 系统:无性能回退预期,测试覆盖率显著提升,统一了各后端的激活支持模式。
  • 团队:降低了维护多后端激活映射的认知负担,后续添加新激活时有可参考的范式。
多后端同步变更 断言移除可能导致运行时错误 新 C++ kernel 未在非 x86 平台验证

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论