yahei · 2020年09月21日

重训练量化(改进QAT)

原文链接:https://www.yuque.com/yahei/hey-yahei/quantization-retrain_improved_qat
欢迎引用&转载,但烦请注明出处~

Quantize Aware Training(QAT)通过在训练过程中融入量化和反量化过程,来实现量化模型的精度恢复,但考虑一下量化过程
image.png


显然取整的求导的时候处处为零,是无法训练的。因此QAT需要引入Straight-Through Estimator(STE)来得到一个近似的梯度,也即令,相当于用去近似来进行求导。通常,如果比特数比较高的时候,这里带来的误差并不明显;但在低精度场景下,STE会导致训练不稳定。所以一直有研究者试图通过避免或优化STE来改进QAT。

Alpha-Blending(AB)

论文:《Learning low-precision neural networks without Straight-Through Estimator(STE) (IJCAI2019)

AB算法将全精度权重跟量化权重加权混合得到新的权重用于训练,反向传播时,量化权重的链路不采用STE,故导数为0,因此只会沿着全精度权重的链路反向传播。
image.png

随着训练的进行,逐渐从0增长到1,增长的方式可以有很多种,比如


并且学习率也随着的增长而衰减

(以下实验中,均采用最小化L2误差的交替优化方案
image.png
image.png
image.png
(ImageNet实验)

QuantNoise

论文:《Training with Quantization Noise for Extreme Model Compression (2020)
来自facebook的工作,算是借鉴了Dropout和增量式量化的思路,在训练过程中随机量化一部分权重而保持其他权重为全精度,以保证训练过程中总有一部分权重是不需要使用STE获得近似梯度。

image.png
Dropout示意,训练时随机丢弃部分权重)

image.png
增量式量化示意,训练时从绝对值较大的权重开始,逐步扩大量化范围)

image.png
(QuantNoise示意,训练时每次随机量化一部分权重)

PyTorch实现上非常简单,原本QAT的代码为

noise = quantize(w) - w
w_q = w + noise.detach()

QuantNoise只需要乘上一个随机生成的掩膜

noise = quantize(w) - w
w_q = w + noise.detach() * mask

论文里做了很多NLP的实验,可惜我对NLP了解的不多,做不出评判。CV也就跑了EfficientNet-B3,诶就不能跑下MobileNet吗,跑EfficientNet不太好跟其他论文直接比较。
image.png
不过看起来EfficientNet int4掉点有点厉害啊(这里的int4应该是同时将权重和激活都量化成int4了)。简单地复现过论文,发现并不能跑出这样的结果,在同等条件下QAT总是比QuantNoise好而且收敛更快。论文其实隐瞒了很多实验细节,倒是指明了QuantNoise激活值是采用PyTorch的HistogramObserver来量化(HistogramObserver实现细节可以参见《后训练量化 - 数据收集方法 - 直方图 - 如何在直方图上计算L2误差? | Hey~YaHei!》),但对QAT没做更多说明。我怀疑实验中QAT是采用了指数平滑平均的方式量化激活值,也做了几个简单的实验,发现QAT采用指数平滑平均量化激活值,QuantNoise采用HistogramObserver量化激活值时实验结果跟论文实验结果“惊人”地相似……于是跑到github项目上(只开源了一小部分代码)提了issue不过没有得到答复,感觉QuantNoise的实际效果存疑。

全精度辅助模块

论文:《Training Quantized Neural Networks with a Full-precision Auxiliary Module (CVPR2020)

AB算法混合了量化权重和全精度权重来训练,那么为什么不干脆分成两个分支,共享一套权重,一个分支走量化权重、另一个分支走全精度呢?这样在反传的时候,就既有来自全精度分支的梯度、也有来自量化分支的梯度。
image.png

这种想法比较朴素,训练代价(主要是训练时间)相比于原始模型就增加了一倍。而论文则是采用辅助模块来做量化补偿以实现这种想法:
image.png
(设计思路)

image.png
(如果觉得上一张图比较绕,我们可以试试换种画法)

蓝色部分的block采用量化的模型,每个block的输出(加和之前的特征图)经过Adaptor来做一定的量化补偿后加到全精度分支里,最后分别求loss,两者加和后反传和更新梯度,此时权重梯度既能来源于量化分支又能来源于“全精度”分支。论文里Adaptor采用的是一个1x1卷积,更复杂的设计会带来一些细微的提升,但1x1卷积基本就够用(后边有实验数据)。

这个思路跟辅助任务、知识蒸馏有点像,论文里还特地比较了一下
image.png
(辅助任务)

image.png
(知识蒸馏)

辅助任务可能存在多个分类器,挑选辅助分类器插入的位置会比较麻烦,而且跟引入全精度分支的思路相比还是差了那么点意思;知识蒸馏两分支则完全独立,训练时用全精度网络来监督量化网络的训练,但训练代价会比较大,再有就是知识蒸馏的是否需要加权,加多大的权重也是需要微调的。

实验细节
量化均采用QIL的算法,保持BN层统计量的更新;对于RetinaNet,各个head之间不共享,论文给出的解释是,在量化模型中,不同尺度特征图语义信息不能被很好的编码,不共享head虽然会增加参数量,但却不会增加计算代价。
image.png
(有无辅助模块的比较实验,ImageNet)

image.png
(与辅助任务、知识蒸馏方法的比较实验,2bit,ImageNet)

image.png
(Adaptor设计比较,2bit,ImageNet)
(3x3卷积稍微好一点点,但不明显)

image.png
(与FQN方法比较,4bit,COCO)

image.png
(共享head,4bit,COCO)
(Backbone only指的是只量化Bakbone)

推荐阅读
关注数
290
内容数
26
计算机视觉相关学习笔记,欢迎关注。[链接]
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息