Prhub

#48330 [Bugfix] Guard mixed-dtype allreduce RMSNorm quant fusions

原始 PR 作者 hugo-cen 合并时间 2026-07-12 17:39 文件变更 2 提交数 4 评论 2 代码增减 +44 / -3

执行摘要

修复混合精度类型下 AllReduce RMSNorm 量化融合导致输出损坏

修复 Issue #48324:FlashInfer 融合的 allreduce + residual RMSNorm + 量化在 FP32 norm 权重下产生损坏输出。用户报告 nvidia/Qwen3.6-27B-NVFP4 模型在 TP=4 且使用 FlashInfer TRT-LLM allreduce 后端时,输出为重复的 !!!!!!!!!!!!!!!!。根本原因是激活(BF16)与 RMSNorm 权重(FP32 因 weight.float() + 1.0 计算)的 dtype 不匹配,导致量化融合模式错误匹配。

值得精读,特别是对 vLLM 图融合模式注册机制感兴趣的开发者。展示了如何通过 extra_check 参数在模式匹配中增加细粒度约束,以及回归测试如何覆盖混合精度场景。

讨论亮点

审核者 ZJY0516 对 PR 描述中的一句话提出疑问:“对于不兼容的混合 dtype 图,vLLM 仍然可用的 specialized fused allreduce + Gemma RMSNorm 路径”具体指什么。作者 hugo-cen 解释:在 mixed-dtype 情况下,融合会回退到 allreduce -> rms_norm(weight) 融合(即不包含量化),量化作为单独 pass 执行。但需要注意的是,如果量化权重也混合 dtype,则可能仍然需要更细粒度的控制。审核后 ZJY0516 批准了 PR。

实现拆解

  1. 定位问题:在 vllm/compilation/passes/fusion/allreduce_rms_fusion.py 中,发现 AllReduceFusedAddRMSNormStaticQuantFP8PatternAllReduceFusedAddRMSNormStaticQuantNVFP4Pattern 两个 residual 量化融合模式在注册时缺少 extra_check=_norm_input_weight_dtype_match 参数,而普通量化模式和普通 residual RMSNorm 模式已经应用了该检查。

  2. 修改模式注册:在两个模式的 pm.register_replacement 调用中添加 extra_check=_norm_input_weight_dtype_match。该函数检查 rms_norm 的输入(激活)和权重的 dtype 是否匹配,如果不匹配则阻止融合。对于不匹配的图,vLLM 仍然使用融合的 allreduce + Gemma RMSNorm 路径(weight_bias=1.0),然后单独执行量化,避免完全禁用融合。

  3. 添加回归测试:在 tests/compile/passes/distributed/test_fusion_all_reduce.py 中新增 TestAllReduceGemmaRMSNormStaticQuantFP8Model 类,继承自 TestAllReduceRMSNormStaticQuantFP8Model,使用 GemmaRMSNorm 并将 dtype 设为 float16(模拟混合精度场景)。测试验证在混合 dtype 下不安全的量化融合被拒绝,且最终融合算子为 flashinfer_trtllm_fused_allreduce_norm

  4. 调整测试参数化:在 all_reduce_fusion_pass_on_test_model 函数中更新条件,使新模型类正确触发融合算子存在性检查。

文件 模块 状态 重要度
vllm/compilation/passes/fusion/allreduce_rms_fusion.py 编译优化 modified 6.43
tests/compile/passes/distributed/test_fusion_all_reduce.py 测试 modified 6.61

关键符号

_norm_input_weight_dtype_match

关键源码片段

vllm/compilation/passes/fusion/allreduce_rms_fusion.py core-logic

核心源码修改,为两个残余量化融合模式(FP8 和 NVFP4)添加 dtype 匹配检查,是修复的关键

# 在 AllReduceFusedAddRMSNormStaticQuantFP8Pattern 中,
# 注册模式时添加 extra_check 防止混合 dtype 的错误融合
pm.register_replacement(
    pattern,
    replacement,
    self.get_inputs(),
    pm.fwd_only,
    pm_pass,
    extra_check=_norm_input_weight_dtype_match, # 新增:检查输入与权重 dtype 是否匹配
)# AllReduceFusedAddRMSNormStaticQuantNVFP4Pattern 同理
pm.register_replacement(
    pattern,
    replacement,
    self.get_inputs(),
    pm.fwd_only,
    pm_pass,
    extra_check=_norm_input_weight_dtype_match, # 新增
)
tests/compile/passes/distributed/test_fusion_all_reduce.py test-coverage

新增回归测试模型和参数化用例,覆盖混合 dtype 场景,验证修复效果

class TestAllReduceGemmaRMSNormStaticQuantFP8Model(
    TestAllReduceRMSNormStaticQuantFP8Model
):
    # 模拟混合 dtype 场景:激活 float16,但 GemmaRMSNorm 权重为 float32
    def __init__(
        self,
        hidden_size=16,
        token_num=16,
        eps=1e-6,
        dtype: torch.dtype = torch.float16, # 注意:使用 float16 而非 bf16
    ):
        super().__init__(hidden_size, token_num, eps, dtype)
        # 使用 GemmaRMSNorm,其内部有 weight.float() + 1.0 操作
        self.norm = [GemmaRMSNorm(hidden_size, eps) for _ in range(4)]
        for norm in self.norm:
            norm.weight.requires_grad_(False)
​
    def ops_in_model_before(self):
        # 不包含 static_scaled_fp8_quant,因为混合 dtype 下不应触发量化融合
        return [torch.ops.vllm.all_reduce.default]

评论区精华

混合 dtype 下的融合回退行为 正确性

ZJY0516 提问:修复后 all-reduce RMSNorm 融合是否仍然应用?

结论:作者确认:对于混合 dtype 情况,融合回退到 allreduce + RMSNorm(不包含量化),量化作为单独 pass 执行。同一 dtype 模型保持完整的全融合路径。 · 已解决

风险与影响

低风险。改动仅在两处模式注册中添加了已有的检查函数,且该函数在其他路径中已被验证。性能测试显示无退化,甚至在高并发下略有提升。主要风险在于:如果未来新增类似模式,开发者可能忘记添加该检查,但通过 review 可以缓解。

直接影响使用 Qwen/Gemma 风格 RMSNorm 且激活与权重 dtype 不一致的模型(如 nvidia/Qwen3.6-27B-NVFP4),修复了输出损坏问题。对同一 dtype 的模型无影响,保持完整融合性能。范围限于 Tensor Parallel 且使用 FlashInfer TRT-LLM allreduce 后端的场景。

核心路径变更 混合精度兼容性

关联 Issue

#48324 [Bug]: FlashInfer fused allreduce + residual RMSNorm + quant produces corrupted output with FP32 norm weights

完整报告

参与讨论