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上实际跑模型,那才是真正见真章的时候。