1.简介
1.1目的
本文档主要对caffe-Progress-m40框架下基于int8量化技术方案的模型压缩方法进行介绍。
1.2范围
本文档将介绍INT8量化技术方案应用在深度学习模型中的方法,以及整个实验的设计。
1.3定义、首字母缩写词和缩略语
序号 | 术语或缩略语 | 说明性定义 |
1 | ||
2 | ||
3 | ||
4 |
1.4参考资料
On the efficient representation and execution of deep acoustic models
2.设计目标
验证int8量化技术方案应用在深度学习模型中的可行性,并对各种可能性的实验进行尝试。
3.设计背景
在传统思维里面,似乎科学计算应该是精度越高越好,然而这几年英伟达公司的推波助澜,精度别说fp64了,fp32,fp16,直到今天,浮点都有被抬出场外的风险(当然仅限于深度学习)。为什么说深度学习这么独特,居然不需要多高精度呢,主要原因还是在于其统计学算法的本质。这种算法本身就是一种纠错过程,试图纠正模型预测与现实的差距,学名“最小化代价函数”。精度的损失,也可以一同算入和现实的差距中,由算法过程来自行减少。虽然理论上还有种种需要细心处理的部分,但至少应该可行的。就算然可行,但是目前能找到的相关资料也不多,大多来自于google。
就目前的资料来看,INT8精度主要用在模型的inference上。无论训练的多么精妙的模型,最终还要给用户使用才行。这个使用的过程即所谓的模型infernece。简单不恰当的说,拿汽车做例子,模型的训练就是制造变速箱的过程,inference就是变速箱实际运作挂档的过程。INT8用于训练流程,仍然是不太足够的,至少我还没找到相关paper。主要是做模型的使用,特别是在手机设备上。
本文档主要是对调研的google论文On the efficient representation and execution of deep acoustic models 里对INT8量化的使用进行介绍。介绍一种将INT8量化技术应用到深度学习模型训练当中的方法。
4.设计方法
4.1整体流程
GOOGLE把INT8量化用于语音识别,是因为它迫切需要降低运算和储存/传输的压力。如果把经典深度神经网络(如CNN)看做一张网,那么用于语音识别的RNN就是一堆网叠加在一块,彼此互联。因为语音是一个时序数据,每一个时间点的信号都需要一整张网来模拟。可想而知数据流之大。论文中也说明了可以显著的减少储存和运算的需求。
如果把神经网络分解到最后,绝大部分都会对应FMA操作。其中FMA操作如公式(1)所示。
y=WX+B | (1) |
INT8量化的操作也是在FMA操作的过程中进行的,如图1所示。
图1 INT8量化的FMA操作
其中W表示的已经量化过的矩阵,对X的Q(.)操作是在Mult(.)之前迅速的完成的。INT8进行Mult(.)操作之后会进行R(.)操作恢复到float32,并保持float32的表示完成Add(.)操作以及F(.)激活操作。
4.2量化策略
本次实验设计的目标是将给定的FLOAT32值变成INT8表示,所以就要选择一种量化方法,根据google的这篇论文,均匀分布的量化器可以取得一个不错的效果,并且不需要额外的解压缩步骤。量化策略主要考虑如下三个部分:
- Quantizing
给定一组FLOAT型的数据V=Vx,一个量化的尺度S
(例如INT8,则S=256
),通过计算一个因子Q
,得到量化后的结果V'=0≤Vx'≤S
。具体的过程如下:给定R=Vminmax
,其中Vmax
是给定的一组float型数据中最大的数,Vmin
为最小的数。论文中因子Q
的计算如下:Q=SR
,最终的量化表达式为:Vx'=Q*Vx-Vmin()
。
- Recovery
同样的,量化后的值可以恢复到量化前高精度值得近似值,具体的恢复表达式为:Vx=Vx'*Q-1+Vmin,其中Q-1=RS
。
- Quantization error and bias
整个的量化过程是两种loss损失的过程,第一种就是输入的值和quantization-recovery操作后的值之间的loss损失,即精度损失。第二种是在quantization-recovery操作计算数值的过程中引入偏差带来的损失,即偏置损失。第一种错误不可避免但是平均上看,带来的影响很小。而第二种偏置错误,如果更注意的去量化是可以避免的,所以花费特别的精力去消除第二种错误是非常必要的。
- Eliminating bias error
FMA的操作为就是去执行一系列的如下操作
Vc=Va*Vb | (2) |
根据之前量化和恢复的方法可以令Vx''=Vx'+QVmin,那么就有:Vx=Vx''Q
。那么量化恢复后的(2)式可以改写成:
Vc=Va''*Vb''Qa*Qb | (3) |
可以看出每个Vx''已经是一个整数类型,Vx'
也已经是一个整型类型,而QVmin
却是一个FLOAT型将要近似为整型,这样就引入一个误差:
E=floatQVmin()QVmin() | (4) |
那么为了避免这种误差,就要求在量化过程中执行的方式和这个公式是一致的,所以就引入一个近似的操作round(.),即有:
Vx'=roundQVx-roundQVmin() | (5) |
因为这些错误在量化和乘积操作中是一致的,并且可以相互抵消。同样的在量化过程中有:
Vx=Vx'+roundQVmin()Q | (6) |
- Efficient implementation
上述将FLOAT32量化成INT8,通过引入SIMD,降低了数据的内存带宽,这样就可以增加cpu对数据的吞吐量。以avx指令集为例子,其指令长度为256bit,如果存储FLOAT32,可以存储有8个,而存储INT8可以存储32个,对于数据的吞吐量是前者的四倍。
4.3 训练算法
整个训练的算法还是维护了一份全精度(例如FLOAT32)的参数,只是在前向传播的过程中按照上述的方法对参数和输入进行了量化操作,这些是在模仿运行时间中模型的inference过程。而反向传播还保持这全精度的形式,目的是保证梯度的计算是以全精度的形式进行的,只是反传的error或者loss是量化后的前向过程得到的。所以梯度更新是以全精度的形式进行的,然后再重新对更新后的权值进行量化再求新一轮的前向的过程。整个算法的流程如下图Algorithm 1所示:
图2 Quantization aware training