Prhub

#44514 Deprecate old FP8 online MoE quantization class

原始 PR 作者 yma11 合并时间 2026-06-24 02:53 文件变更 3 提交数 2 评论 14 代码增减 +19 / -137

执行摘要

废弃旧 FP8 Online MoE 量化类,统一到新前端

旧的 FP8 online quantization 类 (Fp8OnlineLinearMethod 和 Fp8OnlineMoEMethod) 可以被新的 online quantization frontend 替代,因此予以废弃以减少维护负担。

建议阅读该 PR 以了解 FP8 online quantization 的演进方向,特别是新前端 Fp8PerTensorOnlineMoEMethod 的设计。对于量化代码维护者,此变更值得精读。

讨论亮点

Review 中的主要讨论点:

  • AndreasKaratzas 询问 test_fp8.py 中 is_cuda() 是否需要改为 is_cuda_alike(),divakar-amd 确认 ROCm 分支不受影响,当前写法正确。
  • divakar-amd 发现 tests/quantization/utils.py 中意外添加了 return True,yma11 承认是本地更改不应提交,后续已从 commits 中移除。
  • yewentao256 询问 base_loader.py 中增加 XPU 条件的原因,yma11 解释为了在 XPU 设备通过 test_fp8.py。
  • 最终由 yewentao256 和 mgoin 审批通过。

实现拆解

实现分三步:

  1. 核心量化文件 (fp8.py)
    • 在 Fp8Config.get_quant_method 中,将 RoutedExperts 且非 checkpoint FP8 序列化的分支从创建 Fp8OnlineMoEMethod 改为创建 Fp8PerTensorOnlineMoEMethod (来自 online/fp8.py)。
    • 删除整个 Fp8OnlineMoEMethod 类 (含 init, create_weights, process_weights_after_loading 等方法) 及其相关导入 (_custom_ops, initialize_online_processing)。
  2. 模型加载器 (base_loader.py)
    • 在 load_model 中,将峰值 GPU 内存记录的条件从 current_platform.is_cuda_alike() 扩展为 current_platform.is_cuda_alike() or current_platform.is_xpu(),使 XPU 设备也可记录峰值内存,确保 test_fp8.py 在该平台上通过。
  3. 测试文件 (test_fp8.py)
    • 新增导入 MarlinFP8ScaledMMLinearKernel。
    • 调整 force_marlin 参数化:CUDA 上同时测试 True 和 False,非 CUDA 平台保持 False。
    • 将 is_cuda() 判断改为 is_cuda() or is_xpu(),并增加对 fc1.quant_method.fp8_linear 类型的断言,验证是否使用 Marlin 内核。
文件 模块 状态 重要度
vllm/model_executor/layers/quantization/fp8.py 量化层 modified 8.95
vllm/model_executor/model_loader/base_loader.py 模型加载 modified 5.17
tests/quantization/test_fp8.py FP8 测试 modified 4.95

关键符号

Fp8Config.get_quant_method Fp8OnlineMoEMethod.__init__ Fp8OnlineMoEMethod.create_weights Fp8OnlineMoEMethod.process_weights_after_loading BaseModelLoader.load_model test_online_quantization check_model

关键源码片段

vllm/model_executor/layers/quantization/fp8.py data-contract

核心变更文件:删除废弃的 Fp8OnlineMoEMethod 类,修改 get_quant_method 分发逻辑,清理导入依赖。

# vllm/model_executor/layers/quantization/fp8.py# 在 Fp8Config.get_quant_method() 中处理 RoutedExperts 的分支:
elif isinstance(layer, RoutedExperts):
    if is_layer_skipped(prefix, self.ignored_layers, self.packed_modules_mapping):
        return UnquantizedFusedMoEMethod(layer.moe_config)
    if self.store_dtype == 'mxfp4':
        from vllm.model_executor.layers.quantization.mxfp4 import Mxfp4MoEMethod
        return Mxfp4MoEMethod(layer.moe_config)
    if self.is_checkpoint_fp8_serialized:
        return Fp8MoEMethod(self, layer)
    else:
        # 使用新的 online quantization frontend 替代废弃的 Fp8OnlineMoEMethod
        from vllm.model_executor.layers.quantization.online.fp8 import (
            Fp8PerTensorOnlineMoEMethod,
        )
        return Fp8PerTensorOnlineMoEMethod(layer=layer)# 同时移除了整个 Fp8OnlineMoEMethod 类 ( 约 130 行 ),该类继承自 Fp8MoEMethod,
# 用于在线量化 ( 非 checkpoint FP8 序列化 ),现在由 Fp8PerTensorOnlineMoEMethod 替代。
tests/quantization/test_fp8.py test-coverage

更新测试以匹配新的量化类,增强断言覆盖。

# tests/quantization/test_fp8.py# 在 test_online_quantization 的 check_model 函数中:
def check_model(model):
    fc1 = model.model.decoder.layers[0].fc1
    assert isinstance(fc1.quant_method, Fp8PerTensorOnlineLinearMethod)
    if kv_cache_dtype == 'fp8':
        attn = model.model.decoder.layers[0].self_attn.attn
        assert isinstance(attn.quant_method, Fp8KVCacheMethod)
        assert attn._k_scale == 1.0
        assert attn._v_scale == 1.0
​
    if current_platform.is_cuda() or current_platform.is_xpu():
        if current_platform.supports_fp8() and not force_marlin:
            # 支持 FP8 硬件的 GPU,权重保持 fp8 格式
            assert fc1.weight.dtype == torch.float8_e4m3fn
            assert not isinstance(
                fc1.quant_method.fp8_linear, MarlinFP8ScaledMMLinearKernel
            )
        else:
            # 无原生 FP8 支持时,使用 Marlin 内核打包权重
            assert fc1.weight.dtype == torch.int32
            assert isinstance(
                fc1.quant_method.fp8_linear, MarlinFP8ScaledMMLinearKernel
            )
    elif current_platform.is_rocm():
        # ROCm 分支不变 ( 略 )
        ...

评论区精华

test_fp8.py 中 is_cuda() 是否应改为 is_cuda_alike() question

AndreasKaratzas 询问 divakar-amd 是否需要将 is_cuda() 替换为 is_cuda_alike() 以涵盖更多平台。

结论:divakar-amd 确认 ROCm 分支不受影响,当前写法正确,无需修改。 · 已解决

tests/quantization/utils.py 意外添加 return True 正确性

divakar-amd 发现 utils.py 中意外多了一行 return True,询问意图。

结论:yma11 承认是本地修改不应包含在 PR 中,随后从提交中移除。 · 已解决

base_loader.py 添加 XPU 条件的原因 设计

yewentao256 询问为什么需要在 is_cuda_alike() 基础上增加 is_xpu()。

结论:yma11 解释这是为了让 test_fp8.py 在 XPU 设备上通过,需要记录峰值内存。 · 已解决

风险与影响

主要风险:新替代类 Fp8PerTensorOnlineMoEMethod 的行为需与旧类完全一致,否则可能影响在线量化结果。测试覆盖了基本生成和线上量化断言,但未覆盖所有带 bias 的 MoE 模型 (如 GPT-OSS),存在兼容性隐患。另外,XPU 条件放宽可能使非 CUDA/non-XPU 设备错误地执行峰值记录 (但危害低)。

对用户:使用 quantization="fp8" 加载非 FP8 checkpoint 的 MoE 模型将自动使用新前端量化,预期功能不变。对系统:删除旧类减少代码量,统一量化前端,利于维护。对团队:量化模块架构更清晰。

废弃类可能被外部代码引用 新替代类行为未在所有模型上验证 XPU 条件放宽潜在副作用

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论