Prhub

#54845 [ROCm][Perf] Add low-M FP32 router GEMM for gfx950

原始 PR 作者 Fangzhou-Ai 合并时间 2026-09-04 01:42 文件变更 5 提交数 8 评论 33 代码增减 +499 / -18

执行摘要

为 gfx950 添加专用 FP32 路由器 GEMM Triton 内核,显著降低小 token 批处理延迟。

PR body明确指出,此变更旨在为gfx950上的MoE路由器提供专用的高性能路径,解决现有CUDA内核(如csrc/libtorch_stable/fp32_router_gemm.cu)或通用F.linear在小token批量下的性能不足问题。作者通过引用与#50535(BF16 AITER GEMM)、#52668(中等/大M)等PR的差异,阐明了本PR专注于FP32权重/累加、小M、以及无需外部依赖(AITER)的树内方案,是对现有GPU特定内核的补充。

此PR值得精读,特别是其针对特定硬件和形状的内核设计、与现有分发逻辑的无缝集成方式,以及全面的性能与正确性验证方法。其设计决策(如M为运行时参数、基于形状的启动配置、自定义算子包装以支持动态编译和CUDA图)体现了对vLLM编译和捕获流程的深刻理解,具有借鉴价值。对于关注ROCm性能优化、MoE路由器实现或Triton内核开发的工程师,本PR提供了高质量的参考实现。主要关注点是其硬件特异性和形状硬编码带来的维护性问题,以及分发逻辑的优先级管理。

讨论亮点

核心讨论围绕实现细节和正确性展开。reviewer zhou9402(来自Issue评论)提出了关键设计建议:

  1. 将M从tl.constexpr改为运行时参数以避免不必要的编译。
  2. 使用on_gfx950()替代is_device_capability((9, 5))以匹配代码库惯例。
  3. 建议对非连续输入使用.contiguous()而非回退到F.linear。作者Fangzhou-Ai在00f351e4fe提交中全部采纳并实施。reviewer jeejeelee 质疑了内核中对FP32路由器权重进行类型转换的必要性,作者确认并移除了冗余转换。另一个讨论线程涉及支持的5种形状的具体含义,benenzhu 询问了背景,作者详细解释了每种形状对应的模型(如(6144, 128)是MiniMax-M3,(3072, 256)是MiniMax-M2/M2.5),并说明这是通过审计所有树内FP32 GateLinear消费者得出的。reviewer AndreasKaratzas 和 tjtanaa 对.buildkite/test-amd.yaml中--ignore命令的用法产生疑问,作者澄清了--ignore仅针对test_minimax_reduce_rms.py,而新测试是作为独立的pytest目标添加的,并未被忽略。所有讨论均在合并前得到解决或澄清。

实现拆解

  1. 新增Triton内核:在vllm/model_executor/layers/fused_moe/router/rocm_fp32_router_gemm.py中实现_rocm_fp32_router_gemm_kernel。该内核采用标准的矩阵乘法分块算法(BLOCK_M与BLOCK_K),在循环中累加FP32部分和,最终存储结果。M被设计为运行时参数(非tl.constexpr),以避免对每个num_tokens进行不必要的重编译(最多33次)。内核的启动配置_launch_config基于(hidden_size, num_experts)和num_tokens返回BLOCK_M、BLOCK_K和num_warps,为5种已调优形状提供了针对性的配置。
  2. 扩展GateLinear分发逻辑:修改vllm/model_executor/layers/fused_moe/router/gate_linear.py中的GateLinear类。在__init__中增加对gfx950平台的检测,并基于ROCM_FP32_ROUTER_GEMM_SUPPORTED_SHAPES设置allow_fp32_router_gemm标志。在forward方法的Tier 2分发路径(fp32_router_gemm_dispatch自定义算子)中,针对ROCm平台,将调用重定向到新的rocm_fp32_router_gemm。同时,在fp32_router_gemm_dispatch_impl函数中,对ROCm路径添加了非连续输入的.contiguous()处理,并集成can_use_rocm_fp32_router_gemm进行运行时检查。
  3. 添加全面测试:新增tests/kernels/test_rocm_fp32_router_gemm.py,包含384个测试用例,覆盖所有M(0-32)、激活类型(BF16/FP32)、5种形状、top-k保留、无效输入拒绝、CUDA图输入可变性、自定义算子分发以及动态torch.compile。修改tests/kernels/test_gate_linear_rocm_dispatch.py,添加了针对gfx950上allow_fp32_router_gemm标志启用/禁用条件的平台无关测试,使用monkeypatch模拟on_gfx950()。
  4. 更新CI配置:在.buildkite/test-amd.yaml的MI355 Core Operation Kernels任务中,将新测试文件test_rocm_fp32_router_gemm.py及其源码依赖添加到source_file_dependencies和commands列表中,确保测试在AMD CI上自动运行。
文件 模块 状态 重要度
vllm/model_executor/layers/fused_moe/router/rocm_fp32_router_gemm.py 路由器内核 added 9.11
vllm/model_executor/layers/fused_moe/router/gate_linear.py 路由器分发 modified 7.36
tests/kernels/test_rocm_fp32_router_gemm.py 内核测试 added 8.23
tests/kernels/test_gate_linear_rocm_dispatch.py 分发测试 modified 6.95
.buildkite/test-amd.yaml CI 配置 modified 3.54

关键符号

_rocm_fp32_router_gemm_kernel _launch_config can_use_rocm_fp32_router_gemm _validate_inputs rocm_fp32_router_gemm fp32_router_gemm_dispatch_impl

关键源码片段

vllm/model_executor/layers/fused_moe/router/rocm_fp32_router_gemm.py core-logic

核心变更:包含为 gfx950 优化的 Triton GEMM 内核、启动配置和输入验证逻辑。

# 内核核心逻辑:在循环中累加 FP32 部分和,处理 M 可能不是 BLOCK_M 整数倍的情况
@triton.jit
def _rocm_fp32_router_gemm_kernel(
    hidden_states_ptr,
    router_weight_ptr,
    output_ptr,
    M, # 运行时参数,避免为每个 num_tokens 重编译
    K: tl.constexpr, # 隐藏大小
    N: tl.constexpr, # 专家数量
    BLOCK_M: tl.constexpr, # 由 _launch_config 根据形状和 token 数决定
    BLOCK_K: tl.constexpr,
):
    pid = tl.program_id(0)
    pid_m = pid // N
    pid_n = pid - pid_m * N
    offsets_m = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
    offsets_k = tl.arange(0, BLOCK_K)
    partials = tl.zeros((BLOCK_M, BLOCK_K), dtype=tl.float32) # FP32 累加器
​
    for k_start in range(0, K, BLOCK_K):
        offsets_k_block = k_start + offsets_k
        # 加载隐藏状态,当 offsets_m 超出 M 范围时用 0.0 填充
        hidden_states = tl.load(
            hidden_states_ptr + offsets_m[:, None] * K + offsets_k_block[None, :],
            mask=offsets_m[:, None] < M,
            other=0.0,
        ).to(tl.float32) # 提升到 FP32 进行累加
        router_weight = tl.load(router_weight_ptr + pid_n * K + offsets_k_block)
        partials += hidden_states * router_weight[None, :]
​
    accumulator = tl.sum(partials, axis=1)
    # 写回结果,同样使用掩码处理边界
    tl.store(
        output_ptr + offsets_m * N + pid_n,
        accumulator,
        mask=offsets_m < M,
    )

评论区精华

内核 M 参数设计 设计

reviewer jeejeelee 询问是否需要将 M 设为 tl.constexpr。reviewer zhou9402 在 Issue 中明确建议将 M 作为运行时参数,因为它会导致多达 33 次重编译,而通过掩码和动态 BLOCK_M 选择已能处理可变 M。

结论:采纳建议,将 M 改为运行时参数,避免不必要的 JIT 编译。 · 已解决

gfx950 设备检测方式 style

reviewer zhou9402 建议使用 on_gfx950() 函数而非直接使用 is_device_capability((9, 5)),以匹配代码库其他地方的用法。

结论:采纳建议,统一使用 on_gfx950()。 · 已解决

非连续输入处理 正确性

reviewer zhou9402 指出非连续 x 在 M<=32 时回退到 F.linear,但直接 .contiguous() 更便宜。作者在后续提交中实现了该优化。

结论:在 fp32_router_gemm_dispatch_impl 中为 ROCm 路径添加了 x.contiguous() 处理,并通过测试 monkeypatch F.linear 来证明非连续输入确实走了优化内核。 · 已解决

支持的 5 种形状含义 question

reviewer benenzhu 询问 ROCM_FP32_ROUTER_GEMM_SUPPORTED_SHAPES 中 5 个形状代表的具体模型。

结论:作者逐一解释:(3072, 256) MiniMax-M2/M2.5, (4096, 8) Nemotron-H, (4096, 192) HY-V3/Hunyuan V3, (6144, 128) MiniMax-M3, (6144, 256) GLM-5.2。这些是审计所有树内 FP32 GateLinear 消费者后确定的。 · 已解决

CI 测试是否被忽略 测试

reviewer AndreasKaratzas 和 tjtanaa 对 buildkite 命令中的 --ignore 参数产生疑问,担心新测试被忽略。

结论:作者澄清 --ignore 仅针对 test_minimax_reduce_rms.py,新测试作为独立 pytest 目标添加,并通过 CI 运行结果验证。 · 已解决

风险与影响

技术风险主要集中在硬件特异性和正确性验证上。

  1. 硬件特异性:内核专为gfx950调优(on_gfx950()检查),且形状硬编码在ROCM_FP32_ROUTER_GEMM_SUPPORTED_SHAPES中。风险在于未来新形状或硬件变体出现时,可能需要手动更新支持列表。
  2. 正确性验证:内核的正确性依赖于与F.linear的逐元素对比(ATOL=5e-4)。虽然测试非常全面(384用例),但精度误差(最大绝对误差1.23e-4)在可接受范围内,需确保在端到端模型评估(GSM8K, GPQA Diamond, MMMU-Pro)中不会累积。
  3. 性能回归:分发路径的改变(GateLinear.forward中新增条件分支)理论上可能对非gfx950或超出形状范围的调用引入微小开销,但PR中的性能测试显示MiniMax-M3在gfx950上获得显著提升,且未报告其他平台性能下降。
  4. 与现有PR的互操作:PR body指出与#50535(BF16 AITER)、#52668(大M)互补,但fp32_router_gemm_dispatch_impl中的分发逻辑(先尝试gfx950内核,再回退到F.linear或CUDA内核)需要确保不会因优先级问题导致次优选择。

该PR主要影响使用gfx950硬件运行特定MoE模型(MiniMax-M2/M3, Nemotron-H, HY-V3, GLM-5.2)的用户。

  1. 性能影响:直接影响是路由器计算延迟降低约50%,间接提升端到端推理吞吐量(MiniMax-M3在并发1-32下提升3.15%-8.32%)和每令牌时间(TPOT/ITL降低3.11%-6.77%)。模型评估结果(GSM8K, GPQA Diamond, MMMU-Pro)验证了精度无损。
  2. 系统影响:在vLLM核心的MoE路由器分发逻辑中添加了新的硬件特定分支,增加了代码路径的复杂性,但通过清晰的测试和封装(独立文件、自定义算子)进行了控制。CI配置的更新确保了变更在AMD CI上的持续验证。
  3. 团队影响:为vLLM的ROCm性能优化提供了新的模式(Triton内核+形状特定调优),可为其他gfx950优化(如PR#54916)提供参考。清晰的PR描述和review讨论为后续维护者理解设计决策提供了良好基础。
硬件特异性强 形状硬编码需维护 分发路径新增条件分支

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论