量化-02-OBQ

NOTE

因为GPTQ是基于OBQ改进的,所以我们这里先讲OBQ算法

OBQ算法

OBQ (Optimal Brain Quantization) 是在大模型量化领域非常经典的一种 PTQ(训练后量化)方法。它的核心思想源自于神经网络剪枝领域的 OBS (Optimal Brain Surgeon)。

OBQ 的底层哲学非常直观:当我们把某一个全精度权重压缩成低比特(引入了量化误差)时,我们可以通过调整同一层中其他尚未量化的权重,来“补偿”这个误差,从而使得最终输出的特征图(Feature Map)尽可能保持不变。

我们从目标函数开始一步步推导。


第一步:定义目标函数与 Hessian 矩阵

在逐层量化(Layer-wise Quantization)中,我们的目标是让量化后的权重矩阵 产生的输出,尽可能逼近原始权重矩阵 的输出。假设输入激活值为 ,目标函数为最小化输出的平方误差:

因为在线性层中,权重矩阵的不同行(对应不同的输出通道)的计算是彼此独立的,我们可以将问题拆解为独立优化每一行。对于权重矩阵的某一行 ,它的误差函数可以写为:

我们将误差对权重的二阶导数(Hessian 矩阵)记为 。在这个二次型中,Hessian 矩阵是一个常数矩阵:

此时,我们的目标函数可以化简为标准的二次型形式:

其中 是权重发生的变化。


第二步:带约束的优化问题(引入拉格朗日乘子)

现在我们要量化第 个权重 ,使其变为

由于量化,第 个权重发生了固定的变化,误差为

此时的问题变成了:在给定第 个权重变化量为 的约束下,如何调整整个权重向量 (对未量化权重的更新),使得整体误差 最小?

我们引入指示向量 (第 个元素为 1,其余为 0)。约束条件可以写为:

使用拉格朗日乘数法构建目标函数


第三步:求解最优权重更新公式(核心推导)

求偏导并令其为 0:

左乘 ,解出

这就是说,最优的权重更新方向与 Hessian 逆矩阵的第 列成正比。接下来我们需要求出 。将上式代入我们的约束条件

注意 提取出的刚好是 对角线上的第 个元素,记作 。于是:

代回 的公式中,得到最优权重更新公式

(物理意义:当前 量化引入了 的误差,我们通过 的第 列按比例将其分摊给其他所有的权重。)


第四步:计算当前权重的量化敏感度(Saliency)

OBQ 是一个贪心算法,它需要决定先量化哪一个权重对整体误差影响最小

我们将求得的最优 代回原始的误差公式

因为 Hessian 及其逆矩阵是对称的,,所以:

将求得的 代入,得到误差(敏感度)公式

(物理意义:误差大小不仅取决于量化前后的绝对差值平方,还与该权重在 Hessian 逆矩阵对角线上的值成反比。)


第五步:Hessian 逆矩阵的更新(避免重复求逆)

当第 个权重被量化固定后,它就不再参与后续的补偿更新了。这意味着在下一步中,我们需要在剩下的维度上求解。

幸运的是,我们不需要对剩下的 矩阵重新求逆。利用高斯消元(或矩阵分块求逆的性质),可以用 的复杂度直接更新当前的逆矩阵:

这一步在代码中通常表示为从 中去除第 行和第 列的影响。


完整计算流程总结

对于权重矩阵的一行 (长度为 ):

  1. 初始化:传入校准数据集,计算

  2. 求逆:对 Hessian 矩阵加上一个极小的阻尼项(防止奇异)并求逆:

  3. 循环量化(执行 次):

    • (a) 贪心选择:遍历所有尚未量化的权重 ,计算其量化误差 。找出令 最小的索引
    • (b) 执行量化:将 量化为
    • (c) 补偿更新:计算误差 ,对所有剩下未量化的权重执行更新:
    • (d) 矩阵更新:使用高斯消元公式更新 ,去除第 个维度的影响。

复杂度分析与工程痛点

假设权重矩阵的大小是

  1. 计算初始 Hessian 逆矩阵:需要
  2. 贪心选择与更新:每次选择需要 ,更新权重需要 ,更新 Hessian 逆矩阵需要 。因为要量化 个权重,所以这一步的复杂度是
  3. 最致命的问题(Row-wise 依赖):由于 OBQ 是贪心选择,每一行权重的数值不同,导致每一行选出来的量化顺序完全不同。这意味着你不能在 个通道之间共享 Hessian 逆矩阵的更新过程。你必须为每一行维护一个单独的 并独立进行上述循环。

最终总复杂度

在实际的大模型推理基建(如部署支持大规模并行计算的 sglang, TensorRT-LLM 架构)中,当我们面对像 Qwen 这样规模的模型,比如 ,哪怕是一个线性层, 的复杂度也是无法忍受的(校准阶段耗时按天计算)。

这正是为什么后来会诞生 GPTQ——它对 OBQ 做了巧妙的近似,从而大幅降低了复杂度。GPTQ 破除这种行依赖,将复杂度降到