量化总结2-tensorrt、ncnn的后量化方式

1、Tensorrt的量化方式/ncnn

对称的饱和量化,从ncnn的源码来看,使用的是逐通道量化,tensorrt没看源码就不知道了(应该也是):

量化总结2-tensorrt、ncnn的后量化方式_第1张图片

 

问题的核心转化为如何寻找一个最优值T,是的饱和量化能够精度最小,转化为最优化的问题。

英伟达使用kl散度来比较量化前后两个分布的差异,即相对熵,则问题转化为求相对熵的最小值。1、从信息熵的角度来解释,kl散度最小则代表两个分布差异最小。2、将log换为以2为底的数,则代表信息的编码字组组成,编码信息量的差异。

量化流程(尽量去简化理解,其实很简单):

  • 准备一个校准数据集,收集校准表,对每一层:
  1. 收集激活值的直方图
  2. 基于不同的阈值(浮点的截断阈值)产生不同的量化分布
  3. 计算每个分布与原分布的相对熵,选择min值,则得到最像原分布的1个。

此时,便选出了阈值,也就得到了scale。

量化流程伪代码(此处需要注意计算PQ的kl散度的上采样细节):

  1. 不断的截断参考样本P,从长度128(注意:此处说的是长度,即也有可能是从负半轴开始计算的)到2048,从128开始是因为小于128的直接对应,不需要截断。
  2. 将截断外的p值全部求和(为啥要求和,感觉是计算概率是要知道总值)
  3. 将截断外的值全部放到截断样本的P的最后一个值上(为了保证尽可能的真是分布,不要丢弃)
  4. 求P的概率分布
  5. 创建样本Q,其元素值为样本P的int8量化值
  6. 将样本Q长度拓展到与原始样本P一样的长度,求Q的概率分布(用门限值id/target_bin=Q上采样的幅度,每一个target_bin上采样成原始bin长度时左边会进行向上取整计算,右边会进行向下取整计算)
  7. 最后求P、Q的kl散度

不断地构造P、Q,然后计算kl散度,找到最小的min-kl时的截断距离,则scale便知道了。最终阈值=(m+0.5)*1个bin的长度 m就是最小截断长度

一直求的都是T的索引值,并非具体的值。

会带来的问题:

  1. 上文只考虑正半轴的量化,没有考虑负半轴的,有没有影响。

      解:真实的tensorrt应该是对称的、饱和量化方式,上面给出的阈值T应该是使用真实数值的index从128开始计算的,只考虑了relu这种正激活函数的情况。

     2、在真正存在负值时该如何处理呢:

      个人猜测:找到直方图中的0点,从bin[start]=0,这个位置,向两端遍历,求取KL散度的最小值的索引值,同时,每遍历一次只做一次KL散度,并不是两边分别计算kl散度。

英伟达的量化方式是将fp32权重变成了int8,再使用底层int8或者int4的加速整形乘法将将结果转化为int32,最后使用量化表中的scale参数变回fp32与同为fp32的bias进行相加,得到下一层的feature_map。

Tensorrt的int4或者int8乘法未知,也许是用了谷歌的方案等等,没看过,但ncnn使用的是一种整形矩阵乘法(暂时没来得及看,休息一会)。

参考链接:

https://blog.csdn.net/weixin_34910922/article/details/108502449

参考源码:

https://github.com/BUG1989/caffe-int8-convert-tools

https://github.com/Tencent/ncnn

 

 

你可能感兴趣的:(模型压缩加速,神经网络,深度学习,pytorch,caffe)