大模型量化: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.2 量化的缩放因子与零点
3 AWQ (Activation-aware Weight Quantization)
是一种先进的低比特权重量化技术,由 MIT 韩松团队于 2023 年提出。其核心目标是通过减少模型显存占用和加速推理,同时最小化精度损失。
3.1 算法原理
研究发现,大模型中仅有 0.1%-1% 的权重(显著权重,Salient Weights) 对模型输出影响较大。若保留这些权重的原始精度(FP16),量化其他权重可显著降低量化误差。
显著权重的识别:通过激活值分布(而非权重自身分布)确定重要权重。激活值较大的通道对应更关键的权重,因其处理更重要的特征
大模型量化中的 AWQ(Activation-aware Weight Quantization) 是一种先进的低比特权重量化技术,由 MIT 韩松团队于 2023 年提出。其核心目标是通过减少模型显存占用和加速推理,同时最小化精度损失。以下是 AWQ 算法原理的详细解析:
一、核心思想:权重重要性差异与激活感知
权重并非同等重要
- 研究发现,大模型中仅有 0.1%-1% 的权重(显著权重,Salient Weights) 对模型输出影响较大。若保留这些权重的原始精度(FP16),量化其他权重可显著降低量化误差[citation:1][citation:3][citation:5]。
- 显著权重的识别:通过激活值分布(而非权重自身分布)确定重要权重。激活值较大的通道对应更关键的权重,因其处理更重要的特征[citation:1][citation:5]。
缩放保护代替混合精度
- 直接保留部分权重为 FP16 会导致硬件效率低下(混合精度计算开销大)。
- AWQ 的解决方案:对显著权重乘以缩放因子(s > 1),再量化所有权重。缩放后显著权重的相对量化误差减小,而非显著权重的误差增加较少,整体误差最小化[citation:1][citation:3][citation:5]。
- 数学原理:
- 量化公式: w ′ = Round ( w ⋅ s / Δ ′ ) w' = \text{Round}(w \cdot s / \Delta') w′=Round(w⋅s/Δ′)
- 反量化公式: Δ ′ ⋅ w ′ / s \Delta' \cdot w' / s Δ′⋅w′/s
- 缩放后显著权重的误差比例降为原始误差的 1 / s 1/s 1/s[citation:3][citation:5]。
- 数学原理:
二、技术实现:自动缩放系数搜索
目标函数优化
AWQ 最小化量化后的输出误差:
min s ∥ W X − Q ( W ⋅ s ) ⋅ ( X / s ) ∥ F \min_s \left\| WX - Q(W \cdot s) \cdot (X / s) \right\|_F smin∥WX−Q(W⋅s)⋅(X/s)∥F
其中 Q Q Q 为量化函数, X X X 为校准数据集的激活值[citation:3][citation:5]。简化搜索空间
- 缩放因子 s s s 与激活幅度相关: s = ( max ( ∣ A ∣ ) ) α s = \left( \max(|A|) \right)^\alpha s=(max(∣A∣))α, A A A 为激活值, α \alpha α 为平衡参数。
- 通过网格搜索(Grid Search)在 [ 0 , 1 ] [0, 1] [0,1] 区间优化 α \alpha α,平衡显著与非显著通道的保护[citation:1][citation:5]。
硬件友好设计
- 分组量化:权重按输出通道分组(如每组 128 个权重),每组共享量化参数[citation:1][citation:5]。
- 权重量化+激活反量化:权重以 INT4 存储,推理时实时解量为 FP16 计算,避免混合精度瓶颈[citation:1][citation:5]。
三、与其他量化方法的对比
特性 | AWQ | GPTQ |
---|---|---|
量化原理 | 激活感知缩放保护显著权重 | 基于二阶信息的权重重构 |
精度 | 更高(接近 FP16) | 中等 |
推理速度 | 更快(比 GPTQ 快 1.45 倍) | 较快 |
硬件兼容性 | 无需权重重排序,内核融合优化 | 需重排序,计算开销大 |
多模态支持 | 是(首个成功量化视觉语言模型的方法) | 否 |
校准数据需求 | 极少(约 128 样本) | 大量 |
💡 优势总结:AWQ 通过激活感知和自动缩放,在精度、速度和泛化性(支持多模态)上优于 GPTQ 等方案[citation:1][citation:3][citation:5]。
四、实践效果与适用场景
性能表现
- 显存压缩:4 比特量化使模型大小减少至 1/4(如 70B 模型从 140GB → 35GB)[citation:1][citation:5]。
- 速度提升:通过 TinyChat 框架优化(如内核融合、实时解量),推理速度比 FP16 快 3 倍[citation:1][citation:5]。
- 精度保持:在 LLaMA、Vicuna 等模型上,困惑度(PPL)损失小于 1%[citation:1][citation:5]。
典型场景
- 边缘设备:低显存需求(如 4 比特 Qwen-7B 仅需 4GB 显存)[citation:1]。
- 多模态模型:成功量化 LLaVA 等视觉语言模型[citation:5]。
- 小 batch 推理:减少增量推理延迟[citation:1]。
关键参数:
w_bit
(量化位数)、q_group_size
(分组大小)、version
(GEMM 内核优化)。
六、局限性及改进方向
- 局限性:
- 大 batch 场景可能受限于反量化计算(Compute-bound)[citation:5]。
- 敏感层(如注意力头)需更高比特数(如 8 位)[citation:3]。
- 改进方案:
- 层级自适应量化:对不同敏感度的层分配不同比特数[citation:3]。
- 与硬件协同优化:如 NVIDIA TensorRT-LLM 集成 AWQ 内核[citation:5]。
AWQ 通过 “激活感知缩放” 和 硬件友好设计,在精度与效率间实现了最优平衡,已成为大模型部署的主流量化方案之一。其开源生态(如 AutoAWQ、vLLM)进一步推动了工业落地[citation:1][citation:5]。
这里的思想一直沿用到了 GPTQ 算法:也就是对某个 block 内的所有参数逐个量化,每个参数量化后,需要适当调整这个 block 内其他未量化的参数,以弥补量化造成的精度损失。