跳到主要内容
推理优化

4.3 Weight-only INT4 量化:GPTQ、AWQ 与 Marlin Kernel

用 Hessian 二阶信息逐层重建的 GPTQ,用 1% 重要权重保护思路的 AWQ,以及把 4-bit GEMM 做到近理论极限的 Marlin Kernel

GPTQAWQMarlinINT4W4A16权重量化

上一节解决的是”激活难量化”的问题。但现实中还有另一条性价比极高的路线:干脆不动激活,只把权重压到 4 位(W4A16)。为什么可行?因为 Decode 是 Memory Bound——每生成一个 Token 要把权重全读一遍,权重从 16 位降到 4 位,读取的数据量直接减 4 倍,生成速度理论上翻几倍;而激活是动态计算的,本来就在显存里现算现用,压不压它对 Decode 的带宽压力影响不大。

但”把权重压到 4 位”同样不简单:INT4 只有 16 个格子,最简单的 RTN(四舍五入到最近)量化会让 Llama-7B 的困惑度从 5.68 飙到 7.01。这一节讲两个主流解法——GPTQ(用 Hessian 二阶信息逐层重建,精度天花板最高)和 AWQ(基于”1% 的重要权重”洞察做缩放保护,最鲁棒),以及把它们跑快的 Marlin Kernel

📑 目录


1. 为什么是 W4A16:只看权重不看激活

1.1 Decode 的瓶颈是权重带宽

第 1 章讲过,Decode 每步只算 1 个 Token,权重矩阵读一遍(2P2 \cdot P 字节,PP 是参数量),KV Cache 读一遍。当序列不长时,权重读取占了绝对大头。把权重从 FP16 压到 INT4:

  • 权重读取量从 2P2P 字节降到约 0.5P+scale0.5P + \text{scale} 字节 → Decode 带宽压力减约 4 倍
  • 单卡能装的模型变大 4 倍 → 70B 模型从”必须多卡”变成”单卡可跑”
  • 激活不量化 → 算子简单、数值稳定,不需要 SmoothQuant 那套平滑

1.2 为什么激活不量化也没关系

激活是”现算现用”的:Prefill 时激活在显存里,Decode 时每一步的激活是上一层的输出,不涉及”反复从 HBM 读历史激活”。所以激活保持 FP16/BF16 不影响 Decode 的带宽账。权重是静态的、反复读的,所以先压权重。

📌 关键点:W4A16 的收益几乎全部来自 Decode(带宽),对 Prefill 的加速有限——Prefill 是 Compute Bound,GEMM 里激活还是 16 位,张量核没有翻倍收益。所以”在线服务 Decode 主导 → W4A16 最划算”。


2. 基线 RTN:四舍五入为什么不行

RTN(Round-to-Nearest)是最朴素的 weight-only 量化:算好 scale,把每个权重四舍五入到最近的格子上。它零校准、零优化,直接上线。

对 Llama 系列(INT3-g128,WikiText-2 困惑度,越低越好):

模型FP16RTNGPTQAWQ
Llama-7B5.687.016.536.35
Llama-13B5.095.885.645.52
Llama-30B4.104.884.744.61
Llama-65B3.534.244.213.95

RTN 的误差来源是”每个值独立舍入”:INT4 只有 16 个格子,舍入误差相对值可达 ±3%\pm 3\% 以上,且误差不相关也不可抵消——矩阵乘法是大量误差的累加,但累加的是误差的绝对值。另外,若某组内有 outlier 权重,格子同样被稀释(和激活的问题同源)。

💡 提示:奇怪的是,模型越大,RTN 越接近 GPTQ/AWQ(7B 差 0.7,65B 差 0.3)。原因是模型越大、每层权重冗余越高,个别值的舍入对整体影响越小。这也是为什么超大模型(70B+)有时候直接 RTN 4-bit 也够用。


3. GPTQ:Hessian 驱动的逐层重建

3.1 思想:舍入误差可以被”补偿”

RTN 的假设是每个权重独立舍入、互不相关。但矩阵乘法是线性的:W^X\hat{W}X 的输出误差是权重误差的线性组合。GPTQ 的核心思想是——当某个权重被量化产生误差时,可以调整同层其它未量化权重来补偿这个误差,让”量化后的层输出”尽可能接近”原始层的输出”。

这继承了经典工作 OBS(Optimal Brain Surgeon,最优脑外科手术,原本用于剪枝):用二阶 Hessian 信息衡量”动一个权重对输出的影响”,然后逐个权重做最优补偿。GPTQ 把它从剪枝迁移到量化,并做了三个关键工程优化(分块、懒惰更新、分组更新),把复杂度压到可接受。

3.2 算法骨架

对每个线性层(逐层处理,层内逐列迭代):

  1. 用校准集跑一遍前向,缓存该层输入 XX,计算 Hessian H=XXTH = X X^T
  2. 对权重逐列处理:量化当前列 → 按 Hessian 的逆计算出”对剩余列的补偿量” → 更新剩余列
  3. 组内(如 128 个权重)先更新到寄存器/缓存,攒一批再写回(懒惰批量更新)

一句话:每量化一个权重,就用数学最优的方式修正还没量化的权重,把误差”传递”到后续列里消化掉。

3.3 特点

  • 精度上限最高:INT4-g128 下通常是所有 weight-only 方法里最准的(比 AWQ 略好或相当,模型不同互有胜负)
  • 代价:依赖校准集(通常 128-256 条),量化过程较慢(7B 约几十分钟);对校准集分布敏感,若校准集与线上数据分布差异大,质量会下降
  • 生态:HuggingFace 上最主流的 4-bit 格式,gptq 模型遍地都是;GPTQModel/AutoGPTQ 工具链成熟

4. AWQ:保护 1% 的重要权重

4.1 洞察:权重不是平等的重要

AWQ(Activation-aware Weight Quantization,MIT 韩松团队 2023)从一个观察出发:LLM 里大约只有 0.1%~1% 的权重通道是”重要”的。实验证据(OPT-6.7B,INT3-g128):

方案困惑度(↓)
FP1610.86
RTN(全部量化)23.54
RTN + 1% 重要权重留 FP16(按激活选)11.39

只看这一行还不够——关键是怎么找出这 1%:按激活分布选(那些通道的激活平均值大),而不是按权重绝对值选。按权重绝对值选重要通道的效果和随机选差不多(因为权重分布均匀,谁都一样大)。“激活大 = 通道重要”,因为大激活意味着这些通道在计算中贡献更大。

4.2 方法:不混合精度,用缩放保护

但”1% 留 FP16 + 99% 量化”是混合精度,硬件不友好(和 LLM.int8() 同样的问题)。AWQ 的妙处在于不用混合精度,只用一个缩放技巧

对重要通道的权重乘一个 s>1s > 1(对应的激活除以 ss,保持数学等价),再量化。为什么有效?

  • 舍入误差均匀分布在 ±0.5\pm 0.5 格子,平均 0.25
  • 量化误差的相对值 0.25Δw\approx \frac{0.25 \cdot \Delta}{w}Δ\Delta 是格子大小,ww 是权重大小)
  • ss 后:Δ\Delta 几乎不变(ss 不太大时组内最大值不变),而 ww 变成 wsw \cdot s相对误差缩小为原来的 1/s1/s
  • 激活除以 ss 在 FP16 里是精确的,且 s1s^{-1} 可以融进前一层(与 SmoothQuant 完全相同的”免费融合”套路)

⚠️ 注意ss 不能贪大。s=2s=2 时困惑度从 23.54 降到 11.92(最优);s=4s=4 时 21.2% 的组的格子被撑大,非重要通道的误差反而被放大。核心矛盾是:保护重要通道的同时不能牺牲其余通道。

4.3 自动搜索最优 scale

ss 由每层一个超参数 α\alpha 控制:

s=sXαsW1α,α=argminαQ(Wdiag(s))(diag(s)1X)WX2s = \frac{s_X^{\alpha}}{s_W^{1-\alpha}}, \qquad \alpha^* = \arg\min_{\alpha} \|Q(W \cdot \text{diag}(s)) \cdot (\text{diag}(s)^{-1}X) - WX\|^2
  • sXs_X 是校准集上激活的 per-channel 平均幅度,sWs_W 是权重的 per-channel 相对幅度
  • α[0,1]\alpha \in [0, 1] 做网格搜索(20 个点),最小化”量化后层输出 vs 原始层输出”的 MSE
  • 额外加一步激活感知的权重裁剪(clipping):裁剪范围的选择让重要通道的误差权重更大
  • 全程无反向传播、无 Hessian,只需要校准集上每通道激活的平均值这一个统计量

4.4 特点

  • 鲁棒性极强:只用平均激活幅度这种”粗统计量”,对校准集依赖极小——16 条序列就够,分布偏移时困惑度只波动 0.5-0.6
  • 精度:INT4/INT3 下与 GPTQ 相当,甚至普遍略好(见第 2 节表)
  • 速度:量化过程快(比 GPTQ 快一个量级),TinyChat 框架落地后比 HF FP16 快 3 倍以上
  • 生态:AutoAWQ 工具链 + vLLM 的 awq_marlin kernel,开箱即用

5. GPTQ vs AWQ:一个决策表

📊 维度GPTQAWQ
核心机制Hessian 二阶信息 + 误差补偿重建激活感知的通道缩放 + 裁剪
精度极高(INT4-g128 通常最优)极高(与 GPTQ 相当,部分模型更优)
校准集依赖较敏感(需要代表性数据)极低(16 条即可,分布偏移鲁棒)
量化耗时慢(逐列重建)快(网格搜索)
适用场景对精度要求极致、校准集可控数据分布不确定、快速量产
生态HuggingFace 最广(AutoGPTQ/GPTQModel)vLLM/SGLang 官方深度支持(AutoAWQ)
vLLM 支持--quantization gptq / gptq_marlin--quantization awq / awq_marlin

📌 关键点:两者不是二选一的对立关系,而是”误差来源不同”的两种哲学——GPTQ 消除的是舍入误差的累积(通过补偿),AWQ 消除的是outlier 导致的相对误差放大(通过缩放)。工程上选哪个,主要看校准集的可控性和生态偏好,精度差异通常在可忽略的范围内。


6. Marlin Kernel:把 4-bit GEMM 做到近理论极限

量化算法只解决了”精度”,还有一个问题:W4A16 的 GEMM 怎么算才快? 权重是 4-bit,但张量核要的是 8 位以上的操作数——必须把 4-bit 权重解包、反量化成可计算的形式。如果每次 GEMM 前都先解包成 FP16 再算,解包本身的访存和计算就把收益吃光了。

6.1 Marlin 的思路(arXiv 2402.11792)

Marlin 是 vLLM 团队(Frühwirth-Knudsen 等)2024 年发布的 4-bit GEMM Kernel,核心设计:

  1. 解包进流水线:不预先解包,而是让 Kernel 在搬运权重进张量核之前,用寄存器/共享内存完成”解包 + 反量化”,与 GEMM 计算重叠——访存、解包、计算三条流水并行,谁也不等谁
  2. 数据布局重排:把权重按 Tensor Core 的 tile 结构预打包(2:4 稀疏友好的布局),让解包后的数据直接喂给张量核,避免 bank conflict 和低效访存
  3. 针对 memory-bound 优化:既然瓶颈在显存带宽,Kernel 的目标就是”让 HBM 带宽用满”,计算全程不成为瓶颈

效果:在 A100 上,Marlin 的 INT4-g128 GEMM 吞吐达到 cuBLAS FP16 GEMM 的 90% 以上,而数据量只有四分之一——“每字节的算力产出”是 FP16 的近 4 倍,比此前最好的 kernel(ExLlama v2)快约 1.36 倍。

6.2 为什么它重要

没有 Marlin 这类 kernel,GPTQ/AWQ 的 INT4 模型可能比 FP16 还慢(解包开销>带宽收益)。有了它,4-bit 的收益才真正兑现。vLLM 中:

  • GPTQ 模型默认走 gptq_marlin kernel(Ampere 及以上)
  • AWQ 模型默认走 awq_marlin kernel
  • Marlin 家族后续扩展到 FP8、FP4(MXFP4),vLLM 文档明确列出:Marlin(GPTQ/AWQ/FP8/FP4)在 Ampere/Ada/Hopper 上支持

💡 提示:vLLM 硬件支持表里有一条细节:Marlin 在 Turing(RTX 20 系)上部分可用,但 Turing 不支持 Marlin MXFP4;Volta 则完全不支持 Marlin(只能退回非 Marlin 的 GPTQ/AWQ 实现)。


7. vLLM 生态:GPTQ/AWQ 的工程现状

截至 vLLM v0.26.0(2026 年 7 月),GPTQ/AWQ 在 vLLM 的支持情况:

维度GPTQAWQ
加载格式GPTQModel 量化模型(HuggingFace 上最常见)AutoAWQ 量化模型
推荐启动参数--quantization gptq_marlin--quantization awq_marlin
硬件Volta~Hopper(Marlin 需 Ampere+)Turing~Hopper(Marlin 需 Ampere+)
量化工具GPTQModel / AutoGPTQ / llm-compressorAutoAWQ / llm-compressor
兼容的 kernelgptq、gptq_marlinawq、awq_marlin、cpu_awq
  • llm-compressor 新入口:vLLM 官方推荐的 llm-compressor 也能产出 GPTQ/AWQ 格式(INT4 W4A16 章节),与 vLLM 的兼容性经过官方验证
  • 量化模型加载是零配置的:模型目录里带 quantization_config 时,vLLM 会自动识别格式并选择对应实现,--quantization 更多是显式指定
  • MoE 模型:GPTQ/AWQ 对 MoE(如 Mixtral、DeepSeek-V3 类)的专家权重同样支持,vLLM 有专门的 Fused MoE 量化路径

📝 总结

  • W4A16 的动机:Decode 是 Memory Bound,权重砍 4 倍带宽压力减 4 倍;激活动态计算、无需压
  • RTN 不够:INT4 格子太粗,独立舍入误差无法抵消(Llama-7B 困惑度 5.68→7.01)
  • GPTQ:Hessian 二阶信息 + 逐层误差补偿重建,精度天花板最高,校准集敏感
  • AWQ:激活感知找出 1% 重要通道,per-channel 缩放保护(相对误差减 1/s),无 Hessian、最鲁棒
  • Marlin:解包/反量化进流水线 + 布局重排,4-bit GEMM 吞吐接近 cuBLAS FP16 水平,把理论收益兑现
  • 工程现状:GPTQ/AWQ 是 HuggingFace 与 vLLM 生态事实标准,Marlin 默认 kernel,llm-compressor 可统一产出

🎯 自我检验清单

  • 为什么 W4A16 对 Decode 有效而对 Prefill 提升有限?
  • RTN 的误差为什么不能靠”平均化”抵消?
  • GPTQ 的误差补偿为什么需要 Hessian?
  • AWQ 为什么按激活分布而不是权重分布找重要通道?
  • AWQ 的缩放为什么能减小重要通道的相对误差?s 为什么不能太大?
  • Marlin 如何避免”解包开销吃掉带宽收益”?
  • vLLM 里 gptq 和 gptq_marlin 的区别?

📚 参考资料