TinyML是什么?如何从零开始入门学习?本系列上一篇教程中,我们复习了 TinyML 的概念,完成了一个最简单的 ML 模型与微控制器运行。今天,本教程将与你探讨如何在实际的工程应用中对已建立的模型进行技术优化。
本文来自社区投稿与征集,作者王玉成,ML&IoT Google Developers Expert,温州大学智能锁具研究院总工程师。了解更多:https://blog.csdn.net/wfing
TinyML 这本书也详细的向我们介绍了优化的一些方法,以及用这些方法可以达到什么样的效果。通过优化,工程的执行效率会获得很大的提升。
我们先不要急于去看这本书到底介绍了哪些优化方法,我们仔细回顾一下,在之前的项目中,我们接触的工程中包括了优化的哪些方面?
5.1 优化角度
从工程角度来看整个流程,优化涉及到的部分,包括以下几个阶段:
需求分析及产品设计:定位产品的使用范围。产品方向的输入和输出的约定将会极大的影响产品的性能。当产品的需求完全定下来之后,我们便要分析输入和输出的具体内容,这些输入和输出将会造成什么样的影响?数据输入及输出影响着嵌入式硬件选型和 ML 模型选型。在工程设计的前期都必须要充分考虑这些因素。
ML 模型:解决了输入输出的问题之后,接下来便是模型的建立及优化。这一部分的内容是机器学习中老生常谈的问题,但是在每个具体的项目实施中间又是必须考虑的问题。对嵌入式系统中的人工智能模型的优化,已经有了量化,移动优化解释器,硬件加速等方法。这部分内容在手机相关的模型优化中间已经做了很多工作,但是在微控制器的模型优化中又提出了一些新的方法。这一部分方法也是我们讨论的主要方向。
基于低功耗的硬件去开发任何系统,首要考虑的问题是功耗。不同的硬件配置以及片上系统的运行特性,对功耗会产生完全不同的影响。特别需要指出的是,低功耗的设计本身会带来性能的损失,那么我们最优化的一些办法一定是从功耗和性能综合来考虑的,这是工程上面最典型的优化场景,不同的实现会带来完全不同的结果。
由于低功耗微控制器本身的存储容量特别小,不断减小模型的尺寸,也是优化的一个方向。加入了这些限制条件之后,就不得不从系统限制,内存,存储,运行效率等各个方面去评价这个模型是不是最优化的。类似场景的模型优化的评价方法是一直需要不断探讨的。没有最好,只有更好。
通过上面的要素分析,我们会发现工程的优化并不仅仅只是提供一个运行效率最快的模型,还涉及到许多许多其它方面的考虑。那么我们这一次的阅读会重点关注是低功耗的微控制器上如何去做优化。
由于整本书优化的方向比较多,我们就分两个大的部分来讨论优化的具体内容,模型优化主要讲述如何确定产品需求,到最后实现整个模型优化所采取的一些主要方法;工程优化主要讨论当模型导入到低功耗微控制器之后如何去运行所考虑的一些问题。
5.2 模型优化
5.2.1 产品设计优化
产品设计方面的优化从严格意义上来说,并不是技术优化的范围,但是他却直接影响着整个工程运行效率的高低。这一部分内容没办法用特别好的技术方法去做模型上的评估,但是在不同产品的工程需求捕获阶段,确确实实存在很大的差异性。
由于现在人工智能的重点,仍然在图像领域,声音领域和数据采样领域,那么我们就以这个方向为重点,来看一下产品需求中间需要讨论的问题。
图像:TinyML 的应用领域是在低功耗的微控制器上,但是如果我们加上摄像头去采集数据,功耗将是一个重要的考虑方向。摄像头的启动时间最快也要几秒,摄像头启动的时候会带来特别大的瞬时电流,而且摄像头又不能处于常开的模式。摄像头本身长期的开和关的切换会带来很大的功耗损失。摄像头在运行过程中间,不同的分辨率去采集图片,功耗又会不同。采样频率的设定方式不同,对功耗影响也比较大。从这个意义上来说,摄像头的选取就直接决定了优化了方向。
声音:声音相关的硬件和图像硬件有着类似的问题,但是我们需要注意的是,随着麦克风阵列的加入,虽然从模型上来说,能够更好的进行原始声音数据的分析,但是从硬件的使用角度来考虑,功耗会更大。
数据:这儿所理解的数据是一些传感器的数据上报,由于传感器的功耗已经做得非常非常低了,所以优化方向仍然与采样频率相关,如何在合适的时间使模型推断运行的最好?
这样看来,如果是我们需要主导一款低功耗嵌入式人工智能产品的设计研发,需要考虑到微控制器的性能、数据采集终端、采样时间及采样频率的限制。并且从以上的限制条件中,再去定制人工智能模型。
5.2.2 模型改进
以往的人工智能模型设计我们会用最多的资源,最好的环境去研发出最优的模型。但是基于低功耗的微控制器模型的运行环境,并不再强调模型一定是最好的,而在于运行的速度和效率的一个折中。只要最后的推理结果在我们认可的范围内就可以了。
当我们把模型调整优化好了之后,需要对 ML 模型的延迟进行评估。由于低功耗微控制器上面没有浮点运算单元的硬件支撑,那么,评估 ML 模型中浮点操作的次数,用量化的方法去减少浮点运算的执行时间,最终在微控制器上运行量化过的 ML 模型进行推理,成为一个比较好的方法。由于现在神经网络中的大部分计算是矩阵的乘法运算,那么可以用一次推理运行所需的浮点操作 (或 FLOP) 的数量来近似估算。例如,完全连接的层需要的 FLOP 数量等于输入向量的大小,再乘以输出向量的大小。我们也可以从模型架构讨论的论文中间去估计 FLOP 的值。通过这样的方法,我们就可以完全估计出浮点运算,或者量化之后运算所产生的时间损耗。然后再去优化最耗时的代码。获得更低的延迟。
5.3 工程优化
5.3.1 量化
最近几年,对于 TensorFlow 在嵌入式处理器上的应用,已经有很多的优化工作的成果。TensorFlow Lite 针对 TensorFlow 的优化大概包括以下几个方面的内容:量化、FlatBuffer、移动优化解释器和硬件加速。对于 TinyML 来说,主要以软件方式的优化为主。
我们以量化为例,量化的核心在于利用精度的损失来换取运行速度,那么如何平衡精度与效率之间的关系,就成为量化优化中最核心的问题。由于量化的过程是在整个模型已经建立完成之后去换算的,对于权重来说,可以用正确的缩放系数来进行转换。但是对于激活来说比较棘手,因为通过模型参数和连接层检查,并不清楚每层输出的实际范围是什么。如果选择的范围太小,输出将被裁剪为最小值或最大值,但是如果选择的范围太大,则输出的精度将小于其可能的精度,并且冒着使总体结果失去准确性的风险。现在转换器中提供了一个 representative_dataset() 函数,这是一个 Python 函数,可产生激活范围估计过程所需的输入,能够得到更好的优化。
针对于不同的硬件,甚至有时候我还会专门去看硬件指令所能带来的一些优化方法。这种方法虽没有通用性,但是对于单个产品的模型加速仍然比较重要。但麻烦的问题在于:既需要了解 CPU 是否有特殊功能的支持,还需要了解编译器是否对这些指令做了专门的优化。甚至有可能出现最难以预料的方式,加入内联汇编去支持,这已经超出常规的优化范围了。
从这一类方法可以看出,基于微控制器的优化更强调硬件个体有没有优化的空间。
5.3.2 硬件优化
硬件选择性问题,尽量的去选择 TinyML 支持的硬件,这样硬件驱动会有一个完善的支持,而且对开发版的优化已经做的比较充足了。
低功耗的微控制器通常使用的是电池作为电源。休眠是一个重要的因素,合理的设计会极大的延长电池使用时间。我们可以用硬件占空比来设计休眠、唤醒时间。传感器采样频率、时间、功耗等因素,在产品设计优化部分已经阐述,同时也需要做许多折中的选择,但是他们同时也是硬件优化的范围。
级联设计是另一个比较好的考虑角度。与传统的过程编程相比,机器学习的一大优势在于,它可以轻松扩展或缩减所需的计算和存储资源数量,并且准确性通常会适度降低。这意味着可以创建模型级联。比如说我们有一个多级的模型,当第 1 级的硬件计算能力达不到我们的要求时,我们会主动启动第 2 级开销,这样的话我们可以运用更短的时间得到精确的结果。
5.3.3 基于硬件的软件行为优化
无论选择哪种平台,闪存 (Flash) 和内存 (RAM) 都可能非常有限。大多数基于微控制器的系统在闪存中只有不到 1 MB 的只读存储,最小的几十 KB。RAM 也是如此:很少有超过 512 KB 的静态 RAM (SRAM)。针对微控制器的 TinyML 可以低于 20 KB 的闪存和 4 KB 的 SRAM 进行工作,但是您将需要仔细设计应用程序并进行工程设计,以保持较低的占用空间。
大多数嵌入式系统都具有一种体系结构,其中程序和其他只读数据存储在 Flash 中,仅在加载新的可执行文件时才将其写入,作为可以读写的内存使用。此技术与大型 CPU 上的缓存使用的技术相同,它可以快速访问以降低功耗,但尺寸有限。更高级的微控制器可以使用耗电较大但可扩展的技术,例如动态 RAM(DRAM) 来提供第二层可读写的内存。那么,外设读写操作次数的多少,直接影响到运行效率。
Flash 的使用率也是一个考虑的因素。分析 ELF 文件中各段的使用效率,以及无用代码的优化,预编译优化,将会节省大量的 Flash 空间。
RAM 优化,主要包括程序在编译时以及运行时的一些考虑。ML 框架的核心运行时应用并不需要大的内存,并且其数据结构在 SRAM 中的空间不应超过几千字节。这些是作为解释器使用的类的一部分进行分配的,因此,无论您的应用程序代码将它们创建为全局对象还是本地对象,都将决定它们是在堆栈中还是在通用内存中。我们通常建议将它们创建为全局或静态对象,因为空间不足通常会在链接时引起错误,而堆栈分配的本地变量可能会导致运行时崩溃。所以程序编译之前,堆栈的设计,以及程序的内存驻留空间,需要有一个比较好的设计方案。
二进制大小的优化。TensorFlow Lite 占用了多少空间是空间优化的一个重要内容。测最简单方法是注释掉对框架的所有调用(包括创建 OpResolvers 和解释器之类的对象),然后查看二进制文件变小了多少。如果没有看到类似的内容,则应再次检查是否已捕获所有引用,有没有不必要的引用。由于链接器会删除永远不会调用的所有代码,并将其从封装中删除。降低代码的耦合度,规范的编程,会影响到最终生成的二进制文件的大小。
这一部分的讨论涉及到了硬件的选型问题,硬件上的各种参数的限制问题。从编译方向出发,特别是从编译阶段,链接阶段以及代码运行阶段可以优化的一些方向。这一部分优化的过程就是量身打造利器的过程。
5.4 总结
到此为止,这一系列的文章,都已经完全分享完了。我们从这一系列文章中,了解了 TinyML 的作用,并参照项目示例中的源码,实现了一个基于 TinyML 的项目工程,最后,通过剖析项目开发的流程以及关注点,学习了工程优化方法。但是,TinyML 这本书介绍的内容远不止于此,书中还包含一些更复杂的示例以及剖析,包括一些优化方法的原理性解释,如果对于这个方向感兴趣,那就赶快买这本书来阅读吧。
复习 TinyML 基础原理和模型应用相关内容,点击 TinyML 第一集(基础原理篇),TinyML 第二集(模型应用篇)。
如果你对本文中提到的一些知识点存在疑问,欢迎移步“问答”版块发帖提问。你的问题有机会得到 CSDN 百大热门技术博主、资深社区作者或者 TensorFlow 资深开发者的解答哦!同时,我们也欢迎你积极地在这个版块里,回答其他小伙伴提出的问题,成为 CSDN 社区贡献者,迈出出道第一步!马上开始讨论吧!
想了解更多大神的经验分享?扫码关注TensorFlow官方微信公众号(TensorFlow_official),产品更新、课程教学、技术实践、应用实例等精彩内容一网打尽!