目录
一、cube.AI简介及cubeIDE集成
1.1 cube.AI介绍
1.2 cube.AI与cubeIDE集成与安装
1.3 cube.AI支持硬件平台
1.4 cube.AI应用的好处
二、FP-AI-SENSING1
2.1FP-AI-SENSING1简介
2.2FP-AI-SENSING1软件包支持硬件平台
三、FP-AI-SENSING1部署
3.1B-L475E-IOT01A开发板
3.2FP-AI-SENSING1软件包下载及配置
3.3 固件烧录
3.4FP-AI-SENSING1示例工程部署
四、数据采集
4.1 STBLE-Sensor软件下载安装
4.2 STBLESensor配置数据采集
五、数据治理及模型训练
5.1 从开发板取出采集记录数据文件
5.2 神经网络模型训练
六、 cube.AI将训练模型转换为c语言模型
6.1 创建cube.AI支持的STM32工程
6.2cube.AI神经网络配置
6.3 模型分析与PC端验证
6.4 c语言神经网络模型生成及源码输出
七、c语言神经网络模型使用
7.1 C语言神经网络模型源文件
7.2 串口功能自定义实现
7.3 c语言神经网络模型API使用
7.4 编译及程序运行测试
7.5 补充说明
一、cube.AI简介及cubeIDE集成
1.1 cube.AI介绍
cube.AI准确来说是STM32Cube.AI,它是ST公司的打造的STM32Cube生态体系的扩展包X-CUBE-AI,专用于帮助开发者实现人工智能开发。确切地说,是将基于各种人工智能开发框架训练出来的算法模型,统一转换为c语言支持的源码模型,然后将c模型与STM32的硬件产品结合,实现人工智能模型可直接部署在前端或边缘端设备,实现人工智能就地计算。关于cube.AI 的各种信息可以从ST官网上查看和下载其相关资料:X-CUBE-AI – STM32CubeMX的AI扩展包 – STMicroelectronics
cube.AI 以插件形式支持ST相关开发平台如cubeIDE、cubeMX、keil等,整体开发过程分为三个主要部分,1)收集及治理数据,2)训练及验证模型,3)c模型生成及前端或边缘端部署,如下图所示:
目前cube.AI支持各种深度学习框架的训练模型,如Keras和TensorFlow™ Lite,并支持可导出为ONNX标准格式的所有框架,如PyTorch™、Microsoft®Cognitive Toolkit、MATLAB®等,然后通过 cube.MX可视化配置界面导入这些深度学习框架导出的训练模型来配置及生成c模型,进而部署在STM32芯片上。
1.2 cube.AI与cubeIDE集成与安装
在cubeIDE的帮助菜单栏,选择嵌入式软件包管理项(Embedded Software Packages Manager)进入X-CUBE-AI扩展包安装页面。选择X-CUBE-AI需要的版本进行安装即可,如下图所示,安装完成后,该版本前面方框呈绿色标记。
1.3 cube.AI支持硬件平台
得益于ST公司不断的优化及迭代X-CUBE-AI扩展包,神经网络模型生成c模型后得以使用更小的算力资源和几乎无损的算法精度,因此使其能部署到STM32绝大多数的芯片上,目前其支持的MCU及MPU型号如下图所示。
1.4 cube.AI应用的好处
将神经网络边缘化部署后,减少延迟、节约能源、提高云利用率,并通过大限度地减少互联网上的数据交换来保护隐私,而结合X-CUBE-AI使得神经网络部署在边缘端端的便捷、灵活、低成本,微机智能成为更多产品的选择。
二、FP-AI-SENSING1
2.1FP-AI-SENSING1简介
FP-AI-SENSING1是ST公司提供的STM32Cube.AI示例,可通过BLE(低功耗蓝牙)将物联网节点连接到智能手机,并使用STBLESensor应用程序,配置设备,实现数据采集,使得用于训练神经网络模型的数据更贴近实际使用场景,具有更好的训练效果和精度。
FP-AI-SENSING1软件包更多介绍及信息请参考ST官网:
FP-AI-SENSING1 – 具有基于声音和运动感应的人工智能(AI)应用的超低功耗IoT节点的STM32Cube功能包 – STMicroelectronics
在FP-AI-SENSING1案例页面,下载源码包及其数据手册。
2.2FP-AI-SENSING1软件包支持硬件平台
ST公司为FP-AI-SENSING1示例运行提供了硬件平台,支持开发者快速学习了解FP-AI-SENSING1示例,从而了解Cube.AI的开发过程。
三、FP-AI-SENSING1部署
3.1B-L475E-IOT01A开发板
本文采用ST公司的B-L475E-IOT01A开发板,打开CubeMX工具,选择Start my project from ST Board,搜索B-L475E-IOT01A,如下图所示,可以在1、2、3页面下载开发板相关的原理框图、文档及案例、说明手册。
3.2FP-AI-SENSING1软件包下载及配置
下载FP-AI-SENSING1软件包后,解压下载的源码包:en.fp-ai-sensing1.zip,进入“STM32CubeFunctionPack_SENSING1_V4.0.3\Projects\B-L475E-IOT01A\Applications\SENSING1\STM32CubeIDE”目录,用文本编辑工具打开“CleanSENSING1.bat”,(linux系统的,采用CleanSENSING1.sh文件)。
CleanSENSING1.bat运行依赖STM32cube生态的另一个开发工具:STM32CubeProgrammer,该工具可以帮助开发者读取、写入和验证设备内存等。
STM32CubeProg – 用于STM32产品编程的STM32CubeProgrammer软件 – STMicroelectronics
在STM32CubeProgrammer工具下载页面,下载该工具及说明手册:
下载并安装STM32CubeProgrammer工具,例如本文安装目录为:D:\workForSoftware\STM32CubeProgrammer
修改CleanSENSING1.bat依赖工具“STM32CubeProgrammer”的路径:
3.3 固件烧录
将B-L475E-IOT01A开发板用Micro USB连接到电脑上,
连接之后,驱动会自动安装,进入设备管理页面,确认串口编号和配置串口参数。
右键CleanSENSING1.bat文件以管理员身份运行,将在开发板安装引导加载程序和更新固件。
该脚本可以对B-L475E-IOT01A开发板实现以下操作,
•完全闪存擦除
•在右侧闪存区域加载BootLoader
•在右侧闪存区域加载程序(编译后)
•重置电路板
3.4FP-AI-SENSING1示例工程部署
在该目录下,进入“B-L475E-IOT01A”目录,用CubeIDE打开.project,打开FP-AI-SENSING1工程。
打开该工程后如下图所示,用户可调整源码在User目录,关于本工程信息请查看readme.txt文件。
在main.c函数中找到Init_BlueNRG_Stack函数,该函数可以设置BLE(低功耗蓝牙)的服务名,
static void Init_BlueNRG_Stack(void){char BoardName[8];uint16_t service_handle, dev_name_char_handle, appearance_char_handle;int ret;for(int i=0; i<7; i++) {BoardName[i]= NodeName[i+1];}
该函数采用默认的BLE名称,该默认名称定义在SENSING1.h设置,例如:IAI_403
现在调整BLE名称为AI_Test
static void Init_BlueNRG_Stack(void){//char BoardName[8];char BoardName[8] = {'A','I','_','T','e','s','t'};uint16_t service_handle, dev_name_char_handle, appearance_char_handle;int ret;for(int i=0; i<7; i++) {//BoardName[i]= NodeName[i+1];NodeName[i+1] = BoardName[i];}
配置工程输出格式支持如下:
配置运行设置如下:
然后编译及下载程序:
打开串口工具,连接上对于串口,点击开发板上的重置按钮(黑色按钮),串口日志输出如下,日志显示BLE模块启动成功:
四、数据采集
4.1 STBLE-Sensor软件下载安装
确保手机支持低功耗蓝牙通信,进入ST的BLE传感器应用下载页面,
STBLESensor – 用于安卓和iOS的BLE传感器应用 – STMicroelectronics
下载对应的手机应用程序:
4.2 STBLESensor配置数据采集
本文用的是华为手机及android系统,安装完成APP后启动进入界面(当前版本是4.14),点击搜索,得到AI_Test蓝牙服务名。
选择AI_Test蓝牙服务后,进入页面,(android)在左上角菜单下拉菜单选择,Data Log(sensing1),进入数据采集页面,选择Accelerometer(三轴加速度计),并设置参数为1.0Hz、26Hz、1.0X。
在数据记录操作页面,先新建标签,例如Jogging(慢跑),Walking(走了),Stationary(静立)等等。
1)开启数据采集记录时:先打开标签,再点击START LOGGING按钮开启
2)关闭数据采集记录时,先点击START LOGGING按钮关闭,再关闭标签。
例如,本文按上述操作记录了Walking、Jogging两次数据记录,将生成两个.csv文件。
五、数据治理及模型训练
5.1 从开发板取出采集记录数据文件
断掉开发板与电脑的USB连接,在开发板背面将在1-2跳线帽拔掉,插入5-6跳线,然后USB连接从ST-LINK连接转到USB-OTG接口接线,如下图(1->2)。
开发板重新上电后,保持按下user按钮(蓝色),同时按下reset按钮(黑色),然后先松开reset按钮,在松开user按钮,激活USB-OTG。
USB-OTG激活后,开发板将作为一个U盘显示在电脑上,里面有刚才数据采集保存的CSV文件。
在“STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR”目录创建一个文件目录Log_data,将该文件拷贝到该目录下:
该CSV记录数据格式如下,时间、行为、三个传感数值:
5.2 神经网络模型训练
“Training Scripts\HAR”是官方提供的一个人类行为姿态识别训练项目,默认是采用,采用Keras前端+tensorflow后端实现。先安装tensorflow、Keras等支持。
本文安装如下:
#已安装python3.6pip3 install tensorflow==1.14 -i https://pypi.tuna.tsinghua.edu.cn/simpleERROR: tensorboard 1.14.0 has requirement setuptools>=41.0.0, but you'll have setuptools 28.8.0 which is incompatible.python3 -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simplepip3 install keras==2.2.4 -i https://pypi.tuna.tsinghua.edu.cn/simple
根据HAR 项目的readme.txt通过pip install -r requirements.txt命令安装requirements.txt文件制定的相关模块,但本文是采用常用命令逐个安装各个模块的“pip3 install 模块名==版本 -i 源”
numpy==1.16.4argparseosloggingwarningsdatetimepandas==0.25.1scipy==1.3.1matplotlib==3.1.1mpl_toolkitssklearn-learn==0.21.3keras==2.2.4tensorflow==1.14.0tqdm==4.36.1keras-tqdm==2.0.1
完成安装后,进入datasets目录,打开ReplaceWithWISDMDataset.txt文件,根据其提供的网址去下载
下载WISDM实验室的数据集支持。
下载文件如下,将这些文件拷贝到datasets目录下覆盖。
打开RunMe.py文件,可以看到关于各个运行参数的设置:
运行python3 .\RunMe.py -h命令,查看运行参数含义,其中:–dataset使用的是前面下载的WISDM实验室的数据集来训练模型,而–dataDir是指定采用自行采集的数据集训练模型:
PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR> python3 .\RunMe.py -hUsing TensorFlow backend.usage: RunMe.py [-h] [--model MODEL] [--dataset DATASET] [--dataDir DATADIR][--seqLength SEQLENGTH] [--stepSize STEPSIZE] [-m MERGE][--preprocessing PREPROCESSING] [--trainSplit TRAINSPLIT][--validSplit VALIDSPLIT] [--epochs N] [--lr LR][--decay DECAY] [--batchSize N] [--verbose N][--nrSamplesPostValid NRSAMPLESPOSTVALID]Human Activity Recognition (HAR) in Keras with Tensorflow as backend on WISDMand WISDM + self logged datasetsoptional arguments:-h, --helpshow this help message and exit--model MODEL choose one of the two availavle choices, IGN or GMP, (default = IGN )--dataset DATASET choose a dataset to use out of two choices, WISDM orAST, ( default = WISDM )--dataDir DATADIR path to new data collected using STM32 IoT boardrecorded at 26Hz as sampling rate, (default = )--seqLength SEQLENGTHinput sequence lenght (default:24)--stepSize STEPSIZE step size while creating segments (default:24, equalto seqLen)-m MERGE, --merge MERGEif to merge activities (default: True)--preprocessing PREPROCESSINGgravity rotation filter application (default = True)--trainSplit TRAINSPLITtrain and test split (default = 0.6 (60 precent fortrain and 40 precent for test))--validSplit VALIDSPLITtrain and validation data split (default = 0.7 (70percent for train and 30 precent for validation))--epochs Nnumber of total epochs to run (default: 20)--lr LR initial learning rate--decay DECAY decay in learning rate, (default = 1e-6)--batchSize N mini-batch size (default: 64)--verbose N verbosity of training and test functions in keras, 0,1, or 2. Verbosity mode. 0 = silent, 1 = progress bar,2 = one line per epoch (default: 1)--nrSamplesPostValid NRSAMPLESPOSTVALIDNumber of samples to save from every class for posttraining and CubeAI conversion validation. (default =2)PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR>
在RunMe.py文件后面加入下面语句:
#保存Cube.AI支持的数据集格式,用于后续验证测试使用testx_f=resultDirName+"testx.npy"testy_f=resultDirName+"testy.npy"np.save(testx_f,TestX)np.save(testy_f,TestY)
打开命令工具,输入命令python3 .\RunMe.py –dataDir=Log_data ,可以根据实际需要进行参数设置,本文先采用默认参数训练模型,输出日志如下,这显然是一个分类问题,分类为Jogging 、Stationary 、Stairs 、Walking,有卷积层、池化层、2全连接层、压平层、Dropout层等。
PS D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR> python3 .\RunMe.py --dataDir=Log_dataUsing TensorFlow backend.Running HAR on WISDM dataset, with following variablesmerge = TruemodelName = IGN,segmentLength = 24stepSize = 24preprocessing = TruetrainTestSplit = 0.6trainValidationSplit = 0.7nEpochs = 20learningRate = 0.0005decay =1e-06batchSize = 64verbosity = 1dataDir = Log_datanrSamplesPostValid = 2Segmenting Train dataSegments built : 100%|███████████████████████████████████████████████████| 27456/27456 [00:28<00:00, 953.24 segments/s]Segmenting Test dataSegments built : 100%|██████████████████████████████████████████████████| 18304/18304 [00:14<00:00, 1282.96 segments/s]Segmentation finished!preparing data file from all the files in directoryLog_dataparsing data fromIoT01-MemsAnn_11_Jan_23_16h_57m_17s.csvparsing data fromIoT01-MemsAnn_11_Jan_23_16h_57m_53s.csvSegmenting the AI logged Train dataSegments built : 100%|████████████████████████████████████████████████████████| 25/25 [00:00<00:00, 3133.35 segments/s]Segmenting the AI logged Test dataSegments built : 100%|████████████████████████████████████████████████████████| 17/17 [00:00
训练模型及相关输出信息在results目录下,每次训练输出依据时间生成一个独立目录,由于是keras训练模型,因此输出训练模型是一个名为*.h5格式文件,例如har_IGN.h5:
六、 cube.AI将训练模型转换为c语言模型
6.1 创建cube.AI支持的STM32工程
在CubeIDE中新建一个STM32项目,在cubeMX中选择以开发板形式创建
创建一个B-L475E-IOT01A_cube.ai工程名的STM32工程,如下图。
完成创建后,双击.ioc文件打开cube.MX配置界面。
6.2cube.AI神经网络配置
选择X-CUBE-AI包支持,回到主页面后,会多出software Packs栏及多出STMicroelectronics .X-CUBE-AI选项,进入该页面,勾选下图标识的2、3 项,在5中选择采用哪个串口支持程序及调试。
知识点,在X-CUBE-AI配置选项页面,停靠时,会出现说明框,快捷键“CTRL+D”会进一步出现X-CUBE-AI相关文档,
有详细的文档资料:
或者也可以从cube.AI安装目录直接进入,例如:D:\workForSoftware\STM32CubeMX\Repository\Packs\STMicroelectronics\X-CUBE-AI\7.3.0\Documentation
另外,需要注意,开启X-CUBE-AI支持后,其依赖CRC功能,会自动开启CRC。
6.3 模型分析与PC端验证
添加(add network)神经网络如下,在3中可以修改神经网络模型名称,在4中选择支持框架及选择模型文件,例如“STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\Training Scripts\HAR\results\2023_Jan_24_14_40_13\har_IGN.h5”,在5、6中,可以选择随机数据进行模型研制,也可以选择生成的研制数据进行验证(前面训练模型时,在RunMe.py文件后面加入语句,输出testx.npy、testy.npy文件):
可以点击设置按钮进入,在该页面下可以对神经网络进行更多设置和更详细信息查看,主要是以模型优化为主,本文先保持默认。
点击分析按钮(Analyze),输出该模型相关信息及部署模型需要的计算资源(ram、flash等):
Analyzingmodel D:/workForSoftware/STM32CubeMX/Repository/Packs/STMicroelectronics/X-CUBE-AI/7.3.0/Utilities/windows/stm32aianalyze--namehar_ign-mD:/tools/arm_tool/STM32CubeIDE/STM32CubeFunctionPack_SENSING1_V4.0.3/Utilities/AI_Ressources/TrainingScripts/HAR/results/2023_Jan_11_17_50_03/har_IGN.h5--typekeras--compressionnone--verbosity1--workspaceC:\Users\py_hp\AppData\Local\Temp\mxAI_workspace465785871649500151581099545474794--outputC:\Users\py_hp\.stm32cubemx\network_output--allocate-inputs--allocate-outputs NeuralNetworkToolsforSTM32AIv1.6.0(STM.aiv7.3.0-RC5)Exec/reportsummary(analyze) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- modelfile:D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\TrainingScripts\HAR\results\2023_Jan_11_17_50_03\har_IGN.h5 type:keras c_name:har_ign compression:none options:allocate-inputs,allocate-outputs optimization:balanced target/series:generic workspacedir:C:\Users\py_hp\AppData\Local\Temp\mxAI_workspace465785871649500151581099545474794 outputdir:C:\Users\py_hp\.stm32cubemx\network_output model_fmt:float model_name:har_IGN model_hash:ff0080dbe395a3d8fd3f63243d2326d5 params#:3,064items(11.97KiB) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- input1/1:'input_0'(domain:activations/**default**) :72items,288B,ai_float,float,(1,24,3,1) output1/1:'dense_2'(domain:activations/**default**) :4items,16B,ai_float,float,(1,1,1,4) macc:14,404 weights(ro):12,256B(11.97KiB)(1segment) activations(rw):2,016B(1.97KiB)(1segment)* ram(total):2,016B(1.97KiB)=2,016+0+0 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- (*)'input'/'output'bufferscanbeusedfromtheactivationsbufferModelname-har_IGN['input_0']['dense_2'] ------------------------------------------------------------------------------------------------------ idlayer(original)oshapeparam/sizemaccconnectedto ------------------------------------------------------------------------------------------------------ 0input_0(None)[b:None,h:24,w:3,c:1] conv2d_1_conv2d(Conv2D)[b:None,h:9,w:3,c:24]408/1,63210,392input_0 conv2d_1(Conv2D)[b:None,h:9,w:3,c:24]648conv2d_1_conv2d ------------------------------------------------------------------------------------------------------ 1max_pooling2d_1(MaxPooling2D)[b:None,h:3,w:3,c:24]648conv2d_1 ------------------------------------------------------------------------------------------------------ 2flatten_1(Flatten)[b:None,c:216]max_pooling2d_1 ------------------------------------------------------------------------------------------------------ 3dense_1_dense(Dense)[b:None,c:12]2,604/10,4162,604flatten_1 ------------------------------------------------------------------------------------------------------ 5dense_2_dense(Dense)[b:None,c:4]52/20852dense_1_dense dense_2(Dense)[b:None,c:4]60dense_2_dense ------------------------------------------------------------------------------------------------------ model/c-model:macc=14,404/14,404weights=12,256/12,256activations=--/2,016io=--/0Numberofoperationsperc-layer ----------------------------------------------------------------------------------- c_idm_idname(type)#op(type) ----------------------------------------------------------------------------------- 01conv2d_1_conv2d(optimized_conv2d)11,688(smul_f32_f32) 13dense_1_dense(dense)2,604(smul_f32_f32) 25dense_2_dense(dense)52(smul_f32_f32) 35dense_2(nl)60(op_f32_f32) ----------------------------------------------------------------------------------- total14,404Numberofoperationtypes --------------------------------------------- smul_f32_f3214,34499.6% op_f32_f32600.4%Complexityreport(model) ------------------------------------------------------------------------------------ m_idnamec_maccc_romc_id ------------------------------------------------------------------------------------ 1max_pooling2d_1||||||||||||||||81.1%|||13.3%[0] 3dense_1_dense||||18.1%||||||||||||||||85.0%[1] 5dense_2_dense|0.8%|1.7%[2,3] ------------------------------------------------------------------------------------ macc=14,404weights=12,256act=2,016ram_io=0 CreatingtxtreportfileC:\Users\py_hp\.stm32cubemx\network_output\har_ign_analyze_report.txt elapsedtime(analyze):7.692s GettingFlashandRamsizeusedbythelibrary Modelfile:har_IGN.h5 TotalFlash:29880B(29.18KiB) Weights:12256B(11.97KiB) Library:17624B(17.21KiB) TotalRam:4000B(3.91KiB) Activations:2016B(1.97KiB) Library:1984B(1.94KiB) Input:288B(includedinActivations) Output:16B(includedinActivations) Done Analyze complete on AI model
点击PC桌面验证按钮(validation on desktop),对训练模型进行验证,主要是验证原始模型和转为c语言支持的模型时,验证前后计算资源、模型精度等差异情况,验证数据就是我们刚指定的testx.npy、testy.npy文件。
StartingAIvalidationondesktopwithcustomdataset:D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\TrainingScripts\HAR\results\2023_Jan_24_14_40_13\testx.npy... D:/workForSoftware/STM32CubeMX/Repository/Packs/STMicroelectronics/X-CUBE-AI/7.3.0/Utilities/windows/stm32aivalidate--namehar_ign-mD:/tools/arm_tool/STM32CubeIDE/STM32CubeFunctionPack_SENSING1_V4.0.3/Utilities/AI_Ressources/TrainingScripts/HAR/results/2023_Jan_11_17_50_03/har_IGN.h5--typekeras--compressionnone--verbosity1--workspaceC:\Users\py_hp\AppData\Local\Temp\mxAI_workspace46601041973700012072836595678733048--outputC:\Users\py_hp\.stm32cubemx\network_output--allocate-inputs--allocate-outputs--valoutputD:/tools/arm_tool/STM32CubeIDE/STM32CubeFunctionPack_SENSING1_V4.0.3/Utilities/AI_Ressources/TrainingScripts/HAR/results/2023_Jan_24_14_40_13/testy.npy--valinputD:/tools/arm_tool/STM32CubeIDE/STM32CubeFunctionPack_SENSING1_V4.0.3/Utilities/AI_Ressources/TrainingScripts/HAR/results/2023_Jan_24_14_40_13/testx.npy NeuralNetworkToolsforSTM32AIv1.6.0(STM.aiv7.3.0-RC5) CopyingtheAIruntimefilestotheuserworkspace:C:\Users\py_hp\AppData\Local\Temp\mxAI_workspace46601041973700012072836595678733048\inspector_har_ign\workspaceExec/reportsummary(validate) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- modelfile:D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\TrainingScripts\HAR\results\2023_Jan_11_17_50_03\har_IGN.h5 type:keras c_name:har_ign compression:none options:allocate-inputs,allocate-outputs optimization:balanced target/series:generic workspacedir:C:\Users\py_hp\AppData\Local\Temp\mxAI_workspace46601041973700012072836595678733048 outputdir:C:\Users\py_hp\.stm32cubemx\network_output vinputfiles:D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\TrainingScripts\HAR\results\2023_Jan_24_14_40_13\testx.npy voutputfiles:D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\TrainingScripts\HAR\results\2023_Jan_24_14_40_13\testy.npy model_fmt:float model_name:har_IGN model_hash:ff0080dbe395a3d8fd3f63243d2326d5 params#:3,064items(11.97KiB) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- input1/1:'input_0'(domain:activations/**default**) :72items,288B,ai_float,float,(1,24,3,1) output1/1:'dense_2'(domain:activations/**default**) :4items,16B,ai_float,float,(1,1,1,4) macc:14,404 weights(ro):12,256B(11.97KiB)(1segment) activations(rw):2,016B(1.97KiB)(1segment)* ram(total):2,016B(1.97KiB)=2,016+0+0 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- (*)'input'/'output'bufferscanbeusedfromtheactivationsbuffer Settingvalidationdata... loadingfile:D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\TrainingScripts\HAR\results\2023_Jan_24_14_40_13\testx.npy -samplesarereshaped:(12806,24,3,1)->(12806,24,3,1) loadingfile:D:\tools\arm_tool\STM32CubeIDE\STM32CubeFunctionPack_SENSING1_V4.0.3\Utilities\AI_Ressources\TrainingScripts\HAR\results\2023_Jan_24_14_40_13\testy.npy -samplesarereshaped:(12806,4)->(12806,1,1,4) I[1]:(12806,24,3,1)/float32,min/max=[-26.319,32.844],mean/std=[0.075,5.034],input_0 O[1]:(12806,1,1,4)/float32,min/max=[0.000,1.000],mean/std=[0.250,0.433],dense_2 RunningtheSTMAIc-model(AIRUNNER)...(name=har_ign,mode=x86) X86sharedlib(C:\Users\py_hp\AppData\Local\Temp\mxAI_workspace46601041973700012072836595678733048\inspector_har_ign\workspace\lib\libai_har_ign.dll)['har_ign'] Summary"har_ign"-['har_ign'] -------------------------------------------------------------------------------- inputs/outputs:1/1 input_1:(1,24,3,1),float32,288bytes,inactivationsbuffer output_1:(1,1,1,4),float32,16bytes,inactivationsbuffer n_nodes:4 compile_datetime:Jan25202322:55:51(WedJan2522:55:472023) activations:2016 weights:12256 macc:14404 -------------------------------------------------------------------------------- runtime:STM.AI7.3.0(Tools7.3.0) capabilities:['IO_ONLY','PER_LAYER','PER_LAYER_WITH_DATA'] device:AMD64Intel64Family6Model158Stepping9,GenuineIntel(Windows) -------------------------------------------------------------------------------- STM.IO:0%||0/12806[00:006.4 c语言神经网络模型生成及源码输出 将开发板重新选择ST-LINK连接(5-6跳线帽拔出,插入1-2跳线中)
为了后续源码讲解方便,只生产c语言的神经网络模型源码,不输出应用示例程序(有个弊端就是在新建程序加载到开发板后,validation on target功能无法使用),如下图所示。
配置输出工程
七、c语言神经网络模型使用
7.1 C语言神经网络模型源文件
在cubeMX配置神经网络模型时,指明了名称是har_ign,会生成如下文件har_ign.h/c、har_ign_data.h/c、har_ign_data_params.h/c、har_ign_config.h这些源码文件就是转换后的c语言神经网络模型,提供了一系列的API,这些API通过调用cube.AI软件包的内置功能,工程实现了神经网络计算功能:
其中har_ign_generate_report.txt文件是生成c语言神经网络模型的过程记录。
7.2 串口功能自定义实现
由于本文没有选择生成配套的应用程序代码,因此串口功能还需要自己实现,因此我移植了串口功能代码,在工程目录下,创建了ICore源目录,并创建print、usart子目录,分别在两个子目录加入print.h/c和usart.h/c源码。
print.h如下:
#ifndef INC_RETARGET_H_#define INC_RETARGET_H_#include "stm32l4xx_hal.h"#include "stdio.h"//用于printf函数串口重映射#include void ResetPrintInit(UART_HandleTypeDef*huart);int _isatty(int fd);int _write(int fd, char* ptr, int len);int _close(int fd);int _lseek(int fd, int ptr, int dir);int _read(int fd, char* ptr, int len);int _fstat(int fd, struct stat* st);#endif /* INC_RETARGET_H_ */
print.c如下:
#include #include #include #include #include #include #include #include #include #include "print.h"#if !defined(OS_USE_SEMIHOSTING)#define STDIN_FILENO0#define STDOUT_FILENO 1#define STDERR_FILENO 2UART_HandleTypeDef *gHuart;void ResetPrintInit(UART_HandleTypeDef *huart){gHuart = huart;/* Disable I/O buffering for STDOUTstream, so that * chars are sent out as soon as they areprinted. */setvbuf(stdout, NULL, _IONBF, 0);}int _isatty(int fd) {if (fd >= STDIN_FILENO && fd = STDIN_FILENO && fd = STDIN_FILENO && fd st_mode = S_IFCHR;return 0;}errno = EBADF;return 0;}#endif //#if !defined(OS_USE_SEMIHOSTING)
usart.h
#ifndef INC_USART_H_#define INC_USART_H_#include "stm32l4xx_hal.h" //HAL库文件声明#include //用于字符串处理的库#include "../print/print.h"//用于printf函数串口重映射extern UART_HandleTypeDef huart1;//声明LPUSART的HAL库结构体#define USART_REC_LEN256//定义LPUSART最大接收字节数extern uint8_tUSART_RX_BUF[USART_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符extern uint16_t USART_RX_STA;//接收状态标记extern uint8_t USART_NewData;//当前串口中断接收的1个字节数据的缓存voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart);//串口中断回调函数声明#endif /* INC_USART_H_ */
usart.c如下:
#include "usart.h"uint8_tUSART_RX_BUF[USART_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符/* * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000; * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000; * bit13:预留 * bit12:预留 * bit11~0:接收到的有效字节数目(0~4095) */uint16_t USART_RX_STA=0;接收状态标记//bit15:接收完成标志,bit14:接收到回车(0x0d),bit13~0:接收到的有效字节数目uint8_t USART_NewData;//当前串口中断接收的1个字节数据的缓存voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart)//串口中断回调函数{if(huart ==&huart1)//判断中断来源(串口1:USB转串口){if(USART_NewData==0x0d){//回车标记 USART_RX_STA|=0x8000;//标记接到回车}else{if((USART_RX_STA&0X0FFF)<USART_REC_LEN){USART_RX_BUF[USART_RX_STA&0X0FFF]=USART_NewData; //将收到的数据放入数组USART_RX_STA++;//数据长度计数加1}else{USART_RX_STA|=0x4000;//数据超出缓存长度,标记溢出}} HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART_NewData,1); //再开启接收中断}}
7.3 c语言神经网络模型API使用
先不管底层机理,本文给下面代码,看看如何实现这些API调用的,在main.c文件中,通过aiInit函数,实现har_ign模型初始化,并打印模型相关信息。在主函数循环体中,通过串口输入信息,获得数据生成因子,调用acquire_and_process_data进行输入数据生成,然后调用aiRun,并传入生成数据及输出缓存,进行神经网络模型调用。然后调用post_process打印输出信息。
/* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include "main.h"#include "crc.h"#include "dfsdm.h"#include "i2c.h"#include "quadspi.h"#include "spi.h"#include "usart.h"#include "usb_otg.h"#include "gpio.h"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes */#include "../../ICore/print/print.h"#include "../../ICore/usart/usart.h"#include "../../X-CUBE-AI/app/har_ign.h"#include "../../X-CUBE-AI/app/har_ign_data.h"/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *//* Global handle to reference the instantiated C-model */static ai_handle network = AI_HANDLE_NULL;/* Global c-array to handle the activations buffer */AI_ALIGNED(32)static ai_u8 activations[AI_HAR_IGN_DATA_ACTIVATIONS_SIZE];/* Array to store the data of the input tensor */AI_ALIGNED(32)static ai_float in_data[AI_HAR_IGN_IN_1_SIZE];/* or static ai_u8 in_data[AI_HAR_IGN_IN_1_SIZE_BYTES]; *//* c-array to store the data of the output tensor */AI_ALIGNED(32)static ai_float out_data[AI_HAR_IGN_OUT_1_SIZE];/* static ai_u8 out_data[AI_HAR_IGN_OUT_1_SIZE_BYTES]; *//* Array of pointer to manage the model's input/output tensors */static ai_buffer *ai_input;static ai_buffer *ai_output;static ai_buffer_format fmt_input;static ai_buffer_format fmt_output;void buf_print(void){printf("in_data:");for (int i=0; idata)printf(" @0x%X/%d \n",(int)buffer->data,(int)AI_BUFFER_BYTE_SIZE(AI_BUFFER_SIZE(buffer), fmt));elseprintf(" (User Domain)/%d \n",(int)AI_BUFFER_BYTE_SIZE(AI_BUFFER_SIZE(buffer), fmt));}void aiPrintNetworkInfo(const ai_network_report report){printf("Model name: %s\n", report.model_name);printf(" model signature : %s\n", report.model_signature);printf(" model datetime : %s\r\n", report.model_datetime);printf(" compile datetime : %s\r\n", report.compile_datetime);printf(" runtime version: %d.%d.%d\r\n",report.runtime_version.major,report.runtime_version.minor,report.runtime_version.micro);if (report.tool_revision[0])printf(" Tool revision: %s\r\n", (report.tool_revision[0])?report.tool_revision:"");printf(" tools version: %d.%d.%d\r\n",report.tool_version.major,report.tool_version.minor,report.tool_version.micro);printf(" complexity : %lu MACC\r\n", (unsigned long)report.n_macc);printf(" c-nodes: %d\r\n", (int)report.n_nodes);printf(" map_activations: %d\r\n", report.map_activations.size);for (int idx=0; idx<report.map_activations.size;idx++) {const ai_buffer *buffer = &report.map_activations.buffer[idx];printf("[%d] ", idx);aiPrintBufInfo(buffer);printf("\r\n");}printf(" map_weights: %d\r\n", report.map_weights.size);for (int idx=0; idx<report.map_weights.size;idx++) {const ai_buffer *buffer = &report.map_weights.buffer[idx];printf("[%d] ", idx);aiPrintBufInfo(buffer);printf("\r\n");}}/* * Bootstrap */int aiInit(void) {ai_error err;/* Create and initialize the c-model */const ai_handle acts[] = { activations };err = ai_har_ign_create_and_init(&network, acts, NULL);if (err.type != AI_ERROR_NONE) {printf("ai_error_type:%d,ai_error_code:%d\r\n",err.type,err.code);};ai_network_report report;if (ai_har_ign_get_report(network, &report) != true) {printf("ai get report error\n");return -1;}aiPrintNetworkInfo(report);/* Reteive pointers to the model's input/output tensors */ai_input = ai_har_ign_inputs_get(network, NULL);ai_output = ai_har_ign_outputs_get(network, NULL);//fmt_input = AI_BUFFER_FORMAT(ai_input);fmt_output = AI_BUFFER_FORMAT(ai_output);printf(" n_inputs/n_outputs : %u/%u\r\n", report.n_inputs,report.n_outputs);printf("input :");aiPrintBufInfo(ai_input);aiPrintDataType(fmt_input);aiPrintDataInfo(ai_input, fmt_input);//printf("output :");aiPrintBufInfo(ai_output);aiPrintDataType(fmt_output);aiPrintDataInfo(ai_output, fmt_output);return 0;}int acquire_and_process_data(void *in_data,int factor){printf("in_data:");for (int i=0; i
7.4 编译及程序运行测试
配置工程输出文件格式支持,并设置运行配置:
编译及下载程序:
打开串口助手,查看日志输出,发送信息,例如test7,即7作为因子生成输入数据,然后看输出结果。
7.5 补充说明
目前只能说是采用cubeIDE+cube.AI+keras的STM32嵌入式人工智能开发走通了流程,但是串口反馈回来的日志信息是不合理的,因为在数据采集时我们只采集了传感器的三个数值,但在训练模型时,默认的数据输入量是24,显然是不合理的,因此需要还需要重新分析官方提供的HAR训练模型的项目,使得模型训练与采集数据匹配起来,请阅读篇二。
但考虑到官方提供的HAR训练模型的工程项目还是过于复杂,不助于学习和了解cube.AI的真正用法,因此后面将抛弃官方提供的HAR训练模型的项目,自行撰写一个训练模型项目+实际采集数据生成神经网络模型,是的数据输入和输出匹配,并将采用传感器实时采集到的数据进行计算评估,请阅读偏三。