为什么要采用In8,因为它可以带来更高的吞吐率,并且更少的内存占用Int8有更低的精度,并且有更小的动态范围量化后的准确率呢,解决方案 : 对Int8量化后的模型权重和激活函数,进行最小化信息损失。挑战

16位点是-65504 ~ +65504 ,32为浮点具有最大的动态范围是-3.4 * 10^(38) ~3.4 x10^(38),而INT8的动态范围就小的多-128 ~ 127不能通过简单的类型转换,将32位浮点,转换为8位的整数,否则就会带来很大的性能损失。int8 和张量的关系如下
Tensor Values =FP32 scale factor *int8 array +FP32 bias
其中FP32 bias经过研究对性能影响不大,可以去掉
表示为:
Tensor Values =FP32 scale factor *int8 array
对于所有的int 8array 只要一个 FP32 scale factor
有两种量化方式:非饱和的量化、饱和的量化

-127 ~127,通过把负的最大值映射到-127,正的最大值映射到127。但是这会导致显著的准确率下降。
阈值T ,将-T到T这个范围内的映射到-127~127 ,小于-T映射到-127,大于T映射到127 。所以这种就是饱和的量化阈值T的话,就能很好的提高准确率,关键点是如何选取合适的阈值。对In8的表示需要权衡动态范围和精度

上图是不同的网络,横轴是是activation value,纵轴是归一化数出现的次数,从第一张图可以看出,vgg19 conv3_4大的激活值出现的次数比较少,其他两幅图分别是resnet152的激活值分布,和googlenet:inception_3a的激活值分布。
我们想要考虑最小化信息损失,就要考虑32位浮点数转为8位整数只是重新对信息进行编码
Int8 model 和最初的FP32的模型所表达的信息一样,如果做不到的话,我们希望最小化信息损失。KL散度进行度量,KL散度是度量两个概率分布之间的差异,从而度量新的编码方式带来的信息损失。FP32 模型在校准数据集上推理,校准数据集从训练集中抽取一部分图片。
对于每一层:
饱和阈值产生不同的量化分布(quantized distributions)饱和阈值
calibration: 基于实验的迭代搜索阈值
TRT 提供了Int8EntropyCalibrator,该接口需要由回归端实现,以提供校准数据集合一些用于缓存结果的样本代码。
Nvidia选择的是KL-divergence,其实就是相对熵。相对熵表述的就是两个分布的差异程度,这里就是量化前后两个分布的差异程度。差异最小就是最好的了,因此问题转换为求相对熵的最小值

KL散度就是精确度量这种最优和次优之间的差异。
FP32就是原来最优的编码,INT8就是次优的编码,用KL散度来描述这两种之间的差异。
前提
TensorRT所做的工作
Calibration table(校准表)和INT8 可执行的推理引擎
左图是没有考虑饱和的,右图是考虑饱和的,图中白线位置为饱和阈值的位置,小于阈值部分保持不变,大于阈值部分都会量化到一个值上。