大模型--模型量化GPTQ--24
1. 参考
GPTQ 量化技术演进:https://zhuanlan.zhihu.com/p/690834228?utm_id=0
OBS/OBD/GPTQ:https://www.cnblogs.com/wangbingbing/p/17547681.html
GPTQ使用的方法改进自OBC(Frantar, 2022),OBC来源于OBS(Hassibi, 1992),OBS来源于OBD(Lecun, 1990)
2. OBS -- Optimal Brain Surgeon and General Network Pruning
复习:泰勒展开和麦克劳林级数
对于任意一个函数,可以在x=0处展开为
也就是当x的取值在0附近时,p(x)可以用上述多项式近似。
如果要在其他的点展开,则展开式子为:
对于神经网络的损失函数E(W;X)同样可以展开
上式表示权重取值在W0附近时的误差的多项式近似值.
移项得到:
将变化量记作δ,
H 是hessian矩阵,也就是二阶导组成的矩阵。
下文涉及到的二阶偏导矩阵用的是
G(x),实际就是论文中的 Hessian矩阵,
总结多元函数的泰勒展开式为:
其中:
为了计算拆开
直接把G(x0)11简写为了G11。
可以分解为两项的和
而在LeCun的OBD中,把交叉项忽略了!OBS没有忽略。
剪枝和更新都被表达为对权重施加一个变量,
剪枝相当于在当前权重W0附近找一个权重W,该权重将部分元素剪掉,同时error的变化最小也就是让δE最小
剪掉wp就是令权重矩阵中的权重wp=0,也就是,公式表达:
单位向量,只有在q的位置是1.
因为训练到局部最优的网络,一阶导数是0(或者接近0,可以忽略不计),三阶项也忽略。
目标函数:
约束条件:
用拉格朗日乘子法:
得到:
OBS处理流程:
- 训练好一个收敛到最小误差的神经网络
- 计算:
- 计算所有的如果一个权重的对整体误差E的增加很小,那么该权重就需要被删除。进入step4;否则进行step5
- 使用step 3中选择到的权重索引q来进行剪枝并更新剩余权重,转到step2
- 结束剪枝
3. Optimal Brain Compression: A Framework for Accurate Post-Training Quantization and Pruning
上述OBS方法很好,但是,对于大型语言模型,每个循环都要计算,H矩阵的逆矩阵,
假设矩阵的维度是
3.1Row-wise 权重剪枝算法
OBC 原论文首先定义了 layerwise 的模型剪枝问题,也就是说,针对每一层,定义剪枝损失
f表示某层的前向函数,
分别表示原始权重和剪枝后的权重矩阵
X表示矩阵形式的输入。
更具体的说,对于线性层或者卷积层,前向传播函数可以表示为权重和输入矩阵相乘的形式
寻找最优压缩方案就变成了如下优化问题:
更进一步,若将权重矩阵按行分解,则剪枝损失又可以表示为按行求和的形式
记:
则:
N表示X的列数,d_col表示X的行数或者W的列数,
由于每次迭代我们都只对某一行中的权重进行剪枝,也就是说只影响一行的剪枝损失,所以在每次迭代过程中可以认为:
i就是被剪枝权重所在的行索引,基于这样的事实,我们可以推导出 Hessian 矩阵为:
写成矩阵的形式:
注意这是对第i行权重进行剪枝时的 Hessian 矩阵,让我们用 H(i) 来表示
Hessian 矩阵是一个仅与X相关的矩阵,当一次迭代对第q个权重剪枝后,X的第q行就没有用了
下次迭代只需要从中删除第q行和第q列即可
这种方式也节省了每次构造的时间。
另一方面,每次迭代还需要计算 Hessian 逆矩阵,这也是一个复杂度的操作,不过仍然有方法可以简化,
表示中间过程的,F表示未量化的权重索引集合。
表示中去掉第q行和第q列后的矩阵
那么有以下公式成立:
只需要把上一次的中第q列,第q行取出 运算一下就能到的,大大的降低了求逆矩阵的运算量。
算法步骤:
显然,上述过程每次迭代都需要应用d_row次
然后挑选最佳的qi
4. 从 OBS 到 OBQ
剪枝和量化都涉及到对权重值的修改,只不过剪枝是直接将权重设置为 0,而量化则是降低权重值的数值精度,比如将 fp32 数值变成 fp16,int8,int4 等
OBS 的思想可以很自然的应用到量化上来,这种方法也被称为OBQ (Optimal Brain Quantization),为了兼顾剪枝和量化,论文的标题就叫 OBC (Optimal Brain Compression)。
从这个公式出发:
在 OBS 中,对应的约束条件为,
索引为 q 的权重修改量为 ,
而在量化条件下,情况要复杂一点,
参考:https://arxiv.org/abs/2106.08295
量化实际上就是将浮点数权重转换为整数:
其中 表示缩放系数,
z表示零点偏移,
N表示最大整数值。
以为例,量化函数图像如下:
可以看到,该函数将浮点数权重分阶段地映射到了整数值上。
一个训练好的模型,对所有权重值应用量化变换,并保存好相应的参数,这就是经典的量化过程。
与量化过程对应的还有一个逆量化操作可以恢复原先的精度类型
量化后的权重实际上存在两种等价的表示形式,第一种是通过量化函数变换到的整数空间,第二种是通过逆量化函数变换到的浮点数空间。
对于 OBQ 来说,每量化一个权重值,需要调整剩余权重来最小化量化损失,但是我们不能直接在整数空间上调整(因为剩余权重都是浮点数),应该在浮点数空间上调整,
定义函数 quant先对权重进行量化,再逆量化,就得到浮点数空间上的量化值,
剪枝操作中的约束条件在这里就变成了
再次使用拉格朗日乘子法求解最小化问题,可以得到,
表示一行权重的修正量
即
交替使用上面公式 就得到了量化版本的 OBC 算法 OBQ。
5. GPTQ Gradient PreTrained Quantity
OBQ 采用 row-wise 的权重量化方法,将 Hessian 矩阵求逆的复杂度降低到了
并且一个权重矩阵总的参数量为因此总体来说 OBQ 的时间复杂度为
虽然相对于 OBS 有了很大的改进,但对于大模型来说,OBQ 仍然是一个非常耗时的操作。
GPTQ 提出了两点改进来提高 OBQ 的量化效率,
首先是将每一行的量化权重选择方式从贪心策略改成按索引顺序选择,
其次是将权重更新方式修改为批量更新