Prhub

#26786 [GPTQ] Refactor CPU quantization schemes

原始 PR 作者 Alisehen 合并时间 2026-06-08 18:14 文件变更 13 提交数 17 评论 12 代码增减 +348 / -278

执行摘要

重构 GPTQ CPU 量化方案,拆分内核与 scheme 并迁移目录

PR旨在使GPTQ量化方案的代码组织与已有的AWQ方案对齐,保持平台特定内核在后端初始化而非包导入时加载,消除重复配置,便于维护和扩展。

该 PR 是量化模块归档重构的典型范例,值得量化子系统开发人员精读。重点关注 _init_kernel 工厂模式如何实现平台解耦,以及如何在保持现有 API 不变的情况下重组目录。后续新增 CPU 量化方案应遵循 hardware_backend/cpu/quantization 放内核、layers/quantization/<algo>/schemes 放 scheme 的约定。

讨论亮点

代码审查中,gemini-code-assist[bot] 提出了关于属性初始化的建议,要求在 AWQIntelAMXMoEKernelGPTQMoEMarlinKernel__init__ 中预先初始化 moe_runner_configkernel_config 等属性为 None,以防范 AttributeError;同时在 GPTQAscendLinearScheme.create_weights 中建议立即检查 NPU 对 desc_act 的支持以尽早失败。作者随后提交了修改确认。合并后,yanbing-j 发现本PR误删了 Xeon 平台已有的 MXFP4 配置(来自 #16775),作者承认失误,该配置通过 #27782 恢复。

实现拆解

实现过程分为以下步骤:

  1. 创建CPU AMX内核模块:在 hardware_backend/cpu/quantization/ 下新建 gptq_kernels.pyawq_kernels.py,将先前内联在scheme中的 process_weights_after_loadingapply 逻辑提取为独立的Kernel类(例如 GPTQIntelAMXLinearKernelGPTQIntelAMXMoEKernel)。
  2. 搬迁GPTQ CPU scheme:将旧顶层文件 layers/quantization/gptq_cpu.py(含 CPUGPTQConfigGPTQLinearIntelAMXMethod)移动至 layers/quantization/gptq/schemes/gptq_cpu.py,改造为继承 GPTQLinearSchemeGPTQIntelAMXLinearScheme,通过 _init_kernel 工厂方法创建对应的Kernel实例。
  3. 主配置类调整:在 gptq.py 中新增 CPUGPTQConfig 子类,统一处理CPU场景的scheme分发;同时将原有的 GPTQMoEAscendMethodGPTQLinearAscendMethod 分别泛化为 GPTQMoEMethodGPTQLinearMethod,消除平台紧耦合。
  4. AWQ CPU scheme对称清理:将 awq_cpu.py 中内联的 AWQIntelAMXLinearKernelAWQIntelAMXMoEKernel 定义移至 awq_kernels.py,scheme文件只保留对内核的引用和 _init_kernel 工厂。
  5. 更新导出与导入路径:调整所有相关 __init__.py 的导出,并修复 gptq_marlin.pyawq_marlin.py 等文件的内核初始化方式,统一采用 _init_kernel 延迟加载模式。
  6. 测试与配置配套:本次改动不直接包含测试文件,但需确保现有CI(标签 run-ci)通过;后续发现MXFP4配置被误删,已通过 #27782 修复。
文件 模块 状态 重要度
python/sglang/srt/layers/quantization/gptq/schemes/gptq_cpu.py 量化层 renamed 8.84
python/sglang/srt/hardware_backend/cpu/quantization/gptq_kernels.py 硬件后端 added 8.6
python/sglang/srt/hardware_backend/cpu/quantization/awq_kernels.py 硬件后端 added 8.6
python/sglang/srt/layers/quantization/gptq/gptq.py 量化层 modified 7.49
python/sglang/srt/layers/quantization/awq/schemes/awq_cpu.py 量化层 modified 7.79

关键符号

CPUGPTQConfig.get_quant_method GPTQIntelAMXLinearScheme._init_kernel GPTQIntelAMXLinearScheme.create_weights GPTQIntelAMXLinearKernel.process_weights_after_loading GPTQIntelAMXLinearKernel.apply AWQIntelAMXLinearKernel.process_weights_after_loading AWQIntelAMXLinearKernel.apply _check_cpu_amx_support

关键源码片段

python/sglang/srt/layers/quantization/gptq/schemes/gptq_cpu.py rename-or-move

核心搬迁文件,将 GPTQ CPU scheme 从旧顶层模块迁移到 schemes 子目录,并重构为继承 GPTQLinearScheme 的模式,通过 _init_kernel 工厂获取内核实例。

# SPDX-License-Identifier: Apache-2.0
from __future__ import annotationsfrom typing import TYPE_CHECKINGimport torch# 从硬件后端导入内核类,而非内联定义
from sglang.srt.hardware_backend.cpu.quantization.gptq_kernels import (
    GPTQIntelAMXLinearKernel,
    GPTQIntelAMXMoEKernel,
)
from sglang.srt.layers.linear import set_weight_attrs
from sglang.srt.layers.moe import MoeRunnerConfig
from sglang.srt.layers.parameter import (
    ChannelQuantScaleParameter,
    GroupQuantScaleParameter,
    PackedColumnParameter,
    PackedvLLMParameter,
    RowvLLMParameter,
)from .gptq_linear import GPTQLinearScheme
from .gptq_scheme import GPTQMoESchemeBaseif TYPE_CHECKING:
    from sglang.srt.layers.moe.token_dispatcher import StandardDispatchOutput
    from sglang.srt.layers.quantization.gptq.gptq import GPTQConfig__all__ = ["GPTQIntelAMXLinearScheme", "GPTQIntelAMXMoEScheme"]
​
​
def _check_cpu_amx_support(quant_config: "GPTQConfig") -> None:
    # 验证当前量化配置在 CPU AMX 上的限制
    if quant_config.desc_act and not (
        quant_config.true_sequential and quant_config.static_groups
    ):
        raise ValueError(
            "Currently, desc_act (True) is only supported with sequential "
            "and static group on CPU with AMX."
        )
    if quant_config.weight_bits != 4:
        raise ValueError("Currently, only 4bits is supported on CPU with AMX.")
    if quant_config.checkpoint_format == "gptq_v2":
        raise ValueError("Currently, gptq_v2 is not supported on CPU with AMX.")
​
​
class GPTQIntelAMXLinearScheme(GPTQLinearScheme):
    """Linear scheme for GPTQ on Intel CPU with AMX."""
​
    def _init_kernel(self, quant_config: "GPTQConfig"):
        # 工厂方法:返回平台特定的内核实例
        return GPTQIntelAMXLinearKernel(quant_config)
​
    def create_weights(
        self,
        layer: torch.nn.Module,
        input_size_per_partition: int,
        output_partition_sizes: list[int],
        input_size: int,
        params_dtype: torch.dtype,
        weight_loader,
        **kwargs,
    ):
        # 先进行前置校验,尽早失败
        _check_cpu_amx_support(self.quant_config)
​
        if input_size_per_partition % self.quant_config.group_size != 0:
            raise ValueError(
                "The input size is not aligned with the quantized "
                "weight shape. This can be caused by too large "
                "tensor parallel size."
            )
        # ... 后续权重参数创建逻辑
python/sglang/srt/hardware_backend/cpu/quantization/gptq_kernels.py core-logic

新创建的 GPTQ CPU 内核类,封装权重处理和 INT4 矩阵乘法,实现与 scheme 的解耦。

# SPDX-License-Identifier: Apache-2.0
from __future__ import annotationsfrom typing import TYPE_CHECKING, Optionalimport torchfrom sglang.srt.layers.amx_utils import (
    CPUQuantMethod,
    _amx_process_weight_after_loading,
)
from sglang.srt.layers.moe import MoeRunnerConfigif TYPE_CHECKING:
    from sglang.srt.layers.moe.token_dispatcher import StandardDispatchOutput
    from sglang.srt.layers.quantization.gptq.gptq import GPTQConfig__all__ = ["GPTQIntelAMXLinearKernel", "GPTQIntelAMXMoEKernel"]
​
​
class GPTQIntelAMXLinearKernel:
    def __init__(self, quant_config: "GPTQConfig"):
        # 保存量化配置,供后续初始化使用
        self.quant_config = quant_config
​
    def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
        # 对加载后的权重进行 AMX 格式转换(重排、转置等)
        _amx_process_weight_after_loading(
            layer, ["qweight", "qzeros", "scales"], None, "gptq"
        )
        # 将转换后的权重封装为不可训练参数,节省显存
        layer.qweight = torch.nn.Parameter(layer.qweight.data, requires_grad=False)
        layer.qzeros = torch.nn.Parameter(layer.qzeros.data, requires_grad=False)
        layer.scales = torch.nn.Parameter(layer.scales.data, requires_grad=False)
​
    def apply(
        self,
        layer: torch.nn.Module,
        x: torch.Tensor,
        bias: Optional[torch.Tensor] = None,
    ) -> torch.Tensor:
        # 调用底层 CPU INT4 量化矩阵乘法算子
        return torch.ops.sgl_kernel.int4_scaled_mm_cpu(
            x,
            layer.qweight,
            layer.qzeros,
            layer.scales,
            bias,
        )

评论区精华

内核类属性初始化与 NPU desc_act 早期检查建议 正确性

gemini-code-assist[bot] 建议在 AWQIntelAMXMoEKernel 和 GPTQMoEMarlinKernel 的 __init__ 中预先初始化 moe_runner_config、kernel_config 等属性为 None,防止 AttributeError;同时在 GPTQAscendLinearScheme.create_weights 中提前检查 NPU 对 desc_act 的支持以尽早失败。

结论:作者已按要求修正对应文件并提交。 · 已解决

MXFP4 配置被误删 正确性

合并后 yanbing-j 指出本 PR 删除了 Xeon 平台此前已支持的 MXFP4 配置(#16775),作者承认是误删。

结论:通过后续 PR #27782 恢复该配置。 · 已解决

风险与影响

  1. 导入路径变更:大量文件涉及 __init__.py 和模块引用更新,存在遗漏或错误导致运行时 ImportError 的风险。
  2. MXFP4配置误删:已通过随后的 #27782 修复,但仍提醒需要对该类重构进行更全面的配置覆盖检查。
  3. 属性未初始化:尽管反馈已处理,若其他类似代码未遵循同样模式仍可能触发 AttributeError
  4. 回归风险:CPU AMX 量化路径在 CI 中的测试覆盖可能不足,需注意是否通过全部测试。

影响范围集中在 CPU Intel AMX 量化路径,包括 GPTQ 和 AWQ 的 Linear 和 MoE 层。重构后代码结构更清晰,方便未来增加新的 CPU 量化方案。对 GPU 和 NPU 后端无直接影响(仅调整了导入时机和类名泛化)。团队需确保所有平台开发者知晓新的目录约定。

MXFP4 配置误删 导入路径变更 属性初始化遗漏

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论