项目背景与设计思路
本文目标为实现基于MAX78000的农业病虫害识别检测。
病虫害识别是农业生产中的一大难题,监控农田病虫害情况并及时报警,防患于未然,在小范围农田病虫害发展初期识别并传递信息给农民,及时扼制虫害,是非常有意义的。基于 MAX78000开发板支持 CNN 的特性,本项目实现了病虫害识别与上位机信息发送。
鉴于开发板算力有限,因此推理模型需要一定程度简化。本文认为,将需求简化为识别单一农作物的生长叶片状态,将识别问题转换为二分类问题,可以大幅度降低对板卡的推理算力需求。
MAX78000开发板的官方例程中,参考该类问题给出类似的CNN例程,合并稻瘟病、褐斑病与其他虫害数据,二分类目标为“存在病虫害”与“不存在病虫害”。
本文收集了过去竞赛平台上开源的农业水稻作物数据集,选取了5622张图片用于训练,并借助于ADI官方提供的ai8x工具实现了CNN模型训练、量化等操作,最终成功转化为可以传递给嵌入式设备的格式。基于例程改进C++代码,最终实现了新的图像识别模型在MAX78000设备上的烧写。
程序写入后,按下SW5键,MAX78000自带摄像机会启动,拍摄图像后,在板卡中进行推理,得到可靠的推理结论,然后发送给上位机,通过uart串口可以读出判别结果。笔者认为,本文设计的功能基本证明了MAX78000作为低功耗边缘计算设备的实际应用潜力,本文涉及项目在实际落地过程中仍然有较大改进空间,如增加TFT屏幕、拓展无线收发设备等。
展望未来,本研究所进行病虫害识别研究更多基于软硬件开发进行讨论,并未对识别算法进行调整。本研究所选用的数据集中,部分病虫害叶片与正常叶片的正常枯黄相似度较高,笔者认为,针对此类情况,传统算法的识别能力难以在准确度上有质的提升,建议后续可以从农学专业角度探究不同类型叶片的本质区别,并开展相应的识别算法优化。
项目设计框图
本文亮点
介绍了MAX78000处理图像识别二分类问题时,项目实现的具体细节。
基于已有的例程框架微调实现,基于官方教程文档,实现了环境搭建、数据集获取、训练、量化、评估、C代码合成与修改,并成功在板卡编译。
本文技术细节非常详细,可以完全复现,同时围绕几个点调试探索,与官方文档形成互补:
1. 基于VS Code的开发探讨与环境搭建,编译调试细节,并以中文形式给出。
2. 完全实现了Windows平台下的conda环境python 3.8.7训练,该过程官方文档支持wsl2 下的 ubuntu 22.04 LTS,而本文实现的Windows平台下训练,大幅度简化了开发流程。
3. 本文的量化、评估部分在Windows11预览版平台上成功运行,是基于多种细节不断探索得到的。基于此,本文实现了完全不再依赖于Linux平台的开发。
前期板卡数据学习
支持功能
芯片:双核 Arm Cortex-M 4 Processor with FPU, 100 MHz, RISC-V Coprocessor, 60 MHz
512 KB Flash Memory
128 KB SRAM
16 KB Cache
卷积神经网络加速器
12 位并行摄像头接口
-集成的外设
RGB 指示 LED
用户按键
CMOS VGA 图像传感器低功耗立体声 CODEC
数字麦克风
SWD 调试器虚拟 UART Console
10-Pin Cortex Debug Header for RISC-V Coprocessor
MAX 20303 可穿戴式 PMIC,带电量计从 USB 充电板上 DAPLink 调试和编程接口,用于 Arm Cortex-M 4 处理器的调试面板板兼容的连接器
Micro USB 连接器
Micro SD 卡连接器
电池供电方案
单节锂电池供电,3.5 V 到 4.2 V,或者 USB
环境准备
软件:VS Code;Eclipes(备用)使用 MaximMicrosSDK_win.exe 安装(全部安装),不建议安装百度网盘的资源,因为版本较旧,部分 bug 可能没修复。该方法在国内校园网测试,部分时间段网速较快,峰值 4 MB/S ,多数时段无法下载。安装后,配置 SDK。
• SDK 路径配置方法:https://analog-devices-msdk.github.io/msdk/USERGUIDE/#getting-started-with-visual-studio-code
注意 D:\MaximSDK\Tools\OpenOCD 加入环境变量。主要配置 VS Code ,然后进行使用。
VS Code 使用经验
每修改一次,一定按一下,Ctrl+Shift+P,重新加载改过代码需要 reload,经常链接错文件,不用例程先压缩掉,避免相同文件名。下载不进去,可能是占用或者单片机锁死。每运行一个案例,都应该注意修改这个语句。
"target":"MAX78000",
"board":"FTHR_RevA",
全局设置
Ctrl+Shift+P 全局用户配置,里面路径只能用/,不能用 \\,配置内容要写入{}内部写入
//这是给MAXSIM的MSDK开发板使用的
"MAXIM_PATH": "S:/MaximSDK/MaximSDK",
"update.mode": "manual",
"extensions.autoUpdate": true,
修改完工程 setting 后,应该 Ctrl+Shift+P 后输入 Reload Window,重新打开窗口,修改内容 "board":"FTHR_RevA",因为,官方文档中认为,MAX 78000|EvKit_V1 属于带屏幕的板子。
MAX 78000 EVKIT | MAX 78000 | EvKit_V 1 |
MAX 78000 FTHR | MAX 78000 | FTHR_RevA |
对 main. C 进行 Ctrl+Shift+B 编译选择 build 内容,编译结果在 .elf 文件,build 文件夹中,然后 Ctrl+Shift+B 选择 flash 内容,如果需要,运行该任务将自动构建项目,闪存程序二进制文件,并停止程序执行以等待调试器连接。
然后 Ctrl+Shift+B 选择 flash 内容,如果需要,运行该任务将自动构建项目,闪存程序二进制文件,并停止程序执行以等待调试器连接。
单片机锁定与解锁
问题:MAX 78000 单片机,正常运行 example 时,跑了一个 CNN 就无法写入了。该问题不少购买者遇到。前置工作:
1. 检查目标设备是否上电并正常运行;
2. 检查连接线路是否牢固连接,或者替换一根新的连接线试试;
3. 关闭其他程序或者调试器,确保目标设备被你所使用的调试器独占;
4. 检查 openocd 的配置文件,确保配置正确。检查均非上述问题,最终判断单片机锁定。
报错内容
以下为烧录时报错。
* 正在执行任务: arm-none-eabi-gdb --cd="D:\MaximSDK\Examples\MAX 78000\Hello_World" --se="build/Hello_World. Elf" --symbols=build/Hello_World. Elf -x="D:\MaximSDK\Examples\MAX 78000\Hello_World/. Vscode/flash. Gdb" --ex="flash_m 4_run D:/MaximSDK/Tools/OpenOCD cmsis-dap. Cfg max 78000. Cfg" --batch
D:\MaximSDK\Tools\GNUTools\10.3\bin\arm-none-eabi-gdb. Exe: warning: Couldn't determine a path for the index cache directory.
The target architecture is set to "armv 7 e-m".
Open On-Chip Debugger 0.11.0+dev-g 56 a 818 e 4 c (2023-10-09-16:14)
Licensed under GNU GPL v 2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Remote communication error. Target disconnected.: No error.
* 终端进程“C:\WINDOWS\System 32\cmd. Exe /d /c arm-none-eabi-gdb --cd="D:\MaximSDK\Examples\MAX 78000\Hello_World" --se="build/Hello_World. Elf" --symbols=build/Hello_World. Elf -x="D:\MaximSDK\Examples\MAX 78000\Hello_World/. Vscode/flash. Gdb" --ex="flash_m 4_run D:/MaximSDK/Tools/OpenOCD cmsis-dap. Cfg max 78000. Cfg" --batch”已终止,退出代码: 1。
解锁方案
ADI 工程给出的解决方法如下:参考下文文档。
断电,按住 SW 5 (是复位键)后通电,进入调试模式。这个位置的文件下载,重置文件 MaximAI_Documentation/MAX78000_Feather/MAX32625PICO_files at master · MaximIntegratedAI/MaximAI_Documentation (github.com),把这个文件拷贝进去,然后插拔一下然后,新建文本文档,命名 auto_on.cfg,然后会自动重连;然后,新建文本文档,命名 erase.act,然后会自动重连
注意:这一轮操作后,串口从 COM 3 变为 COM 4
调试运行结果
刷入基础例程,实现正常串口收发。
数据集
来源与展示
本文基于kaggle中开源的病虫害分类数据集,链接如下:
https://www.kaggle.com/datasets/nizorogbezuode/rice-leaf-images/data
全量下载并扩充后,共 5622 张图片,数据集充足。
训练时实际分配的数据集为training=4047, validation=449, test=1126。
病虫害存在图片:
病虫害不存在图片:
数据集预处理与存放位置
为了防止报错,本文直接使用原猫狗识别的训练代码进行训练,其中,cats对应正常叶片, dogs对应病虫害叶片。训练集与测试集比例为8:2(官方推荐9:1),利用python中的PIL库“img = img.resize((128, 128))”语句,可以将图片批量转换为128*128格式。需要注意,该开发板最大支持该分辨率,而原数据集分辨率为256*256,因此本项目处理数据集图片是必要的。
原数据集为正常叶片样本与三类病虫害类型,本文探讨分类问题,因此将“三类病虫害类型”合并为“非正常叶片”,本文认为,该步处理是导致收敛效果有限的主要原因。
因此本文直接存储替换路径:
病虫害测试集:S:\condaenv\ai8x-training-develop\data\cats_vs_dogs\test\cats
正常测试集:S:\condaenv\ai8x-training-develop\data\cats_vs_dogs\test\dogs
病虫害训练集:S:\condaenv\ai8x-training-develop\data\cats_vs_dogs\train\cats
正常训练集:S:\condaenv\ai8x-training-develop\data\cats_vs_dogs\train\dogs
为便于复现,本项目提供夸克网盘存储的已加工好的数据集,数据集链接如下:
「MAX78000病虫害数据集.zip」链接:https://pan.quark.cn/s/06e72e6b57f0
提取码:EZQj
训练
分析需求
基于官方给出的训练代码实现训练,只需要提供数据集,因此应该构建与官方教程文件完一致的环境。
用于模型训练的唯一官方支持平台是 Ubuntu Linux 20.04 LTS 和 22.04 LTS(amd64/x86_64),PyTorch 的官方支持版本是在 Python 3.8.x 上运行的 1.8.1 (LTS)。
安装 CUDA
本项目所用3060显卡最高支持12.3,安装版本为11.5,推荐训练环境对应版本为11。系统环境如下:
安装参考的链接为Windows下安装CUDA并配置cuDNN教程_cuda安装_这也太南了趴的博客-CSDN博客
由于CUDA安装较为复杂且上述链接较为详尽,不再展开。本项目训练前安装了CUDA。
Conda环境配置
$ git clone --recursive https://github.com/MaximIntegratedAI/ai8x-training.git
$ git clone --recursive https://github.com/MaximIntegratedAI/ai8x-synthesis.git
基于python3.8.7
然后激活环境
python -m venv venv --prompt ai8x-training
环境安装,在Windows的conda环境下,使用:
pip3 install -r requirements-win-cu11.txt
模型训练调试
Conda训练
首先激活环境,
conda activate python38112
移动到目标位置,
cd S:\condaenv\ai8x-training-develop
查看这个位置的 S:\condaenv\ai8x-training-develop\scripts的evaluate_catsdogs.sh 文件。
内部代码为命令行执行
#!/bin/sh
python train.py --epochs 200 --optimizer Adam --lr 0.001 --wd 0 --deterministic --compress policies/schedule-catsdogs.yaml --qat-policy policies/qat_policy_cd.yaml --model ai85cdnet --dataset cats_vs_dogs --confusion --param-hist --embedding --device MAX78000 "$@"
所以为了便捷,本文直接在ai8x目录下的命令行执行以下命令:
python train.py --epochs 200 --optimizer Adam --lr 0.001 --wd 0 --deterministic --compress policies/schedule-catsdogs.yaml --qat-policy policies/qat_policy_cd.yaml --model ai85cdnet --dataset cats_vs_dogs --confusion --param-hist --embedding --device MAX78000
由于3060卡显存较低,且笔记本是16G内存,租云服务器有成本,因此本文首先扩大conda所在硬盘提供的虚拟内存解决内存低的问题,降低batch size解决显存不够问题。
经过测试,在256*256分辨率图片数据集下,只能运行batch-size 32,而压缩到128*128分辨率可以运行batch-size 32,但是运行中可能内存不够,比如硬件消耗波动,打开浏览器等瞬时消耗,会导致训练崩掉,所以选择batch-size 32。最终执行训练的命令如下:
python train.py --epochs 200 --optimizer Adam --lr 0.001 --wd 0 --deterministic --compress policies/schedule-catsdogs.yaml --qat-policy policies/qat_policy_cd.yaml --model ai85cdnet --dataset cats_vs_dogs --confusion --param-hist --embedding --device MAX78000 --batch-size 32
经过5小时训练,最终完成:
量化
首先从网上拉取量化所需文件,https://github.com/MaximIntegratedAI/ai8x-synthesis 。
仍然在conda环境中运行,前文训练过程得到的qat_best.pth.tar文件,位于S:\condaenv\ai8x-training-develop\logs\2023.11.26-171522。
激活环境
conda activate python38112
切换到安装目录
cd S:\condaenv\ai8x-synthesis-develop
配置环境
pip install -r requirements.txt
在命令行运行如下内容,以在目标路径中生成量化检查点 qat_best-q.pth.tar。
python quantize.py S:\condaenv\ai8x-training-develop\logs\2023.11.26-171522/qat_best.pth.tar S:\condaenv\ai8x-training-develop\logs\2023.11.26-171522/qat_best-q.pth.tar --device MAX78000
量化完成:
评估
切换回原训练代码的路径。
cd S:\condaenv\ai8x-training-develop
打开评估sh文件有如下代码:
python train.py --model ai85cdnet --dataset cats_vs_dogs --confusion --evaluate --exp-load-weights-from S:\condaenv\ai8x-training-develop\logs\2023.11.26-171522/qat_best-q.pth.tar -8 --device MAX78000
bug解决
在该步骤中,首先报错:
RuntimeError: Unable to find a valid cuDNN algorithm to run convolution
这是因为我们使用的Windows平台下的conda环境,而cudnn对该平台运行中pytorch调用支持得非常差,所以我们在“S:\condaenv\ai8x-training-develop\ train.py”中禁用cudnn,加入语句“torch.backends.cudnn.enabled = False”即可禁用。
然后遇到显存不足的问题,主要原因还是本文所有机器开启独显直连,且win11下启动,所以可以给torch调用的显存有限。建议如果对显存有更高需求的项目使用linux独立系统进行开发。
RuntimeError: CUDA out of memory. Tried to allocate 256.00 MiB (GPU 0; 6.00 GiB total capacity; 304.24 MiB already allocated; 4.05 GiB free; 306.00 MiB reserved in total by PyTorch)
解决内存不足,最终命令行代码如下:
python train.py --model ai85cdnet --dataset cats_vs_dogs --confusion --evaluate --exp-load-weights-from S:\condaenv\ai8x-training-develop\logs\2023.11.26-171522/qat_best-q.pth.tar -8 --device MAX78000 --batch-size 32
评估结果图
C代码创建
示例数据集创建
继续运行代码,后面添加“--save-sample”加数字,这个数字应该小于(不能等于)前文调用的batch size,生成示例数据集,与train.py目录相同,为了方便不再改名(原文件名sample_cats_vs_dogs.npy),拷贝到S:\condaenv\ai8x-synthesis-develop\tests。
python train.py --model ai85cdnet --dataset cats_vs_dogs --confusion --evaluate --exp-load-weights-from S:\condaenv\ai8x-training-develop\logs\2023.11.26-171522/qat_best-q.pth.tar -8 --device MAX78000 --batch-size 32 --save-sample 31
Yaml创建
复制 S:\condaenv\ai8x-synthesis-develop\networks\cats-dogs-hwc.yaml,使模型和数据集进行更新。
C代码生成
S:/condaenv/ai8x-synthesis-develop ai8x-synthesis/scripts/gen_catsdogs_max78000.sh
文件内容如下:
#!/bin/sh
DEVICE="MAX78000"
TARGET="sdk/Examples/$DEVICE/CNN"
COMMON_ARGS="--device $DEVICE --timer 0 --display-checkpoint --verbose"
python ai8xize.py --test-dir $TARGET --prefix cats-dogs --checkpoint-file trained/ai85-catsdogs-qat8-q.pth.tar --config-file networks/cats-dogs-hwc.yaml --fifo --softmax $COMMON_ARGS "$@"
首先在S:\condaenv\ai8x-synthesis-develop\tests文件夹内,替换sample_cats_vs_dogs.npy为之前根据已有数据集生成的示例数据集;
然后在S:\condaenv\ai8x-synthesis-develop\trained 文件夹内,替换ai85-catsdogs-qat8-q.pth.tar为本文训练的检查点文件;
在S:\condaenv\ai8x-synthesis-develop\networks文件夹内,替换cats-dogs-hwc.yaml文件。
接下来对比本轮代码生成所用文件与原文件:
conda activate python38112
cd S:\condaenv\ai8x-synthesis-develop\
最终生成代码所用的命令行
python ai8xize.py --test-dir sdk/Examples/MAX78000/CNN --prefix cats-dogs --checkpoint-file trained/ai85-catsdogs-qat8-q.pth.tar --config-file networks/cats-dogs-hwc.yaml --fifo --softmax --device MAX78000 --timer 0 --display-checkpoint --verbose
最终生成文件。
C代码修改
引入训练后文件
基于例程 cat_vs_dog 创建项目,微调部分代码。
The code uses a sampledata header (sampledata.h) file to test a pre-defined input sample.
把前文训练、量化后得到的 c++文件拷贝到新创建的项目中,前文曾经强调,为了减少报错概率,训练集等所有命名,与猫狗识别项目命名保持一致。与猫狗识别demo相比,前文生成的C代码差别主要体现在,如下文件:
cnn.c
cnn.h
sampledata.h
sampleoutput.h
softmax.c
weights.h
关闭TFT输出
由于没有购置TFT显示器,注释相关功能
* * To _disable_ the TFT display code, comment out `PROJ_CFLAGS += -DTFT_ENABLE` in [project.mk](project.mk)
```Makefile
ifeq "$(BOARD)" "EvKit_V1"
# PROJ_CFLAGS+=-DTFT_ENABLE
IPATH += TFT/evkit/
VPATH += TFT/evkit/
endif
```
VS Code编译修改
在项目——.vscode——setting.json修改以下语句,因为原来默认的不是羽毛板。
"target":"MAX78000",
"board":"FTHR_RevA",
然后先刷新,Ctrl + Shift + P,一定要重新载入窗口。
烧写与运行情况
编译
注意编译前确认,路径不能有中文。
编译,Ctrl + Shift + B,Build。程序正常运行。
烧写
Ctrl + Shift + B,然后 Flash&run
注意烧写时关闭VOFA+的连接,否则会报错,报错内容如下:
* 终端进程“C:\WINDOWS\System32\cmd.exe /d /c arm-none-eabi-gdb --cd="D:\01FileinScience\AIboard\crop_if_demo_end" --se="build/crop_if_demo_end.elf" --symbols=build/crop_if_demo_end.elf -x="D:\01FileinScience\AIboard\crop_if_demo_end/.vscode/flash.gdb" --ex="flash_m4_run D:/MaximSDK/Tools/OpenOCD cmsis-dap.cfg max78000.cfg" --batch”已终止,退出代码: 1。
正常烧写完成的界面如下:
调试运行
我们使用VOFA+ 1.3.10作为串口调试工具,波特率设置115200,其他设置8-1-N-N。
调试工具地址:https://www.vofa.plus/
调试结果:
病虫害图片识别结果:
正常叶片图片识别结果:
可以看到识别效果可以接受,具体运行细节可以观看bilibili视频。至此,本项目实现了预期目标,项目完成。感谢活动主办方给予的支持。