3. 模型准备与转换:从训练框架到STM32的桥梁
说实话,模型准备这一步,看着简单,坑却不少。我见过太多人花了两周训出一个漂亮的模型,结果发现导不进STM32——那种感觉,就像菜都炒好了发现没开火。今天咱们就把这条路捋顺了。
3.1 支持哪些框架?
STM32Cube.AI目前主要支持三个来源:Keras、TFLite和ONNX。我个人习惯用Keras做快速原型,用ONNX做跨平台部署。
| 框架 | 文件格式 | STM32Cube.AI版本支持 | 我的推荐场景 |
|---|---|---|---|
| Keras (TensorFlow 2.x) | .h5 | 全部版本 | 快速验证、教学演示 |
| TFLite | .tflite | ≥ 7.0.0 | 量化模型、移动端迁移 |
| ONNX | .onnx | ≥ 7.1.0 | PyTorch用户、跨框架协作 |
3.2 模型导出格式详解
每种框架的导出方式不太一样。我挑最常用的三种说一下。
3.2.1 Keras (.h5)
最简单,一行代码的事:
model.save('my_model.h5')
嗯,这里要注意:save和save_weights是两回事。前者保存完整图结构+权重,后者只存权重。STM32Cube.AI要的是前者,我刚开始就搞混过。
3.2.2 TFLite (.tflite)
这个格式的好处是自带量化信息。导出时记得指定输入输出形状:
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8
tflite_model = converter.convert()
with open('model_quant.tflite', 'wb') as f:
f.write(tflite_model)
3.2.3 ONNX (.onnx)
PyTorch用户看这里:
import torch
dummy_input = torch.randn(1, 3, 32, 32)
torch.onnx.export(model, dummy_input, "model.onnx",
input_names=['input'],
output_names=['output'],
dynamic_axes={'input': {0: 'batch_size'},
'output': {0: 'batch_size'}})
为什么我推荐ONNX?因为它的算子覆盖面广,而且STM32Cube.AI对ONNX的支持越来越好了。说白了,ONNX就是模型界的通用语言。
3.3 输入输出张量约束
这是最容易翻车的地方。STM32的RAM和Flash有限,对张量形状有硬性要求。
| 约束项 | 具体要求 | 踩坑记录 |
|---|---|---|
| 输入维度 | 固定4维 (NCHW或NHWC) | 我试过3维输入,直接报错 |
| Batch size | 必须为1 | 推理时batch>1会内存溢出 |
| 数据类型 | float32 / int8 / uint8 | float16不支持,别踩 |
| 最大张量尺寸 | 取决于芯片RAM(通常≤256KB) | F4系列建议输入≤128x128x3 |
3.4 量化感知训练(QAT)简介
你想想看,一个float32的模型,直接转成int8,精度掉多少?我做过测试,有的模型掉5%,有的直接掉到没法用。这时候就需要QAT了。
QAT说白了就是:在训练过程中模拟量化误差,让模型自己学会适应低精度。这样部署到STM32上时,精度损失能控制在1-2%以内。
3.4.1 QAT怎么做?
TensorFlow里有一套完整的QAT API:
import tensorflow_model_optimization as tfmot
# 在原始模型上应用QAT
quantize_model = tfmot.quantization.keras.quantize_model
qat_model = quantize_model(original_model)
# 用较小的学习率继续训练
qat_model.compile(optimizer='adam', loss='categorical_crossentropy')
qat_model.fit(x_train, y_train, epochs=5, batch_size=32)
# 导出时自动包含量化信息
converter = tf.lite.TFLiteConverter.from_keras_model(qat_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_qat_model = converter.convert()
3.4.2 什么时候必须用QAT?
- 模型对精度极其敏感(比如关键部位检测)
- 部署芯片RAM极小(比如STM32F0系列)
- 后训练量化(PTQ)掉点超过3%
3.5 知识体系总览
下面这张图,把模型准备到部署的整个流程串起来了。我建议你保存下来,每次做项目前看一眼。
3.6 本章小结
模型准备这一步,说白了就是给STM32「喂对饭」。框架选对、格式导对、张量约束卡对、量化策略选对——四件事都做对了,后面部署就顺了。
我个人建议:第一次做项目时,先用Keras导出.h5,走通全流程。等熟悉了,再尝试TFLite量化或ONNX跨平台。别一上来就搞QAT,那玩意儿是锦上添花,不是雪中送炭。
model.summary()和print(input_shape)反复确认三遍。这个习惯救过我很多次。