原文链接:https://www.yuque.com/yahei/hey-yahei/shift_quantization
移位量化也可以称为对数量化,将数值从浮点数的形式量化为一个整数或定点数,但它与线性量化不同,两个相邻数之间是在以2为底的对数域上均匀分布的,这使得实际推理当中可以直接通过移位运算来快速实现,同时也拥有随比特数增长而指数增长的大动态范围。
移位量化既可以只量化权重(对**值移位),也可以只量化**(对权重值移位),当然也可以同时量化权重和**(对值1移位)。由于涉及底层的位移运算,可以设计出各种比较花哨的近似位移或并行位移的技巧,这些方案大多更适用于FPGA。
此外,ShiftCNN也采用了一种不完全的移位相加形式来替代乘法,也算是相对折中的一种处理方案。
LogNN
论文:《Convolutional Neural Networks using Logarithmic Data Representation (2016)》

仅量化**
如图(b),量化**值为整数
x~i=Quantize(log2(xi))
此时与权重之间的乘法计算就可以简化为移位
wTx≈i=1∑nwi×2x~i=i=1∑nBitshift(wi,x~i)
也可以量化为定点数,此时加上一个常量偏移FSR,即x~i,FSR=x~i+FSR
此时**值需要存储一系列的x~i,FSR和一个共享的FSR;
当然,实际量化还要考虑溢出问题,
{x~ix~i,FSR=Clip(Quantize(log2(xi)),−FSR,−FSR+2bitwidth)=x~i+FSR
再来看看Quantize(⋅),
- 最直观:直接向上、向下或四舍五入来取整
- 最快(等价向下取整):如图(b),直接取二进制串中最左侧1的位置,比如x=15=0b001111量化为x~=3
量化权重和**
权重的量化方式与**相同,此时乘法计算进一步简化为
sn=wTx≈i=1∑n2Quantize(log2(wi))+Quantize(log2(xi))=i=1∑nBitshift(1,w~i+x~i)
写作递推式为
sn=sn−1+wnxn≈sn−1+Bitshift(1,w~n+x~n)
记p~i=w~ix~i,则可以推导出对数域的近似累加公式,
s~n=log2sn≈log2(sn−1+2p~n)={log2(1+2p~n−log2(sn−1))+log2(sn−1),log2(2log2(sn−1)−p~n+1)+p~n, if p~n<s~n−1 if p~n>s~n−1={log2(1+2p~n−s~n−1)+s~n−1,log2(2s~n−1−p~n+1)+p~n, if p~n<s~n−1 if p~n>s~n−1={2p~n−s~n−1+s~n−1,2s~n−1−p~n+p~n, if p~n<s~n−1 if p~n>s~n−1(... note that log2(1+z)≈z if 0<z<1 ...)≈2−∣s~n−1−p~n∣+max(s~n−1,p~n)≈Bitshift(1,−∣⌊s~n−1⌋−p~n∣)+max(s~n−1,p~n)
在对数域上直接近似累加,比原始的“累加+量化”过程更加高效
ShiftCNN
论文:《ShiftCNN: Generalized Low-Precision Architecture for Inference of Convolutional Neural Networks (2017)》
表示形式
为权重设置N个子码本(codebook),每个码本包含M=2B−1个码字,每个码字位宽B bits,此时量化后的权重可以如此表示:
w^i=n=1∑NCn[idxi(n)]Cn={0,±2−n+1,±2−n+2,±2−n−⌊M/2⌋+2}
其中Cn是N个子码本的第n个;idxi(n)是wi在第n个子码本上对应的索引;
假设N=2,B=4,那么码本可以表示为
C1={0,±20,±2−1,±2−2,±2−3,±2−4,±2−5,±2−6}C2={0,±2−1,±2−2,±2−3,±2−4,±2−5,±2−6,±2−7}
显然,
- 当N=1,B=1且码本不包含0值时,退化为二值量化
- 当N=1,B=2时,退化为三值量化

量化方案

简单来说,就是先对权重作归一化,然后逐个码本去找误差最小的位移方案,然后保留索引idx
推理细节
本质是用移位替代乘法。
假定乘法y=wx,w已经被量化为若干2n求和的形式w^,那么乘法过程就可以被简化成移位相加的形式。
比如对于N=2的码本有w^=2−1+2−2,
那么乘法y=wx就优化为y^=(x>>1)+(x>>2)
考虑到多码本的情况下可能同一个数值存在多种表示的情况
比如N=2,B=3,w=0.7
C1={0,±20,±2−1,±2−2}C2={0,±2−1,±2−2,±2−3}
那么既可以量化为w^=20−2−2=0.75,也可以量化为w^=2−1+2−2=0.75但如果按照前述的算法进行量化,那么只会量化成w^=20−2−2=0.75
所以实际上只有P=M+2(N+1)种不同的码字,那么对于一个输入x,它只有P−1种移位情况(忽略零码);
对于C×H×W的输入特征图,可能存在的移位组合只有(P−1)×C×H×W种,也就是说我们可以预设好所有情况,然后通过查表直接并行得到移位结果,直接按元素加和起来作为输出特征图。


INQ
论文:《Incremental Network Quantization: Towards Lossless CNNs with Low-Precision Weights (ICLR2017)》
实现:https://github.com/AojunZhou/Incremental-Network-Quantization

量化方案
仅量化权重。
把第l层卷积的权重Wl量化为b bits的W^l,其中1bit用来表示权重值是否为0,另外(b−1)bits用来存储非零权重的量化结果,其余量化形式与LogNN相类似,记偏移量为N,那么W^l将在如下Pl里取值:
Pl={0,±2N,±2N+1,...,±2N+2b−2+1}
接下来确定N,
N=⌊log234max(abs(Wl))⌋
对于每个权重值,
W^l(i,j)={βsign(Wl(i,j)),0, if 2α+β≤abs(Wl(i,j))<23βotherwise
其中α,β是排序好的Pl中相邻的两个值 ——(这波量化怎么有点云里雾里)
增量式量化
作者参考增量式裁剪,设计了增量式量化的方案。先对权重取绝对值,取比较大的一批先量化,其他权重值保持浮点数,然后对浮点数权重做恢复训练;如此反复,逐渐扩大量化的范围直到所有权重都完成量化(如50%->75%->87.5%->100%)。
另外按照作者的实验,根据绝对值的尺度来确定哪些权重需要量化效果要比随机挑选的好。

DeepShift
论文:《DeepShift: Towards Multiplication-Less Neural Networks (2019)》
参考:《把CNN里的乘法全部去掉会怎样?华为提出移动端部署神经网络新方法 | 机器之心》
实现:https://github.com/mostafaelhoushi/DeepShift
也不算有很多花样,依旧是对数形式的量化,只量化权重,提出两种形式的训练过程DeepShift-Q和DeepShift-PS,但效果都差不多。但用CUDA在GPU上实现了移位版本的全连接、卷积,算是也有不少工作吧。


DeepShift-Q
Q指的是Quantization,也即传统的将量化操作纳入训练过程的形式。
S~P~W~=Sign(W)=Round(log2∣W∣)=S~⋅2P~
Round(⋅)函数的求导依旧是采用STE近似,也即∂W∂W~≈1
DeepShift-PS
PS指的是Power、Sign,顾名思义,不再保留浮点数的权重W,而是直接训练参数S和P,训练过程中参数S和P均用浮点数存储,训练完毕后再固定为整数。
S~P~W~=⎩⎪⎨⎪⎧+1,0,−1, if S≥0.5 if −0.5<S<0.5 if S≤−0.5=Round(P)=S~⋅2P~
注意使用L2惩罚时,惩罚项应为∑W2=∑S24P而不是∑P2+∑S2
其他
LogQuant:《A Deep Look into Logarithmic Quantization of Model Parameters in Neural Networks (IAIT2018)》