论文: GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers
作者: Elias Frantar, Saleh Ashkboos, Torsten Hoefler, Dan Alistarh
发表: ICLR 2023 | arXiv:2210.17323

一句话总结: GPTQ 证明了二阶补偿式 post-training weight quantization 可以扩展到大模型,让低比特 weight-only 量化从简单取整走向真正可用。

一、为什么 SmoothQuant 之后还需要 GPTQ

LLM.int8() 发现了大模型里的 activation outlier:少数 hidden dimension 会出现稳定且幅度极大的异常值,导致朴素 INT8 量化失效。它的处理方式是把 outlier channel 拆出来,用 FP16 单独计算。

SmoothQuant 则进一步问:能不能不保留 FP16 outlier 分支,而是把 activation 的量化难度迁移到 weight,让主要矩阵乘走更硬件友好的 W8A8 路线?

GPTQ 切入的是另一个问题。

如果 activation 不动,只把 weight 压到 3/4 bit,能不能仍然保持大模型的能力?

这个问题看似简单,但在 GPTQ 之前,答案并不乐观。


二、预备知识:Layer-wise Quantization 与 OBQ

GPTQ 属于 post-training quantization,也就是不重新训练模型,直接把全精度权重压到低比特。理解 GPTQ 之前,最重要的不是先看工程优化,而是先理解它继承的两个思想:layer-wise reconstructionOBQ 的二阶补偿

1. Layer-wise Quantization

原始权重是 ,输入 activation 是 ,原始输出就是:

量化后,权重变成 ,输出变成:

layer-wise quantization 的核心想法是:不直接优化整个模型最终的 loss,而是把模型拆成一层一层处理。对每一层,用少量 calibration data 跑出这一层的输入 ,然后找一个量化后的权重矩阵 ,让它尽可能重构原始层的输出。

写成目标函数就是:

这个式子里, 是量化前后这一层的输出差异。 是 L2 范数,可以理解成误差向量的长度;外面的平方表示把这个长度平方。对于向量来说:

实际线性层通常一次处理多个 token、多个输出维度,所以输出差异更像一个矩阵。更严谨地写,也可以用 Frobenius 范数:

它表示对所有样本、所有输出维度上的误差做平方求和。

这个目标很重要,因为它改变了我们看待量化误差的方式。我们真正关心的不是每个 weight 自己被改了多少,而是这些 weight 在真实输入 上共同产生的输出变了多少。换句话说,weight 的重要性不是孤立的,而是由 activation 分布决定的。

2. 为什么 Hessian 会出现

这里的 Hessian 记作 ,可以先把它理解成一个“敏感度矩阵”:它描述的是 weight 发生扰动后,layer output 的重构误差会变大多少。

对线性层的重构目标:

它的 Hessian 主要由输入 activation 的二阶统计量决定。按照本文 的写法,可以理解成:

论文在介绍 OBQ 时按 row 处理权重,因此记号会写成 。这和本文的写法只是矩阵方向约定不同,核心含义相同: 来自 calibration activation,而不是来自 weight 本身。

它的作用有两个。

第一,衡量某个 weight 量化后会造成多大影响。如果某个方向在 里对应的敏感度高,那么这个方向上的量化误差就更容易放大成输出误差;如果敏感度低,同样大小的取整误差影响就小一些。

第二,描述不同 weight 之间的耦合关系。某个 weight 被量化后产生的误差,可能可以通过调整其他还没量化的 weight 来抵消。这个“该往哪里补偿”的方向,就是通过 Hessian inverse,也就是 来计算的。

所以在 GPTQ/OBQ 里, 用来回答两个实际问题:哪个 weight 量化代价小,以及量化之后应该怎样补偿剩余 weight。

3. RTN:最朴素的量化基线

有了 layer-wise 目标和 Hessian 的概念,再看 RTN 的问题就很清楚了。

RTN,也就是 round-to-nearest,是最直接的 weight quantization 方法。它的思路非常朴素:给定一个量化网格,把每个 weight 独立地映射到最近的量化值。

1
2
3
原始 weight: 0.37
量化格点: 0.00, 0.25, 0.50, 0.75
RTN 结果: 0.25

这在 8-bit 时通常还可以。因为 8-bit 有 256 个状态,量化格点比较密,单个 weight 的误差不大,累积起来也未必立刻毁掉模型。

但到 4-bit,只有 16 个状态;到 3-bit,只有 8 个状态。格点变稀疏后,独立取整的问题就暴露出来了:RTN 只关心每个 weight 自己离哪个格点最近,却不关心整个 layer 的输出会发生什么。

换句话说,RTN 并没有显式优化 layer-wise reconstruction 目标,也没有利用 Hessian inverse 去补偿量化误差。某个 weight 被量化后造成的输出偏差,本来可能通过调整其他还没量化的 weight 抵消,但 RTN 完全没有这个过程。

4. OBQ:量化一个,补偿一批

OBQ,也就是 Optimal Brain Quantization,正是用这个 layer-wise 目标来做逐权重量化。它可以看成 GPTQ 的理论起点。

它的基本思路是:当某个 weight 从 被量化成 时,不要只记录这个误差然后结束,而是立刻调整其他还没量化的 weight,让它们尽量抵消这次量化造成的输出偏差。

直觉上,OBQ 每一步做四件事:

  1. 从还没量化的 weight 里,选择一个当前最适合量化的 weight。
  2. 把它映射到最近的量化格点。
  3. 计算这一步引入的量化误差。
  4. 根据 Hessian inverse,把误差补偿到剩余未量化的 weight 上。

把这个过程写成公式,会更接近论文里的描述。设 是当前还保持全精度的 weight 集合,对应的 Hessian inverse 是 。记 的第 个对角元, 为它的第 列。

OBQ 会先选择量化代价最小的 weight:

然后对剩余 full-precision weights 做补偿更新:

第一个式子回答“下一步量化谁”:不只看取整误差本身,还要看这个误差在 Hessian 意义下的代价。第二个式子回答“量化之后怎么补”:沿着 这个方向更新剩余 weight,把刚产生的量化误差分摊出去,让 layer output 尽量保持不变。

所以 OBQ 和 RTN 的区别非常关键:

1
2
RTN:每个 weight 独立找最近格点。
OBQ:量化一个 weight,再用剩余 weight 补偿它造成的输出误差。

不过,原始 OBQ 的问题也很明显:它会对每一行 weight 独立做贪心量化,每一步还要维护和更新 Hessian inverse。对 ResNet-50 这种 2500 万参数模型,这类方法还能接受;但对 OPT-175B、BLOOM-176B 这种模型,逐权重贪心和频繁矩阵更新完全不可行。

所以 GPTQ 的核心贡献不是从零发明二阶补偿,而是把 OBQ 这套准确但昂贵的方法,改造成能跑在百亿、千亿参数模型上的算法。


三、GPTQ:把 OBQ 改造成大模型可用

有了前面的铺垫,GPTQ 的核心就很好理解了:它不是重新发明一种量化目标,而是保留 OBQ 的二阶补偿思想,同时把原始 OBQ 中最贵、最不稳定的部分改掉。

第一步是放弃逐权重贪心顺序。OBQ 会为每一行 weight 单独选择“当前最适合量化”的位置,这很精细,但代价太高。GPTQ 观察到,在大模型的大矩阵里,固定一个 column 顺序一起量化,效果和贪心顺序差距不大。这样所有 row 可以共享同一套未量化集合和 Hessian inverse 更新,复杂度立刻降下来。

第二步是做 lazy batch update。GPTQ 不在每量化一列之后就立刻更新后面所有 weight,而是按 block 处理,比如一次处理 128 个 columns。块内先完成递归更新,块处理完之后,再把累积误差统一应用到后面的 columns。这样理论目标没变,但矩阵操作更连续,更适合 GPU。

第三步是用更稳定的 Cholesky reformulation。OBQ/GPTQ 都依赖 Hessian inverse,直接反复更新容易积累数值误差。GPTQ 提前用 Cholesky decomposition 计算量化过程中真正需要的信息,并配合轻微 dampening,让算法在几十亿、上百亿参数模型上更稳定。

所以 GPTQ 的本质可以概括成一句话:

保留 OBQ 的二阶误差补偿,但放弃完整 OBQ 的昂贵贪心过程,把它改造成固定顺序、分块更新、数值稳定的大模型量化算法。


四、实验结果与部署意义

实验部分可以抓住三个结论。

第一,GPTQ 只用很少的 calibration data。论文使用 128 个来自 C4 的随机 2048-token 片段,不使用任务特定数据,仍然可以完成 one-shot quantization。

第二,GPTQ 在 175B 级别模型上仍然可运行。OPT-175B 和 BLOOM-176B 的量化都能在几小时内完成,这说明它不是只能用于小模型的精细 PTQ 方法。

第三,精度上 GPTQ 明显优于 RTN。4-bit GPTQ 基本接近 FP16;3-bit 虽然有损失,但仍然保持可用。相反,RTN 在 3-bit 下会直接崩溃,perplexity 会大幅恶化。

部署意义也来自这里:weight-only 低比特量化主要减少权重读取和显存占用。论文中 3-bit OPT-175B 可以放进一张 80GB A100,而 FP16 需要多张 GPU。decode 阶段往往受显存带宽限制,因此少读权重也能带来实际 latency 改善。


五、个人评价:真正的价值不是 4-bit,而是可扩展

GPTQ 的价值在于取舍:它没有追求完整 OBQ 的每一步最优,而是保留最关键的二阶补偿,把剩下的部分改造成 GPU 友好、数值稳定、可以在大模型上跑完的流程。

这也是为什么 GPTQ 到今天仍然有意义。很多后续系统不一定原封不动使用论文里的实现,但它留下了一个清晰判断:weight-only 低比特量化不能只做局部取整,必须考虑量化误差如何影响 layer output。