这篇文章是Google发布的关于神经网络量化方面的文章,文章地址:https://arxiv.org/abs/1712.05877
本博客参考了微信公众号“AI芯片算法”中的原创文章《Google CVPR2018 8bit 量化论文》一文。
1、本文的贡献
本文主要侧重将推断中的浮点数运算量化为整数运算(Integer-Arithmetic-Only),最终将权重和激活函数量化为8-bit,只有一小部分参数(bias)为32-bit整数。另外,本文提出一种新的量化框架,在训练过程中引入伪量化的操作,用于模拟量化过程带来的误差(这一框架在mobilenet等本身比较精简的网络上效果不错)。
2、量化推断
2.1、量化方案
令 q 为实数值 r 量化后的值,有
其中,S 和 Z 为量化参数。 S 为浮点型的scale,Z 为 zero-point。具体的数据结构如下
与传统的一致非对称量化不同,这里是将最小值对应的量化值(zero-point)也做了量化。这样做的原因是为了推断时候做整数乘法累加运算(但偏差会稍微大一些,损失一点精度)。这里,同一层采用相同的量化参数。
2.2、矩阵乘法的整数运算
首先,两个实数矩阵相乘可以表示为
这里,除了M外,其他都是整数。
因此,需要将“乘以M”这一浮点操作,转化为整数运算和移位运算的合成。
(这里将M0控制在[0.5,1)的范围内,应该是为了更好的表示成int32类型,这个地方一直有点疑惑)。
第二步,缩减公式(4)中的运算次数,将公式(4)转化为公式(7)。
公式(8)可以用2N^2次假发得到,剩下的运算主要集中在计算公式(9)中(2N^3)
而uint8的乘法累加运算需要int32来存储,即
第三步,将bias表示为int32,对应的量化参数为
然后将 r_bias = S_1·S_2·q_bias 加到公式(3)的右边,再转化为类似公式(7)的形式。转化后,括号中的运算为int32类型,乘以M可以看作先乘以int32类型的定点数M0,再进行移位操作。最后,将得到的结果截取到[0, 255]区间内,实现uint8类型的输出。需要注意的是,由于后面采用了伪量化操作,因此ReLU的效果已经由clamping(0,255)代替,故而不再需要激活函数。
3、模拟量化训练
一般量化的方法都是先用浮点数训练,然后量化权重。但这种方法对参数冗余的网络很适用,但是对本身比较精简的网络效果不太好。效果不好的原因主要有两点:(1)每一层中的各输出通道对应的权重差距过大(大于100x);(2)outlier weight会降低其他权重的量化精度。
本文提出在前向的时候进行模拟量化的方法。后向传播不变,仍按照浮点型存储数据。在前向传播时,在推断时需要量化的地方,插入伪量化操作。这里需要注意的是,
(1)权重是在与输入进行卷积前进行量化,如果有BN层,需要将BN层的参数在量化前folded into权重中。
(2)activation的量化在激活函数或者bypass(resnet)之后进行。
伪量化操作为
即先量化,再还原。
3.1、学习量化range
对权重来说,可以令a,b为最小和最大的权重。对activation来说,[a,b]由EMA计算得到。
一般的量化流程(不带BN层)为
3.2、BN层的folding
对于BN层,需要将BN参数考虑进权重,然后再进行量化。
如图
4、实验
略,后续有空再补