1. 背景
- 从速度看
- 访存耗时远多于计算
- 浮点数计算耗时和整型计算耗时差不多?(from 张志),但是浮点数计算单元需要占用更多额外的芯片面积
- 从energy看
- 访存消耗energy远多于计算(200倍)
- 浮点数运算消耗energy多于int8类型(十几倍),因此量化有助于keep efficient
2. 数值类型(浮点数)
- FP32:1+8+23
- FP16:1+5+10,通常使用在混合精度训练中
- BF16:1+8+7,直接将FP32进行截断,方便直接进行转换
- TF32:1+8+19,保留了FP32的范围(8位范围)与FP16的精度(10位精度),用于TensorCore中
- FP24:
3. 量化基础
K-Means-based Quantization
- 原理:权重进行kmeans聚类(每个类别cluster视为一个模式),每个cluster对应一个浮点数,构成一个codebook(lookup table),权重矩阵中保存的是codebook中的索引
- 微调过程:给定权重矩阵对应的梯度矩阵,将梯度矩阵按照模式进行分组(对应不同的cluster),每组梯度进行求和,再更新codebook中对应cluster的浮点数
- 效果:
- 从pruning ratio看:剪枝+量化同时使用,可以获得更小的pruning ratio(量化后再微调一下,有助于恢复精度)
- 从准确率看:剪枝+量化准确率与只进行量化差不多
- 优化:霍夫曼编码
- 将更频繁的权重使用更短的编码表示(但是这样会导致权重矩阵中各个元素大小不一❓)
- 特点:量化后存储的是低比特,但是计算仍然是浮点数(只是节省了存储,但是访存翻倍❓)
- 原理:权重进行kmeans聚类(每个类别cluster视为一个模式),每个cluster对应一个浮点数,构成一个codebook(lookup table),权重矩阵中保存的是codebook中的索引
Linear Quantization
原理:直接进行映射,相当于线性的codebook,权重矩阵中存储的是量化值,运算时先反量化到浮点数范围、再使用不同的量化参数量化到int8 $$ 量化:&uint &=& round( \frac{float}{scale} + offset) \ 反量化:&float &=& (uint - offset) * scale $$
tricks:
公式中的很多部分可以pre-compute
scale的浮点乘法可以转换为定点小数的位移
详见Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference 第2.2章
分类
- 对称量化
- 非对称量化(由于补码负数比正数多一个,因此区分两种模式,构造成左右对称的形式,不同框架可能使用不同的mode)
- full range mode:正数128加进来
- restricted range mode:负数-128去掉
特点:量化后存储的是int8,计算中也是int8
4. 量化种类
4.1 Post-Training Quantization(PTQ)
权重量化Weight Quantization:减小模型大小
Per-tensor vs Per-channel
Weight Equalization
背景:
- Per-tensor量化简单,但是由于channel之间range差异较大,导致效果很差
- Per-channel量化效果较好,但是需要特殊硬件支持❓
- 目标:make weight ranges similar (or equalize the weight range), so that per-tensor quantization can be applied(既想要per-tensor的简单,又想要per-channel的效果)
原理:positive scaling equivariance伸缩等价性
对于conv、fc和relu,满足:
$$f(s x) = s f(x), where \quad s \gt 0 $$
方法:对于连续的两个卷积层,第一个卷积层乘上一个scale,第二个卷积核对应通道除以一个scale,这样与原来是等价的,但是调整了第一个卷积核的range;然后逐渐连续地调整
Adaptive Rounding
背景:
看似符合直觉的round-to-nearest其实精度并不是最优的
因为并非每个单独的weight的量化损失越小越好,weight之间存在相互影响
方法:Adaptive地决定weight量化时将浮点数转到最近右定点还是最近左定点❓
激活值量化Activation Quantization:减小内存占用
目标:由于激活值无法提前确定,因此要找到激活值的$r_{min}, r_{max}$
During Training
EMA
在训练时使用exponential moving averages (EMA)来得到$r_{min}, r_{max}$ $$ &\hat{r} ^ {(t)} _ {max, min} = \alpha r ^ {(t)} _ {max, min} + (1 - \alpha) \hat{r} ^ {(t-1)} _ {max, min} \ &其中 \hat{r} ^ {(t)} _ {max, min} 是EMA激活值范围, \ &r ^ {(t)} _ {max, min} 是 epoch=t时的激活值范围 $$
Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference 3.1段
Use calibration after training
统计calibration中每个sample的$r_{min}, r_{max}$,然后取平均
ACIQ
基本思想:最小化激活值X与量化值Q(X)的MSE,具体假设原始激活值的分布,展开求导 $$ \mathop{min}\limits_{|r|_{max}} \mathbb{E} \left[ (X - Q(X))^2 \right] $$
Post training 4-bit quantization of convolutional networks for rapid-deployment
缺点:需要假设原始的激活值浮点分布(因为需要密度函数)
KL-divergence based
基本思想:使用KL散度来衡量量化的信息损失(原始激活值的分布与量化后的分布)
偏置量化Bias Quantization
背景:权重量化之后,权重分布会产生一个shift。一方面希望量化误差尽量小,另一方面希望量化误差的期望为0(但并非如此)
后训练量化——Data free quantization 中Bias Correction,可以看到蓝色的量化误差明显左偏
方法:
- 如果当前有数据:全精度和量化模型分别跑一遍,bias减去这个量化误差,注意对于每一个卷积层或全连接层都要跑一遍
- 如果当前没有数据:
4.2 Quantization Aware Training(QAT)
STE方法:
想法:权重信息经过伪量化操作,来模拟产生量化误差,反向传播的梯度信息跳过伪量化节点直接更新原始权重,相当于更新权重信息考虑到了量化误差、梯度下降进行优化
过程:
拿到训练好的模型
在权重、激活值、输入输出等(对应权重量化与激活值量化)前面插入伪量化节点(将浮点权重量化再反量化,模拟推理时的量化)
一开始伪量化节点中量化参数是怎么来的?
在微调的forward过程中,顺便计算出量化参数:
- 如果是针对权重的量化:直接统计权重中的最小值、最大值,从而计算量化参数
- 如果是针对激活值的量化:使用指数移动平均EMA来更新量化参数
前向推理,模拟量化的过程
反向传播:正常更新权重(权重是浮点类型),相当于梯度信息跳过了伪量化节点
LSQ方法:在反向传播时可以更新量化参数
5. 低比特量化
- Binary Quantization
- Ternary Quantization
- Mixed-Percision Quantization
参考: