1 Low Precision Inference
现有的深度学习框架 比如:TensorFlow,pytorch,Caffe, MixNet等,在训练一个深度神经网络时,往往都会使用 float 32(Full Precise ,简称FP32)的数据精度来表示,权值、偏置、激活值等。但是如果一个网络很深的话,比如像VGG,ResNet这种,网络参数是极其多的,计算量就更多了(比如VGG 19.6 billion FLOPS, ResNet-152 11.3 billion FLOPS)。如此多的计算量,如果中间值都使用 FP 32的精度来计算的话,势必会很费时间。而这对于嵌入式设备或者移动设备来说,简直就是噩梦,因为他们的计算能力和内存数量是不能与PC相比的。
因此解决此问题的方法之一就是在部署推理时(inference)使用低精度数据,比如INT8。除此之外,当然还有模型压缩之类的方法,不过此处不做探究。注意此处只是针对 推理阶段,训练时仍然使用 FP32的精度。
从经验上来分析一下低精度推理的可行性:
文章的作者认为网络在训练的过程中学习到了数据样本的模式可分性,同时由于数据中存在的噪声,使得网络具有较强的鲁棒性,也就是说在输入样本中做轻微的变动并不会过多的影响结果性能。与图像上目标间的位置,姿态,角度等的变化程度相比,这些噪声引进的变动只是很少的一部分,但实际上这些噪声引进的变动同样会使各个层的激活值输出发生变动,然而却对结果影响不大,也就是说训练好的网络对这些噪声具有一定的容忍度(tolerance )。
正是由于在训练过程中使用高精度(FP32)的数值表示,才使得网络具有一定的容忍度。训练时使用高精度的数值表示,可以使得网络以很小的计算量修正参数,这在网络最后收敛的时候是很重要的,因为收敛的时候要求修正量很小很小(一般训练初始 阶段学习率稍大,越往后学习率越小)。
那么如果使用低精度的数据来表示网络参数以及中间值的话,势必会存在误差,这个误差某种程度上可以认为是一种噪声。那也就是说,使用低精度数据引进的差异是在网络的容忍度之内的,所以对结果不会产生太大影响。
以上分析都是基于经验的,理论上的分析比较少,不过文章提到了两篇 paper,如下:
这里不对这两篇paper做探究。
TensorRT 的INT8模式只支持计算能力为6.1的GPU(Compute Capability 6.1 ),比如: GP102 (Tesla P40 and NVIDIA Titan X), GP104 (Tesla P4), and GP106 GPUs,主要根源是这些GPU支持 DP4A硬件指令。DP4A下面会稍微介绍一下。
2 TensorRT INT8 Inference
首先看一下不同精度的动态范围:
动态范围最小正数
FP32
−3.4×1038+3.4×1038−3.4×1038 +3.4×1038
1.4×10−451.4×10−45
FP16
−65504+65504−65504 +65504
5.96×10−85.96×10−8
INT8
−128+127−128 +127
11
实际上将FP32的精度降为INT8还是比较具有挑战性的。注:python的float类型式FP64的。
2.1 Quantization
将FP32降为INT8的过程相当于信息再编码(re-encoding information ),就是原来使用32bit来表示一个tensor,现在使用8bit来表示一个tensor,还要求精度不能下降太多。
将FP32转换为 INT8的操作需要针对每一层的输入张量(tensor)和 网络学习到的参数(learned parameters)进行。
首先能想到的最简单的映射方式就是线性映射(或称线性量化,linear quantization), 就是说映射前后的关系满足下式:
$\text {FP32 Tensor (T)}=\text {scale_factor(sf)} * \text {8-bit Tensor(t)}+\text {FP32_bias (b)}$
试验证明,偏置实际上是不需要的,因此去掉偏置,也就是
T=s f * t
sf是每一层上每一个tensor的换算系数或称比例因子(scaling factor),因此现在的问题就变成了如何确定比例因子。然后最简单的方法是下图这样的:
简单的将一个tensor 中的 -|max| 和 |max| FP32 value 映射为 -127 和 127 ,中间值按照线性关系进行映射。
称这种映射关系为不饱和的(No saturation )&#x