开心的程序猿@NXP
2021-01-28 Thursday

本文专为参加今年大学生智能车竞赛AI视觉组的同学们而写,也很适合其他对MCU上AI应用感兴趣的朋友。

神经网络模型最大的一个特点就是拥有宰相一样的肚量:宰相肚里能撑船,而神经网络模型的肚子里装满了权重。权重的多少往往直接反映出一个模型的复杂程度,而权重越大,模型的效果一般会更加好。

那么问题来了,我们的目的是让模型在MCU上奔跑,但是MCU的计算资源和存储资源都远不能和PC相比。在PC上顺风顺水的大家伙,也想到MCU上玩儿玩儿,要怎么办呢?

模型量化的概念


出于这一目的,模型量化技术应运而生。而量化又分为训练中量化,以及训练后量化,我们此处着重介绍训练后量化。

训练后量化技术可以理解成一种有损压缩,会损失一点精度,但是,会显著降低模型尺寸,同时提高运行效率。

量化的原理其实很简单。模型在训练时一般是使用float32类型来存储的,每一个权重数据需要占用4个字节,这样才能精确地降loss。但是,模型的推理却没有这个要求了,那么是否可以换种方式来存储呢?比如改用int8,这样,每存储一个权重,将只消耗1个字节,模型的尺寸会缩小为之前的1/4,何乐而不为?

幸运的是,这样对精度的影响通常极小,只要是在可接受的范围内,我们就降低了模型的存储尺寸。而且,目前神经网络加速器或是神经网络加速库,一般只支持int8类型的数据输入,对float类型无能为力。

模型小也大大减轻了对存储器系统和Cache的压力。这样一来,在减小了模型尺寸的同时,还可以加速模型的运行。

接下来我们会分别介绍tflite和nncu中的量化原理与实现方式。

在tflite中训练后量化

关于训练后量化,不仅仅局限于上文所提到的int8类型量化,如下表所示,之后会重点介绍全整型量化:

技术 优势 运行环境
动态范围量化 缩小4x
jwsu 2 ~ 3x
CPU
全整形量化 缩小4x
加速3x+
CPU, Edge
Edge TPU
MCU
Float16量化 缩小2x
GPU加速
CPU
GPU

1.动态范围量化

首先介绍动态范围量化,这是简单的训练后量化方式,仅仅将权重数据由float类型转换为8位整数,其他例如激活层和输入输出还依然保留为float类型。

● 实现方式

这种方式有个局限性,当模型推理的时候,权重数据会被转换为浮点数进行计算,无法发挥Cortex-M内核的整数计算能力。不过,为了提高运行效率,这个转换只会被做一次并缓存,以减少延时。

2.全整型量化

全整型量化,顾名思义就是保证模型中的所有数据,都会被转换成整型数据表示,除了权重数据,还有各个中间结果数据,也就是常说的tensor(张量)。由于模型只存储了权重/偏置信息,所以模型尺寸上和动态范围量化相比不会有太大变化。但是,对于那些只能做整数运算的硬件设备或是硬件加速器,只有全整型量化才能派上用场。

实现全整型量化有一个重大的问题要解决:要事先知道模型中所有float类型tensor的取值范围,包括输入,输出,每一层的激活值。然而,和那些静态数据(权重,偏置)比起来,它们是由模型的输入数据决定的,并且是随着模型的执行而动态变化的。

这样看来,准确判断tensor的取值范围成了不可能的任务。幸运的是,这个范围可以是估计的(当然就会损失精度)或者是估算出来的。就如同统计学中的抽样,我们也同样提供一个mini数据集,representative_dataset(),以供迭代之用,并且用在它们上跑出来的各个tensor的取值范围来做代表。

话不多说,放码过来:


这样一来,所有模型内部数据,包括模型的输入和输出,均会被转换为整数型表示,以保证兼容那些特殊的整型数据依赖设备。如果发现有不支持量化的操作符,会丢出一个异常。

要注意的是,想要使用这些新的API,要保证tensorflow版本为2.3.0,tensorflow从2.3.0版本开始才加入了inference_input_type和inference_output_type属性的支持,即加入对输入输出节点量化的支持,实现真正的全整数量化支持。

需要特别指出的是,tflite目前推出了最新的tflite-micro库,专门针对于嵌入式设备,

其内部实现了与最新的CMSIS-NN库的加速支持,但其仅支持signed int8 (s8)的全整型量化模型,否则,会直接调用tflite的原生API,无法实现模型加速。在最新的CMSIS-NN中,有一众后缀为”_s8”的NN算子,tflite就是调用它们实现计算的。

Tensorflow训练量化


讲到这里,大家要注意一件事情,采用后量化的方式进行模型的量化,肯定会造成一定的精度损失。那么,当发现精度下降太大时候,可以增加representative dataset的规模或者换一批数据集的代表。

考虑使用训练中量化,这种量化方式会将量化误差耦合进模型训练中,在根本上减小模型量化精度的损失。但是,比起后量化来说,我们需要修改模型训练脚本,插入被称作fake-quant的节点,对模型进行重新训练,可参考

https://www.tensorflow.org/model_optimization/guide/quantization/training

而这样一来,我们就无法直接使用网上的预训练模型来进行直接部署,无疑使得可操作性变得复杂了许多。

因此,还是推荐使用后量化的方式进行模型的量化。在实际使用中,要进行权衡以确定使用何种方式。

NNCU中模型训练量化

nncu只支持训练后量化。

其实在在去年的电磁AI中,本加油站里有一篇文档就已经提到了nncu工具:AI机器学习实战の电磁智能车篇。

这个推文简洁地介绍了nncu的GUI。下载了nncu的同学也可以在nncu根目录\docs\ nncu_user_guide_cn.pdf文件中查看更详细的介绍。

1.量化原理

在nncu底层使用的CMSIS-NN老式库中,量化系数给出了是由多少个位来表达tensor中的整数部分和分数部分,并且整数都是有符号整数。

比如,对于8位量化,如果由3个位表示分数,那么就有1个符号位,4个整数位,和3个分数位,表达范围是[-128/8,127/8],分辨率为1/8;如果是4个位表达分数,则表达范围就是[-128/16,127/16],分辨率为1/16。下图就演示了手工指定全局(所有层)的量化都使用3个位来表达分数部分:

在nncu中量化模型,既可以由用户指定一个全局的数值来配置表达分数的位数,就像是在电磁AI中的做法;又可以像tflite那样提供一个代表性的数据集来估算各tensor的取值范围。下图是使用自动量化时的一个例子:


在自动量化模式下,可以限定nncu生成的量化系数中,最少有几个位来表达分数部分,建议不要设置得太大。

2.手动还是自动

由于电磁AI用的是9-16位量化,分辨率高,所以手动指定全局分数位数也不会造成什么精度损失。在本次比赛的图像分类任务上,当然也可以使用9-16位量化,不过没有8位量化产生的模型跑得快。只是,8位量化下,大一点的模型就不能再用全局量化参数了,否则精度很容易比较惨。

3.迷你数据集

在nncu上,自动量化也需要类似于tflite中“representative dataset”的机制,称为“迷你数据集(mini dataset)”,使用它们来指导量化。并且,nncu为了弥补CMSIS-NN旧式API在量化精度上的逐层损失,还添加了一种“启发式量化”的机制,来微调各层量化的分数位数,具体的说明也在nncu根目录\docs\ nncu_user_guide_cn.pdf文件中。简单来讲,需要制作迷你数据集并编写胶水代码来加载和使用。

4.制作迷你数据集

nncu支持所谓的”后处理”,这是nncu配套的量化质量测试工具所必需的。对于水果与动物的分类,后处理类型选用“分类”即可。

要在nncu上使用迷你数据集,在nncu需要经过一系列的操作步骤得到2个文件:

  • <数据集名_x>.npy

  • <数据集名_y>.npy

但是,由于本文中参考数据集已经足够“迷你”了,所以可以直接使用数据集中的“x.npy”和”y.npy”。

5.借用cifar10示例来加载和使用迷你数据集

在制作了迷你数据集之后,还需要在.\nncu_pc\下的loaddata.py和test_file_gen.py中,分别添加迷你数据集的加载函数和测试向量的生成函数,步骤可能有点多。

不过,有一个“移花接木”的方法:在本文给出的参考数据集中,动物和水果共有10种,恰好和nncu自带的”cifar-10”示例的类型相同。

所以,可以用这个数据集中的npy文件替换nncu\datasets\cifar10\ 下的文件,具体来讲,是:

  • 用x.npy替换nncu根目录\datasets\cifar10\c10x.npy

  • 用y.npy替换nncu根目录\datasets\cifar10\c10y.npy

替换后,就可以借用nncu自带的cifar10示例来量化了。在nncu的GUI中点击”加载…”按钮并且选择c10.ini,再在“选择模型文件”按钮中改用自己训练的模型即可。

如果觉得这样做有点“赖皮”,有兴趣的同学可以跟着nncu_user_guide_cn.pdf中的完整介绍,为自己的数据集立一个名份。

写在最后


至此,部署模型中最关键的模型量化就介绍完了,万望同学们充分重视这至关重要的环节,以得到和训练模型尽量接近的量化效果。
总结一下可以得到以下几个小贴士:

  1. nncu的量化性能高,但误差层层积累快;tflite量化精度高,但性能有损失

  2. 8位量化效果不够好,改用tflite,或者nncu的9-16位量化(建议使用14位)

  3. 使用代表性数据集(tflite)或迷你数据集(nncu)来指导量化

  4. 在nncu中还可以使用启发式量化来微调各层的量化参数(慢)

▌备注


本文来自于: AI视觉组仙人一步之模型量化

AI视觉组仙人一步之模型量化相关推荐

  1. AI视觉组仙人一步之模型调优

    开心的程序猿@NXP 2021-02-04 Thursday 本文专为参加今年大学生智能车竞赛AI视觉组的同学们而写,也很适合其他对MCU上AI应用感兴趣的朋友.   在前一篇推文,"智能车 ...

  2. AI视觉组仙人一步之高级玩法——从Python回归C语言

    开心的程序猿@NXP 2021-02-04 Thursday   读过之前两篇的童鞋们,想来已经开始着手开发属于自己的AI视觉应用了,当然,手中还没有OpenART套件的朋友们,也不用着急,可以先参照 ...

  3. 恩智浦AI视觉组之逐飞岁末彩蛋

      2020一年的工作已告一段落,昨天逐飞也已经发布了放假通知,虽然还有很多工作没做完,但春节改放假还是得放假,所以,先为2021年的工作放个彩蛋吧.   先回顾一下第十六届AI视觉组诞生,12月18 ...

  4. 第十六届全国大学生智能车| AI视觉组新手入门教程

    ▌00 整体内容 进入正文前,我们通过下方框图整体了解每个章节的内容,先大概了解每个章节做的工作是什么作用,这样有助于理解每个章节的内容.同学们可以参考以下章节内容训练模型,但这只是一个初级参考,相信 ...

  5. 第十六届全国大学生智能汽车竞赛总决赛 AI视觉组线上赛细则草案 - 初步版本

    简 介: 关于室内AI视觉组在线上比赛的特殊性,本文由逐飞起草的比赛细则给出了比赛过程的详细描述. 关键词: 智能车竞赛,室内视觉,线上比赛 §01 比赛方式   由于AI视觉组的特殊识别任务,比如分 ...

  6. AI视觉组培训第二弹——入门篇

    ▌入门篇   由恩智浦赞助的AI视觉组,今年把人工智能应用在智能车竞赛中的难度由提高了一步.这里面最重要的部分就是,用人工智能的神经网络进行图片识别.   上一次培训,我们已经介绍了人工智能和神经网络 ...

  7. 第十六届全国大学生智能汽车竞赛总决赛 AI视觉组线上赛细则

    简 介: 本文对于参加2021年第十六届智能车竞赛全国总决赛线上比赛室内AI视觉组比赛细则. 关键词: 智能车竞赛,线上比赛,室内视觉AI 一.比赛方式   由于AI视觉组的特殊识别任务,比如分赛区的 ...

  8. 智能车大赛AI视觉组培训第一弹——基础篇

    智能车大赛AI视觉组培训第一弹: ▌基础篇 1.培训简介 ■时间安排: 2021年03月18日 14:00 ■内容简介: 由恩智浦赞助的AI视觉组,今年由于把人工智能应用在智能车竞赛中,使得难度提升了 ...

  9. 智能车大赛AI视觉组参考答案

      礼让动物采摘水果--最近, 智能车大赛AI视觉组 的题目已经发布,我们先为大家探探路.   前一期,逐飞科技给大家带来了一篇开幕大作: 智能车竞赛,AI视觉组赛题浅析 ,对该组别的核心赛题任务进行 ...

最新文章

  1. makefille的使用
  2. Android游戏开发笔记(一)
  3. 多目标粒子群优化算法_基于粒子群优化的投资组合优化研究
  4. Hibernate+Spring整合使用二级缓存
  5. Git之 手把手教你使用Git
  6. 洛谷P3195 [HNOI2008]玩具装箱TOY
  7. python学习笔记第9天《文件的管理办法》
  8. Windows下的gcc/gc++编译环境配置
  9. python系统性能模块笔记
  10. 洛阳地铁一号线无人驾驶_刚刚,最新消息!涉及洛阳地铁1号线、2号线…
  11. gis等时圈怎么做_如何批量制作交通等时圈
  12. 搭建Harbor docker镜像仓库
  13. 导出所有DB2存储过程的四种方法
  14. 笔记:linux中tcp_tw_reuse和tcp_tw_recycle的作用
  15. 网络工程师考试知识点总结
  16. 如何提高思考能力,(一个绝对能帮到你的科普)取自《思维混乱:是因为大脑没有结构》谢春霖
  17. 百词斩不复习_百词斩是不是真的好用?
  18. ICPC World Finals 2015 D题 - Cutting Cheese 【二分答案】【球缺体积公式】
  19. 招标 | 近期隐私计算项目招标14(数据资产、运营商、航运)
  20. python3编译成pyc文件

热门文章

  1. Yarn 组件的指挥部 – 调度器Scheduler
  2. 时间序列数据和MongoDB:第三部分 - 查询,分析和呈现时间序列数据
  3. 谈谈机器学习模型的部署
  4. python的模块itsdangerous
  5. Set Matrix Zeroes leetcode
  6. 3745路由器配置简单的dhcp server
  7. php call_user_func_array 性能,php-call_user_func_array是否太慢?
  8. java55矩阵output_leetcode 59 螺旋矩阵2 Java 用时较短-Go语言中文社区
  9. 通过.obj生成2d图像_自动生成 凹凸法线灯贴图 插件
  10. pde中微元分析法的主要思想_果然是清北学霸,高中数学解题思想与技巧方法,学会不下145分...