4. STM32Cube.AI 模型分析:内存、算力与推理时间
模型训练完了,量化也做了,接下来就是最关键的一步——分析报告解读。这一步很多人会跳过,直接点“生成代码”。但我建议你,花 10 分钟仔细看看 Cube.AI 生成的报告。它能告诉你,这个模型在 MCU 上到底能不能跑,瓶颈在哪。
说白了,这份报告就是 MCU 部署的“体检单”。内存够不够?算力吃不吃得消?推理一次要多久?全写在这了。我刚开始用 Cube.AI 时,也吃过亏——模型在 PC 上跑得飞快,一部署到 STM32F4 上,直接内存溢出。后来才发现,报告里早就警告了。
4.1 模型内存占用分析
MCU 的内存是稀缺资源。STM32F4 系列通常只有 128KB~256KB RAM,F7/H7 系列能到 512KB~1MB。模型占了多少,心里得有数。
Cube.AI 报告会把内存占用拆成三块:
| 内存类型 | 说明 | 典型占比 |
|---|---|---|
| Activations | 中间激活值,运行时动态分配 | 最大的一块,通常占 60%~80% |
| Weights | 模型权重,量化后固定存储 | 10%~30%,取决于模型大小 |
| Code + Scratch | 代码段 + 临时缓冲区 | 5%~15% |
关键指标:报告里会给出 Total RAM 和 Total ROM。RAM 必须小于芯片 SRAM 大小,ROM 必须小于 Flash 大小。否则,部署必失败。
我记得有一次,一个 MobileNetV1 模型,量化后权重只有 80KB,但激活值飙到了 180KB。我用的 STM32F407 只有 192KB RAM,差点就超了。后来我把输入分辨率从 224x224 降到 160x160,激活值直接砍到 110KB,问题解决。
我的习惯:先看 Activations 大小。如果它超过芯片 RAM 的 70%,我就会考虑缩小输入尺寸,或者换更轻量的网络结构。别等到编译报错再回头。
4.2 MACs 计算:算力需求到底多大?
MACs(Multiply-Accumulate Operations)是衡量模型计算量的标准单位。一个 MAC 就是一次乘加操作。MCU 没有 GPU 那种并行能力,MACs 越高,推理越慢。
报告里会给出每层的 MACs 和总 MACs。我一般这样看:
- 总 MACs < 10M:STM32F4 系列可以流畅运行,帧率 10~30 FPS
- 总 MACs 10M~50M:需要 F7/H7 系列,或者开启硬件加速
- 总 MACs > 50M:建议用 MPU 或 NPU,纯 MCU 跑会很吃力
举个例子。一个 3x3 卷积层,输入 32x32x16,输出 32x32x32,它的 MACs 怎么算?
MACs = 输出特征图尺寸 × 卷积核尺寸 × 输入通道 × 输出通道
= (32 × 32) × (3 × 3) × 16 × 32
= 1024 × 9 × 16 × 32
= 4,718,592 ≈ 4.7M
嗯,这里要注意:MACs 和 FLOPs 不是一回事。一个 MAC 等于两次 FLOP(一次乘,一次加)。有些工具报告 FLOPs,数值会翻倍。看报告时先确认单位。
我曾经踩过的坑:有个项目用了 Depthwise 卷积,我以为 MACs 会很低。结果报告显示,Depthwise 层本身 MACs 确实低,但后面的 Pointwise 层(1x1 卷积)因为通道数多,MACs 反而成了瓶颈。所以,别只看总 MACs,要逐层分析。
4.3 推理时间预估:准不准?
Cube.AI 会基于芯片型号和主频,给出一个推理时间预估。这个值准不准?我的经验是:参考价值很大,但别全信。
为什么?因为预估模型用的是理想条件——内存无竞争、缓存全命中、中断不触发。实际跑起来,可能会有 20%~50% 的偏差。
报告里通常给出两种时间:
- Cycle 数:纯 CPU 周期,不受主频影响,适合跨芯片对比
- 毫秒数:基于主频换算,方便直观理解
我一般这样用:
- 先看 Cycle 数,除以芯片主频,得到理论时间
- 加上 30% 的余量,作为实际预期
- 如果这个时间还满足需求,那就放心部署
- 如果不满足,就得优化了
举个例子:报告显示推理需要 12M Cycles,芯片主频 168MHz。理论时间 = 12M / 168M ≈ 71ms。加上 30% 余量 ≈ 92ms。我的应用要求 100ms 以内,嗯,刚好卡线。实际测试下来是 88ms,跟预估很接近。
4.4 分析报告解读:逐块拆解
报告生成后,你会看到类似下面的结构。我带你逐块看:
+--------------------------------------------------+
| STM32Cube.AI Analysis Report |
| Model: my_model.tflite |
| Target: STM32F746ZG (Cortex-M7, 216MHz) |
+--------------------------------------------------+
| Memory |
| - Activations: 92.3 KB |
| - Weights: 45.6 KB |
| - Total RAM: 137.9 KB |
| - Total ROM: 45.6 KB |
+--------------------------------------------------+
| Complexity |
| - Total MACs: 8.7 M |
| - Total MAdd: 17.4 M |
| - Top-1 layer: conv2d_3 (2.1 M MACs) |
+--------------------------------------------------+
| Timing (estimated) |
| - Total cycles: 6,234,567 |
| - Estimated time: 28.9 ms |
| - Per-layer breakdown available |
+--------------------------------------------------+
重点看三块:
- Memory:确认 RAM 和 ROM 不超限。如果超了,优先减输入尺寸或量化
- Complexity:找到 Top-1 层,那就是优化目标。我通常先看它是不是全连接层,是的话考虑替换成全局平均池化
- Timing:看 Per-layer breakdown,找出最耗时的层。有时一个 5x5 卷积能占 40% 的时间,换成两个 3x3 就能大幅提速
我的习惯:把 Per-layer breakdown 导出成 CSV,在 Excel 里排序。一眼就能看到哪些层是“胖子”。先砍胖子,再考虑其他优化。
4.5 知识结构图:模型分析全流程
下面这张图总结了从拿到报告到最终决策的完整流程。你可以对照着看,自己现在处在哪一步。
4.6 实战建议:如何快速定位问题
拿到报告后,我一般按这个顺序排查:
- 看 Total RAM 是否超限——超了直接优化,不废话
- 看 Total MACs 是否在芯片能力范围内——超了考虑换芯片或剪枝
- 看 Per-layer breakdown,找 Top-3 耗时层——这些层就是优化重点
- 看是否有全连接层——全连接层是内存和算力大户,能换就换
- 看是否有大卷积核(5x5 以上)——拆成小卷积核通常能省 30%~50% 算力
我曾经遇到的一个案例:一个手势识别模型,报告显示 Total RAM 只有 80KB,但推理时间要 200ms。我一看 Per-layer breakdown,发现一个 7x7 卷积占了 60% 的时间。换成两个 3x3 卷积后,推理时间降到 90ms,精度只掉了 0.3%。这就是看报告的价值。