STM32CubeMX AI尝尝鲜
我是在学习Tensorflow 2.0的时候,当然,最终还是为了跑在嵌入式设备上,因为这次疫情影响,在离住的地方比较近的办公场所办公,手头上只有一块STM32F407ZG的开发板,没错,是某点某子的开发板,想着要不在这板子上跑跑,刚好之前看到了Cube-AI,所以就进行了一波尝试。
同时感谢这个视频,可以算是个新手入门指南视频,就是画质***->新手入门视频
X-Cube-AI介绍
X-CUBE-AI是STM32Cube.AI生态系统的STM32Cube扩展软件包的一部分,通过自动转换预训练的神经网络并将生成的优化库集成到用户的项目中,扩展了STM32CubeMX功能。
官方链接在这里,从来没听说的朋友们可以先去预览一波啊:ST X-Cube-AI
我就来浓缩一下,简而言之就是通过X-Cube-AI扩展将当前比较热门的AI框架进行C代码的转化,以支持在嵌入式设备上使用,目前使用X-Cube-AI需要在STM32CubeMX版本5.0以上,STM8CubeMX没注意看,目前支持转化的模型有Keras、TF lite、ONNX、Lasagne、Caffe、ConvNetJS,还算比较牛*的,Cube-AI把模型转化为一堆数组,而后将这些数组内容解析成模型,和Tensorflow里的模型转数组后使用原理是一样的。
&&开发前提
- 假设大家使用过STM32CubeMX,当然没学过的可以取微雪课堂看看,记得刚开始我也是从微雪入门,现在已经是白雪皑皑了啊,不过注意,当时我看的微雪课堂的教程是5.0以前版本,会有些许不同,不过百度大部分能解决的;
- 假设大家能够安装X-Cube-AI扩展。
- Python版本3.7;
- Tensorflow 2.0;
- 支持Tensorflow2.0的各种插件
创建模型
在PC上建立模型,我的模型是建立一个能源等级检测输出,输入电压,输出对应等级,我模型做成了分类,热乎乎热代码来啦:
'''
电源等级检测测试
训练模型阈值
一级 -> v>=8.0
二级 -> 7.8<=v<8.0
三级 -> v<7.8
输入层 -> 隐藏层 -> 输出层
'''
'''
电源等级检测测试
训练模型阈值
一级 -> v>=8.0
二级 -> 7.8<=v<8.0
三级 -> v<7.8
输入层 -> 隐藏层 -> 输出层
'''
#导入工具包
import tensorflow as tf
import pandas as pd
import numpy as np
#读取数据
data = pd.read_csv('data/voltage.csv', sep=',', header=None)
voltage = data.iloc[:,0]
level = data.iloc[:,1:]
level.astype(int)
#建立模型
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(units=20, activation='relu', input_shape=(1,)))
model.add(tf.keras.layers.Dense(units=10, activation='relu'))
model.add(tf.keras.layers.Dense(units=3, activation='softmax'))
model.summary()
model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
loss=tf.keras.losses.categorical_crossentropy,
metrics=[tf.keras.metrics.mse])
history = model.fit(x=voltage, y=level, epochs=40000)
print(model.evaluate(voltage, level))
#保存模型
model.save('level_check.h5')
然后再来个PC上对模型的载入与测试,并且将模型转换为TF lite格式(ps:如果直接使用.h5文件也是可以的,在CubeMX里输入模型类别选Keras),代码如下:
'''
电源等级检测测试
训练模型阈值
一级 -> v>=8.0
二级 -> 7.8<=v<8.0
三级 -> v<7.8
'''
#导入工具包
import tensorflow as tf
import numpy as np
import time
import datetime
#输出函数 输出更加直观
def level_output(level=np.zeros(3)):
for i in range(level.shape[1]):
if level[0,i] == 1.0:
return i+1
#测试电压
test_v = 7.78
t1 = time.time()
#导入模型计算
load_model = tf.keras.models.load_model('level_check.h5')
out = load_model.predict([test_v])
print(out)
cal_level = np.around(out).astype(int)
t2 = time.time()
#输出能源等级
level = level_output(cal_level)
print(level)
print((int(t2*1000)-int(t1*1000)))
#转换模型为tf lite格式 不量化
converter = tf.lite.TFLiteConverter.from_keras_model(load_model)
tflite_model = converter.convert()
#保存到磁盘
open("level_check.tflite", "wb").write(tflite_model)
训练数据不能漏呀,训练加后期测试使用哦,新建txt,然后另存为CSV就可以啦:
7.61,0,0,1
7.62,0,0,1
7.63,0,0,1
7.64,0,0,1
7.65,0,0,1
7.66,0,0,1
7.75,0,0,1
7.78,0,0,1
7.71,0,0,1
7.72,0,0,1
7.8,0,1,0
7.83,0,1,0
7.92,0,1,0
7.85,0,1,0
7.81,0,1,0
7.81,0,1,0
7.84,0,1,0
7.89,0,1,0
7.98,0,1,0
7.88,0,1,0
8.02,1,0,0
8.12,1,0,0
8.05,1,0,0
8.15,1,0,0
8.11,1,0,0
8.01,1,0,0
8.22,1,0,0
8.12,1,0,0
8.14,1,0,0
8.07,1,0,0
创建工程
大家可以先跟着官方网站的使用特定模型的进行学习创建工程,当然也可以直接看我的这个步骤哦。
- 新建项目,然后导入我们的模型计算,点击Analyze,CubeMX会提示我们哪些MCU型号能支持我们使用,当然啦,你也可以直接选STM32F407ZGTX,模型很小,所以绝对支持的啦;
- 添加模型,解析后就可以进行桌面级的测试了,默认输入时随机数,输出无,所以没法做比对,大家可以自己做一下数据集哦,就把训练数据拆分为输入和输出两个.csv就可以了 ;
- 启用外部时钟与USART;
- 设置下代码输出位置与格式;
- 生成代码;
修改工程
- 经过上面繁琐的步骤,这样TFlite在STM32F407上的工程代码就生成好啦,下面来对咱们的程序进行修改,初始化串口,重构控制台输出,方便使用printf打印输出;
- 新增代码,以使用模型;
输出结果
是不是非常的简单啊,不过比较难受的是,支持神经网络的底层代码是一个库文件,但是不影响我们使用,突发奇想,查看了代码,并没有启用STM32的专用的CRC校验,那么,是不是只要ROM和RAM足够,任何一个嵌入式设备都可以直接使用了呢?嚯嚯嚯,搞起来!!!!