大模型量化:GPTQ与AWQ
0 前言
前面在介绍QLoRA的时候,我们介绍了 NF4 和 LLM.int8() 量化,这两种量化方式是比较常用的大模型在线量化方式,对于离线量化,目前比较常用的是 GPTQ 和 AWQ。当然,我个人做过对比实现,发现 GPTQ 和 AWQ 效果都不好容易导致模型智商下降,但面试的时候又经常被问到,因此在此对这两种量化方式做个详细的介绍。本文涉及到了比较多的数学推导,读者最好知道多元函数的泰勒泰勒展开、运筹优化的标准数学表达式和 L2 范数的含义,其他像拉格朗日乘数、Cholesky 分解。
本文主要参考了知乎博主杨远航的文章QLoRA、GPTQ:模型量化概述。
1 GPTQ 的基础
1.1 海森矩阵
定义
海森矩阵(Hessian Matrix)是一个描述多元函数局部曲率性质的二阶偏导数方阵,由德国数学家路德维希·奥托·赫斯(Ludwig Otto Hesse)于19世纪提出,因此得名。它在优化、图像处理、机器学习等领域有广泛应用。以下从数学形式、性质和应用场景展开说明:
对于一个 n 元实值函数 f ( w 1 , w 2 , … , w n ) f(w_1, w_2, \ldots, w_n) f(w1,w2,…,wn),若其二阶偏导数均存在,其海森矩阵 H ( f ) \mathbf{H}(f) H(f) 是一个 n×n 的对称矩阵,定义为:
H ( f ) = [ ∂ 2 f ∂ w 1 2 ∂ 2 f ∂ w 1 ∂ w 2 ⋯ ∂ 2 f ∂ w 1 ∂ w n ∂ 2 f ∂ w 2 ∂ w 1 ∂ 2 f ∂ w 2 2 ⋯ ∂ 2 f ∂ w 2 ∂ w n ⋮ ⋮ ⋱ ⋮ ∂ 2 f ∂ w n ∂ w 1 ∂ 2 f ∂ w n ∂ w 2 ⋯ ∂ 2 f ∂ w n 2 ] \mathbf{H}(f) = \begin{bmatrix} \frac{\partial^2 f}{\partial w_1^2} & \frac{\partial^2 f}{\partial w_1 \partial w_2} & \cdots & \frac{\partial^2 f}{\partial w_1 \partial w_n} \\ \frac{\partial^2 f}{\partial w_2 \partial w_1} & \frac{\partial^2 f}{\partial w_2^2} & \cdots & \frac{\partial^2 f}{\partial w_2 \partial w_n} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{\partial^2 f}{\partial w_n \partial w_1} & \frac{\partial^2 f}{\partial w_n \partial w_2} & \cdots & \frac{\partial^2 f}{\partial w_n^2} \end{bmatrix} H(f)= ∂w12∂2f∂w2∂w1∂2f⋮∂wn∂w1∂2f∂w1∂w2∂2f∂w22∂2f⋮∂wn∂w2∂2f⋯⋯⋱⋯∂w1∂wn∂2f∂w2∂wn∂2f⋮∂wn2∂2f
关键点:
- 矩阵元素为函数对变量两两组合的二阶偏导数 ∂ 2 f ∂ w i ∂ w j \frac{\partial^2 f}{\partial w_i \partial w_j} ∂wi∂wj∂2f;
- 若函数二阶连续可导,则矩阵对称 ( ∂ 2 f ∂ w i ∂ w j = ∂ 2 f ∂ w j ∂ w i (\frac{\partial^2 f}{\partial w_i \partial w_j} = \frac{\partial^2 f}{\partial w_j \partial w_i} (∂wi∂wj∂2f=∂wj∂wi∂2f)。
核心性质
-
对称性:
当函数二阶偏导数连续时,海森矩阵是对称矩阵,混合偏导数与求导顺序无关。 -
与泰勒展开的关系:
函数在点 w 0 \mathbf{w}_0 w0 处的二阶泰勒展开为:f ( w ) ≈ f ( w 0 ) + ∇ f ( w 0 ) T ( w − w 0 ) + 1 2 ( w − w 0 ) T H ( f ) ( w 0 ) ( w − w 0 ) f(\mathbf{w}) \approx f(\mathbf{w}_0) + \nabla f(\mathbf{w}_0)^T (\mathbf{w} - \mathbf{w}_0) + \frac{1}{2} (\mathbf{w} - \mathbf{w}_0)^T \mathbf{H}(f)(\mathbf{w}_0) (\mathbf{w} - \mathbf{w}_0) f(w)≈f(w0)+∇f(w0)T(w−w0)+21(w−w0)TH(f)(w0)(w−w0)
其中 H ( f ) \mathbf{H}(f) H(f) 决定了函数的局部曲率(凸性/凹性)。 -
极值判定(了解即可,不重要):
在梯度 ∇ f = 0 \nabla f = 0 ∇f=0 的临界点 w 0 \mathbf{w}_0 w0 处:- 若 H \mathbf{H} H 正定(所有特征值 > 0)→ 局部极小值;
- 若 H \mathbf{H} H 负定(所有特征值 < 0)→ 局部极大值;
- 若 H \mathbf{H} H 不定(特征值有正有负)→ 鞍点(非极值)。
1.2 OBD(Optimal Brain Damage)算法原理
这是发表于1990年的关于神经网络的剪枝算法,关于模型剪枝,实际上就是去掉神经网络中的一些不重要的连接,表现在权重矩阵上,就是把矩阵中的一些元素改成0。剪枝最大的挑战在于,你不知道哪些连接该剪,哪些不该剪。这需要有一套规则来进行判断,不同的剪枝算法,对应的判断规则不一样。
OBD算法则是通过泰勒展开近似替代原始模型,进而计算各个参数对目标函数(损失函数)的影响,以此来判断剪枝的优先级。
先假设模型的输入数据是固定的,E 表示损失函数,那么 E = f ( w 1 , w 2 , … , w n ) E=f(w_1, w_2, \ldots, w_n) E=f(w1,w2,…,wn), Δ E \Delta E ΔE 表示参数变化( Δ w \Delta \mathbf w Δw)给损失函数带来影响,则有:
Δ E = f ( w 1 + Δ w 1 , w 2 + Δ w 2 , … , w n + Δ w n ) − f ( w 1 , w 2 , … , w n ) = f ( w 1 , w 2 , … , w n ) + ∑ i g i Δ w i + 1 2 ∑ i h i i Δ w i 2 + 1 2 ∑ i ≠ j h i j Δ w i Δ w j + O ( Δ w 3 ) − f ( w 1 , w 2 , … , w n ) = ∑ i g i Δ w i + 1 2 ∑ i h i i Δ w i 2 + 1 2 ∑ i ≠ j h i j Δ w i Δ w j + O ( Δ w 3 ) \begin{align*} \Delta E &= f(w_1+\Delta w_1, w_2+\Delta w_2, \ldots, w_n+\Delta w_n) - f(w_1, w_2, \ldots, w_n) \\ &= f(w_1, w_2, \ldots, w_n) + \sum_{i} g_{i} \Delta w_{i} + \frac{1}{2} \sum_{i} h_{ii} \Delta w_{i}^{2} + \frac{1}{2} \sum_{i \neq j} h_{ij} \Delta w_{i} \Delta w_{j} + O\left( \Delta \mathbf{w}^{3} \right) - f(w_1, w_2, \ldots, w_n) \\ &= \sum_{i} g_{i} \Delta w_{i} + \frac{1}{2} \sum_{i} h_{ii} \Delta w_{i}^{2} + \frac{1}{2} \sum_{i \neq j} h_{ij} \Delta w_{i} \Delta w_{j} + O\left( \Delta \mathbf{w}^{3} \right) \end{align*} ΔE=f(w1+Δw1,w2+Δw2,…,wn+Δwn)−f(w1,w2,…,wn)=f(w1,w2,…,wn)+i∑giΔwi+21i∑hiiΔwi2+21i=j∑hijΔwiΔwj+O(Δw3)−f(w1,w2,…,wn)=i∑giΔwi+21i∑hiiΔwi2+21i=j∑hijΔwiΔwj+O(Δw3)
式中加黑部分表示向量,此外:
- g i = ∂ E ∂ w i g_{i} = \dfrac{\partial E}{\partial w_{i}} gi=∂wi∂E 为参数的一阶偏导
- h i j = ∂ 2 E ∂ w i ∂ w j h_{ij} = \dfrac{\partial^{2} E}{\partial w_{i} \partial w_{j}} hij=∂wi∂wj∂2E 为海森矩阵的元素
- h i i h_{ii} hii 为对角线元素
OBD 简化假设:
- 假设目标函数是二阶的,因此忽略高阶项 O ( Δ w 3 ) O(\Delta \mathbf w^{3}) O(Δw3)
- 模型训练充分收敛,所有参数一阶偏导为零: g i = 0 , ∀ i g_{i} = 0,\quad \forall i gi=0,∀i
- 假设删除任意一个参数后,其他参数对目标函数的影响不变。也就是说,每个参数对目标函数的影响是独立的。于是我们也可以不考虑交叉项:: h i j = 0 , ∀ i , j , i ≠ j h_{ij} = 0,\quad \forall i,j,\ i \neq j hij=0,∀i,j, i=j
基于上述假设,公式可简化为:
Δ
E
=
1
2
∑
i
h
i
i
Δ
w
i
2
\Delta E = \frac{1}{2} \sum_{i} h_{ii} \Delta w_{i}^{2}
ΔE=21i∑hiiΔwi2
若将神经网络中参数 w i w_i wi 对应的连接删除,即令 Δ w i = − w i \Delta w_i = -w_i Δwi=−wi,其他参数不变,则对目标函数的影响为: Δ E = 1 2 h i i w i 2 \Delta E = \frac{1}{2} h_{ii} w_{i}^{2} ΔE=21hiiwi2
剪枝次序确定:
通过计算参数对应的海森矩阵对角元素: h i i = ∂ 2 E ∂ w i 2 h_{ii} = \dfrac{\partial^{2} E}{\partial w_{i}^{2}} hii=∂wi2∂2E,可以按照下面的方式确定剪枝的优先级:
- 按 h i i w i 2 h_{ii} w_{i}^{2} hiiwi2 值升序排序
- 优先删除影响最小的参数。
1.3 OBS(Optimal Brain Surgeon)算法原理
(1)基本原理与首次剪枝
OBS 认为,参数之间的独立性不成立,因为真实模型无法用数学表达式表达出来,上面的泰勒展开式只是近似,我们还是要考虑交叉项,因此有:
Δ
E
=
1
2
∑
i
h
i
i
Δ
w
i
2
+
1
2
∑
i
≠
j
h
i
j
Δ
w
i
Δ
w
j
=
1
2
Δ
w
T
H
Δ
w
\Delta E = \frac{1}{2} \sum_{i} h_{ii} \Delta w_{i}^{2}+\frac{1}{2} \sum_{i \neq j} h_{ij} \Delta w_{i} \Delta w_{j} = \frac{1}{2} \Delta \mathbf{w}^{\mathrm{T}} \mathbf{H} \Delta \mathbf{w}
ΔE=21i∑hiiΔwi2+21i=j∑hijΔwiΔwj=21ΔwTHΔw
式中加黑部分表示向量或者矩阵。
现在我们假设删除一个权重后,可以调整其他权重参数,来抵消剪枝带来的影响。
若删除权重
w
q
w_q
wq,即
Δ
w
\Delta \mathbf{w}
Δw 的第
q
q
q 维固定为
−
w
q
-w_q
−wq,但其他维度的值可变,用以抵消剪枝带来的影响,那么此时可以得到一个约束条件:
e
q
T
⋅
Δ
w
+
w
q
=
0
\mathbf{e}_{\mathbf{q}}^{\mathbf{T}} \cdot \Delta \mathbf{w} + w_{q} = 0
eqT⋅Δw+wq=0
其中, e q \mathbf{e}_{\mathbf{q}} eq 为 one-hot 向量,第 q q q 个分量为 1,其他分量为 0。
接下来要寻找最优的权重索引 q q q,使得将 w \mathbf{w} w 的第 q q q 个维度置零后,通过调整其他权重 Δ w i \Delta w_i Δwi( i ≠ q i \neq q i=q),使剪枝给损失函数 E E E 带来的影响最小。当然,这个听起来有点绕,说得浅显一点就是,先预判每个权重删除+系统补偿后的最小损失变化,然后选择影响最小的权重(假设索引为 q) 优先剪枝,以此模型压缩中的性能-精简度最优平衡。
寻找 q q q 的过程,可以表示为一个最优化问题:
min Δ w , q 1 2 Δ w T H Δ w subject to e q T ⋅ Δ w + w q = 0 \min _{\Delta \mathbf{w}, q} \frac{1}{2} \Delta \mathbf{w}^{\mathrm{T}} \mathbf{H} \Delta \mathbf{w} \\ \quad \text{subject to} \quad \mathbf{e}_{q}^{\mathrm{T}} \cdot \Delta \mathbf{w} + w_{q} = 0 Δw,qmin21ΔwTHΔwsubject toeqT⋅Δw+wq=0
学过运筹学的同学对上面的表达式会比较熟悉,这是一个凸优化问题,可以通过 Lagrange 乘数法求解。
定义函数:
L
=
1
2
Δ
w
T
H
Δ
w
+
λ
(
e
q
T
⋅
Δ
w
+
w
q
)
L = \frac{1}{2} \Delta \mathbf{w}^{\mathrm{T}} \mathbf{H} \Delta \mathbf{w} + \lambda \left( \mathbf{e}_{q}^{\mathrm{T}} \cdot \Delta \mathbf{w} + w_{q} \right)
L=21ΔwTHΔw+λ(eqT⋅Δw+wq)
优化结果为:
Δ
w
=
−
w
q
[
H
−
1
]
q
q
H
−
1
⋅
e
q
and
L
=
1
2
w
q
2
[
H
−
1
]
q
q
\Delta \mathbf{w} = -\frac{w_{q}}{ \left[ \mathbf{H}^{-1} \right]_{qq} } \mathbf{H}^{-1} \cdot \mathbf{e}_{q} \quad \text{and} \quad L = \frac{1}{2} \frac{w_{q}^{2}}{ \left[ \mathbf{H}^{-1} \right]_{qq} }
Δw=−[H−1]qqwqH−1⋅eqandL=21[H−1]qqwq2
上式中, H − 1 \mathbf{H}^{-1} H−1 表示海森矩阵的逆矩阵, [ H − 1 ] q q [\mathbf{H}^{-1} ]_{qq} [H−1]qq 表示逆矩阵的第 q q q 行第 q q q 列。这部分涉及运筹学知识,不需要掌握,只需要知道优化结果的表达式即可。
从最后的优化结果来看,我们只需要求解海森矩阵的逆,就可以计算每个参数对目标的影响 L q = 1 2 w q 2 [ H − 1 ] q q L_q = \frac{1}{2} \frac{w_{q}^{2}}{ \left[ \mathbf{H}^{-1} \right]_{qq} } Lq=21[H−1]qqwq2。
剪枝的时候,可以先按照影响从小到大给参数排序,然后删除影响最小的权重 w q w_q wq,最后更新其他参数以补偿剪枝带来的影响(只有补偿后,影响才能降到 1 2 w q 2 [ H − 1 ] q q \frac{1}{2} \frac{w_{q}^{2}}{ \left[ \mathbf{H}^{-1} \right]_{qq} } 21[H−1]qqwq2),其他参数更新的公式为: w new = w + Δ w \mathbf{w}_{\text{new}} = \mathbf{w} + \Delta \mathbf{w} wnew=w+Δw。
(2)迭代剪枝
删除完第一个参数后,如果想继续剪枝,需要更新
H
−
1
\mathbf{H}^{-1}
H−1,更新的公式如下:
H
new
−
1
=
H
−
1
−
H
−
1
e
q
e
q
⊤
H
−
1
[
H
−
1
]
q
q
\mathbf{H}_{\text{new}}^{-1} = \mathbf{H}^{-1} - \frac{\mathbf{H}^{-1} \mathbf{e}_q \mathbf{e}_q^{\top} \mathbf{H}^{-1}}{\left[\mathbf{H}^{-1}\right]_{qq}}
Hnew−1=H−1−[H−1]qqH−1eqeq⊤H−1
随后使用更新后的
H
−
1
\mathbf{H}^{-1}
H−1 进行下一轮剪枝。
在OBS的算法流程中,过程可以总结为以下几步:
- 初始化:训练收敛后,计算全局 H − 1 \mathbf{H}^{-1} H−1(仅需一次)。
- 迭代剪枝:
- 计算每个权重的显著性(saliency) L q = 1 2 w q 2 [ H − 1 ] q q L_q = \frac{1}{2} \frac{w_{q}^{2}}{ \left[ \mathbf{H}^{-1} \right]_{qq} } Lq=21[H−1]qqwq2。
- 删除显著性最小的权重 w q w_q wq,即在参数向量 w \mathbf{w} w 中,把第 q 维置0。
- 增量更新 H − 1 \mathbf{H}^{-1} H−1 和剩余权重(使用公式 w new = w + Δ w \mathbf{w}_{\text{new}} = \mathbf{w} + \Delta \mathbf{w} wnew=w+Δw)。
- 重复:直接使用更新后的 H − 1 \mathbf{H}^{-1} H−1 进行下一轮剪枝,无需重算。
(3)何时更新 H \mathbf{H} H 和 H − 1 \mathbf{H}^{-1} H−1
上面在迭代剪枝的时候,没有重复计算海森矩阵及其逆矩阵,那什么时候需要重新计算呢?在以下两种情况下可能需要完全重算:
- 跨层剪枝:当剪枝涉及不同层时,参数间的相关性可能因层结构变化而改变,此时需为每层独立计算 H \mathbf{H} H 和 H − 1 \mathbf{H}^{-1} H−1(如L-OBS方法)
- 数值稳定性问题:增量更新可能因舍入误差累积导致数值不稳定,此时可定期(如每剪枝100个权重)重新计算 H \mathbf{H} H 和 H − 1 \mathbf{H}^{-1} H−1,以重置误差。
(4)剪枝效果对比:OBS VS OBD
在LeNet5上的剪枝实验表明:
- 使用优化补偿法(OBS):精度损失仅 0.8%
- 使用简单指定法(OBD):精度损失达 2.3%
- 差异来源:关联参数未能主动补偿
1.4 OBC(Optimal Brain Compression)算法原理
OBD 和 OBS 都存在一个缺点,就是剪枝需要计算全参数的海森矩阵(及其它的逆矩阵)。但在动辄上亿参数的神经网络下求解海森矩阵显然不可能。于是,我们可以假设参数矩阵的同一行参数互相之间是相关的,而不同行之间的参数互不相关,这样就只需要在每一行内单独计算海森矩阵就行了。
假如模型的参数是一个 3×3 的矩阵,每一行都有3个参数。在 OBD 或 OBS 中是统一计算模型的全部参数的海森矩阵,这将是一个 9×9 的矩阵,而在 OBC 中,则是对其的每一行计算海森矩阵,那么每个海森矩阵都是一个 3×3 的矩阵,这样的矩阵有3个,示意图如下:
参数矩阵定义与目标函数
假设参数矩阵的维度为 ( d row d_{\text{row}} drow, d col d_{\text{col}} dcol),OBC 论文中,将目标函数定义为:
E = ∑ i = 1 d row ∥ W i , : X − W ^ i , : X ∥ 2 2 E = \sum_{i = 1}^{d_{\text{row}}} \| \mathbf{W}_{i,:} \mathbf{X} - \hat{\mathbf{W}}_{i,:} \mathbf{X} \|_{2}^{2} E=i=1∑drow∥Wi,:X−W^i,:X∥22
- W i , : \mathbf{W}_{i,:} Wi,::原始参数矩阵的第 i i i 行向量
- W ^ i , : \hat{\mathbf{W}}_{i,:} W^i,::压缩(剪枝或量化)后的参数矩阵第 i i i 行向量,如果第 q q q 个参数被剪枝,则对应位置置为0
- X \mathbf{X} X:输入特征矩阵(隐含定义)
- ∥ ⋅ ∥ 2 \| \cdot \|_2 ∥⋅∥2: L 2 L_2 L2 范数(欧几里得范数)
注意,这里 E 不再是损失函数了。
直观来看,E 反映的是,参数压缩前后,在同样的输入(具有代表性的校准数据)下,输出结果的差异。
由于每一行的参数相互独立,我们只需为每行量化后的参数 W ^ i , : \hat{\mathbf{W}}_{i,:} W^i,: 计算对应的海森矩阵:
∂ E ∂ W ^ i , : 2 = H i = 2 X X T , ∀ i = 1 , 2 , ⋯ , d row \frac{\partial E}{\partial \hat{\mathbf{W}}_{i,:}^{2}} = \mathbf{H}_{i} = 2\mathbf{X}\mathbf{X}^{\mathrm{T}}, \quad \forall i = 1, 2, \cdots, d_{\text{row}} ∂W^i,:2∂E=Hi=2XXT,∀i=1,2,⋯,drow
参数矩阵一行共
d
col
d_{\text{col}}
dcol 个参数,如果删除 k 个参数,那么 OBC 的算法流程如下,截图中,M是参数的索引(从1开始):
从 for 循环开始逐行分析:
- Line 1:找到对目标函数影响最小的参数所在索引 p;
- Line 2:对第 p 个参数剪枝,并更新其他参数;
- Line 3:更新 H − 1 \mathbf{H}^{-1} H−1,这里用了数学的等价表达,其实和我们前面介绍的 OBS 更新 H − 1 \mathbf{H}^{-1} H−1 的方式没差,这里 H : , p − 1 H p , : − 1 \mathbf{H}^{-1}_{:,p} \mathbf{H}^{-1}_{p,:} H:,p−1Hp,:−1 表示第 p 列乘第 p 行。
OBC 还对性能做了一些优化(空间换计算、计算换空间),不过这些和本文主题无关。
总的来说,OBC 就是对每一行使用 OBS 算法,就这么简单。
1.5 OBQ(Optimal Brain Quantization)的算法原理
OBQ 和 OBC 是同一篇文章提出来的,OBQ 认为,剪枝是一种特殊的量化(即剪枝的参数等价于量化到 0 点),即:
lim
quant
(
w
q
)
→
0
量化解
=
剪枝解
\lim_{\operatorname{quant}(w_q) \to 0} \text{量化解} = \text{剪枝解}
quant(wq)→0lim量化解=剪枝解
式中, quant ( w q ) \operatorname{quant}(w_q) quant(wq) 是参数 w \mathbf{w} w 的第 q q q 维经过量化后的值,当然,这里说的量化,指的是 “量化+反量化”。
我们只需要修改一下 OBC 的约束条件,即可把 OBC 推广到一般量化场景。
一般量化的约束条件按如下方式修改:
e
q
T
⋅
Δ
w
+
w
q
=
quant
(
w
q
)
\mathbf{e}_{q}^{\mathrm{T}} \cdot \Delta \mathbf{w} + w_{q} = \operatorname{quant}(w_{q})
eqT⋅Δw+wq=quant(wq)
量化后,参数 w \mathbf{w} w 的第 q q q 维的变化量为 quant ( w q ) − w q \operatorname{quant}(w_q) - w_q quant(wq)−wq,即 Δ w q = quant ( w q ) − w q \Delta w_q= \operatorname{quant}(w_q) - w_q Δwq=quant(wq)−wq
接下来要计算其他参数 Δ w i \Delta w_i Δwi( i ≠ q i \neq q i=q )的更新量,以及 Δ w q \Delta w_q Δwq 量化后的影响(其他参数更新后的补偿影响)。
在OBC中,
Δ
w
q
=
−
w
q
\Delta w_q= -w_q
Δwq=−wq,而这里为
Δ
w
q
=
quant
(
w
q
)
−
w
q
\Delta w_q= \operatorname{quant}(w_q) - w_q
Δwq=quant(wq)−wq,因此只需要将OBC剪枝解中的
w
q
w_q
wq 替换为
w
q
−
quant
(
w
q
)
w_q - \operatorname{quant}(w_q)
wq−quant(wq),可以得到通用解:
Δ
w
=
−
w
q
−
quant
(
w
q
)
[
H
−
1
]
q
q
H
−
1
⋅
e
q
L
=
1
2
(
w
q
−
quant
(
w
q
)
)
2
[
H
−
1
]
q
q
\Delta \mathbf{w} = -\frac{w_{q} - \operatorname{quant}(w_{q})}{\left[\mathbf{H}^{-1}\right]_{qq}} \mathbf{H}^{-1} \cdot \mathbf{e}_{q} \\ L = \frac{1}{2} \frac{\left( w_{q} - \operatorname{quant}(w_{q}) \right)^{2}}{\left[\mathbf{H}^{-1}\right]_{qq}}
Δw=−[H−1]qqwq−quant(wq)H−1⋅eqL=21[H−1]qq(wq−quant(wq))2
此公式组实现了OBC框架从剪枝到量化的完美扩展,通过量化误差替代剪枝量保持数学一致性。该结果是OBQ算法(OBC的量化版本)的理论基础,已在GPTQ等现代量化技术中广泛应用。
如果要量化 k 个参数,那么 OBQ 的算法流程如下:
OBQ算法对 k 个参数做量化的时间复杂度为
O
(
k
⋅
d
c
o
l
2
)
O(k\cdot d^2_{col})
O(k⋅dcol2),这里
O
(
d
c
o
l
2
)
O(d^2_{col})
O(dcol2) 是排序的开销(我个人认为不需要排序,只需要选最小就行了,选最小的时间复杂度是
O
(
n
)
O(n)
O(n),但为何要有平方,这个我就不清楚了)。
量化一般都是整行一起做(下一段会介绍细节),即 k = d c o l k=d_{col} k=dcol,所以对一行做量化的时间复杂度为 O ( d c o l 3 ) O(d^3_{col}) O(dcol3),对整个参数矩阵做量化的时间复杂度为 O ( d r o w ⋅ d c o l 3 ) O(d_{row} \cdot d^3_{col}) O(drow⋅dcol3) 。
若整行一起量化,第 1 个参数量化时,会更新第 2、3、…… 、 d c o l d_{col} dcol 个参数,以补偿量化第 1 个元素带来的影响,但第 2 个参数量化时,只会更新第 3、4、…… 、 d c o l d_{col} dcol 个参数,不会更新第 1 个参数,也就是说,只会更新后面的,不影响前面已量化的。这个和剪枝的时候,计算其他参数的更新值,只计算未剪枝的,不计算已剪得,道理类似。
至此,GPTQ 的前置知识介绍完毕。
2 GPTQ(Gradient-based Post-training Quantization) 算法
GPTQ 是一种针对大型语言模型(LLMs)的高效训练后量化(PTQ)算法,其核心目标是在不重新训练模型的前提下,将模型权重压缩至低比特(如4-bit),同时最小化精度损失。其原理基于分层误差补偿和海森矩阵优化,结合计算效率改进,实现大规模模型的高效量化。
2.1 原理
OBQ 的算法复杂度还是太高了,GPTQ 对 OBQ 做了一些算法和性能上的优化,以实现大模型的高效量化。
GPTQ 的创新点有:
- 1 OBS 采用贪心策略,先量化对目标影响最小的参数,但 GPTQ 发现直接按顺序做参数量化,对精度影响也不大。
- 这项改进使得参数矩阵每一行的量化可以做并行的矩阵计算,同时将时间复杂度从 O ( d r o w ⋅ d c o l 3 ) O(d_{row} \cdot d^3_{col}) O(drow⋅dcol3) 降低到 O ( d c o l 3 ) O(d^3_{col}) O(dcol3),在大模型环境下,这项改进使得量化速度快了一个数量级;
- 2 Lazy Batch-Updates (惰性批量更新),延迟一部分参数的更新,它能够缓解 bandwidth (带宽)的压力;
- 3 Cholesky Reformulation,用 Cholesky 分解(柯列斯基分解法)求海森矩阵的逆,在增强数值稳定性的同时,不再需要对海森矩阵做更新计算,进一步减少了计算量。
上述改进中,第一点比较好理解,第三点需要有数值计算方法的基础(理论上说应该是线性代数的知识,但国内本科线性代数普遍不学这个,我是在硕士期间的《数值计算》方法那门课上学的),我们只需要知道第三点用了更稳定的方法计算海森矩阵的逆,了解到这一点就行了。
这里我们重点谈一下第2点:
OBQ 算法在量化某一行时,每次量化一个参数,但本行的其他所有未量化的参数都要更新,以补偿量化带来的影响,也就是说,量化第一个参数要读写参数矩阵 d c o l − 1 d_{col}-1 dcol−1 次,量化第二个参数,要读写参数矩阵 d c o l − 2 d_{col}-2 dcol−2 次,以此类推,整行量化完,读写参数矩阵的时间复杂度为 O ( d c o l 2 ) O(d^2_{col}) O(dcol2) 。
OBQ更新时,若多行并行量化,则参数量化是一列一列按次序进行的,第 i 列的参数的量化结果受到前 i-1 列量化的影响,但第 i 列的量化结果不影响前面列的量化,示意图如下:
对于第 i 列之前的参数(i 从1到 i-1),我们不需要每量化一次就更新一遍第 i 列的参数(这样第 i 列还没量化时,就更新了 i-1 次了),而是可以先记录第 i 列的更新量,等到量化到第 i 列时,再一次性更新参数,这样就可以减少 IO 的次数。
实际操作时,为了减少读写参数矩阵的次数,可以将参数矩阵按每 128 列划分为一个个 group,量化某一列时,同一个 group 内的后面的参数立即更新,后面的 group 只记录更新量。当一个 group 的参数全部量化完成,再统一对后面的所有参数做一次更新,这就是 Lazy Batch-Updates。
Lazy Batch-Updates 示意图如下:
2.3 海森矩阵与组内补偿
在GPTQ算法中,当模型权重按分组(Block)独立量化时,其他组的参数更新量并非直接计算,而是通过“延迟批量更新”(Lazy Batch Update)机制间接实现。其核心思想是:分组内量化误差通过海森矩阵局部补偿,而分组间的影响则通过全局误差累积后统一调整。
以下是具体原理和实现步骤:
- 分组独立计算:将权重矩阵的每行按列分组(例如每组128列),每个组称为一个Block,对每个Block内的权重单独计算海森矩阵,组内权重的量化和更新与 OBQ 算法没差
- 跨组延迟批量更新:量化当前组时,先记录组外权重变化量(加入到累积误差中),但不更新组外权重,当前组量化完成后,一次性应用到全局剩余权重矩阵(即所有未处理的组):
W global ← W global − ∑ block ϵ block ⋅ H global − 1 e block W_{\text{global}} \leftarrow W_{\text{global}} - \sum_{\text{block}} \epsilon_{\text{block}} \cdot \mathbf{H}_{\text{global}}^{-1} \mathbf{e}_{\text{block}} Wglobal←Wglobal−block∑ϵblock⋅Hglobal−1eblock
其中, H global \mathbf{H}_{\text{global}} Hglobal 是全局海森矩阵的近似(实际工程中通过分组预计算获得), ϵ block \epsilon_{\text{block}} ϵblock 是当前组量化时,组外未处理的权重的变化量的累积,假如当前组有128列,那么 ϵ block \epsilon_{\text{block}} ϵblock 是128次变化量累加的结果。
百度飞火平台实测显示,当 group_size=128
时,GPTQ量化百亿模型精度损失<1%。
2.4 量化参数
GPTQ量化一般是分组线性量化,量化用的缩放因子和零点每个分组计算一次,组内参数共享一套量化参数。当然,也可以是每一列计算一次量化参数,不过这样容易导致量化参数过多。
3 AWQ (Activation-aware Weight Quantization)算法
AWQ(Activation-aware Weight Quantization)的算法逻辑步骤围绕“保护关键权重”的核心思想展开,通过激活感知动态调整量化策略,实现低比特量化下的高精度保持。以下是其算法逻辑的完整步骤:
3.1 算法原理
-
权重并非同等重要
- 研究发现,大模型中仅有 0.1%-1% 的权重(显著权重,Salient Weights) 对模型输出影响较大。若保留这些权重的原始精度(FP16),量化其他权重可显著降低量化误差。
- 显著权重的识别:通过激活值分布(而非权重自身分布)确定重要权重。激活值较大的通道对应更关键的权重,因其处理更重要的特征。
-
缩放保护代替混合精度
- 直接保留部分权重为 FP16 会导致硬件效率低下(混合精度计算开销大)。
- AWQ 的解决方案:对显著权重乘以缩放因子(s > 1),再量化所有权重。缩放后显著权重的相对量化误差减小,而非显著权重的误差增加量也不多,可以实现整体误差最小化。
- 数学原理:
- 量化公式: w ′ = Round ( w ⋅ s / Δ ′ ) w' = \text{Round}(w \cdot s / \Delta') w′=Round(w⋅s/Δ′),这里 Δ ′ \Delta' Δ′ 是量化参数
- 反量化公式: Δ ′ ⋅ w ′ / s \Delta' \cdot w' / s Δ′⋅w′/s
- 缩放后显著权重的误差比例降为原始误差的 1 / s 1/s 1/s。
- 数学原理:
3.3 量化步骤
一、激活统计与通道重要性评估 [citation:1][citation:2]
-
校准数据前向传播
使用少量校准数据(如128~512样本)输入FP16模型,收集每层输入激活值(Activation)的统计分布。- 关键指标:计算每个输入通道(Channel)的激活绝对值均值或分位数( s X j = E [ ∣ X j ∣ ] s_{X_j} = \mathbb{E}[|X_j|] sXj=E[∣Xj∣])。
- 物理意义:激活幅度大的通道处理更重要的特征(如语义关键词、图像轮廓),其对应权重对输出影响更大。
-
识别显著权重通道
根据激活幅度排序通道,筛选Top 0.1%~1%的通道作为显著权重(Salient Weights)。实验表明:- 基于激活的筛选使OPT-6.7B的困惑度(PPL)从43.2降至13.0,而基于权重L2范数的筛选仅降至23.54。
二、缩放因子优化与动态保护
-
参数化缩放因子
为每个通道设计缩放因子 s j s_j sj,关联其激活统计值:
s j = ( s X j ) α s_j = (s_{X_j})^\alpha sj=(sXj)α- α \alpha α 的作用:控制缩放强度( α = 0 \alpha=0 α=0:不缩放; α = 1 \alpha=1 α=1:最强缩放)。
- 设计动机:放大显著权重,使其量化后相对误差减小至原始误差的 1 / s 1/s 1/s。
-
网格搜索最优 α \alpha α
在校准集上优化目标函数:
min α ∥ Q ( W ⋅ diag ( s ) ) ⋅ ( diag ( s ) − 1 X ) − W X ∥ F \min_{\alpha} \| Q(W \cdot \text{diag}(s)) \cdot (\text{diag}(s)^{-1} X) - WX \|_F αmin∥Q(W⋅diag(s))⋅(diag(s)−1X)−WX∥F- 搜索方式:在 α ∈ [ 0 , 1 ] \alpha \in [0,1] α∈[0,1] 区间网格搜索,选取使输出误差最小的 α \alpha α。
- 高效性:仅需单参数搜索,成本远低于GPTQ的二阶优化。
三、权重缩放与量化执行
-
权重预缩放
将权重矩阵按通道缩放: W scaled = W ⋅ diag ( s ) W_{\text{scaled}} = W \cdot \text{diag}(s) Wscaled=W⋅diag(s)。- 数学等价性:缩放后线性运算 y = ( W ⋅ s ) ⋅ ( x / s ) = W x y = (W \cdot s) \cdot (x / s) = Wx y=(W⋅s)⋅(x/s)=Wx 保持不变。
- 误差控制:显著权重的量化误差比例降至 1 / s 1/s 1/s,非显著权重误差容忍度提高。
-
分组量化(Group Quantization)
- 量化方式:对 W scaled W_{\text{scaled}} Wscaled 进行低比特均匀量化(如INT4)。
- 硬件友好设计:
- 按输出通道分组(如每组128个权重),共享量化参数(scale/zero_point)。
- 避免混合精度,支持SIMD指令并行处理。
-
可选权重裁剪
限制 W scaled W_{\text{scaled}} Wscaled 的数值范围(如裁剪至 [ − c , c ] [-c, c] [−c,c]),降低离群值影响,进一步减小量化缩放系数 Δ ′ \Delta' Δ′。
四、反量化与推理加速
-
运行时反量化
推理时,权重从INT4动态反量化为FP16:
W dequant = Δ ′ ⋅ INT4 / s W_{\text{dequant}} = \Delta' \cdot \text{INT4} / s Wdequant=Δ′⋅INT4/s- 硬件优化:与内核融合(Kernel Fusion)结合,减少内存访问开销。
-
框架级优化
- vLLM/TinyChat:将反量化融入GEMM运算,实现3-4倍加速[citation:1][citation:7]。
3.4 关键创新与优势总结
步骤 | 技术贡献 | 效果 |
---|---|---|
激活感知重要性评估 | 用输入激活(非权重自身)识别关键通道 | 避免权重冗余干扰,提升显著权重筛选精度 |
单参数缩放因子搜索 | α \alpha α 控制全局缩放强度,替代混合精度 | 硬件友好,保持全低比特存储 |
通道分组量化 | 组内共享量化参数,适配SIMD指令 | 推理延迟降低60%(对比GPTQ) |
动态反量化融合 | 与计算内核融合,减少DRAM访问 | 资源受限设备(如树莓派)可运行70B模型 |
4 AWQ 与 GPTQ 的对比
在模型量化领域,AWQ(Activation-aware Weight Quantization)和GPTQ(Generative Pre-trained Transformer Quantization)是两种主流技术,各自适配不同的部署场景。以下是基于技术特性、硬件兼容性和任务需求的综合对比与选择建议:
4.1 核心差异对比
维度 | AWQ | GPTQ |
---|---|---|
核心原理 | 激活感知缩放保护关键权重(0.1%-1%显著权重) | 基于海森矩阵的逐层误差补偿(二阶优化) |
量化精度 | 更优(低比特下精度损失<5%) | 良好(4-bit下可能损失5-10%) |
推理速度 | 更快(比GPTQ快1.45倍) | 中等(需权重重排序) |
硬件兼容性 | GPU/边缘设备(适配vLLM/TinyChat) | 主流GPU(依赖CUDA/exllama) |
模型泛化 | 支持多模态(视觉+语言) | 专注Transformer类模型(如GPT/LLaMA) |
部署复杂度 | 中等(需校准数据) | 较低(AutoGPTQ工具链成熟) |
校准数据需求 | 少(128样本) | 多(512-1024样本) |
4.2 选择建议:优先使用AWQ的场景
-
边缘设备部署(如手机/嵌入式系统)
- 理由:AWQ通过权重打包(4-bit打包为INT16)和内核融合优化内存访问,显存占用降至1/4,树莓派5可运行7B模型。
- 工具链:TinyChat框架适配Jetson Orin等低功耗设备。
-
多模态模型(视觉-语言联合任务)
- 理由:AWQ首次实现视觉语言模型的高效量化(仅量化语言部分),GPTQ缺乏此类支持。
-
高精度敏感型任务(如医疗/金融决策)
- 理由:激活感知保护显著权重,INT4量化下困惑度(PPL)接近FP16(如OPT-6.7B的PPL从43.2→13.0)。
-
小batch推理与低延迟API
- 理由:AWQ在增量生成任务中延迟更低,配合TGI引擎支持动态批处理。
4.3 选择建议:优先使用GPTQ的场景
-
云端高吞吐服务(如聊天机器人API)
- 理由:GPTQ量化模型在vLLM引擎下吞吐量更高(70B模型达100+ tokens/s),适合并发请求。
- 工具链:AutoGPTQ + vLLM组合成熟度高。
-
极致压缩需求(显存严重受限)
- 理由:GPTQ支持更低比特(如3-bit)压缩,显存占用比AWQ更低。
-
纯Transformer架构模型(如LLaMA/Mistral)
- 理由:专为GPT类模型优化,社区支持广泛(HuggingFace模型库覆盖全)。
4.4 决策流程图
graph TD
A[部署场景] --> B{资源受限?}
B -->|是| C{是否边缘设备?}
C -->|是| D[选AWQ]
C -->|否| E{是否多模态?}
E -->|是| D[选AWQ]
E -->|否| F[选GPTQ]
B -->|否| G{是否高吞吐?}
G -->|是| F[选GPTQ]
G -->|否| H{是否低比特压缩?}
H -->|是| F[选GPTQ]
H -->|否| D[选AWQ]
4.5 实践注意事项
-
量化校准
- AWQ需确保校准数据代表实际输入分布,否则显著权重识别可能偏差。
- GPTQ需调优分块大小(block size),平衡速度与精度。
-
混合精度策略
- 对敏感层(如输出层)保留FP16,其余用AWQ/GPTQ量化,可进一步提升精度。
-
工具链更新
- AWQ生态快速发展(如AutoAWQ支持Qwen/Mistral),建议定期跟踪GitHub更新。
4.6 总结
- 选AWQ:边缘设备、多模态模型、高精度需求、低延迟场景。
- 选GPTQ:云端高并发、纯Transformer模型、极致压缩需求。
两者并非互斥,生产环境中可对模型分层混合使用(如关键层AWQ+其他层GPTQ),实现精度与效率的帕累托最优。