python int32 int8_Int8量化-介绍(一)

前 言

本系列的目是详细叙述当前移动端Int8的方方面面,从最底层的Int8的汇编层实现原理以及汇编性能优化手段,到中间层的移动框架的配套代码实现(标准就以NCNN为例吧),以及上层对应的PC端量化方法(各种论文思路)总结及实现,和最后模型端re-train的方法、策略及指标介绍。

此外,利用PowerPerf(一种专门针对ARM CPU应用性能优化而开发的调试工具)对卷积kernel(汇编算子)各项硬件参数指标进行量化优化也是本文的重点,旨在提炼出一套通用的汇编代码调优方法论,从而使得PowerPerf能适用于所有移动端CPU性能优化场景。

第一章 背景

1.1量化背景

尽管模型size在不断地压缩,但是其计算量通常还是有一两百MFLOPS的样子,这个计算量对于目前的(中低端)移动端CPU算力来说,还是有点吃力的,因此模型端做了最大的努力,移动端也要不甘示弱努力加油!

通常移动端加速的方案时分CPU派跟GPU派的,目前在低端机型上arm的mali GPU性能较差,所以基本配备的还是CPU方案,而中高端机其配备的GPU大部分就是高通的了,其性能整体比CPU强劲,因此,目前在不同的定位平台上不同的方案各有优势,各自根据具体的场景适配选择方案即可。图1-1 ARM芯片规划图

上图1-1是前一阵子(2018.7.12)ARM在腾讯做介绍的ppt,可以看到性能可观!!!可以看到arm在cpu这块会针对性地加强AI能力,我们再看个截图:图1-2 ARM芯片ML部分

看红色框内信息可知arm会在cpu里面加大AI的算力,目前GPU大概就比CPU强个几倍的样子!(高端机还不一定有这么多,特别时ARMV8-A64V3系列的点乘出来后)但是这里说的是50倍、80倍啊!简直不敢想象!未来可期!

在CPU端做优化,我们可以从上到下考虑:最上面就是算法层,如可以用winograd从数学上减少乘法的数量(仅在大channel尺寸下有效);

框架实现层可以实现内存池、多线程等策略;

底层就是硬件相关细节了:硬件架构特性、pipeline、cache、内存数据重排、NEON汇编优化等。。。

底层的我之前已讨论过一部分,后面继续配合Powerperf进行补充,这里先讨论量化方法。

既然谈到量化,那么我们从最基础开始讲起,从对量化的3个问题开始进行研究:为什么量化有用?因为CNN对噪声不敏感。

2. 为什么用量化?模型太大,比如alexnet就200MB,存储压力大的哟,必须要降一降温;

每个层的weights范围基本都是确定的,且波动不大,适合量化压缩;

此外,既减少访存又减少计算量,优势很大的啊!

3. 为什么不直接训练低精度的模型?因为你训练是需要反向传播和梯度下降的,int8就非常不好做了,举个例子就是我们的学习率一般都是零点几零点几的,你一个int8怎么玩?

其次大家的生态就是浮点模型,因此直接转换有效的多啊!

从宏观上回答了这三个问题,那么接下来我就就可以从量化的原理开始逐步研究了,进而在汇编层实现kernnel(PowerPerf辅助进行调试),最终分别和NCNN、QNNPACK进行等标对比。

1.2量化方法综述

量化方法有很多,具体的可以看下面的链接,里面有很多的论文,可以慢慢去看,有时间把这些论文单独整理出一章出来进行总结。

量化方法汇总链接:Ewenwan/MVision​github.com

第二章 INT8量化算法原理

2.1 INT8量化原理

目前最简单的实现方案是英伟达的tensorRT方案,直接量化,无需retrain,实现简单;

其次就是谷歌的那套方案,稍显复杂需要retrain;

retrain的要求就是,你的权值、激活值(实测对最终精度的影响不是很大)都必须是分布比较均匀的,也就是方差不要太大。其次是能否控制每层的输出在一定的范围内,这对我们做int8量化时,溢出的处理很有帮助。

NVIDIA的方案是公开了的,但是并没有开源,也就是说你只能用他的那一套工具(tensorRT)来进行量化、部署,当然很正常的,我们也想用他的量化校准部分获取校准参数,然后移动端直接用,目前发现是导不出来这些中间参数的,而且也没源码,在安装包内的python借口也是调用的so文件;它们给的ppt链接如下:http://on-demand.gputechconf.com/gtc/2017/presentation/s7310-8-bit-inference-with-tensorrt.pdf​on-demand.gputechconf.com

接下来我在这章将详细分析其原理(python实现单独拿一篇来讲,因为里面有一些小细节需要说清楚),并将在实现过程中碰到的坑一一解剖之(也就是ppt中说的一个很简单的思路,但是在实现的时候是有很多小细节是不确定的,需要一一验证的,NVIDIA的ppt是不会告诉你这些细节的,需要我们来好好理解消化)。

我们首先整体过一遍原理:

我们的目的是把原来的float 32bit 的卷积操作(乘加指令)转换为int8的卷积操作,这样计算就变为原来的1/4,但是访存并没有变少哈,因为我们是在kernel里面才把float32变为int8进行计算的。

最粗糙、最本质的原理就是这个图:

很简单是吧!就是把你一个layer的激活值范围的给圈出来,然后按照绝对值最大值作为阀值(因此当正负分布不均匀的时候,是有一部分是空缺的,也就是一部分值域被浪费了;这里有个小坑就是,假如我的激活址全是正的,没有负值,那么你怎么映射呢?),然后把这个范围直接按比例给映射到正负128的范围内来,公式如下:

FP32 Tensor (T) = scale_factor(sf) * 8-bit Tensor(t) + FP32_bias (b)

通过实验得知(英伟达说的啊,没验证过~),bias值去掉对精度的影响不是很大,因此我们直接去掉:

T = sf * t

上面是简单的max-max 映射,这是针对均匀分布的,很明显的可以知道,只要数据分布的不是很均匀,那么精度损失是很大很明显的,于是很多情况下是这么干的:

这个图我们来粗略解读下:为什么量化是可以保证原信息的?

这个原因就好比高清图跟低分辨率图的区别,只要你的目标是大体识别出图中是啥这一信息,那么低分辨率的图也是允许的。

你看网上的视频加入马赛克后还会不会影响你的判断呢?并不会,你会脑补出额外的细节,只有当满屏的马赛克的时候才会影响你的观影体验,因此这个打码,噢不,量化其实就是一个程度的问题,一个你能否接受的程度问题。

2. 为什么说最大值映射会精度损失严重?

你看值的分布,由于正负分布很不均匀,如果按照对称最大值映射(原意是为了尽可能多地保留原信息)的话,那么+max那边有一块区域就浪费了,也就是说scale到int8后,int8的动态范围就更小了,举个极限的例子就是量化后原本int8的动态范围只剩1bit了(就是正的样本没有,负的全部扎堆在一个很小的值附近),就是上面说到的满屏马赛克~这种情况下。。。那还表示个毛的原信息啊!

3. 为什么右边的饱和截取就ok呢?

因为非饱和截取的问题是当数据分布极不均匀的时候,有很多动态范围是被浪费的,也就是说打的马赛克很大!而饱和截取就是弥补这个问题的。

当你数据分布很不均匀的时候,如图左边比右边多,那么我把原始信息在影射之前就截断一部分,然后构成对称且分布良好的截断信息,再把这个信息映射到int8上去,那么就不会有动态范围资源被浪费了,也就是说马赛克打的比较细腻了~你可以估摸着脑补出细节画面了(我说的是商标打码~你们想到哪去了?!!黑人问号.jpg)~

像上图这样,先找一个阀值T,然后低于最低阀值的就全部都饱和映射到-127上,如上图的左边的三个红色的点就是这么处理的。

(这也就是一个很自然的思路对吧~把无关的高频细节给去掉,从而获取性能上的好处!网络图像压缩技术不就是这么整的么!PCA主成分、傅立叶分解的思路不都是这样的么!抓住事物的主要矛盾,忽略细节,从而提高整

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值