3. 模型准备与格式转换:支持的主流框架与导出方法

好,咱们进入正题。模型训练好了,怎么喂给STM32?

说白了,STM32CubeAI不是啥模型都能吃。它有自己的“口味偏好”。我个人习惯,先把模型转成它认识的格式,再往下走。这一步卡住了,后面全是白搭。

3.1 支持的主流框架:Keras、TFLite、ONNX

STM32CubeAI目前主要支持三个“门派”:

  • Keras(.h5):我最常用的。TensorFlow的嫡系,API简洁,调试方便。我在项目里80%的模型都是用Keras搭的。
  • TensorFlow Lite(.tflite):专门为嵌入式优化的格式。量化、压缩都在这一步搞定。你想想看,模型从几百MB压到几MB,全靠它。
  • ONNX:这个算是“通用语言”。PyTorch、MXNet训练的模型,先转成ONNX,再喂给CubeAI。我遇到过客户非要用PyTorch,最后就是走这条路。

我的建议:如果你从零开始,直接用Keras + .h5。省事。如果模型已经训练好了,再看它是什么框架,再决定转换路径。

3.2 模型导出为 .h5 格式

.h5是Keras的原生格式。保存起来很简单:

# 训练完模型后
model.save('my_model.h5')  # 一行代码搞定

嗯,这里要注意。保存的时候,模型结构、权重、训练配置都会打包进去。我刚开始做的时候,以为只保存权重就够了,结果加载时报错——少了结构信息。

小技巧:保存前先用 model.summary() 看一眼网络结构。确认输入输出尺寸对不对。我曾经有个模型,输入是224x224,结果导出时忘了改,CubeAI直接报尺寸不匹配。

3.3 模型导出为 .tflite 格式

.tflite是专门为边缘设备设计的。转换时可以做量化,把float32变成int8。模型体积能缩小4倍,推理速度也快不少。

import tensorflow as tf

# 加载Keras模型
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)

为什么推荐量化?

STM32的算力有限,float32的运算太慢了。量化成int8后,速度能提升2-4倍。我在一个手势识别项目里,量化前推理要120ms,量化后直接降到35ms。效果肉眼可见。

避坑指南:我曾经量化一个模型,精度从98%掉到了92%。后来发现是激活值分布太广,量化时信息丢失严重。解决办法是先用代表性数据做校准(calibration)。具体做法:

def representative_dataset():
    for data in sample_data[:100]:
        yield [data.astype(np.float32)]

converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()

加了校准后,精度回到了96%。嗯,这一步不能省。

3.4 ONNX 格式的导出

ONNX的好处是“一次转换,到处使用”。如果你用的是PyTorch,可以这样转:

import torch
import torch.onnx

# 假设你有一个PyTorch模型
model = torch.load('my_model.pth')
model.eval()

# 构造一个示例输入
dummy_input = torch.randn(1, 3, 224, 224)

# 导出ONNX
torch.onnx.export(model, dummy_input, "model.onnx",
                  input_names=['input'],
                  output_names=['output'],
                  dynamic_axes={'input': {0: 'batch_size'},
                                'output': {0: 'batch_size'}})

然后,在CubeAI里导入ONNX文件即可。我有个客户,模型是用PyTorch训练的,转成ONNX后,CubeAI直接识别,省去了重写Keras的麻烦。

个人经验:ONNX转换时,注意算子兼容性。有些PyTorch的高级算子(比如自定义的激活函数),ONNX可能不支持。解决办法是替换成标准算子,或者用ONNX的算子库扩展。我遇到过最头疼的是 torch.nn.functional.grid_sample,ONNX不支持,最后改成了双线性插值。

3.5 格式选择总结

格式 适用场景 优点 缺点
.h5 Keras训练,直接使用 简单,保留完整信息 文件较大,不支持量化
.tflite 嵌入式部署,需要量化 体积小,速度快 转换时可能精度损失
ONNX 跨框架模型迁移 通用性强 算子兼容性问题

我个人建议:

  • 如果模型不大(< 10MB),直接用.h5。省事。
  • 如果对速度有要求,或者Flash空间紧张,转.tflite并量化。
  • 如果模型来自PyTorch或其他框架,走ONNX路线。

好了,模型准备好了。下一步就是把它导入CubeAI,开始验证和调试。咱们下一章见。