【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【上篇】

    • 一、TFLM是什么?
    • 二、TFLM开源项目
      • 2.1 下载TFLM源代码
      • 2.2 TFLM基准测试说明
      • 2.3 TFLM基准测试命令
    • 三、TFLM初步体验
      • 3.1 PC上运行Keyword基准测试
      • 3.2 PC上运行Person detection基准测试
      • 3.3 No module named 'numpy'问题解决
    • 四、TFLM源码浅析
      • 4.1 编译生成的.o文件
      • 4.2 基准测试的构建目标
      • 4.3 基准测试的构建规则
      • 4.4 TFLM库的构建规则
    • 五、TFLM主体移植
      • 5.1 实现TFLM库的构建
      • 5.2 实现辅助函数microlite_test
      • 5.3 实现keyword基准测试的构建
      • 5.4 实现Person detection基准测试的构建
      • 5.5 实现基准测试依赖的功能——计时和日志
    • 六、参考链接

本系列将介绍如何将TensorFlow Lite for Microcontrollers一直到STM32H7S78-DK上。由于整个过程较为繁琐,本系列将分为上下两篇进行介绍。本文为系列内容的上篇,主要分为TFLM是什么、TFLM初步体验、TFLM源码浅析、TFLM主体移植几个部分。其中,TFLM初步体验部分将会介绍如何在PC上运行TFLM基准测试,TFLM源码浅析部分主要介绍TFLM源码是如何进行构建的,TFLM主体移植主要介绍如何在基于CMake的STM32项目中构建TFLM库和基准测试。

一、TFLM是什么?

你或许都听说过TensorFlow——由谷歌开发并开源的一个机器学习库,它支持模型训练和模型推理。

今天介绍的TFLM,全称是TensorFlow Lite for Microcontrollers,翻译过来就是“针对微控制器的TensorFlow Lite”。那TensorFlow Lite又是什么呢?

TensorFlow Lite(通常简称TFLite)其实是TensorFlow团队为了将模型部署到移动设备而开发的一套解决方案,可以简单理解为TensorFlow的手机版。下面是TensorFlow官网上关于TFLite的一段介绍:

TensorFlow Lite 是一组工具,可帮助开发者在移动设备、嵌入式设备和 loT 设备上运行模型,以便实现设备端机器学习。

而我们今天要介绍的TensorFlow Lite for Microcontrollers(TFLM)则是 TensorFlow Lite的微控制器版本。这里是官网上的一段介绍:

TensorFlow Lite for Microcontrollers (以下简称TFLM)是 TensorFlow Lite 的一个实验性移植版本,它适用于微控制器和其他一些仅有数千字节内存的设备。 它可以直接在“裸机”上运行,不需要操作系统支持、任何标准 C/C++ 库和动态内存分配。核心运行时(core runtime)在 Cortex M3 上运行时仅需 16KB,加上足以用来运行语音关键字检测模型的操作,也只需 22KB 的空间。

这三者一脉相承,都出自谷歌,区别是TensorFlow同时支持训练和推理,而后两者只支持推理。TFLite主要用于支持手机、平台等移动设备,TFLM则可以支持单片机。从发展历程上来说,后两者都可以说是TensorFlow项目的“支线项目”。或者说这三者是一个树形的发展过程,目前是三个并进发展的。

简单总结: TensorFlow Lite是 TensorFlow的移动版,少了训练功能,TensorFlow Lite for Microcontrollers 是 TensorFlow Lite 的MCU优化版。这三者,CPU推理的代码基本上完全一致,后两者也可以理解为TensorFlow 的裁剪版。

二、TFLM开源项目

TFLM代码仓链接:https://github.com/tensorflow/tflite-micro

2.1 下载TFLM源代码

下载TFLM需要使用如下git命令:

 git clone https://github.com/tensorflow/tflite-micro.git

TFLM顶层目录下的文件和目录,如下图所示:

image-20240915212410086

2.2 TFLM基准测试说明

TFLM顶层目录有README.md文件,其Additional Documentation节列出来Benchmark说明,Benchmark(基准测试)用于衡量关键模型和工作负载的性能。

README.md前一半内容为:

image-20240915212828124

完整内容参考: tflite-micro/tensorflow/lite/micro/benchmarks/README.md at main · tensorflow/tflite-micro (github.com)

2.3 TFLM基准测试命令

从README的”Run on x86”可以看到,在x86 PC上运行关键词基准测试的命令是:

make -f tensorflow/lite/micro/tools/make/Makefile run_keyword_benchmark

在x86 PC上运行人体检测基准测试的命令是:

make -f tensorflow/lite/micro/tools/make/Makefile run_person_detection_benchmark

以上两个命令都会调用make命令,并以tensorflow/lite/micro/tools/make/Makefile为构建规则,分别构建run_keyword_benchmarkrun_person_detection_benchmark两个目标。

查阅tensorflow/lite/micro/tools/make/Makefile文件夹内容,可以看到:

image-20240915213658373

这段代码中的 595行、601行、605行、612行、613行 分别会下载一些文件,具体下载的是tflm依赖的库和测试数据集;

而执行上面两个make命令,实际上会依次执行如下步骤:

  1. 下载依赖库和数据集;
  2. 编译测试程序;
  3. 运行测试程序;

必须至少一遍make命令,才会下载测试数据集,才能进行后续的移植步骤。

三、TFLM初步体验

由于TFLM开源项目依赖部分三方软件代码没有直接放在TFLM源码仓中,需要运行一次基准测试才会下载下拉进行编译。因此,我们需要先在PC上体验一下TFLM基准测试。

PC上运行TFLM推荐使用Ubuntu系统,其他操作系统运行可能会有些问题。

3.1 PC上运行Keyword基准测试

PC Linux系统上,运行如下命令,可以执行Keyword基准测试:

make -f tensorflow/lite/micro/tools/make/Makefile run_keyword_benchmark

命令执行完毕,最后输出如下:

image-20240915220542913

PC上运行10次耗时3毫秒。

3.2 PC上运行Person detection基准测试

make -f tensorflow/lite/micro/tools/make/Makefile run_person_detection_benchmark命令执行完毕,最后输出如下:

image-20240915220904048

image-20240915220841572

PC上运行10次,有人的耗时343毫秒,无人的耗时337毫秒。

3.3 No module named 'numpy’问题解决

make命令报错:

image-20240915214404249

解决方法:

pip install numpy

四、TFLM源码浅析

开始移植TFLM之前,需要清楚TFLM整个源码项目是如何构建的(也就是构建规则)。

4.1 编译生成的.o文件

PC上运行完基准测试命令过程中,会执行源码编译命令。运行完成后,使用如下命令,可以找到所有.o文件:

find . -name '*.o'

部分输出如下图所示:

image-20240918205828262

通过该命令的输出,我们可以知道刚刚的两个命令一共有多少源文件参与了编译。

4.2 基准测试的构建目标

要移植TFLM,仅仅知道有多少源文件参与编译还不够,我们需要知道具体的构建规则。本节将通过分析Makefile解读基准测试的具体构建目标(target)。

从前面的PC端运行Keyword基准测试的输出可以看到,可执行程序名称为keyword_benchmark,通过搜索源码,可以找到对应的Makefile构建规则代码为:

image-20240918213031151

这里调用了Makefile的宏函数microlite_test,并传递了4个参数,分别为:

  • 参数1:keyword_benchmark
  • 参数2:$(KEYWORD_BENCHMARK_SRCS)
  • 参数3:$(KEYWORD_BENCHMARK_HDRS)
  • 参数4:$(KEYWORD_BENCHMARK_GENERATOR_INPUTS)

4.3 基准测试的构建规则

下面以keyword_benchmark为例分析具体构建规则。

宏函数microlite_test的具体定义为:

image-20240918214047186

image-20240918215156216

前面我们执行了如下命令:

make -f tensorflow/lite/micro/tools/make/Makefile run_keyword_benchmark

这个命令指定的目标名称为run_keyword_benchmark,对应到helper_function.inc文件中的84行,参数1为keyword_benchmark,下方规则的TEST_SCRIPT变量的值定义在tensorflow/lite/micro/tools/make/Makefile文件中为空白字符串,因此不起作用;

84行还可以看到run_keyword_benchmark目标依赖$(keyword_benchmark_BINARY)目标,回看到52行,可以知道:

  • $(keyword_benchmark_BINARY)目标表示可执行程序文件路径,:

  • $(keyword_benchmark_BINARY)目标依赖$(keyword_benchmark_LOCAL_OBJS)目标;

  • $(keyword_benchmark_BINARY)目标依赖$(MICROLITE_LIB_PATH)目标;

  • $(keyword_benchmark_BINARY)目标的构建规则为:

    $$(CXX) $$(CXXFLAGS) $$(INCLUDES) \-o $$(keyword_benchmark_BINARY) $$(keyword_benchmark_LOCAL_OBJS) \$$(MICROLITE_LIB_PATH) $$(LDFLAGS) $$(MICROLITE_LIBS)
    

根据传参,可以知道,一些变量的值为:

  • keyword_benchmark_LOCAL_SRCS的初始值为: tensorflow/lite/micro/benchmarks/keyword_benchmark.cc

  • keyword_benchmark_LOCAL_HDRS的值为:tensorflow/lite/micro/benchmarks/micro_benchmark.h

  • 得到GEN_RESULTS的命令为: python3 tensorflow/lite/micro/tools/generate_cc_arrays.py gen/linux_x86_64_default_gcc/genfiles tensorflow/lite/micro/models/keyword_scrambled.tflite,该命令会将模型文件转为.h.cc文件,其中.h为声明,.cc为数据:

    #include <cstdint>constexpr unsigned int g_keyword_scrambled_model_data_size = 34576;
    extern const unsigned char g_keyword_scrambled_model_data[];
    

    命令的输出为:gen/linux_x86_64_default_gcc/genfiles/tensorflow/lite/micro/models/keyword_scrambled_model_data.cc

  • keyword_benchmark_LOCAL_SRCS值会变为包含刚刚生成的模型keyword_scrambled_model_data.cc

  • keyword_benchmark_LOCAL_OBJS的值是:先将keyword_benchmark_LOCAL_SRCS值中所有.cc替换为.o,再给每个值添加前缀gen/linux_x86_64_default_gccobj/core/

  • MICROLITE_LIB_PATH的值为库文件libtensorflow-microlite.a的完整路径: gen/linux_x86_64_default_gcc/lib/libtensorflow-microlite.a

好了,到这里就可以看到$(keyword_benchmark_BINARY)目标构建规则下方命令的主要参数了:

  • -o选项为gen/linux_x86_64_default_gcc/bin/keyword_benchmark

  • $(keyword_benchmark_LOCAL_OBJS)为所有目标文件(.o)列表;

  • $(MICROLITE_LIB_PATH)是链接的库文件(.a)路径;

  • $(LDFLAGS)是链接器命令行选项;

  • $(MICROLITE_LIBS)是额外库选项,实际为 -lm

    到这里,Keyword基准测试的构建规则以及分析清楚了。

4.4 TFLM库的构建规则

接下来,我们分析keyword链接的库文件libtensorflow-microlite.a(简称TFLM库)的链接规则。

该目标的定义为:

image-20240918223607739

这里可以看到,该库是由以下目标文件列表归档(使用ar命令)而来:

  • $(MICROLITE_LIB_OBJS)
  • $(MICROLITE_KERNEL_OBJS)
  • $(MICROLITE_THIRD_PARTY_OBJS)
  • $(MICROLITE_THIRD_PARTY_KERNEL_OBJS)
  • $(MICROLITE_CUSTOM_OP_OBJS)

其中,前四个变量的值来自:

image-20240918223939972

这里可以看到,前面的几个目标文件列表分别来自:

  • $(MICROLITE_LIB_OBJS)来自于$(MICROLITE_CC_SRCS)
  • $(MICROLITE_KERNEL_OBJS)来自于$(THIRD_PARTY_CC_SRCS)
  • $(MICROLITE_THIRD_PARTY_OBJS)来自于$(THIRD_PARTY_KERNEL_CC_SRCS)
  • $(MICROLITE_THIRD_PARTY_KERNEL_OBJS)来自于$(MICROLITE_CC_KERNEL_SRCS)
  • $(MICROLITE_CUSTOM_OP_OBJS)没有在Makefile中定义,默认为空,可以忽略(实际使用时,可以通过命令行参数指定);

经过在Makefile中加入日志打印,发现上述几个xxx_SRCS变量的值为:

image-20240919211922448

五、TFLM主体移植

从TFLM官方介绍文档、测试命令以及源码分析可以知道,在STM32H7S78-DK上移植TFLM可以分解为以下几个主要任务:

  • 实现TFLM库的构建
  • 实现CMake版的辅助函数microlite_test
  • 实现keyword基准测试的构建
  • 实现person detection基准测试(可选)的构建
  • 实现基准测试依赖的功能——计时和日志

接下来分别介绍,如何完成上述任务。

5.1 实现TFLM库的构建

有了以上分析之后,我们就可以进行今天最重要的工作,将Makefile转换为CMake构建规则文件(CMakeLists.txt)。

这部分是整个移植过程中工作量和难度最大的部分,涉及到很多CMake的语法细节,这里不详细介绍。

实现TFLM库构建的CMake代码为:

TFLM-libtflite-micro

5.2 实现辅助函数microlite_test

TFLM源码中,构建基准测试使用了GNU Make的microlite_test宏函数,实现了代码的复用和逻辑精简。和GNU Make类似的,CMake也支持函数。本节我们实现GNU Make的microlite_test宏函数的CMake移植版。

CMake具体代码如下:

TFLM-microlite_test

这部分做了几个特殊处理:

  • 目标类型从可执行程序修改为静态库,即生成文件类型由.elf文件改为.a文件;
  • 使用宏将main函数重命名为${NAME}_main

做出如上两处修改的原因是——由CubeMX生成的基础已经有main函数,并且可以生成elf文件。通过上述两个修改,我们可以将基准测试代码链接到CubeMX生成的代码中去,进而实现整个项目可以在STM32H7S78-DK上运行。

5.3 实现keyword基准测试的构建

有了CMake辅助函数microlite_test之后,实现keyword基准测试的构建就很简单了,直接看代码:

TFLM-keyword_benchmark

5.4 实现Person detection基准测试的构建

同样的,有了CMake辅助函数microlite_test之后,实现Person detection基准测试的构建也很简单,直接看代码:

TFLM-person_detection

5.5 实现基准测试依赖的功能——计时和日志

TFLM本身是一个边缘AI推理库,可以理解为一个举证向量计算库,纯CPU计算不依赖任何外设功能。但是,TFLM的基准测试则依赖计时和日志功能。在不同平台上,计时和日志功能的实现方式有所不同,对应的代码也不同(例如Linux、Windows、MacOS操作系统、STM32单片机、ESP32单片机上,实现计时和日志的代码是不是一样的)。

TFLM源码中,已经为移植进行了设计,其中两个文件名分别对应计时和日志:

  • debug_log.cc,用于实现计时功能,不同平台有不同版本;
  • micro_time.cc,用于实现计时功能,不同平台有不同版本;

默认的debug_log.cc实现为tensorflow/lite/micro/debug_log.cc,其主要代码内容为:

TFLM-debug_log_stderr

这里实现了——使用vfprintfstderr输出。借助过往经验,我们知道CubeMX生成的项目稍加修改就能够支持printf,这种方式应该也可以支持。

因此,对于STM32单片机这部分可以不用修改!

默认的micro_time.cc实现为tensorflow/lite/micro/micro_time.cc,其主要代码内容为:

TFLM-micro_time_ctime

这个文件里面提供了两种实现,通过TF_LITE_USE_CTIME宏进行切换:

  • 如果没定义TF_LITE_USE_CTIME宏,则为空实现,提供空壳函数,可以编译通过,无法正常计时;
  • 如果定义了TF_LITE_USE_CTIME宏,则为基于C标准库clock()CLOCKS_PER_SEC的计时;

对于STM32单片机,C标准库的clock()的计时不能直接使用。

因此,对于STM32单片机,需要单独实现一个micro_time.cc文件,具体代码为:

TFLM-micro_time_stm32_hal

到这里,TFLM移植的主体内容基本已经完成了,还有一些问题需要解决,我能将在下篇进行介绍,欢迎关注。

本篇内容到此为止,感谢阅读!

六、参考链接

  1. TensorFlow Lite for Microcontrollers介绍: TensorFlow Lite for Microcontrollers (google.cn)
  2. TensorFlow Lite for Microcontrollers入门: 微控制器入门 | TensorFlow (google.cn)
  3. tflite-micro 源码GitHub仓: https://github.com/tensorflow/tflite-micro
  4. CMake最新文档: CMake Reference Documentation — CMake 3.30.3 Documentation

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/435816.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis篇(缓存机制 - 分布式缓存)(持续更新迭代)

目录 一、单点 Redis 的问题 1. 数据丢失问题 2. 并发能力问题 3. 故障恢复问题 4. 存储能力问题 5. 四种问题的解决方案 二、Redis持久化&#xff08;两种方案&#xff09; 1. RDB持久化 1.1. 简介 1.2. 执行时机 save命令 bgsave命令 停机时 触发RDB条件 1.3. …

phpstudy简易使用

注意&#xff0c;本文所述的操作步骤均建立在电脑上已经完成php环境变量的配置与vscode的安装之上 、

河南移动:核心营业系统稳定运行超300天,数据库分布式升级实践|OceanBase案例

河南移动&#xff0c;作为电信全业务运营企业&#xff0c;不仅拥有庞大的客户群体和业务规模&#xff0c;还引领着业务产品与服务体系的创新发展。河南移动的原有核心营业系统承载着超过6000万的庞大用户量&#xff0c;管理着超过80TB的海量数据&#xff0c;因此也面临着数据规…

网络安全法中,个人信息保护的措施和原则有哪些?

《中华人民共和国网络安全法》中关于个人信息保护的规定强调了几项基本原则和措施&#xff0c;以确保个人信息的安全。以下是其中的一些要点&#xff1a; 原则 合法性&#xff1a;个人信息的收集和使用必须符合法律规定。 正当性&#xff1a;信息收集和使用的目的是正当的&…

算法葫芦书(笔试面试)

一、特征工程 1.特征归一化&#xff1a;所有特征统一到一个区间内 线性函数归一化&#xff08;0到1区间&#xff09;、零均值归一化&#xff08;均值0&#xff0c;标准差1&#xff09; 2.类比型特征->数值性特征 序号编码、独热编码、二进制编码&#xff08;010&#xf…

数学建模--什么是数学建模?数学建模应该怎么准备?

前言 这是去年底学数学建模老哥的建模课程笔记&#xff1b;未来本人将陆陆续续的更新数学建模相关的一些基础算法&#xff0c;大家可以持续关注一下&#xff1b;提示&#xff1a;数学建模只有实战才能提升&#xff0c;光学算法没有啥意义&#xff0c;也很难学的很懂。 文章目录…

基于ESP8266—AT指令连接阿里云+MQTT透传数据(2)

MQTT_TX设备为发送数据的Topic&#xff0c;使用MQTT-fx软件实现 MQTT_RX设备为接收(订阅)数据的Topic&#xff0c;使用ESP8266通过AT指令实现 一、使用MQTT-fx实现发送数据 首先进入控制台&#xff0c;获取发送设备 “ MQTT_TX ” 的MQTT连接参数&#xff0c;具体具体操作如…

【Redis入门到精通五】Java如何像使用MySQL一样使用Redis(jedis安装及使用)

目录 Jedis 1.jedis是什么 2.jedis的安装配置 3.jedis的基础命令操作展示 1.set和get操作&#xff1a; 2.exists和del操作&#xff1a; 3.keys和type操作&#xff1a; 4. expire和ttl&#xff1a; Jedis Java 操作 redis 的客⼾端有很多&#xff0c;其中最知名的是 jedi…

Mysql 存储过程

1.需求&#xff1a; users表中的数据 如果在users_copy1表中存在&#xff08;2各表id相等&#xff09;&#xff0c;则根据users表的数据更新users_copy1表的数据&#xff0c;这两个表id相等。 例子&#xff1a; users表数据&#xff1a; users_copy1表数据&#xff1a; 当执…

docker运行arm64架构的镜像、不同平台镜像构建

背景 Docker 允许开发者将应用及其依赖打包成一个轻量级、可移植的容器&#xff0c;实现“一次构建&#xff0c;到处运行”的目标。然而&#xff0c;不同的操作系统和硬件架构对容器镜像有不同的要求。例如&#xff0c;Linux 和 Windows 系统有不同的文件系统和系统调用&#…

单臂路由详解

目录 单臂路由概念 单臂路由实验 路由器配置 交换机配置 实验验证 基于Eth-Trunk的单臂路由 路由器配置 交换机配置 实验验证 单臂路由概念 单臂路由技术能让路由器的一个物理接口对应不同VLAN数据的实质是把物理接口分成若干个子接口&#xff0c;这些子接口通过封装…

需求5:增加一个按钮

在之前的几个需求中&#xff0c;我们逐步从修改字段到新增字段&#xff0c;按部就班地完成了相关工作。通过最近的文章&#xff0c;不难看出我目前正在处理前端的“未完成”和“已完成”按钮。借此机会&#xff0c;我决定趁热打铁&#xff0c;重新梳理一下之前关于按钮实现的需…

【CSS in Depth 2 精译_040】6.3 CSS 定位技术之:相对定位(下)—— 用纯 CSS 绘制一个三角形

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09;第二章 相对单位&#xff08;已完结&#xff09;第三章 文档流与盒模型&#xff08;已完结&#xff09;第四章 Flexbox 布局&#xff08;已…

ECCV 2024 | 融合跨模态先验与扩散模型,快手处理大模型让视频画面更清晰!

计算机视觉领域顶级会议 European Conference on Computer Vision&#xff08;ECCV 2024&#xff09;将于9月29日至10月4日在意大利米兰召开&#xff0c;快手音视频技术部联合清华大学所发表的题为《XPSR: Cross-modal Priors for Diffusion-based Image Super-Resolution》——…

Visual Studio Code下载安装及汉化

官网&#xff1a;https://code.visualstudio.com/ 按照指示一步步操作即可&#xff1a; 汉化&#xff1a;

②EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器

EtherCAT转Modbus485RTU网关多路同步高速采集无需编程串口服务器https://item.taobao.com/item.htm?ftt&id798036415719 EtherCAT 串口网关 EtherCAT 转 RS485 &#xff08;接上一章&#xff09; 自由协议通信步骤 &#xff08;以MS-A2-1041为例&#xff09; 接收与…

C++ 3 个有序点的方向(Orientation of 3 ordered points)

给定三个点 p1、p2 和 p3&#xff0c;任务是确定这三个点的方向。 平面中有序三重点的方向可以是 逆时针 顺时针 共线 下图显示了 (a,b,c) 的不同可能方向 如果 (p1, p2, p3) 的方向共线&#xff0c;则 (p3, p2, p1) 的方向也共线。 如果 (p1, p2, p3) 的方向是顺时针&a…

鸿蒙HarmonyOS开发生态

1、官网 华为开发者联盟-HarmonyOS开发者官网&#xff0c;共建鸿蒙生态 2、开发工具IDE下载及使用 https://developer.huawei.com/consumer/cn/ 3、使用帮助文档 4、发布到华为应用商店 文档中心

迈威通信闪耀工博会,以创新科技赋能工业自动化

昨日&#xff0c;在圆满落幕的第24届中国国际工业博览会上&#xff0c;迈威通信作为工业自动化与智慧化领域的先行者&#xff0c;以“创新打造新质通信&#xff0c;赋能工业数字化”为主题精彩亮相&#xff0c;向全球业界展示了我们在工业自动化领域的最新成果与创新技术。此次…

Qt的互斥量用法

目的 互斥量的概念 互斥量是一个可以处于两态之一的变量:解锁和加锁。这样&#xff0c;只需要一个二进制位表示它&#xff0c;不过实际上&#xff0c;常常使用一个整型量&#xff0c;0表示解锁&#xff0c;而其他所有的值则表示加锁。互斥量使用两个过程。当一个线程(或进程)…