update:在 0x08. 中更新了代码 视频 PPT 以保证作品完整性
0x00.前言
早在报名当初时填写的期望作品是可以给家里的 ESXi 服务器远程开关机的开关,类似于 IP-KVM 或者 Pi-KVM 中包含的功能之一,真的是在物理层面上去控制开关机,可能有人觉着这种实现有点 low。但现实生活中类似的商业化产品是真实存在的,举两个例子,一个例子是比如想给家里的普通开关换成智能开关,不一定非得拆掉普通开关,可以外接一个 SwitchBot(https://www.amazon.com/SwitchBot-app-controlled-device-mechanically-rocker/dp/B07B4D9KVX),然后只要 SwitchBot 上云了,普通开关也就相当于也上云了;另一个例子是说工厂里的三色灯,想在一个大屏上统一查看状态就需要进行采集,但毕竟是一直运转的工厂,把普通三色灯换成智能三色灯势必会影响正常的生产,而有一种采集方案就是把传感器外挂在普通三色灯的外层,通过光学颜色识别来实现的,没错,说的就是自己上一家公司的 TS-10(https://www.alsi.cn/alsi/product_detail/id_18.html),注:没收广告费
在刚收到开发板的时候,因为从来没有接触过 i.MX RT1062 处理器,以为把它当做 STM32 然后按照常规着手嵌入式开发就完事了。但是,当看完比赛主办方推出的直播课程之后,对 NXP 的跨界处理器有了崭新的认知,所谓跨界,跨的两个界指的是微控制器和微处理器,它兼具两者的特点,既具备高频率(最高 600M) 又具备高实时性。并且直播课程的最后两期,讲的都是 AI 方面的,至此才恍然大悟主办方为什么起了个“AIOT”的名字,原来是“AI” “IOT”的意思
在好奇心的驱动下,决定一定要搞一个与 AI 相关的作品出来,这里就要提到谷歌开源的——TensorFlow(下文简称 TF)了。当初还在上大学的时候就特别关注(自己毕设做的就是人脸识别),在油管看过两次直播,印象最深刻的就是,在推出适合跑在移动端运行的 TensorFlow Lite(下文简称 TFL)之后,还推出了可以跑在资源受限的嵌入式设备的 TensorFlow Lite for Microcontrollers(下文简称 TFML),一个语音识别的仅 22K 的 Micro Speech 跑在 Cortex M3 上,运行 RAM 占用也仅 10K(https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/micro_speech/README.md)。并且,当初自己拿官方项目编译的 TFL detect app 现在还装在自己的手机里(https://github.com/yuangezhizao/TensorFlow-Lite-Android-Apps)。在看到 RT1060 的官方例程里有用到 TFML 时简直开心的不得了,必须要动手亲自尝试一下。
0x01.EIQ
官网:https://www.nxp.com/design/software/development-software/eiq-ml-development-environment:EIQ
什么是 EIQ
从上面的图表中可以看出 i.MX RT1060 是支持 DeepViewRT™、TFLM 和 Glow 这三种推理技术的
对于 TFML 我们需要替换自己的 .tflite 模型,而这个.tflite 模型可以通过 eIQ Portal 提供的工具迁移学习得到,迁移学习就是在其他训练好的模型之上,再次进行训练以省略掉从零开始所花费的时间
看网上的资源不多,这里再按步骤介绍一下,如何使用 eIQ Portal 训练自己的模型
因为手里没有模型,所以选择 BYOD 的方式,自备数据开始训练,当然如果有现成的模型可以走右边的 BYOM 的方式
初次运行后,运行 COMMAND LINE 打开命令行,这个命名行里会含有工具自带的 Python 环境变量以及第三方包 site-packages,然后运行示例脚本 CIFAR_uploader.py
代码语言:javascript复制C:nxpeIQ_Toolkit_v1.2.5>cd workspace
C:nxpeIQ_Toolkit_v1.2.5workspace>python CIFAR_uploader.py
2022-03-12 16:28:44.439917: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library cudart64_110.dll
Project cifar10.deepview was successfully created at C:nxpeIQ_Toolkit_v1.2.5workspace...!
uploading train partition...
100%|██████████████████████████████████████████████████████████████████████████████| 1000/1000 [00:12<00:00, 79.32it/s]
uploading test partition...
100%|████████████████████████████████████████████████████████████████████████████████| 500/500 [00:06<00:00, 82.69it/s]
这样就以脚本的方式导入了数据集,并新建了一个名为 cifar10.deepview 的工程文件,这里说明一下除了 .deepview,.eiqp 也是支持的文件拓展名,但两者没有任何区别
通过查阅相关资料可知 .eiqp 的本质就是一个 SQL 数据库,并且支持存储大量的数据集
打开工程,进入到第一步数据标记,因为脚本里下载的是 CIFAR10 数据集是被标记好 label 的,且指定了 ["airplane", "automobile","bird","cat","deer", "dog","frog","horse","ship","truck"] 分类,所以就省去了自己做标记的一步了,点击右上角的按钮可以重新拆分训练集和验证集,默认验证集是 20% 的比例
还可以通过 Augmentations 来进行数据增广,左边有很多参数可以设置,比如说对图像进行旋转、反转、加入随机高光,噪声,对比度,高度等等,可以以此来获得更多的数据集,并且也能提高模型的鲁棒性
然后是模型的选择,要么选择分类模型(以下简称 CF)要么选择目标检测模型(以下简称 OD),注意两者的数据集不可混用,OD 比 CF 麻烦的点在于,CF 的整个图像就是要识别的部分,而 OD 需要先判断出位置信息,然后再针对于该位置信息进行识别。所以 OD 的数据集相比 CF 的数据集还多了位置信息,并且 OD 的数据集要不 CF 的数据集大的多,比如常见的 COCO,下载需 ~40GB,解压后不到 100GB,也是挺大的了
参照:https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/person_detection/training_a_model.md
所以,先采用 CF 的数据集
一直点下去选择“Balanced”和“MCU”是一种方法
通过查阅相关资料可知具体的细节,CF 用得是 Mobilenet v2 而 OD 用的是 Mobilenet SSD,性能平衡和精准对应的是 alpha 或 scale 的值,MCU/CPU/GPU/NPU 暂时未做区别,后期会针对硬件引擎作区分
而另一种方法,是可以直接在左下角选择基础模型的,比如最简单的 mobilenet_v1,在这个模型的基础上迁移学习
在训练的界面,首先需要将输入的大小改成 128*128,在导入脚本中 new_dimension = (128, 128) 这句话已经帮我们把数据源都变成这个大小的了,然后可以调节 Epochs To Train,这里调节到了 25
开始训(lian)练(dan),可以看到精确度越来越高,但是后面大概率是过拟合的状态,所以需要选择前面的精确度还不错的一种
可以在检查点中还原到指定的 checkpoint,这里只有 25,21,4,2,1
选择 21 这个 checkpoint
验证过程需要打开 int8 的量化,嵌入式设备上跑的模型大都是经过量化的,这里的精确度是 71%,感觉有一点低,可以在右边的红色表格中详细看是实际是哪种判断错误了
可以看出识别错误最高的是实际是猫结果识别成了狗
最后一步导出模型,选择 TFL 类型并且要打开量化,同样是 int8,至此就得到了自己训练出来的 .tflite 模型啦
如果手上有官方的 1060 开发板,还可以跑一个 model_runner 的例程,那个是用网线连接到电脑上,在一个局域网内依赖到了 LoRa 的 SOCKET 来进行通信的,可以直接把模型在开发板上跑起来,而自己虽然有 LoRaWAN 模块,家里也通过 HT_M00L 覆盖了信号,但是不确定无线调试是否行的通,所以就没去折腾移植
0x02.Camera_ov5640 例程移植 TencentOS-tiny
回到开发板,跟着前两个直播视频搭建过一遍之后,自己又从零把 Camera_ov5640 下的 evkmimxrt1060_csi_rgb565 例程(之所以选择这个例程的原因是,摄像头和显示屏的驱动是移植过的,但是 TencentOS-tiny 需要自己动手移植
),成功移植并上云(可以同时跑多个任务:点灯,mqtt,摄像头 视频),确信自己搞定移植 TencentOS-tiny https://github.com/OpenAtomFoundation/TencentOS-tiny)是没啥问题了,其实主要的操作就是复制需要的文件夹,然后修改 IDE 的宏和头文件配置,并补充 include 语句等等~
软件层面上
- 特殊的就是有一个引脚路由的概念,IOMUXC
- 针对于外置 SDRAM 需要修改 DCD(Device Configuration Data)文件
- NCACHE_REGION 不足时按需修改内存配置
- 显示屏需要对应修改分辨率,板子的时钟频率
硬件层面上
- 打印无输出时,注意 AT 或 MCU 的开关
- 程序跑飞不能再次下载时,切换核心板上的开关
- 避免摄像头长时间工作,防止过热烧坏
- 音频部分电路需要自行修改,包含麦克风和两个原件的位置互换
以上这些就都不再赘述了,除去这些平台的差异之外,剩下的开发流程应该是类似于 STM32 的了
0x03. EIQ 例程烧录
上手一块芯片难道是需要从手册一页一页看起吗?当然不是,自己对 mculover666 在直播里的观点表示赞同,1060 官方 SDK 里提供了非常多的例程,可以先跑起来看看效果,然后自己再动手改,实现自己的作品,这是最快的上手方式
自己直接烧录了几个 SDK 中 eiq_example 下的例程,未做任何修改就编译,先看看效果再说
evkmimxrt1060_glow_cifar10(上图)
evkmimxrt1060_glow_lenet_mnist(上图)
evkmimxrt1060_tensorflow_lite_micro_cifar10(上图)
evkmimxrt1060_tensorflow_lite_micro_label_image(上图)
glow 的推理时长和文档中描述的类似,这里差异比较大的是 tensorflow_lite,文档中静态图片仅需 70~80 毫秒实际跑起来却需要 800~900 毫秒,是硬件的差异还是得修改某些配置,不太清楚原因在哪里?
0x04.EIQ 例程移植 TencentOS-tiny(未完成)
TL;DR
【此章节建议跳过,仅为记录历史】都是瞎折腾,还是自己太菜了
在成功移植 evkmimxrt1060_csi_rgb565 例程之后,觉得自己又可以了(第一次高估了自己),2 次抽出晚上的时间静心去移植evkmimxrt1060_tensorflow_lite_micro_label_image 都失败了,搞到凌晨三四点最后还是放弃了,遇到过各种奇奇怪怪的问题,有的解决有的放弃,简单贴几种就不占版面了,虽然这文章的长度已经过于离谱了
又绿屏又红屏,真是让人哭笑不得……
0x05.NXP_RT1062_TecentOS_AIoT_OD 抄作业(未完成)
TL;DR
【此章节建议跳过,仅为记录历史】都是瞎折腾,还是自己太菜了
evkmimxrt1060_tensorflow_lite_micro_label_image 例程移植搞不定,群里不是还有现成的人脸检测的例程吗?拿那个改一改换成自己的模型应该也能搞定吧(第二次高估了自己)
在烧录之后看到可以框出人脸的现象之后,是时候来研究一下工程里值得去看的部分吧
首先这个工程是基于 SDK 中的 led_output 驱动示例,并且引入了 CSI RGB565 example,这样就有了摄像头 显示屏的基础。然后通过 video.c 去调用的 TFML,在 eiq 文件夹下可以看到 libaia_cmsisnn_cm7.a 和 libtf_eiq.a 两个 .a 文件,前者是 80K 大小的 CMSIS NN 的加速库,而后者是 31.4M 的 TFML 封装,在 libtf_eiq.h 中可以看到函数引用,并且后者的调用还依赖 model.c 里的函数,model_data.s 中通过 .incbin 方式导入的模型有 face_detect_128x128.tflite 或者 face_detect_64x64.tflite,实测后者推理起来会更快
先来捋一下工程的逻辑,MQTT 任务就不说了,显示任务中,首先初始化模型 MODEL_Init(model_data),然后读取摄像头的帧序列采集到的图片,进行 resize 预处理,没记错的话是到 RGB565 格式 128*128 的大小
最后调用 MODEL_RunOD(),其返回值是运行成功失败与否,如果有报错会输出到 py_tf_putchar_buffer 里,返回结果是 MODEL_GetODTensorByIdx() 取到的,boxes 框,scores 评分,labels 标签(单分类可忽略),nums 数量?
最后读取 boxes 的位置信息通过并 IMAGE_DrawRect 在屏幕上绘制出绿色的框框(通过 PXP 即像素处理通道
RGB565_To_XRGB8888 将视频帧输出到屏幕)
而因为 BYOD OD 所需的数据集过大,又不知道啥样的 BYOM 的 OD 模型好用,wx 群里其他同学有在做 BYOM 的 OD
所以就用了之前章节说的 BYOD CF 方案,模型已经炼丹完成,只剩下调用了,因为看不到 libtf_eiq.a 里的函数定义也找不到相关文档,所以祭出 IDA 看里面到底有啥,经过一番摸索,发现这个 .a 文件里面嵌套了多个 .o 文件,最终找到了函数定义
MODEL_Run 的返回是 v12,MODEL_GetOutputSensorData()
MODEL_GetOutputSensorData() 的返回是 GetTensorData()
真的是照猫画虎,瞎写出来的,毕竟也不是特别理解 TensorFlow 里面的相关概念
注:上图写法应该不对,也不知道该怎么写
本来就是 C 语言半吊子水平,对于返回值只能猜测应该是包含了 label 和 score 的(毕竟只是分类模型),调试了几次整个函数的返回值一直是 1,然后这个 data[0] 也太诡异了吧
代码语言:javascript复制tensor_dims_t.size:0
tensor_dims_t.data[0]:1610680881
tensor_type_t:0
在这个过程中,还请教了 wx 群里的两位做 OD 的大佬,给出了一些建议,但毕竟最后还是得自己搞,除了用自己的模型还尝试过一次换成 SDK 例程里的 cifarnet_quant_int8.tflite,最大的问题估计在于 C 写的不对吧,血压飙升~
注:其实也尝试拿手机 TFL Detect 用到的 OD 模型(http://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip)来 BYOM,但是因版本问题转换失败了
0x06.Benchmark
在做之前,最好先了解一下可行性,心里好有个大致的预期,不然跑到多少 FPS 算正常都是个未知数,通过查阅相关资料可知
嗯,CF 和 OD 都是可以跑的
模型量化,缩小输入,减少类别,精简骨干都是提高 FPS 的方法
算子?
YOLO 是「你只看一眼」的意思 2333,可以做到多目标检测,但是想在开发板上跑多目标检测估计有点困难
推荐使用 YOLO V4,不满足可降级至 SSD(疑问为啥不能用 YOLO V5?
公版 YOLO 直接跑是不太行的样子
0x07.补充
- 通过与 wx 里的两位做 OD 的大佬的沟通,得知最后都没有用 libtf_eiq.a 这种方式,而是原生调用 TFML,是真正的大佬,类似这种
- 关于是怎么编译生成 libtf_eiq.a 的,https://github.com/tensorflow/tflite-micro/actions/runs/1978608990
0x08.代码 视频 PPT
- 自己瞎折腾的代码仓库,就摄像头例程移植并上云,加了几个 GPIO 的控制,腾讯连连用的标准面板,好像也没有必要公开了?https://github.com/yuangezhizao/EVB_AIoT/tree/master/getting_started/Camera_ov5640/evkmimxrt1060_csi_rgb565
- 只能把前文 0x02 中提到的 evkmimxrt1060_csi_rgb565 移植上云工程拿来交作业了
用来做封面
0x09.后记
感谢比赛主办方举办这次比赛,感谢汪总以及热心群友在 wx 群里的技术支持,以及感谢耐心看到这里的你!
以下是帮过自己的热心群友的文章推荐(不分先后顺序):
- AIoT应用创新大赛-基于TencentOS Tiny 的多功能行人检测仪,https://cloud.tencent.com/developer/article/1955718
- AIoT应用创新大赛-基于TencentOS Tiny的办公区厕所蹲位监控系统,https://cloud.tencent.com/developer/article/1955596
- 好像还没发文
自己转行互联网写代码一年多了,没错脱离嵌入式行业也一年多了
感叹芯片的发展是真快,也感叹才一年没碰就已经有些许生疏了
虽说可以写比赛经历,但是看别人都搞出实际作品而自己寄了
觉得辜负了比赛举办方满满的诚意,愧对汪总(认真脸)
心里多少还是有亿点点失落呢
2022-03-15
远哥制造