1 Lecture Plan
- 训练后量化 PTQ
- 量化感知训练 QAT
- 二元、三元量化
- 自动混合精度量化
2 Post-Training Quantization
How should we get the optimal linear quantization parameters (S, Z)
Topic1: Weight Quantization
Topic2: Activation Quantization
Topic3: Bias Quantization
2.1 Weight Quantization
[[Reference_Data-Free Quantization Through Weight Equalization and Bias Correction]]
[[Reference_Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference]]
- 对权重进行量化时,实数的最大值=权重最大值
- 每个output channel的权重范围差别很大(more than 100x),所以如果使用一个scale作为整个权重的参数(Per-Tensor Quantization,上篇笔记中oldpan大佬的博客有介绍过 权重没法per-tensor 通常都是per-channel)就会出现问题
- 对大模型而言,比较work,对小模型而言,accuracy损失非常大
- outlier weight values会导致其它所有权重量化精度降低
- Solution:使用Per-Channel Quantization
2.1.1 Per-Channel Weight Quantization
首先看一个Per-Tensor Quantization的例子
重建后的权重矩阵跟原始矩阵差别较大
再看Per-Channel的计算方法
-1.03在这里被量化成-1,而Per-Tenosr时被量化为0
round(1.03/2.12) = round(0.48) = 0
round(1.03/1.92) = round(0.53) = 1
Per-Channel精度更高但同时也要存储更多的scale参数;
我们能不能让权重范围的差异更小呢?
2.1.2 Weight Equalization
对不同输出通道的权重范围进行调节(static,without training)
- 第 i 层权重的output channel 2 乘上一个系数或除以一个系数,在第 i+1 层对应除以一个系数或乘上一个系数,当该运算是线性时,计算的结果是等价的
- 定义缩放因子 S 如下(per-charnnel)
s j = 1 r i c = j i + 1 r o c = j i r i c = j i + 1 s_{j}=\frac{1}{r_{ic=j}^{i+1}}\sqrt{r_{oc=j}^{i}r_{ic=j}^{i+1}} sj=ric=ji+11roc=jiric=ji+1
其中 r o c = j i r_{oc=j}^{i} roc=ji 是第 i 层,第 j 个通道的权重范围
对第 i 层和第 i+1 层的权重范围进行计算,得到的结果都是,因此减少了不同通道间权重范围的差异
r o c = j i r i c = j i + 1 \sqrt{r_{oc=j}^{i}r_{ic=j}^{i+1}} roc=jiric=ji+1 - 假设一个的权重范围是1,一个的权重范围是100,经过这样的Equalization就都变成了10!且这个过程是完全静态的,不需要训练的
What is the limitations of this method?
- 每次要对相邻两层的权重进行计算,并且要对整个网络进行计算
- 假设了相邻两层的计算是线性
如果使用的activation是sigmoid就gg了,但如果是ReLU就可以,ReLU是分段线性的(piece-wise linear)
2.1.3 Adaptive Rounding for Weight Quantization、
Rounding-to-nearest is not optimal
[[Reference_Up or Down? Adaptive Rounding for Post-Training Quantization]]
- 对每个weight进行rounding只考虑了它自己,没有考虑权重之间的interaction
- rounding可以最好的重建原始激活activation;
- 仅对权重进行量化,short-term tuning,几乎是PTQ
Adaptive Rounding 通过对一点tuning,实现了在量化权重时考虑权重间的相关性(在学习h(V)的时候所有权重一起tuning)
- 拿一点数据来训练得到tensor V
- 目标函数是最小化:量化前的W和量化后的W与输入x相乘之后的差异
- 向下取整+h(V)),h(V)在0-1之间,加上一项正则项鼓励h(V)是二值化的,也就是说floor(W) 先向下取整,学到的h(V)是0的话就说明保持向下取整ok,学到的h(V)是1的话就说明应该向上取整更好
2.2 Activation Quantization
与weight quantization的最大不同,weight量化是静态的,range可以在模型训练完成后直接计算得到;
而对于不同的image,activation的range是不同的
- 在部署模型之前,要先统计activation的浮点数范围
Collect activations statistics before deploying the model
2.2.1 Type1:During training
[[Reference_Quantization and Training of Neural Networks for Efficient Integer-Arithmetic-Only Inference]]
- 使用EMA(Exponential moving averages)指数滑动平均
- 观察范围的平滑在数千个训练的步骤中
2.2.2 Type2:By running a few “calibration” batches of samples on the trained FP32 model
- 在outlier上消耗动态范围会损失量化后的representation ability
- 使用calibration batched中每个样本min/max的均值
解析计算analytical calculation
2.2.2.1 最小化MSE
[[Reference_Post-Training 4-Bit Quantization of Convolution Networks for Rapid-Deployment]]
- 最小化mean-square-error 输入
X
X
X 和重建后的量化输入
Q
(
X
)
Q(X)
Q(X)
m i n ∣ r ∣ m a x [ ( X − Q ( X ) ) 2 ] min_{|r|_{max}}[(X-Q(X))^{2}] min∣r∣max[(X−Q(X))2] - 假设输入符合高斯或拉普拉斯分布
- 对于服从Laplace(0,b)分布的数据,最佳的截断值可以求得数值解
- 对于2,3,4bits而言: ∣ r ∣ m a x = 2.83 b , 3.89 b , 5.03 b |r|_{max}=2.83b,3.89b,5.03b ∣r∣max=2.83b,3.89b,5.03b
- Laplace参数 b 可以通过calibration batches的分布来进行估计
如果输入数据不符合假设的分布就没啥意思,所以广泛应用的是下一种方法,minimize loss of information
2.2.2.2 最小化信息损失minimize loss of information
[[Reference_8-bit Inference with TensorRT]]
- 左图统计了不同activation value的数量,可以看到数值很大的激活非常少,所以maybe不用把最大值取在真正的最大值,可以向左截断
- 如何选取这个值呢?
- KL散度(相对熵)计算量化后损失的information
- 利用KL散度选择截断的最大值,大于这个值的都变为这个值,所以计数增加很多,变成上面那个点点(图上数据突如其来的jump)
2.3 Bias Quantization
[[Reference_Data-Free Quantization Through Weight Equalization and Bias Correction]]
一个常见的假设是,量化误差是无偏的,因此在一个层的输出中被抵消,确保一个层的输出均值不会因为量化而改变。然而这篇文献中表明,情况并不是这样!
-
量化误差引起了对应输出中的有偏误差(均值发生变化)
KaTeX parse error: Undefined control sequence: \symbfit at position 8: E[\hat{\̲s̲y̲m̲b̲f̲i̲t̲{y_{j}}}-\symbf… -
定义量化误差为 KaTeX parse error: Undefined control sequence: \symbfit at position 14: \epsilon = Q(\̲s̲y̲m̲b̲f̲i̲t̲{W})-\symbfit{W…
KaTeX parse error: Undefined control sequence: \symbfit at position 3: E[\̲s̲y̲m̲b̲f̲i̲t̲{y}]=E[\symbfit…
加一项减一项不变,第一个 ϵ \epsilon ϵ 展开,第二个不展开;
消去一项 E [ W x ] E[Wx] E[Wx] , ϵ \epsilon ϵ 只包含权重的运算可以视作常数,直接从期望中提出来; -
E [ x ] E[x] E[x] 可以在batch normalization中推断出来 BN层
Q:上一次可以在BN层直接得到的trick是什么来着?
A:是通道剪枝中可学习的scaling factor
![[L03-Pruning1#^kkcprq]]
2.4 Post-Training INT8 Linear Quantization
[[Reference_Data-Free Quantization Through Weight Equalization and Bias Correction ]]
[[Reference_Quantizing Deep Convolutional Networks for Efficient Inference_A Whitepaper]]
[[Reference_8-bit Inference with TensorRT]]
- 对于large的模型,各种PTQ方法accuracy的损失都比较小
- smaller模型的实验表明,Weight Equalization + Bias Correction的方法很有效
Can we recover such loss of accuracy from training???
3 Quantization-Aware Training
为了最小化accuracy的损失,尤其是在4bit或更少bit位宽的量化中,神经网络会采用量化后的权重和激活进行训练和fine-tuned
Usually, fine-tuning a pre-trained floating point model provides better accuracy than training from scratch.
回顾K-means量化更新权重的方法:
- 利用原始32bit浮点数计算梯度
- 根据centroids聚类中心将梯度分组
- 将组内的梯度求和(也可以求平均之类的)
- 更新centroids的值,得到fine-tuned的centroids values
线性量化时如何将量化考虑进训练中?
- 一份原始精度的权重副本
- 保留梯度计算的精度
- 模型训练完毕后,只留下量化好的权重用于推理
伪量化节点Fake-Quantize
W:全精度原始权重
q
W
q_{W}
qW:2-bit 有符号整数权重
Q
(
W
)
Q(W)
Q(W):recover的权重 or dequantization权重
在前向传播时,使用quantization+dequantization来模拟量化round引起的误差,将这种误差当作一种训练噪声,在QAT finetune的同时模型会适应这种噪声,从而在最后量化为INT8的时候减少精度损失 量化感知训练(Quantization-aware-training)探索-从原理到实践
这一步具体在代码中如何体现呢?
神经网络量化入门–量化感知训练
```python
class QConv2d(QModule):
def forward(self, x):
if hasattr(self, 'qi'):
self.qi.update(x)
self.qw.update(self.conv_module.weight.data)
self.conv_module.weight.data = self.qw.quantize_tensor(self.conv_module.weight.data)
self.conv_module.weight.data = self.qw.dequantize_tensor(self.conv_module.weight.data)
x = self.conv_module(x)
if hasattr(self, 'qo'):
self.qo.update(x)
return x
在进行卷积运算前先对weight进行量化——self.qw.quantize_tensor;
然后又立刻反量化成float——self.dequantize_tensor;
看一下量化函数的具体操作:
def quantize_tensor(x, scale, zero_point, num_bits=8, signed=False):
if signed:
qmin = - 2. ** (num_bits - 1)
qmax = 2. ** (num_bits - 1) - 1
else:
qmin = 0.
qmax = 2.**num_bits - 1.
q_x = zero_point + x / scale
q_x.clamp_(qmin, qmax).round_()
return q_x.float()
其中,round函数是没有办法进行训练的,因为这个函数几乎每个位置上的梯度都是0
也就是课件中提到的 How should gradients back-propagate through the Fake quantization?
3.1 Straight-Through Estimator(STE)
[[Reference_Estimating or Propagating Gradients Through Stochastic Neurons for Conditional Computation]]
- quantization operator的slope是0,梯度无法反向传播
- STE假设Q(W)对W的偏微分=1(一种广泛使用的近似)
- 梯度直接传回来 不考虑量化op
INT8 线性量化感知训练结果
好奇为什么后面的没讲,讲完STE就到下一个topic了?
翻了下课件,原来是在后面Low Bit-Width Quantization里讲的DoReFa和PACT
4 Binary/Ternary Quantization
更加aggressive的量化方法
[[Reference_BinaryConnect: Training Deep Neural Networks with Binary Weights during Propagations]]
[[Reference_XNOR-Net: ImageNet Classification using Binary Convolutional Neural Networks]]
- Operations变成只有加减,不再需要乘法计算
- 进行二值化
4.1 Binarization
两种二值化的方法
^vf9pec
- Deterministic Binarization确定性二值化:sign函数,大于等于0就变为1;小于0的等于0
- Stochastic Binarization随机二值化:值大就有更大的概率量化成+1,值小有更大的概率量化成-1(不容易部署,因为需要在量化时产生随机bit)
论文中提到,第二种方法似乎更加合理,但它也引入了按概率分布的随机比特数,因此硬件实现会消耗很多时间,所以通常会选定第一种方法来对权重和输出值进行量化。
- 确定性二值化sign函数,直接把整数变为+1,负数变为-1:两个权重矩阵的差异为9.28;精度损失21.2%
- 引入scaling factor后两个权重矩阵差异为9.24,精度损失为0.2%
- 课件里直接给了scaling factor
=
1
n
∣
∣
W
∣
∣
1
=\frac{1}{n}||W||_{1}
=n1∣∣W∣∣1 的计算方法
推导过程见[[Reference_XNOR-Net: ImageNet Classification using Binary Convolutional Neural Networks]]
4.2 If both activations and weights are binarized
左边为权重和激活均被二值化后的真值表
将原始表中所有的-1映射为0得到右边的真值表,就变成了XNOR Function(相同为1 不同为0)
Unfortunately,直接映射成XNOR后得到的计算结果与原来的不一致
那么我们怎么将XNOR得到的结果1转换到原始计算结果-2呢?
- 假设所有的累加项都是 -1(因为我们把之前真值表的-1变成了0,现在我们把它变回去):得到的结果是-4
- 数一数有多少个1(计算时的映射是将-1变为0,step1中却把所有的值都变为1了)
- 将step1中的结果 + Num_1 x 2
整理成一般形式表达式:
y i = − n + p o p c o u n t ( W i x n o r x ) < < 1 y_{i}=-n+popcount(W_{i}\text{ } xnor\text{ } x)<<1 yi=−n+popcount(Wi xnor x)<<1
popcount:返回1的个数 Num_1
这个operation非常容易部署
看一个具体计算的例子:
将weights和activation中的-1替换成0然后进行同或运算,结果为1000
popcount返回1000中1的个数=1,左移1位=2,n为activation的长度=4,最终计算结果为-4+2=-2
4.3 Accuracy Degradation of Binarization
[[Reference_Binarized Neural Networks_Training Deep Neural Networks with Weights and Activations Constrained to +1 or −1.]]
[[Reference_XNOR-Net: ImageNet Classification using Binary Convolutional Neural Networks]]
5 Ternary Weight Networks(TWN)
[[Reference_Ternary Weight Networks]]
二值化网络只看正负值,映射到+1 or -1
三元网络选择一个阈值
Δ
\Delta
Δ ,映射到 +1 0 -1
阈值
Δ
\Delta
Δ 和映射后的值具体是多少,由 r 的期望决定
0.7是一个经验值
- Scaling factor计算的时候不除以kernel size 而是除以映射后的非零权重个数
- 精度下降的比BNN少一些
5.1 Trained Ternary Quantization
三元神经网络映射后的
r
t
r_{t}
rt :把固定值换为trainable的参数
w
p
,
w
n
w_{p},w_{n}
wp,wn
- 将原始精度权重归一化到-1~1
- 对权重进行量化(在-t~t之间的量化为0)
- 对量化后的权重进行训练,得到 w p , w n w_{p},w_{n} wp,wn
- 精度损失只有3%
6 Low Bit-Width Quantization
(2022年的课程视频里没讲 2023的slides)
Train Binarized Neural Networks From Scratch
- 考虑饱和效应的STE直通估计器
- 保留梯度信息,在y太大时取消梯度
- 截取浮点数权重副本到-1~1区间
- 用于正则化的权重约束
DoReFa-Net with Low Bit-Width Gradients
[[Reference_DoReFa-Net-Training Low Bitwidth Convolutional Neural Networks with Low Bitwidth Gradients]]
课件中列出了浮点数转K-bit定点数、激活、权重、梯度的量化方法
Dorefa-Net是第一个被提出用来进行任意 bit量化的工作。原始 [0, 1]之间的float32位的数据通过量化函数 𝑓:𝑞𝑢𝑎𝑛𝑡𝑖𝑧𝑒𝑘约束映射到 [0, 1]之间的 k位定点数。再通过反量化函数映射到 float32域,完成 FackQuant的过程。
- 替换Activation Function
- 最常用的激活函数ReLU是无界的,而由于非常有限的范围和分辨率,inputs的动态范围变成地量化位宽需要考虑的问题
- ReLU被替换成具有hard-coded的激活函数:ReLU6,ReLU1,etc.
- 每层截断值得方法在PACT中也被使用
Parameterized Clipping Activation Function
- 在PCAT中,ReLU激活函数被替换成0到可学习的上界
- 定义了PCAT的STE
- 学习到的上界越大,这个函数就和ReLU越相似
- 为了避免由于大的 α \alpha α 引入的量化误差,在损失函数中加入 α \alpha α 的L2正则
这里就是PCAT对DoReFa-Net做出的改进了:
- DoReFa-Net将每层的激活值暴力的截断在[0~1]的范围内
- PACT把截断的上界交给模型自己去学习
PACT(Parameterized Activation Threshold)是提出的第一个带训练参数的量化感知训练模型,相对于 Dorefa-Net而言,其在激活值量化层面上引入了可学习的参数 𝛼表征输出激活值的可量化最大值,也即量化范围。在 Dorefa-Net由于限制了激活值 在量化前必须截断到 [0,1]之前导致了精度的损失, PACT的改进能够有效地保留输出信息,从而提高模型精度。
Wide Reduced-Precision Networks
增加神经网络的宽度来弥补量化来带的信息损失
[[Reference_WRPN-Wide Reduced-Precision Networks]]
用多个二进制卷积来替换单个浮点数卷积
[[Reference_Towards Accurate Binary Convolutional Neural Network]]
不量化第一层和最后一层
- 对量化更敏感
- 总体计算量中很小的一部分
- 量化到8bit不损失精度
迭代量化
[[Reference_Incremental Network Quantization-Towards Lossless CNNs with Low-precision Weights]]
Iterative Quantization,增量量化所有权重可以获得更好的精度
先量化一部分->重训练->继续量化
-
设置
- 只量化权重
- 量化权重的位数为2的n次方, 为了用bit shift代替乘法加快计算
-
算法
- 从一个预训练好的fp32模型开始
- 剩余的fp32权重
- 分成两个不相交的组(例如用幅值)
- 量化第一组(幅值更高的),retrain另一组来恢复精度
- 重复流程直到所有权重都被量化(50%,75%,87.5%,100%)
-
算法流程的可视化
7 Mixed-Precision Quantization
Uniform Quatization将每层的权重和激活量化到一个固定的位宽 如8bits
混合精度量化是指在不同层、对权重和激活,采用不同的bits量化
Challenge: Huge Design Space
假设最多是8bits量化,对于权重和激活各有8中可能,每层就是64种,对于n层的网络就有
6
4
n
64^{n}
64n 种情况
Solution: Design Automation
强化学习
[[Reference_HAQ_Hardware-Aware Automated Quantization with Mixed Precision]]
与AMC方法去寻找每层最佳的sparsity ratio很类似
加入硬件行为仿真,根据不同的weight activation bits的方案,给出latency和efficiency的Feedback
HAQ的表现(MobileNetV1)
depthwise和pointwise在edge/cloud weight/activation具有明显不同的pattern