3. 模型选型原则:在边缘设备的镣铐下跳舞
做嵌入式AI,说白了就是戴着镣铐跳舞。你模型再牛,跑不起来也是白搭。我刚开始接触STM32Cube.AI时,就犯过这个错——在PC上跑得飞快的模型,一部署到芯片上直接内存溢出。嗯,从那以后我学乖了,选模型前先看三样东西:算力、内存、量化方式。
3.1 边缘设备的算力约束
STM32系列芯片的算力跨度很大。从低端的Cortex-M0到高端的Cortex-M7,甚至带NPU的STM32N6,性能差了几十倍。选模型前,你得先搞清楚目标芯片的算力天花板。
| 芯片系列 | 典型频率 | 算力(DMIPS) | 适合模型规模 |
|---|---|---|---|
| STM32F0/G0 | 48 MHz | ~40 | 极轻量(<10K参数) |
| STM32F4 | 168 MHz | ~210 | 轻量(<100K参数) |
| STM32H7 | 480 MHz | ~1027 | 中等(<500K参数) |
| STM32N6 | 800 MHz + NPU | ~6000 | 较大(<5M参数) |
我个人习惯的做法是:先估算模型的计算量(MACs),再除以芯片的峰值算力,留出30%的余量。举个例子,一个MobileNetV1大约需要569M MACs,在STM32H7上跑,理论推理时间大约是569M / (1027M * 0.7) ≈ 0.79秒。如果应用要求实时性,这个数字就得重新掂量了。
3.2 内存与Flash限制
边缘设备的内存和Flash是硬约束。STM32F4系列通常只有128KB-1MB的Flash和64KB-256KB的SRAM。模型参数、中间激活值、输入输出缓冲区,全得挤在这点空间里。
我遇到过最头疼的情况:模型参数占用了80%的Flash,结果输入图像缓冲区没地方放了。后来只能把输入图像从640x480压缩到320x240,虽然精度掉了点,但总算能跑了。
这里有个经验公式:模型参数量(字节) + 中间激活值(字节) + 输入输出缓冲区(字节) ≤ 芯片可用内存的80%。剩下的20%留给系统栈和RTOS。
- 模型参数:参数量 × 量化位宽(如INT8为1字节)
- 中间激活值:每层输出特征图大小 × 量化位宽
- 输入输出缓冲区:图像分辨率 × 通道数 × 量化位宽
3.3 量化感知训练(QAT)与后训练量化(PTQ)
量化是让模型在边缘设备上跑起来的关键。说白了,就是把FP32的模型变成INT8甚至INT4的,这样模型体积能缩小4倍,推理速度也能快2-4倍。但量化会掉精度,怎么选?
| 量化方式 | 精度损失 | 训练成本 | 适用场景 |
|---|---|---|---|
| PTQ(后训练量化) | 1-3% | 低(只需校准集) | 模型较大、训练数据不足 |
| QAT(量化感知训练) | 0.5-1% | 高(需重新训练) | 精度要求高、模型较小 |
我个人建议:优先尝试PTQ。为什么?因为省事。你只需要准备几百张校准图片,跑一遍校准流程,就能得到量化后的模型。如果PTQ后的精度满足要求,那就没必要折腾QAT。
但如果你发现PTQ后精度掉了超过3%,或者模型本身就很轻量(比如MobileNetV2),那QAT就是更好的选择。QAT在训练过程中模拟量化误差,让模型学会适应量化噪声,精度损失通常能控制在1%以内。
3.4 模型选型决策流程
说了这么多,到底怎么选?我总结了一个决策流程,你照着走就行。
3.5 实战中的量化选择
在STM32Cube.AI中,PTQ和QAT都有对应的工具链支持。PTQ可以直接在STM32Cube.AI Developer Desktop中完成,导入模型后选择量化选项,提供校准数据集就行。
QAT则需要你在训练框架(如TensorFlow、PyTorch)中完成。以TensorFlow为例,你需要使用tf.quantization.quantize_model或tfmot库进行量化感知训练。
# TensorFlow QAT示例
import tensorflow_model_optimization as tfmot
# 加载预训练模型
model = tf.keras.models.load_model('model.h5')
# 应用量化感知训练
quantize_model = tfmot.quantization.keras.quantize_model
qat_model = quantize_model(model)
# 重新训练(少量epoch即可)
qat_model.compile(optimizer='adam', loss='categorical_crossentropy')
qat_model.fit(train_data, train_labels, epochs=5)
# 导出为TFLite
converter = tf.lite.TFLiteConverter.from_keras_model(qat_model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()
嗯,这里要注意:QAT训练时,学习率要调小一点,我一般用原学习率的1/10。不然量化模拟的噪声会让模型震荡,反而掉精度。
- 算力不够?换更轻量的模型(如MobileNetV3、EfficientNet-Lite)
- 内存不够?降低输入分辨率或减少通道数
- 精度不够?从PTQ切换到QAT
- 还不行?考虑模型剪枝或知识蒸馏
最后说一句:没有完美的模型,只有合适的模型。在边缘设备上,你永远在精度、速度、大小之间做权衡。我的经验是,先跑通再优化,别一开始就追求极致精度。毕竟,能跑起来的模型,才是好模型。