MIT-TinyML学习笔记【5】Quantization2

1 Lecture Plan

image.png

  • 训练后量化 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]]
image.png

  • 对权重进行量化时,实数的最大值=权重最大值
  • 每个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的例子
重建后的权重矩阵跟原始矩阵差别较大
image.png
再看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

image.png

Per-Channel精度更高但同时也要存储更多的scale参数;
我们能不能让权重范围的差异更小呢?
image.png

2.1.2 Weight Equalization

对不同输出通道的权重范围进行调节(static,without training
image.png

  • 第 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?

  1. 每次要对相邻两层的权重进行计算,并且要对整个网络进行计算
  2. 假设了相邻两层的计算是线性
    如果使用的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]]

image.png

  • 对每个weight进行rounding只考虑了它自己,没有考虑权重之间的interaction
  • rounding可以最好的重建原始激活activation;
  • 仅对权重进行量化,short-term tuning,几乎是PTQ

Adaptive Rounding 通过对一点tuning,实现了在量化权重时考虑权重间的相关性(在学习h(V)的时候所有权重一起tuning)

image.png

  • 拿一点数据来训练得到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是不同的

image.png

  • 在部署模型之前,要先统计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]]
image.png

  • 使用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]]
image.png

  1. 最小化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}] minrmax[(XQ(X))2]
  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 rmax=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∣∣W1 的计算方法
    推导过程见[[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(因为我们把之前真值表的-1变成了0,现在我们把它变回去):得到的结果是-4
  2. 数一数有多少个1(计算时的映射是将-1变为0,step1中却把所有的值都变为1了)
  3. 将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

8 Summary

9 References

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值