行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解

在之前的文章中也提到过,模型的部署可以理解为是:python训练权重转换为量化工具所需要的文件格式、模型量化、输出一致性校准和将模型放置于计算端运行测试这几部分的集合。

上面提到的整个模型部署过程中,相对比较困难的是模型量化过程

量化背景

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

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

CPU派一般使用NCNN或者同系列工具,而GPU派多使用TensorRT,这也是我们这篇博客为什么以这两个工具为题目的原因

量化Q&A

既然谈到量化,那么我们从最基础开始讲起,从对量化的3个问题开始进行研究:

1.为什么量化有用?

因为CNN对噪声不敏感(一场报告的原话:),其实就是或CNN对噪声的包容性较强,对误差偏移的容忍性较强)

2. 为什么用量化?

(1)模型太大,比如alexnet就200MB,存储压力非常大;
(2)每个层的weights范围基本都是确定的,且波动不大,适合量化压缩;
(3)此外,既减少访存又减少计算量,优势很大!

3. 为什么不直接训练低精度的模型?

因为训练是需要反向传播和梯度下降的,int8就非常不好做了,举个例子就是我们的学习率一般都是零点几零点几的,使用int8驱动模型存在很多麻烦烦

4.一般的量化范围是什么

float16和int8两种比较常用,前者精度一般不会有很大的损失,后者的量化压缩效果立竿见影,但可能会损失一定的精度

我们重点介绍一下int8的量化

Int8量化一般步骤

这部分的主要参考:TensorRT INT8量化原理以及如何编写校准器类进行校准_eric-zhang的博客-CSDN博客

1、INT8量化过程

众所周知,一个训练好的深度学习模型,其数据包含了权重(weights)和偏移(biases)两部分,在其进行前向推理(forward)时,中间会根据权重和偏移产生激活值(activation)。

关于INT8的量化原理,Int8量化-介绍(一) - 知乎写的非常详尽,我这里就简单说结论了:

  • TensorRT在进行INT8量化时,对权重直接使用了最大值量化,对偏移直接忽略,对前向计算中的激活值的量化是重点;
  • 对激活值进行INT8量化采用饱和量化:因为激活值通常分布不均匀,直接使用非饱和量化会使得量化后的值都挤在一个很小的范围从而浪费了INT8范围内的其他空间,也就是说没有充分利用INT8(-128~+127)的值域;而进行饱和量化后,使得映射后的-128~+127范围内分布相对均匀,这相当于去掉了一些不重要的因素,保留了主要成分。

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第1张图片

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第2张图片

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第3张图片

图1-3. 直接忽略bias

图1告诉我们,完全可以直接忽略bias,这是官方给出的实验结论。 

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第4张图片

图4. 非饱和量化(左图)和饱和量化(右图)

图4告诉我们权重没必要使用饱和映射,因为没有根本性的提高,而激活值使用饱和映射能调高性能,这好理解,因为权重通常分别较为均匀直接最大值非饱和映射和费劲力气找阈值再进行饱和映射,其量化后的分布很可能是极其相似的,而激活值分布不均,寻找一个合适的阈值进行饱和映射就显得比较重要了;并展示了直接使用最大值量化到INT8和选择一个合适的阈值后饱和地量化到INT的区别,可以看出:右图的关键在于选择一个合适的阈值T,来对原来的分布进行一个截取,将-T~+T之间的值映射到-128~+127,而>T和<-T的值则忽略掉。

如何寻找这个阈值T就成了INT量化的关键

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第5张图片

图5. 各模型激活值分布

图5可以看出,不同模型的激活值分布差异很大,这就需要进行动态的量化,也即针对每一个模型,寻找一个对它来说最合适的T。

于是,NVIDIA就选择了KL散度(KL散度:用于衡量两种概率之间的相似程度)也即相对熵来对量化前后的激活值分布进行评价,来找出使得量化后INT8分布相对于原来的FP32分布信息损失最小的那个阈值。如图6所示:

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第6张图片

图6. 相对熵:KL散度

于是,整个的量化过程就给了出来,如图7所示:

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第7张图片

图7. INT8量化校准过程

意思就是:

  • 先在一个校准数据集上跑一遍原FP32的模型;
  • 然后,对每一层都收集激活值的直方图,并生成在不同阈值下的饱和量化分布;
  • 最后,找出使得KL散度最小的那个阈值T,即为所求。

这个过程同时也告诉了我们,要做INT8量化,需要准备哪些东西——原来的未量化的模型、一个校准数据集进行量化过程的校准器。如图8所示:

行为分析(十一):模型部署部分(二):INT8模型量化以及TensorRT和NCNN的简单了解_第8张图片

图8. TensorRT的INT8工作流程

图8可以看出,校准过程我们是不用参与的,全部都由TensorRT内部完成,但是,我们需要告诉校准器如何获取一个batch的数据,也就是说,我们需要重写校准器类中的一些方法。下面,我们就开始介绍如何继承原校准器类并重写其中的部分方法,来获取我们自己的数据集来校准我们自己的模型。

NCNN框架

nihui大佬的NCNN简介:“ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架。ncnn 从设计之初深刻考虑手机端的部署和使用。无第三方依赖,跨平台,手机端 cpu 的速度快于目前所有已知的开源框架。基于 ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开发出人工智能 APP,将 AI 带到你的指尖。ncnn 目前已在腾讯多款应用中使用,如 QQ,Qzone,微信,天天P图等。”

TensorRT框架

TensorRT源程序是一个能提高英伟达GPU(Griphics processing units)推理性能的C++库。它与TensorFlow、Caffe、PyTorch、MXNet等训练框架相辅相成。它更加关注在GPU上快速高效地运行一个已经存在的学习网络,这个学习网络的目标是生成一个结果(在许多地方也称为得分、检测、回归或推理的过程)。

一些训练框架类似于tensorflow已经集成了TensorRT,所以TensorRT能够被用来加速框架中的推理过程。作为一种选择,TensorRT可以用作用户应用程序中的库。它包含了很多解析器,这些解析器可以从Caffe、ONNX或者tensorflow中解析已经存在的模型,还可以用于以编程方式构建模型的c++和Python api

其他参考资料

链接1:https://github.com/Ewenwan/MVision/tree/master/CNN/Deep_Compression/quantization

你可能感兴趣的:(行为分析)