简介
固定bit下的量化始终无法在Accuracy和 (FLOPs & Parameters)之间达到一个非常细粒度的trade-off,所以就需要混合精度量化(Mixed-Precision Quantization, MPQ)来对模型实现进一步的高效压缩
混合精度量化区别于混合精度训练这个概念,后者指的是在模型训练过程中使用FP16来代替传统的FP32从而达到占用显存更少,计算速度更快的目的,而本文要谈的混合精度量化指的是通过设计某种policy,来对模型各层的weights和activations的量化bit位宽进行合理分配,其重点就是如何设计这个policy,从而使得混合精度量化之后模型能够在精度和硬件指标上达到最佳的平衡。
量化并不是什么新知识,我们在对图像做预处理时就用到了量化。回想一下,我们通常会将一张 uint8 类型、数值范围在 0~255 的图片归一成 float32 类型、数值范围在 0.0~1.0 的张量,这个过程就是反量化。类似地,我们经常将网络输出的范围在 0.0~1.0 之间的张量调整成数值为 0~255、uint8 类型的图片数据,这个过程就是量化。
所以量化本质上只是对数值范围的重新调整,可以「粗略」理解为是一种线性映射。之所以加「粗略」二字,是因为有些论文会用非线性量化,但目前在工业界落地的还都是线性量化
不过,可以明显看出,反量化一般没有信息损失,而量化一般都会有精度损失。这也非常好理解,float32 能保存的数值范围本身就比 uint8 多,因此必定有大量数值无法用 uint8 表示,只能四舍五入成 uint8 型的数值。量化模型和全精度模型的误差也来自四舍五入的 clip 操作。
量化其实是离散化。基本保持定点值在对应原浮点值的相对大小关系的情况,利用了定点值计算快开销小来进行加速,达到这个目的要求将不同的全精度值尽可能映射到不同的定点值,采用什么映射方法是没有关系的,只要能够来回映射就可以。
这是因为在图像任务中,具体的值是没有意义的,我们并不关心具体的取值是多少,我们需要的其实是一群值之间组成的相对大小关系。
也就是说,其实不同层的conv采用相同的S和Z在原则上也是可行的,但是由于定点值区间就是0-255,而不同层的浮点值值区间不一样,如果采用相同的S和Z,会导致有些层的映射损失很大,因此需要采取适应的 S 和 Z
需要对 weight 量化到 int8 然后又反量化回 float,这里其实就是所谓的伪量化节点,因为我们在实际量化 inference 的时候会把 weight 量化到 int8,这个过程本身是有精度损失的 (来自四舍五入的 round 带来的截断误差),所以在统计 min、max 的时候,需要把这个过程带来的误差也模拟进去
理解:
首先float32也是一种精度,只不过精度比较高,但是他也不是 R R R这么大的范围。其实同理于int8,uint8能表示的范围就是 [ 0 , 2 b − 1 ] [0, 2^b - 1] [0,2b−1]即 [ 0 , 255 ] [0, 255] [0,255]你每表达一个数就是 1 256 \frac {1}{256} 2561。255也就是我们说的quantization
level
神经网络的表达能力,主要体现在网络本身的结构,还有数的精度。数在神经网络中可以抽象成占比的大小,越高代表权重越重要。数的精度肯定是越精细越好,但你像bit
width很低的神经网络也能达到好的效果,一定程度上说明了数只是表达的一部分,相对大小是保留了的。能达到好的效果的很重要的一部分是因为你这个网络结构足够复杂足够深。
量化的主要过程是先模拟量化然后再反量化,像0.32,量化到8bit,先乘以255,0.32*255=81.6,经过round函数以后就是82。然后再反量化到32-bit,82/255=0.321568627451,这样子量化前和反量化以后的值就不相同了,原来的值等于0.32,反量化以后等于0.321568627451
PTQ
PTQ一般是不需要重新训练的,PTQ就是在full precision后,用一点测试集估计一下minmax这些量化参数就可以。
QAT
在量化的过程中,对网络进行训练,从而让网络参数能更好地适应量化带来的信息损失。量化中的round函数会导致反向传播的梯度也变成 0。换言之,这个函数是没法学习的,从而导致量化训练进行不下去。
训练时量化对于权重和激活输出采用模拟量化操作来衡量量化效果。对于反向传播,使用“直通估计器”去建模量化。
模拟量化操作是在训练时就进行量化的,操作实际包括一个量化再紧跟一个逆量化。具体的,就是在前向传播的时候(forward)模拟了量化的这个过程,在forward时首先会把权值和激活值量化到8bit再反量化回有误差的32bit,整体训练还是浮点
量化时反向传播梯度使用了 STE,即straight-through estimator,去掉round函数,然后直接将梯度传递给浮点数
QAT时,要进行两步的,要经过量化和反量化,前向传播进行量化和反量化,反向传播梯度还是给的浮点数
LSQ对量化公式里的参数scale进行了调整,可以让网络训练的同时,训练scale值,不再是定值了
总结
PTQ是没有backward不进行weight更新,forward只是用来统计,所以其实伪量化对PTQ来说可有可无;QAT还会再训练一下得出loss进行反向传播更新参数,这个地方的训练采用的是伪量化,要不然由于导数为0无法进行梯度更新。
AI小男孩:
一般是先train一个全精度的,区别主要是PTQ一般是不需要重新训练的,用一点测试集估计一下minmax这些量化参数就可以,QAT一般是会结合具体任务再训练的,或者说finetune。
AI小男孩:
finetune就是正常的训练,伪量化只是方便求导
详解per channels / per layer的区别