fix(moe): keep per-token FP8 quant scales finite for tiny activations - #5024
fix(moe): keep per-token FP8 quant scales finite for tiny activations#5024yilin-void wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughThe change replaces single-value FP8 scale computation with residual-aware quantization and dequantization scale pairs. Both fused MoE FP8 paths use the new helper. The Humming regression test verifies finite, nonzero, and numerically accurate output for tiny activations. ChangesFP8 quantization safety
Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: ⚪ Minimal · up to This change preserves recoverable tiny FP8 activation signals in fused-MoE quantization and adds regression coverage for both quantization stages. No concrete current-head merge risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 1 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
0501a31 to
a70bda3
Compare
📌 Description
The CUTLASS fused-MoE per-token FP8 quantization paths currently compute the
E4M3 quantization scale as
448.0f / row_amax. For a positive activation amaxsmaller than
448.0f / FLT_MAX(approximately1.317e-36), that divisionoverflows to infinity. Multiplying the row by the infinite scale can then
produce non-finite FP8 values and poison the entire MoE output row.
Qwen3.5-397B model-level impact
We found this failure while evaluating Qwen3.5-397B-A17B with MXFP4 expert
weights and FP8 activations on 8 GPUs. All results below use the same 1,314
GSM8K examples, 5-shot prompts, raw completion API, and deterministic decoding:
Preventing the overflow recovered 89 answers, or 6.7732 percentage points.
The corrected MXFP4 result was within 3 answers of FP8 and 7 answers of the
calibrated WINT4 run. The remaining MXFP4-vs-WINT4 difference was not
significant in the paired comparison (exact McNemar
p=0.44263).The failure was traced to a routed, effectively dormant expert in layer 5. Its
gate/up and down-projection weights had RMS values around
1e-20, producing apost-SwiGLU row around
1e-38. The subsequent448 / row_amaxoverflowgenerated 4,096 non-finite values, poisoning one complete hidden row. Replaying
that saved row with a finite-scale kernel reduced the non-finite count from
4,096 to zero; the local-MoE output had 1.455% relative RMSE and 0.999894 cosine
similarity against the safe reference.
The full-model
1244 / 1314result above used an earlier kernel-safe guard atthe same two quantization sites that maps the overflowing tiny row to a finite
zero-quantization path. This PR uses a less destructive denominator clamp and
saturates the scale at
FLT_MAX. The focused H200 tests below validate theexact implementation in this PR; the full-model result is included as
model-level evidence for the root cause and the impact of removing the
non-finite path.
This PR:
448.0f / FLT_MAX, guaranteeing a finite quantization scale;GEMM2 input quantization paths; and
Zero rows retain the existing scale of
1.0f, and rows above the overflowthreshold are numerically unchanged. Tiny nonzero rows use the largest finite
FP32 scale, avoiding non-finite values in the downstream MoE computation.
🔍 Related Issues
N/A
🚀 Pull Request Checklist
✅ Pre-commit Checks
ruff checkandruff format --check.git diff --checkpasses.🧪 Tests
test_moe_fp8_mxfp4_humming_tiny_amax_stays_finite— 2 passed(
inputandpost_activation).test_moe_fp8_mxfp4_humming_prescale_hopper_correctness[False-small]—passed.
The new post-activation case has a reference SwiGLU amax of approximately
3.806e-37. With the original division, all 512 output elements are NaN andthe regression test fails. With this patch, the output remains finite and the
test passes.
🔬 Experimental Track
Not applicable; this PR does not add or change an experimental API/backend.
Reviewer Notes
The failure was originally isolated from a dormant expert in a
Qwen3.5-397B-A17B W4A8 run. Its near-zero post-SwiGLU row exercised the same
overflow path reproduced by the focused test in this PR.
Summary by CodeRabbit
Bug Fixes
Tests