4.3 Weight-only INT4 量化:GPTQ、AWQ 与 Marlin Kernel
用 Hessian 二阶信息逐层重建的 GPTQ,用 1% 重要权重保护思路的 AWQ,以及把 4-bit GEMM 做到近理论极限的 Marlin Kernel
上一节解决的是”激活难量化”的问题。但现实中还有另一条性价比极高的路线:干脆不动激活,只把权重压到 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:只看权重不看激活
- 2. 基线 RTN:四舍五入为什么不行
- 3. GPTQ:Hessian 驱动的逐层重建
- 4. AWQ:保护 1% 的重要权重
- 5. GPTQ vs AWQ:一个决策表
- 6. Marlin Kernel:把 4-bit GEMM 做到近理论极限
- 7. vLLM 生态:GPTQ/AWQ 的工程现状
- 总结
- 自我检验清单
- 参考资料
1. 为什么是 W4A16:只看权重不看激活
1.1 Decode 的瓶颈是权重带宽
第 1 章讲过,Decode 每步只算 1 个 Token,权重矩阵读一遍( 字节, 是参数量),KV Cache 读一遍。当序列不长时,权重读取占了绝对大头。把权重从 FP16 压到 INT4:
- 权重读取量从 字节降到约 字节 → 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 困惑度,越低越好):
| 模型 | FP16 | RTN | GPTQ | AWQ |
|---|---|---|---|---|
| Llama-7B | 5.68 | 7.01 | 6.53 | 6.35 |
| Llama-13B | 5.09 | 5.88 | 5.64 | 5.52 |
| Llama-30B | 4.10 | 4.88 | 4.74 | 4.61 |
| Llama-65B | 3.53 | 4.24 | 4.21 | 3.95 |
RTN 的误差来源是”每个值独立舍入”:INT4 只有 16 个格子,舍入误差相对值可达 以上,且误差不相关也不可抵消——矩阵乘法是大量误差的累加,但累加的是误差的绝对值。另外,若某组内有 outlier 权重,格子同样被稀释(和激活的问题同源)。
💡 提示:奇怪的是,模型越大,RTN 越接近 GPTQ/AWQ(7B 差 0.7,65B 差 0.3)。原因是模型越大、每层权重冗余越高,个别值的舍入对整体影响越小。这也是为什么超大模型(70B+)有时候直接 RTN 4-bit 也够用。
3. GPTQ:Hessian 驱动的逐层重建
3.1 思想:舍入误差可以被”补偿”
RTN 的假设是每个权重独立舍入、互不相关。但矩阵乘法是线性的: 的输出误差是权重误差的线性组合。GPTQ 的核心思想是——当某个权重被量化产生误差时,可以调整同层其它未量化权重来补偿这个误差,让”量化后的层输出”尽可能接近”原始层的输出”。
这继承了经典工作 OBS(Optimal Brain Surgeon,最优脑外科手术,原本用于剪枝):用二阶 Hessian 信息衡量”动一个权重对输出的影响”,然后逐个权重做最优补偿。GPTQ 把它从剪枝迁移到量化,并做了三个关键工程优化(分块、懒惰更新、分组更新),把复杂度压到可接受。
3.2 算法骨架
对每个线性层(逐层处理,层内逐列迭代):
- 用校准集跑一遍前向,缓存该层输入 ,计算 Hessian
- 对权重逐列处理:量化当前列 → 按 Hessian 的逆计算出”对剩余列的补偿量” → 更新剩余列
- 组内(如 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):
| 方案 | 困惑度(↓) |
|---|---|
| FP16 | 10.86 |
| RTN(全部量化) | 23.54 |
| RTN + 1% 重要权重留 FP16(按激活选) | 11.39 |
只看这一行还不够——关键是怎么找出这 1%:按激活分布选(那些通道的激活平均值大),而不是按权重绝对值选。按权重绝对值选重要通道的效果和随机选差不多(因为权重分布均匀,谁都一样大)。“激活大 = 通道重要”,因为大激活意味着这些通道在计算中贡献更大。
4.2 方法:不混合精度,用缩放保护
但”1% 留 FP16 + 99% 量化”是混合精度,硬件不友好(和 LLM.int8() 同样的问题)。AWQ 的妙处在于不用混合精度,只用一个缩放技巧:
对重要通道的权重乘一个 (对应的激活除以 ,保持数学等价),再量化。为什么有效?
- 舍入误差均匀分布在 格子,平均 0.25
- 量化误差的相对值 ( 是格子大小, 是权重大小)
- 乘 后: 几乎不变( 不太大时组内最大值不变),而 变成 → 相对误差缩小为原来的
- 激活除以 在 FP16 里是精确的,且 可以融进前一层(与 SmoothQuant 完全相同的”免费融合”套路)
⚠️ 注意: 不能贪大。 时困惑度从 23.54 降到 11.92(最优); 时 21.2% 的组的格子被撑大,非重要通道的误差反而被放大。核心矛盾是:保护重要通道的同时不能牺牲其余通道。
4.3 自动搜索最优 scale
由每层一个超参数 控制:
- 是校准集上激活的 per-channel 平均幅度, 是权重的 per-channel 相对幅度
- 对 做网格搜索(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:一个决策表
| 📊 维度 | GPTQ | AWQ |
|---|---|---|
| 核心机制 | 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,核心设计:
- 解包进流水线:不预先解包,而是让 Kernel 在搬运权重进张量核之前,用寄存器/共享内存完成”解包 + 反量化”,与 GEMM 计算重叠——访存、解包、计算三条流水并行,谁也不等谁
- 数据布局重排:把权重按 Tensor Core 的 tile 结构预打包(2:4 稀疏友好的布局),让解包后的数据直接喂给张量核,避免 bank conflict 和低效访存
- 针对 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_marlinkernel(Ampere 及以上) - AWQ 模型默认走
awq_marlinkernel - 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 的支持情况:
| 维度 | GPTQ | AWQ |
|---|---|---|
| 加载格式 | GPTQModel 量化模型(HuggingFace 上最常见) | AutoAWQ 量化模型 |
| 推荐启动参数 | --quantization gptq_marlin | --quantization awq_marlin |
| 硬件 | Volta~Hopper(Marlin 需 Ampere+) | Turing~Hopper(Marlin 需 Ampere+) |
| 量化工具 | GPTQModel / AutoGPTQ / llm-compressor | AutoAWQ / llm-compressor |
| 兼容的 kernel | gptq、gptq_marlin | awq、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 的区别?
📚 参考资料
- Frantar et al., GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers(https://arxiv.org/abs/2210.17323)
- Lin et al., AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration(https://arxiv.org/abs/2306.00978)
- Frantar et al., Marlin: A Fast 4-bit Inference Kernel for LLMs(https://arxiv.org/abs/2402.11792)
- vLLM 文档:AutoAWQ(https://docs.vllm.ai/en/latest/features/quantization/auto_awq/)
- vLLM 文档:GPTQModel(https://docs.vllm.ai/en/latest/features/quantization/gptqmodel/)
- vLLM 文档:LLM Compressor INT4 W4A16(https://docs.vllm.ai/en/latest/features/quantization/llm_compressor/int4/)