Prhub

#34505 [Diffusion][MiniMax H3] Extend exact QKNorm+RoPE rounding to SM103

原始 PR 作者 BBuf 合并时间 2026-08-12 16:25 文件变更 1 提交数 1 评论 1 代码增减 +6 / -5

执行摘要

SM103 启用精确 QKNorm+RoPE 舍入修复

PR body 说明:The exact QKNorm+RoPE path added for SM120 also needs the explicit BF16 rounding helpers on B300 (SM103)。没有这些 helper 时,nvcc 会 contracts/promotes 打包的 rotary 表达式,使融合结果与 split BF16 QKNorm + RoPE 参考实现相差 1 ULP。也就是说,SM120 引入的位精确舍入路径在 B300(SM103)上同样必要,否则融合内核与 split 参考实现存在 1 ULP 数值偏差。

值得快速浏览(约 10 分钟)。这是 #34347 的后续补丁,展示了跨 GPU 架构维护 bit-exact 数值语义的典型做法:用条件编译精确枚举受影响架构,而不是对所有架构开启精确路径。若要深入学习,可结合 test_qknorm_rope_preserves_split_bf16_rounding 理解 split 参考与融合实现的舍入差异。

讨论亮点

该 PR 没有 review 评论和讨论线程。唯一的评论是作者 BBuf 的 CI 操作指令 /tag-and-rerun-ci,用于重新标记并触发测试。准确性结论(B300 上 torch.equal 通过、无保护时测试失败)均由作者在 PR body 中自测陈述,未出现 reviewer 的质疑或设计权衡争论;PR Test (Extra) 当前显示失败状态,但评论中未记录失败原因。

实现拆解

  1. 定位改动点:确认 python/sglang/kernels/jit/csrc/diffusion/qknorm_rope.cuh 中三个 SGL_DEVICE 内联函数 rotary_mul_rnrotary_addrotary_sub 的精确 BF16 舍入分支原先只在 __CUDA_ARCH__ >= 1200 时编译。
  2. 扩展条件编译:三处 #if 条件统一改为 __CUDA_ARCH__ == 1030 || __CUDA_ARCH__ >= 1200,使 SM103(B300)也进入位级 round-to-nearest 路径;SM120+ 行为保持不变,非 Blackwell 仍走默认融合乘加路径。
  3. 同步注释:rotary_add 上方的说明从 "on SM120" 更新为 "on Blackwell SM103/SM120",让后续维护者理解 nvcc 收缩问题适用的架构范围。
  4. 验证配套:未新增测试文件,复用既有 test_qknorm_rope_preserves_split_bf16_rounding,在 B300 上以 torch.equal 同时校验 Q、K;并在生产形状 (7936, 56, 128)、rope dim 96、BF16 下给出性能对比(166.10us vs 166.55us,约 0.3% 噪声),确认无性能回归。
  5. 影响面:仅影响 SM103 平台编译该 JIT 内核时的数值路径,kernel launch 配置、非 Blackwell 代码路径均未触碰。
文件 模块 状态 重要度
python/sglang/kernels/jit/csrc/diffusion/qknorm_rope.cuh JIT 内核 modified 3.59

关键符号

rotary_mul_rn rotary_add rotary_sub

关键源码片段

python/sglang/kernels/jit/csrc/diffusion/qknorm_rope.cuh core-logic

唯一变更文件:三个 rotary 辅助函数(rotary_mul_rn、rotary_add、rotary_sub)的精确 BF16 舍入分支通过条件编译扩展覆盖 SM103(B300),修复融合结果与 split 参考实现相差 1 ULP 的问题。

// 文件:python/sglang/kernels/jit/csrc/diffusion/qknorm_rope.cuh
// 本次变更:把精确 BF16 舍入辅助逻辑的启用范围从仅 SM120+ 扩展到 SM103(B300)。
// 背景:nvcc 在 Blackwell 上可能收缩打包的 rotary 表达式,导致融合结果与
// split BF16 QKNorm + RoPE 参考实现相差 1 ULP。template <typename T>
SGL_DEVICE T rotary_mul_rn(T lhs, T rhs) {
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ == 1030 || __CUDA_ARCH__ >= 1200)
  // 精确路径:按 BF16 位模式分别对乘积做 round-to-nearest 舍入,
  // 确保与 split 参考实现的语义一致。
  uint16_t lhs_bits;
  uint16_t rhs_bits;
  if constexpr (std::is_same_v<T, bf16_t>) {
    // ... 位级乘法与舍入原实现,本次仅放宽架构条件
  }
#endif
  // 其他架构仍走默认融合乘加路径,函数体未改动
}template <typename T>
SGL_DEVICE T rotary_add(T x, T cos, T y, T sin) {
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ == 1030 || __CUDA_ARCH__ >= 1200)
  // nvcc 可能在 SM103/SM120 收缩打包表达式:
  // 先对两个乘积分别做精确 BF16 舍入,再逐位相加。
  const T lhs = rotary_mul_rn(x, cos);
  const T rhs = rotary_mul_rn(y, sin);
  uint16_t lhs_bits;
  // ... 位级加法与舍入原实现,本次仅更新注释与 guard
#endif
  // 默认路径:直接 fused 乘加
}template <typename T>
SGL_DEVICE T rotary_sub(T x, T cos, T y, T sin) {
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ == 1030 || __CUDA_ARCH__ >= 1200)
  const T lhs = rotary_mul_rn(x, cos);
  const T rhs = rotary_mul_rn(y, sin);
  uint16_t lhs_bits;
  // ... 位级减法与舍入原实现,guard 与 rotary_add 同步扩展
#endif
}

(说明:函数体内部位操作属于 SM120 时期既有实现,本次 diff 未涉及,故以注释占位。)

评论区精华

CI 重跑请求 other

作者 BBuf 在评论区发送 `/tag-and-rerun-ci`,请求为 PR 重新标记并触发 CI 运行。

结论:PR Test (Base) 处于进行中状态,Extra CI 显示失败,未在评论中记录失败原因。 · closed

风险与影响

1) 条件编译覆盖范围窄:guard 精确写为 __CUDA_ARCH__ == 1030 || __CUDA_ARCH__ >= 1200,若后续出现同样受 nvcc 收缩影响的其它 Blackwell 变体(如 SM100/SM110),需要再次显式补充,存在可维护性成本。
2) 该改动依赖 nvcc 的代码收缩行为,不同 CUDA 版本行为可能有差异;但由于精确路径只是显式复现 split 舍入语义,最坏情况是回到未启用状态,不会引入新的错误。
3) 测试依赖 B300 实物,常规 CI(非 B300 runner)可能无法覆盖;当前 PR Test (Extra) 显示失败状态,需确认是否与硬件依赖或环境有关。
4) 性能风险低:实测 166.10us vs 166.55us,差异为测量噪声,无实质回归。

对用户:B300(SM103)上运行 MiniMax H3(以及复用 qknorm_rope.cuh 的 Diffusion 模型)时,QKNorm+RoPE 融合结果与 split BF16 参考实现 bit-exact 对齐,消除 1 ULP 偏差;性能不变。对系统:仅影响 JIT kernel 头文件的编译期分支,不影响运行时基础设施、调度或内存管理。对团队:确立了 Blackwell 各架构(SM103 与 SM120+)数值精度策略的一致性;后续新增架构时需注意同步该 guard。

平台条件编译覆盖窄 B300 硬件测试依赖 位精确性回归风险低 单文件低风险改动

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论