tensorrt int8量化原理几点问题记录

1.重新编码后是如何运算得到最终结果的?

(1)如何用int8表示float32的计算?

  其实就是多了一个放大倍数的问题,举个例子:比如原来float32的计算为:0.1 * 0.2 + 0.3 * 0.4 = 0.14,那么使用int8计算:1*2 + 3*4 = 14,相当于原来的数值都取10倍放大倍数(int8标定也就是标定这个放大倍数),那么由于乘法的原因,最后的结果相当于放大了100倍.这样就能使用Int8来取代float32的计算.

(2)怎么解决偏置问题及溢出问题?

  假设我们的网络是卷积后面紧跟着偏置,例如:原来float32的计算为:0.1*0.2 + 0.1 = 0.12,这时候如果采取和上面一样的策略,那么就会得到:1*2+1 = 3,再缩小100倍得到结果:0.03,问题出在偏置放大了10倍,前面是个乘法运算,相当于放大了100倍,也就是说带偏置的层要特殊处理一下?

  另一个问题:用Int8计算卷积是很容易溢出了,比如:56*45这个值明显大于INT8_MAX == 127,这时候怎么处理?

nvdia官方的tensorrt-int8文档(http://on-demand.gputechconf.com/gtc/2017/presentation/s7310-8-bit-inference-with-tensorrt.pdf)给了一个计算卷积层的例子,可以很好的解释这两个疑惑,如图所示:

 可以看出:

①在计算卷积的时候,使用了int32作为中间值,这样就解决了溢出问题(对于目前的卷积核大小,用Int8乘积之后再做和是不可能超出int32的范围的).

②带偏置的层不是直接用int8计算,而是先转换为fp32计算出结果,再变换为int8,变换过程就是一个线性映射,不会太耗费资源.

另外还可以解释一些其他疑惑:比如权重的scale是如何确定的?看上图中的weights_scale[K]是个数组,代表的应该是不同输出channel的放大倍数值,因此可以猜测,weights的不同输出通道可能有不同的放大倍数,但是因为weights的分布是固定的,因此通常weights采用不饱和量化就可以(参考https://zhuanlan.zhihu.com/p/58208691https://arleyzhang.github.io/articles/923e2c40/),个人感觉采用饱和的量化方式,精度可能有提高,比如确定了每个通道的最大值和最小值,将最大值映射为127,最小值映射为-128,总比将float32_max映射为127能取得更好的精度(仅为个人猜测).

2.KL散度的基本概念?

https://www.zhihu.com/question/41252833

tensorrt如何利用KL散度求取放大倍数(或者称为映射阈值)?

求取过程大致如下:

①选择一个测试集的子集,获取原来分布的直方图(直方图的区间个数为2048个(bins),每个区间的范围就是:(最大激活值-最小激活值)/ 2048)

②依次取第i个bins的值为阈值(为什么i从128开始取,因为如果i取小于127时,KL散度肯定要比i取127时大,因此i小于128的情况根本不用考虑),然后求取以此值为阈值的Int8分布。再求取原分布与新分布的KL散度值,最终取使KL最小的索引值,设为m,然后阈值设为(m+0.5)*一个bin的长度.

文章:https://arleyzhang.github.io/articles/923e2c40/中提出一个疑问:标定的T值怎么会小于128,原因是作者误将索引和激活值混为一谈,m的值是不会小于128的,但是m只是个索引,T = (m+0.5)*一个bin的长度,T是激活值,激活值是有可能出现任意值的.

3.激活值的分布不考虑负值么?

上面的例子发现bin的的索引从128开始取,是没有考虑激活值为负数的情况,原因是nvidia官方给的tensorrt-int8量化的例子激活函数都是relu,意味着激活值没有负值,因此可以不考虑负值,但是如果激活函数采用的不是relu,比如会产生负的激活值的tanh函数,那么在量化的时候(即确定放大倍数的时候)就要考虑负的激活值.具体如何考虑,个人猜测为:找到直方图中的0点,从bin[start] = 0,这个start±128位置向两端遍历,求取KL散度的最小值的索引值.

4.求KL散度时长度不同问题怎么解决?

在上面计算KL散度之前有一步为:expand candidate_distribution_Q to 'i' bins,计算两个分布的KL散度时,要求分布长度是相同的,原分布映射为int8分布后,长度变为128,而原分布的长度为i(将大于i的直方图分布结果加和值bin[i],保证分布完整性),因此必须先将分布长度调整一致,参考官方文档:

另外计算KL散度前,要先进行归一化处理.

猜你喜欢

转载自www.cnblogs.com/deepllz/p/11672912.html