量化的目标
In8推理
INT8相对于FP32具有较低的精度和动态范围从表中可以看出32位浮点,16位浮点,INT8的动态范围有很大的不同,比如16位点是-65504~+655032为浮点具有最大的动态范围是-4*10^~4x10^,而INT8的动态范围就小的多-128~127所以我们不能通过简单的类型转换,将32位浮点,转换为8位的整数,否则就会带来很大的性能损失。
线性量化
int8和张量的关系如下TensorValues=FP32scalefactor*int8array+FP32bias其中FP32bias经过研究对性能影响不大,可以去掉
表示为:TensorValues=FP32scalefactor*int8array对于所有的int8array只要一个FP32scalefactor
量化方法
有两种量化方式:非饱和的量化、饱和的量化
非饱和的量化方式将上面浮点数的运算范围,映射到-127~12通过把负的最大值映射到-12正的最大值映射到12但是这会导致显著的准确率下降。饱和的量化方式通过设定一个阈值T,将-T到T这个范围内的映射到-127~127,小于-T映射到-12大于T映射到12所以这种就是饱和的量化如果我们能够很好的确定阈值T的话,就能很好的提高准确率,关键点是如何选取合适的阈值。
如何优化阈值选择
对In8的表示需要权衡动态范围和精度上是不同的网络,横轴是是activationvalue,纵轴是归一化数出现的次数,从第一张可以看出,vgg19conv3_4大的激活值出现的次数比较少,其他两幅分别是resnet152的激活值分布,和googlenet:inception_3a的激活值分布。
我们想要考虑最小化信息损失,就要考虑32位浮点数转为8位整数只是重新对信息进行编码
相对熵
解决方案:Calibration
FP32模型在校准数据集上推理,校准数据集从训练集中抽取一部分片。对于每一层:
收集激活值的分布用不同的饱和阈值产生不同的量化分布从阈值中选择一个,使得对应的量化分布和激活值的分布,可以最小化KL散度。KL_pergenceKL\_pergenceKL_pergence,通过迭代就能得到一个最合适的饱和阈值
校准算法
calibration:基于实验的迭代搜索阈值
TRT提供了Int8EntropyCalibrator,该接口需要由回归端实现,以提供校准数据集合一些用于缓存结果的样本代码。
如何利用KL散度选择合适的阈值
Nvidia选择的是KL-pergence,其实就是相对熵。相对熵表述的就是两个分布的差异程度,这里就是量化前后两个分布的差异程度。差异最小就是最好的了,因此问题转换为求相对熵的最小值KL散度就是精确度量这种最优和次优之间的差异。
FP32就是原来最优的编码,INT8就是次优的编码,用KL散度来描述这两种之间的差异。
TensorRT量化的流程
FP32的训练Model校准数据集
TensorRT所做的工作
用FP32的模型在校准数据集上做推理收集不同阈值下权重、激活值的统计量执行校准算法得到最优的Scalefactors然后可以将FP32的权重量化到INT8最终生成一个Calibrationtable和INT8可执行的推理引擎
文章为作者独立观点,不代表观点
八水2022-12-01
鱼大讲的很对,对我们这种新手很有帮助,我十月份就在底部割肉了几只股票,中间操作很容易引起情绪性操作,我最近基本不在收盘前操作了,非常感谢鱼大不厌其烦的提示!