3. 模型准备与转换:从训练到部署的关键一步
说实话,模型准备这块,我见过太多人栽跟头了。明明在电脑上跑得好好的模型,一放到STM32上就罢工。问题出在哪?多半是模型转换这关没过好。
今天咱们就聊聊,怎么把训练好的模型,变成STM32能吃的格式。嗯,这里头门道不少。
3.1 支持的深度学习框架
STM32CubeAI目前支持三大主流框架:Keras、TFLite和ONNX。我个人的习惯是,能用Keras就用Keras,因为它的API最友好。但如果你要部署到边缘设备,TFLite往往是更好的选择。
| 框架 | 适用场景 | 我的建议 |
|---|---|---|
| Keras (.h5) | 快速原型验证 | 新手首选,调试方便 |
| TFLite (.tflite) | 嵌入式部署 | 量化支持好,体积小 |
| ONNX (.onnx) | 跨框架迁移 | 适合从PyTorch转过来 |
小技巧: 我在项目中遇到过,用Keras训练完直接转TFLite,有时候会报一些奇怪的算子不支持。这时候先转ONNX再转TFLite,反而能绕过去。
3.2 模型导出格式
说白了,模型导出就是把训练好的网络结构+权重,打包成一个文件。STM32CubeAI能直接吃的格式,主要有这么几种:
- .h5文件:Keras的原生格式,包含完整模型
- .tflite文件:Google的移动端格式,做了优化
- .onnx文件:开放神经网络交换格式,通用性强
你想想看,为什么要有这么多格式?因为不同场景需求不一样。在PC上训练用Keras,部署到MCU用TFLite,中间可能还要经过ONNX做格式转换。这就是典型的「训练-转换-部署」流程。
# 我常用的导出方式
# Keras -> TFLite
import tensorflow as tf
# 加载训练好的模型
model = tf.keras.models.load_model('my_model.h5')
# 转换为TFLite
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()
# 保存
with open('model.tflite', 'wb') as f:
f.write(tflite_model)
注意: 我曾经遇到过,导出的.tflite文件在STM32CubeAI里解析失败。后来发现是模型里用了自定义层,TFLite不支持。所以导出前,最好先检查一下算子兼容性。
3.3 模型量化概念
量化,说白了就是把模型里的浮点数,变成整数。为什么要这么做?因为STM32这类MCU没有浮点运算单元(FPU),跑浮点运算慢得要命。量化后,运算速度能提升好几倍。
我刚开始做量化时,总觉得会损失很多精度。后来发现,对于大多数应用场景,8位整数量化后的精度损失不到1%。但模型体积能缩小4倍,推理速度能提升3-5倍。这笔账,怎么算都划算。
| 量化类型 | 精度损失 | 体积缩小 | 速度提升 |
|---|---|---|---|
| 浮点(FP32) | 无 | 1x | 1x |
| 动态量化 | ~0.5% | 2x | 2-3x |
| 全整数量化(INT8) | ~1% | 4x | 3-5x |
核心要点: 量化不是简单的截断,而是通过校准数据集,找到最佳的缩放因子和零点偏移。我建议用100-500张代表性图片做校准,效果最好。
3.4 输入输出张量定义
嗯,这里要注意。STM32CubeAI对输入输出张量的格式有严格要求。我见过太多人,模型转换成功了,但部署时发现输入输出对不上。
常见的输入格式要求:
- 图像输入:NHWC格式(批次、高度、宽度、通道数)
- 数据范围:0-255(uint8)或0.0-1.0(float32)
- 通道顺序:RGB,不是BGR
输出格式要求:
- 分类任务:softmax后的概率分布
- 回归任务:原始数值
- 检测任务:边界框坐标+置信度
# 检查输入输出张量
import tensorflow as tf
# 加载TFLite模型
interpreter = tf.lite.Interpreter(model_path='model.tflite')
interpreter.allocate_tensors()
# 获取输入输出详情
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
print("输入张量信息:")
print(f" 名称: {input_details[0]['name']}")
print(f" 形状: {input_details[0]['shape']}")
print(f" 类型: {input_details[0]['dtype']}")
print("输出张量信息:")
print(f" 名称: {output_details[0]['name']}")
print(f" 形状: {output_details[0]['shape']}")
print(f" 类型: {output_details[0]['dtype']}")
避坑指南: 我曾经在项目里,模型输入是224x224的RGB图像,但STM32CubeAI默认要求输入是BGR格式。结果推理结果全错了。后来我加了一步颜色空间转换,问题才解决。所以,一定要确认你的预处理和后处理,和模型训练时保持一致。
好了,模型准备这块,核心就是三件事:选对框架、导出正确格式、做好量化。每一步都有坑,但只要你按照我说的流程走,基本不会出大问题。下一章,咱们聊聊怎么在STM32上实际跑模型,那才是真正见真章的时候。