AdaRound:Up or Down? Adaptive Ro

2021-07-25  本文已影响0人  加油11dd23

一、摘要

  1. 该论文首先从数学的角度证明了在模型量化中,直接将浮点数进行四舍五入round到最近定点数的方法并不是精度最优的,同时,分析Round对于最终task loss的影响。并且抽象成一个优化问题: Quadratic Unconstrained Binary Optimization
  2. 通过一个简单的实验证实了这个猜想
  3. 然后作者通过一系列的数学推导和先验假设,得到了AdaRound算法。通过per-layer的fine-tuning来获取对于Round误差的补偿。这个补偿和每个weight相关的,有的weights会被Round Up,有的weights会被 Round down。 这个补偿是一个可以train的东西,通过梯度回传的方法而学习获得。
  4. 通过一系列消融实验和对比实验验证了该算法的优越性。

AdaRound算法一言以蔽之:对conv中每个weight值进行量化时,不再是四舍五入的round-to-nearest,而是自适应的决定weight量化时将浮点值转到最近右定点值还是左定点值。(例如根据round-to-nearest规则,4.3,4.5,4.7会分别转到定点值4,5,5。而AdaRound则可能将其转换为5,4,4的定点值)。

二、背景

1、 Round的类型

Rounding 有挺多种类和不同的行为。Deeplearning量化常用的Rounding,通常有以下几个

2、量化流程

量化指的是将一个范围的浮点值转换成定点值,常规的模型量化流程是:

先根据量化算法计算scale值。
浮点值除以scale后进行round操作。
最后再按照定点取值范围进行clip,得到量化定点值。

3、反量化流程

而如果对量化产生的定点值再乘个scale(该过程也被称为反量化),得到的就是伪量化值记做W_hat(虽然又回到了浮点值,但由于量化过程中有round和clip操作,伪量化值已经不同于原始浮点值)。整个反量化过程如公式(1) 所示:


image.png

4、量化误差

W - W_hat的绝对值就是weight量化产生的误差。

三、动机

1、四舍五入的量化误差从理论上来说并不是最优的

image.png
image.png
  1. Hessian矩阵的求解。Hessian矩阵理论上是可以求解的,但是所需要的计算的内存是一个特别夸张的数据。假设网络权重的个数是N,那Hessian是一个 NN的矩阵。当然,在实际应用中,也有一些类似的近似解的求法,但在这里就不特别展开了。

四、AdaRound

简化优化问题(21)

1、 from task loss to local loss

为了便于理解,作者首先从一个简单的例子出发:假设一个模型最后输出层l是一个只有两个weight的全连接,对weight计算二阶偏导即为:


image.png

这里z(l)表示当前层的输入也就上一层w和x的乘,所以我们可以计算得出第l层权重的海森矩阵即为:


image.png

从这个公式中不难看出,计算第L层weight的海森矩阵,需要借助第L-1层的二阶导信息,也就是这个原因导致直接计算每一层的海森矩阵是极其困难的。所以为了继续求解我们最小量化误差,需要对海森矩阵的计算进行进一步的简化:

image.png
将公式(16)推导到公式(17),作者引入了一个比较强的假设:假设公式(16)中关于L-1层(也就是z(L))的海森矩阵是一个对角矩阵也就是L-1层的weights之间的相互关联对第L层weights的海森矩阵求导是不相关的。

然后再将公式(17)带入到公式(13)中,得到公式(18):

image.png
而从公式(18)到公式(19)也是用了一个很强的先验假设,即对于第L层来说:
image.png
也就是说,作者假设在对第L层计算量化损失时,认为第L-1层对L层的量化损失影响是一个不依赖于校准数据集输入的常量,所以在公式(18)中可以直接省略。(在论文的实验中证明了该假设对最终结果的影响)。

于是通过多个假设,我们要求解的公式就从公式(13)简化成了公式(20)。观察公式(20),可以发现此时待求解公式变成了一个每个layer独立的、不依赖于其它layer和task loss的求解公式。问题变成了找到可以使∆WX的MSE loss值最小的∆W。

2、NP-hard问题简化

为了求解∆W,我们还需要对公式(20)进行简化,得到下面的一组公式:

image.png
这四个公式是AdaRound的核心计算公式,下面对这四个公式进行逐一解释:

下图展示了优化前和优化后h(Vi,j)之间的对应关系,可以发现所有h(Vij)都已收敛到0或1两个值上,而图中的虚线则是round-to-nearest的量化截取方法得到的效果(两条垂直虚线分成的四个格子中,右上的h(Vij)应该被量化到1,左下的h(Vij)应该被量化到0.)可以看到AdaRound对不同值的量化选择和round-to-nearest是不相同的。


image.png

3、正文

至此我们得到了公式(21~24)一组公式就可以一层一层的对weight进行优化。然而公式(21)存在一个缺陷:无法避免量化误差的不断累积也没有考虑到激活函数,所以作者对公式(21)进行进一步的优化:


image.png

其中fa()为激活函数。x_hat为当前层的反量化输入,x为当前层的浮点输入。也就是将对∆W的优化转换为对conv计算后结果的优化。

公式(25) 即为AdaRound最后表达式,我们可以直接使用梯度下降算法进行求解。

4、代码

首先安装AMIET,有tf和pytorch两个版本可以安装
https://quic.github.io/aimet-pages/releases/1.16.2/user_guide/adaround.html#ug-adaround

params = AdaroundParameters(data_loader=data_loader, num_batches=num_batches, default_num_iterations=10000,
                                default_reg_param=0.01, default_beta_range=(20, 2))
# W4A8
param_bw = 4
output_bw = 8 
quant_scheme = QuantScheme.post_training_tf_enhanced

adarounded_model = Adaround.apply_adaround(model, torch.rand(1, 3, 224, 224).cuda(), params, path='./',
                                               filename_prefix=filename_prefix, default_param_bw=param_bw,
                                               default_quant_scheme=quant_scheme)


# Create QuantSim using adarounded_model, set and freeze parameter encodings and then invoke compute_encodings
sim = QuantizationSimModel(adarounded_model, quant_scheme=quant_scheme, default_param_bw=param_bw,
                               default_output_bw=output_bw, dummy_input= torch.rand(1, 3, 224, 224).cuda())
sim.set_and_freeze_param_encodings(encoding_path=f'./{filename_prefix}.encodings')
sim.compute_encodings(model_eval, forward_pass_callback_args=1)

quantized_model_accuracy = model_eval(model=sim.model, early_stopping_iterations=None)

五、实验

由于整个AdaRound的推导过程引入了不少强先验假设,作者首先在ResNet18上进行了消融实验,从实验的角度验证先验假设对模型精度的影响。同时作者对比了AdaRound和其它主流后量化算法对不同CV任务的精度量化效果。

1、5.1 消融实验

作者用ResNet18进行消融实验,实验配置如下:

六、阅读中的疑惑点

1、优化公式13如何得到使用何种round方法?

image.png
其中weihgt floor即表示floor round 方法,weight ceil的计算方法类似。s表示量化用的scale值,而∆W就是浮点weight和伪量化weight之间的差值。
优化公式13得到了\deltaw,即浮点weight和伪量化weight之间的差值。又因为已知了浮点量化weight,则可以得到伪量化weight,进而求出是上round哈市下round

提出AdaRound的方法,通过per-layer的fine-tuning来获取对于Round误差的补偿。这个补偿和每个weight相关的,有的weights会被Round Up,有的weights会被 Round down。 这个补偿是一个可以train的东西,通过梯度回传的方法而学习获得。
在一个多层的网络中,文章中采取逐层fine-tuning的方法来对每一层进行adaround的操作。 这样,非常有利于嵌入到post-training的工具里边,只需要获得 full-precision的输出,以及量化后的网络的输出,就可以来train该层的V.
AdaRound是train了一个变量V来控制每一个individual的weights是往上还是往下Round

2、优化公式20如何何种round方法?

V取0还是1决定是上round还是下round。
七、改进点:

AdaRound是train了一个变量V来控制每一个individual的weights是往上还是往下Round。那么是否可以有类似的想法,用在Pruning上呢?
AdaRound能否用在quantization-aware的training上? Training中虽然可以用到STE,但是也会有Round的误差,是否可以用类似的方法来取代STE?
Activaiton可以用这个方法吗?通常Activation的每次都会随着输入的变化而改变,但是否能发现某些区域的activation更偏向于round up,而某些区域更偏向于 rounddown。如果这样的话,是否可以train V 来代表round up/down 的概率。

参考:
https://zhuanlan.zhihu.com/p/391203508
https://zhuanlan.zhihu.com/p/363941822
https://quic.github.io/aimet-pages/releases/1.16.2/user_guide/adaround.html#ug-adaround

上一篇下一篇

猜你喜欢

热点阅读