1. 本章学习目标
学完本章后,应能够理解:
-
轻量模型和微控制器推理框架为什么共同推动了 TinyML 的发展。
-
LiteRT for Microcontrollers 与 CMSIS-NN 分别承担什么工作。
-
Reference Kernel 与 Optimized Kernel 有什么区别。
-
为什么缩短推理周期能够降低功耗并延长电池续航。
-
Cycle-bound 与 Memory-bound 两类性能瓶颈如何区分。
-
纯 C、DSP / SIMD 和 MVE / Helium 三类内核实现有什么不同。
-
为什么编译选项错误可能抵消模型、库和硬件带来的全部优化收益。
-
为什么 int8 或 int4 量化并不等于模型已经获得最佳性能。
-
张量形状、数据对齐、内存访问和算子支持为什么会影响实际速度。
-
如何将这些优化思路迁移到 EEG、ECG、EMG、PPG、HRV、GSR / EDA 项目。
2. 本章内容导读
早期 TensorFlow、PyTorch 等机器学习框架主要面向桌面计算机、GPU 和服务器,而微控制器通常只有有限的 RAM、Flash 和计算能力。近几年,轻量神经网络、模型量化和微控制器推理框架逐渐成熟,使越来越多的模型可以运行在 Cortex-M 等资源受限设备上。
但"模型能运行"只是起点。实际产品还要面对推理延迟、功耗、内存峰值和实时性限制。本章由 Arm 固件工程师 Felix 讲解 CMSIS-NN 的优化思路,并指出一个很容易被忽略的事实:
最终推理性能
并不只由模型大小决定
而是由:
模型结构
+ 量化方式
+ 推理框架
+ 优化算子库
+ 编译配置
+ 内存访问
+ 处理器指令
共同决定
3. 本章在系列笔记中的位置
前一章主要回答:
哪些处理器具有 DSP、向量指令或 NPU,什么才算真正的 AI 硬件加速?
本章进一步回答:
即使处理器已经确定,软件和模型怎样配合,才能真正发挥硬件性能?
因此,本章不再展开硬件架构本身,而是把重点放在以下优化链路:
轻量模型设计
→ 模型量化
→ 微控制器推理框架
→ 优化算子库
→ 编译器配置
→ 内存和张量布局
→ 目标硬件运行
→ 实测延迟、RAM 和能耗
本章最重要的方法论是:
优化是一项团队工程,而不是某一个人的最后一步工作。
4. TinyML 得以实现的两个关键支点
4.1 支点一:模型本身变得更轻
早期图像、语音神经网络通常具有较大的参数量和计算量,很难直接放进 MCU。随后出现的 MobileNet 等轻量网络,通过深度可分离卷积、倒残差结构和线性瓶颈等方式降低运算量与模型体积。
MobileNetV2 采用 Inverted Residual,倒残差,以及 Linear Bottleneck,线性瓶颈,使模型能够在保持一定表达能力的同时减少计算与内存需求。(arXiv)
课程中用两个量级差异明显的模型说明这一变化:
| 对比项目 | 常规 MobileNetV2 浮点模型 | 课程中的 Person Detection 轻量模型 |
|---|---|---|
| 模型规模 | 超过约 3 MB | 约 250 KB |
| 运算量 | 超过约 3 亿次 MAC | 约 700 万次 MAC |
| 典型环境 | 移动端或较高资源平台 | 微控制器级视觉检测 |
| 部署难度 | 很难放入普通 MCU | 在特定 MCU 上具备可行性 |
这些数字主要用于说明模型规模下降的数量级,不代表两个模型任务、精度和网络结构完全相同,因此不能把它们当作严格的一对一性能比较。
4.2 支点二:出现了专门面向 MCU 的推理框架
模型变小以后,还需要一个能够在微控制器上解释和执行模型的运行时。
课程中的 TensorFlow Lite for Microcontrollers,TFLM ,目前在 Google 官方文档中称为 LiteRT for Microcontrollers 。它面向只有少量内存的微控制器设计,不要求完整操作系统、动态内存分配或标准 C / C++ 运行库;其核心运行时可以适配 Cortex-M 和 ESP32 等多种架构。(Google AI for Developers)
它主要负责:
读取模型结构
→ 分配 Tensor Arena
→ 查找模型所需算子
→ 调用对应 Kernel
→ 执行各层计算
→ 输出推理结果
但推理框架主要解决"怎样正确运行模型"的问题,并不代表其中每个算子已经针对所有硬件进行了最高程度的优化。
这就需要 CMSIS-NN。
5. LiteRT Micro 与 CMSIS-NN 是什么关系?
可以用"调度者"和"专业工具箱"来理解二者。
| 组件 | 通俗理解 | 主要职责 |
|---|---|---|
| LiteRT for Microcontrollers | 模型执行的总调度员 | 读取模型、管理张量、按顺序执行算子 |
| Reference Kernel | 通用版本算子 | 优先保证正确性和可移植性 |
| CMSIS-NN | Cortex-M 专用高速算子库 | 使用目标处理器特性加速卷积、全连接等计算 |
| CMSIS-DSP | 信号处理工具箱 | 优化滤波、FFT、矩阵和统计运算 |
| 编译器 | 把代码变成目标指令 | 根据处理器和优化参数生成机器码 |
CMSIS-NN 是面向 Arm Cortex-M 的开源神经网络内核库,其目标是在降低内存占用的同时提高神经网络推理性能。当前官方文档包含卷积、激活、全连接、池化、Softmax、逐元素运算、SVDF 和 LSTM 等算子类别。(Arm Software)
CMSIS-NN 使用 Apache 2.0 许可证,可以用于开源项目和商业项目,并按照 LiteRT / TFLM 的 int8、int16 量化规范实现相应算子。(GitHub)
5.1 Optimized Kernel 与 Reference Kernel
同一个算子可能有两种实现。
Reference Kernel:参考内核
特点是:
-
通用性较高;
-
便于移植;
-
重点保证计算正确;
-
不一定充分使用目标处理器的 DSP 或向量指令;
-
性能通常不是最优。
Optimized Kernel:优化内核
特点是:
-
针对特定处理器架构;
-
可能使用 SIMD、MVE、内联函数或汇编;
-
更重视循环效率、数据复用和内存访问;
-
可能对张量形状、通道数或数据类型提出额外限制。
实际运行逻辑可以理解为:
当前算子有目标平台优化版本
→ 调用 CMSIS-NN 等优化 Kernel
当前算子不满足优化条件
或没有优化版本
→ 使用 Reference Kernel
这种设计的价值在于:即使 CMSIS-NN 暂时没有覆盖模型中的全部算子,模型仍有机会通过参考实现完成运行,而优化库可以逐步扩大算子覆盖范围。
6. 为什么必须进行 TinyML 优化?
6.1 减少推理时间
模型推理必须在规定时间内完成。例如:
-
关键词识别需要在下一个音频窗口到来前完成;
-
EMG 手势识别需要及时响应动作;
-
ECG 异常检测不能长时间阻塞采集;
-
多通道 EEG 模型不能影响连续采样;
-
闭环控制系统不能因为模型过慢而错过控制周期。
假设采样窗口每 100 ms 更新一次,而模型推理需要 180 ms,就会出现数据积压或丢失。
6.2 降低能耗
微控制器通常在以下状态之间切换:
睡眠
→ 定时唤醒
→ 读取传感器
→ 完成信号处理和推理
→ 重新睡眠
在平均运行功率近似稳定的情况下,每次推理能量可以粗略表示为:

缩短推理时间,通常意味着处理器能够更快回到低功耗状态。因此,减少执行周期不仅改善响应速度,也有机会延长电池续航。
不过,频率、电压、缓存、外设和无线通信都会影响实际功耗,所以最终应在真实硬件上测量,而不能仅根据循环数推断能耗。
6.3 在相同时间预算内部署更复杂的模型
假设设备允许每次推理最多占用 20 ms:
原模型推理时间:25 ms
→ 无法满足要求
经过优化以后:
优化后推理时间:8 ms
→ 可以满足要求
还可能利用剩余时间:
-
增加输入通道;
-
扩大时间窗口;
-
使用精度更高的模型;
-
加入异常检测;
-
进行多模态融合。
因此,优化不只是"让已有模型更快",也可能把原本无法实现的应用变成可实现的应用。
7. TinyML 优化不是一个人的工作
课程用"养育一个孩子需要整个村庄"的比喻说明:优化同样需要整个开发链参与。
| 参与者 | 可负责的优化内容 | 常见问题 |
|---|---|---|
| 硬件设计人员 | CPU、DSP、缓存、SRAM、总线和存储设计 | 运算快但数据供给不足 |
| 模型设计人员 | 网络深度、通道数、算子、张量形状 | 模型准确但不适合目标 MCU |
| 量化工程人员 | int8、int16、int4、校准数据 | 模型变小但精度明显下降 |
| 框架维护者 | 算子调度、内存规划、模型兼容性 | 算子无法在 MCU 运行 |
| 优化库开发者 | SIMD、MVE、内联函数和汇编内核 | 算子速度仍然过慢 |
| 编译和构建人员 | CPU 类型、优化等级、ABI 和链接设置 | 优化内核被错误编译 |
| 应用开发人员 | 采样、缓存、任务调度和功耗策略 | 模型快但系统仍然延迟高 |
| 测试人员 | 延迟、RAM、准确率和能耗测量 | 只测试模型,没有测试完整应用 |
这一关系可以概括为:
硬件能力
× 编译器是否正确使用硬件
× 算子库是否经过优化
× 模型是否适合这些算子
× 内存是否高效访问
= 最终可获得的实际性能
其中任何一项接近零,整体优化收益都可能大幅下降。
8. 优化的第一层:软件与编译环境
课程强调,软件环境看起来不如模型结构有吸引力,却是其他优化能否生效的基础。
8.1 目标处理器必须设置正确
CMSIS-NN 会根据编译器提供的架构 Feature Flags,功能标志,选择适合目标处理器的实现:
-
Cortex-M0 / M3:纯 C 实现;
-
Cortex-M4 或带 DSP 扩展的 M33:DSP / SIMD 实现;
-
Cortex-M55 / M85:MVE / Helium 实现。
正确实现通常在编译阶段自动选择。如果目标 CPU 配置错误,编译器可能生成通用标量代码,而没有使用目标处理器的 DSP 或向量指令。(GitHub)
例如:
实际硬件:Cortex-M55
编译目标:通用 Cortex-M
结果:
MVE 内核可能没有启用
→ 模型可以运行
→ 但没有获得预期加速
8.2 Debug 版本不能代表最终性能
调试阶段常使用较低的优化等级,便于设置断点和观察变量,但这类构建可能带来:
-
循环没有优化;
-
函数没有内联;
-
常量传播不足;
-
向量化未启用;
-
大量调试代码保留。
CMSIS-NN 当前构建文档明确指出,编译优化等级会影响性能;某些会关闭编译器内建优化的选项,还可能显著降低 memcpy、memset 等常用操作的效率。(GitHub)
所以测试模型速度时,需要区分:
Debug Build:
用于调试正确性
Release Build:
用于测量最终性能
8.3 编译环境检查表
当优化库没有带来预期收益时,建议先检查:
| 检查项 | 需要确认的问题 |
|---|---|
| Target CPU | 是否设置成真实处理器核心 |
| Optimization Level | 是否使用了合理的 Release 优化等级 |
| DSP / MVE 标志 | 是否真正启用了目标指令集 |
| Float ABI | 浮点调用约定是否匹配工程和库 |
| 优化库 | CMSIS-NN 是否被编译并实际链接 |
| 日志信息 | 是否仍在调用 Reference Kernel |
| Cache / TCM | 关键代码和数据是否位于合适存储区域 |
| 调试代码 | 串口打印是否被计入推理时间 |
| 计时范围 | 是否只测了模型,还是连采样和预处理一起测量 |
9. 优化的第二层:计算瓶颈与内存瓶颈
课程把算子性能问题概括为两类:
Cycle-bound:
主要受计算周期限制
Memory-bound:
主要受内存读取和数据搬运限制
9.1 Cycle-bound:计算受限
当处理器的大部分时间都在执行乘法、加法、比较和循环时,任务更接近计算受限。
常见优化方法包括:
-
减少不必要的运算;
-
简化嵌套循环;
-
移除最内层循环中的条件判断;
-
使用 SIMD;
-
使用 DSP 指令;
-
使用 MVE / Helium;
-
使用编译器 Intrinsics;
-
在必要时使用汇编;
-
合并能够连续完成的运算。
例如,不理想的内层循环:
for (int i = 0; i < length; i++)
{
if (i < valid_length)
{
sum += input[i] * weight[i];
}
}
条件判断会在循环中不断执行。若能提前确定有效范围,可整理为:
for (int i = 0; i < valid_length; i++)
{
sum += input[i] * weight[i];
}
这类调整虽然简单,但在执行数百万次的卷积内层循环中可能产生明显差异。
9.2 Memory-bound:内存受限
有些算子并不是乘法执行得慢,而是处理器不断等待权重、输入和中间张量从存储器传入。
常见原因包括:
-
相同权重被反复读取;
-
数据排列不连续;
-
地址未对齐;
-
缓存命中率低;
-
中间张量过大;
-
频繁在不同存储区域之间复制;
-
张量布局与算子访问顺序不匹配。
对应优化方法包括:
-
尽量复用已经读入寄存器或高速内存的数据;
-
使用连续数据布局;
-
避免不必要的数据复制;
-
合理安排 SRAM、TCM 和外部存储;
-
压缩权重;
-
缩小中间激活;
-
按块计算;
-
合理选择 im2col 缓冲区大小。
可以简单理解为:
计算受限:
处理器一直在算
内存受限:
处理器有能力算,但数据还没送到
10. CMSIS-NN 如何针对不同 Cortex-M 优化?
CMSIS-NN 并不是给所有 Cortex-M 使用同一套实现,而是根据处理器能力提供不同路径。
| 处理器类型 | 典型核心 | 常见优化方向 |
|---|---|---|
| 无 DSP / SIMD | Cortex-M0、M0+、M3 | 简化循环、降低复杂度、优化内存访问 |
| 带 DSP 扩展 | Cortex-M4、部分 M33、M7 | SIMD、双 16 位或多 8 位并行运算 |
| 带 MVE / Helium | Cortex-M55、M85 | 更宽的向量计算、向量点积和高级数据处理 |
CMSIS-NN 会基于架构特征在编译时选择对应实现,开发者不必为每个 Cortex-M 手动重写全部算子。(Arm Software)
10.1 没有 SIMD 的处理器如何优化?
对于 Cortex-M0 / M0+ 等处理器,主要依靠:
-
纯 C 高效实现;
-
简化循环层级;
-
减少分支;
-
减少函数调用;
-
降低内存访问次数;
-
使用整数运算;
-
选择更简单的模型。
这种优化不会创造处理器本身没有的向量能力,但仍能减少不必要的执行周期。
10.2 带 DSP / SIMD 的处理器如何优化?
SIMD 是 Single Instruction Multiple Data,即"一条指令同时处理多个数据"。
例如,普通实现可能逐个完成:
x0 × w0
x1 × w1
x2 × w2
x3 × w3
SIMD 可以在一次或较少指令中并行处理多个较低位宽数据,特别适合 int8 和 int16 神经网络。
这也是量化模型在 Cortex-M4、M7、M33 等带 DSP 扩展处理器上常能获得明显加速的重要原因。
10.3 MVE / Helium 为什么更适合神经网络?
MVE 提供更强的向量运算能力,适合:
-
int8 点积;
-
卷积;
-
矩阵乘法;
-
滤波;
-
FFT;
-
多通道信号处理。
课程中展示了 Cortex-M55 配合 CMSIS-NN,在 MobileNetV2 和 Wav2Letter 等特定模型上获得约一个数量级性能提升的示例。但该数字取决于模型结构、编译配置、缓存、内存延迟和目标系统,不能理解为所有模型都会固定加速十倍。
11. im2col:用额外内存换取更高卷积效率
卷积运算在实现时常被转换为矩阵乘法。CMSIS-NN 的部分卷积实现采用:
输入特征图
→ im2col
→ GEMM 矩阵乘法
→ 输出特征图
im2col 会把卷积窗口中的数据重新排列成矩阵列,使卷积可以利用更高效的矩阵乘法内核。CMSIS-NN 为降低内存峰值,不一定一次转换完整输入,而可以每次只生成部分列,计算后继续处理下一块。(Arm Software)
它体现了一种典型权衡:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 不使用或少用 im2col | 临时 RAM 较少 | 计算和数据读取可能更慢 |
| 完整 im2col | 矩阵运算效率高 | 临时缓冲区较大 |
| 部分 im2col | 平衡速度与 RAM | 实现和调度更复杂 |
这说明 TinyML 中"最快"与"最省内存"经常不是同一个方案。
12. 优化的第三层:量化不是终点
12.1 int8 量化能带来什么?
Post-training Quantization,训练后量化,可以把浮点模型转换为低位宽模型。完整整数化通常能够:
-
缩小模型;
-
降低峰值内存;
-
提高 CPU 推理速度;
-
适配整数运算单元和硬件加速器。
Google 官方文档指出,完整整数化可以使模型显著缩小,并改善 CPU、微控制器及整数加速器上的延迟,但需要代表性数据进行校准。(Google AI for Developers)
int8 值与真实数值之间常用以下关系表示:

LiteRT 的 8 位量化规范支持按张量和按通道的量化方式,其中卷积权重通常可以按输出通道量化,以改善量化精度。(Google AI for Developers)
12.2 量化后为什么不一定更快?
量化解决的是数据位宽问题,但实际速度还取决于:
-
是否有对应 int8 优化内核;
-
算子是否被 CMSIS-NN 支持;
-
张量形状是否满足快速内核约束;
-
输入通道数是否适合向量化;
-
是否发生数据格式转换;
-
是否存在未对齐访问;
-
临时缓冲区是否足够;
-
编译器是否生成了目标指令。
所以:
模型已经是 int8
≠ 所有算子都会自动使用最快内核
12.3 当前 CMSIS-NN 的低精度支持
课程主要介绍 int8 和较低位宽模型。当前 CMSIS-NN 官方仓库以 int8 和 int16 为主要成熟量化路径,同时部分算子支持"int4 权重 + int8 激活"的组合;此外也提供实验性的 float16 / float32 接口,但浮点接口主要面向带 Helium 的处理器,并非所有 Cortex-M 的主要性能路线。(GitHub)
这说明 4 位模型不能简单理解为"所有输入、输出和中间结果都变成 4 位"。实际实现可能只是把权重压缩为 int4,而激活仍使用 int8。
13. 张量形状也会决定模型速度
很多初学者只关注:
-
参数数量;
-
模型文件大小;
-
MAC 数;
-
准确率。
但在优化库中,张量形状同样重要。
例如:
输入通道数:16
可能比:
输入通道数:15
更容易充分利用一次处理多个数据的向量指令。
虽然两者参数量相差不大,但实际速度可能不同。
影响优化效率的形状因素包括:
-
通道数是否适合向量宽度;
-
数据地址是否对齐;
-
卷积核尺寸;
-
Stride;
-
Padding;
-
输入和输出通道关系;
-
是否能使用专用 Depthwise Convolution 内核;
-
是否需要额外 im2col;
-
张量布局是 NHWC 还是其他格式。
CMSIS-NN 的部分高效卷积内核对输入高度、通道倍数、步长、填充方式等参数存在明确约束,不满足条件时通常需要选择更通用的实现。(Arm Software)
因此,两个 MAC 数相近的模型,也可能因为张量形状不同而出现明显延迟差异。
14. 性能优化应先找"热点算子"
不应该一开始就优化所有代码。更合理的方法是先进行 Profiling,性能分析。
14.1 建议测量的项目
| 指标 | 作用 |
|---|---|
| 总推理时间 | 判断模型是否满足实时要求 |
| 单个算子耗时 | 找到最慢的层 |
| Tensor Arena 峰值 | 判断 RAM 是否足够 |
| 模型 Flash 占用 | 判断程序能否装入 |
| CPU 占用率 | 判断是否影响采样和通信 |
| 每次推理能量 | 判断电池续航 |
| 前处理耗时 | 确认滤波和特征提取是否成为瓶颈 |
| 后处理耗时 | 确认阈值、平滑和控制逻辑成本 |
| Reference Kernel 比例 | 判断优化库是否真正被调用 |
14.2 推荐的优化顺序
第一步:建立未优化基线
↓
第二步:确认模型输出正确
↓
第三步:测量端到端延迟和 RAM
↓
第四步:找到最耗时的算子
↓
第五步:确认优化内核是否启用
↓
第六步:检查量化与算子兼容性
↓
第七步:调整张量形状或模型结构
↓
第八步:重新测量准确率、延迟和能耗
不要在没有基线数据时盲目调整模型,否则很难判断某次改动究竟带来了收益还是退化。
MLPerf Tiny 的设计也强调同时测量准确率、延迟和能耗,而不是只比较某一项指标。其基准覆盖关键词识别、Visual Wake Words、图像分类和异常检测等典型 TinyML 任务。(arXiv)
15. 如何理解课程中的"十倍加速"?
课程展示了 Cortex-M55 上 CMSIS-NN 对 MobileNetV2 和 Wav2Letter 等模型带来的明显加速。这个案例的重点不是记住一个固定倍数,而是理解性能提升的来源:
Reference Kernel
→ CMSIS-NN 优化实现
→ DSP / SIMD
→ MVE / Helium
→ 合适的模型和张量形状
→ 正确的编译环境
不同项目的实际收益可能差别很大:
| 情况 | 可能结果 |
|---|---|
| 模型主要由已优化的 int8 卷积组成 | 加速效果可能明显 |
| 模型主要是未覆盖的特殊算子 | 加速有限 |
| 编译目标配置错误 | 可能仍运行通用实现 |
| 网络很小,框架开销占比较高 | 加速比例可能不明显 |
| 外部 Flash 或内存速度较慢 | 可能受到内存带宽限制 |
| 前处理比神经网络更耗时 | 整体应用加速小于模型加速 |
| 张量形状不适合快速内核 | 可能回退到通用内核 |
因此,优化结果必须以目标开发板实测为准。
16. 与生理信号 TinyML 项目的联系
本章不再重复各种生理信号的一般采集流程,而是重点分析它们的主要计算瓶颈和优化优先级。
16.1 不同信号的优化重点
| 信号 | 常见计算瓶颈 | 优先优化内容 | 可能使用的优化方式 |
|---|---|---|---|
| EEG | 多通道、频谱计算、中间张量大 | FFT、滤波、通道数和模型内存 | CMSIS-DSP、int8 CNN、减少通道、窗口复用 |
| ECG | 连续滤波、R 峰检测、1D CNN | 流式缓存、卷积算子、避免阻塞采样 | 环形缓冲、int8 1D CNN、CMSIS-NN |
| EMG | 采样率高、多通道、频域特征多 | SIMD 滤波、RMS / MAV、通道布局 | CMSIS-DSP、向量化、适合 SIMD 的通道数 |
| PPG | 滤波、峰值检测、运动伪迹处理 | 前处理延迟和缓存 | 定点滤波、滑动窗口复用、小型 1D CNN |
| HRV | 心搏间期统计和窗口特征 | 减少重复计算、延长睡眠时间 | 增量统计、特征模型、小型 MLP |
| GSR / EDA | 变化较慢、模型通常较小 | 低功耗采样和推理调度 | 降低推理频率、固定点特征、小型分类器 |
| 多模态信号 | 同步、缓存、通道融合 | RAM 峰值和任务调度 | 分阶段特征提取、晚期融合、共享缓冲区 |
16.2 EEG:往往先遇到 RAM 和前处理瓶颈
多通道 EEG 可能需要:
-
多个带通滤波器;
-
工频陷波;
-
多通道 FFT;
-
不同频带能量计算;
-
较长时间窗口;
-
CNN 或时序模型。
因此,EEG 项目不应只优化神经网络,也要测量频谱特征提取的耗时。若前处理已占据大部分周期,仅替换为 CMSIS-NN 不一定显著改善端到端速度。
可重点优化:
多通道数据使用环形缓冲区
→ 避免重复复制完整窗口
FFT 和滤波使用 CMSIS-DSP
→ 减少纯 C 运算开销
减少无效通道
→ 降低输入张量和中间特征图
模型量化为 int8
→ 使用 CMSIS-NN 卷积内核
16.3 ECG:不能让推理阻塞连续采样
ECG 采样需要保持较稳定的时间间隔。如果模型推理期间停止 ADC 数据处理,可能丢失关键波形。
适合的系统结构是:
ADC / SPI + DMA
→ 持续写入环形缓冲区
采样窗口完成
→ 通知推理任务
推理任务读取上一窗口
→ ADC 同时采集下一窗口
优化重点不是只减少模型延迟,还要确保:
-
采集任务优先级;
-
缓冲区不会覆盖;
-
推理最坏执行时间小于窗口更新周期;
-
滤波状态连续;
-
R 峰检测不会因任务阻塞丢失。
16.4 EMG:通道数量和形状会影响 SIMD 效率
EMG 常使用多通道输入,例如 4、8、16 通道。通道数不仅影响数据量,还可能影响向量内核能否高效处理。
例如,将中间层通道数设计为适合向量处理的数量,可能比任意通道数更容易获得高效实现。但不能只为了对齐而盲目增加通道,因为增加通道也会提高模型参数量和 RAM。
EMG 项目需要在以下目标之间平衡:
动作识别准确率
模型通道数量
SIMD 利用率
中间张量大小
推理延迟
16.5 PPG:模型可能不是最大的耗时来源
PPG 容易受到运动伪迹影响,常需要:
-
带通滤波;
-
峰值检测;
-
加速度辅助去噪;
-
信号质量评估;
-
心搏间期计算。
如果模型只是一个小型分类器,前处理可能比推理更耗时。因此应分别测量:
滤波时间
峰值检测时间
特征计算时间
神经网络推理时间
然后再决定优化 CMSIS-DSP、CMSIS-NN,还是降低前处理复杂度。
16.6 HRV 和 GSR / EDA:重点可能是省电,而不是追求极限算力
HRV 和 GSR / EDA 常使用窗口统计特征或较小模型,普通 MCU 通常就能够完成推理。
这类项目的优化重点更可能是:
-
不要对每个采样点都进行模型推理;
-
按窗口或事件触发推理;
-
使用增量统计避免重复遍历;
-
降低无线发送频率;
-
尽快回到休眠状态;
-
用较小的传统模型替代不必要的深度网络。
例如:
GSR 每 10 ms 采样
并不意味着每 10 ms 都要运行一次模型
更合理的是:
持续采样
→ 更新窗口特征
→ 每 1 s 或窗口结束时推理
→ 其余时间保持低功耗
17. 不同主控平台的优化路径
本章只比较各平台的优化生态,不再重复一般硬件参数。
| 平台 | 主要优化路径 | 适合关注的问题 |
|---|---|---|
| Arm Cortex-M4 / M7 / M33 | CMSIS-NN + CMSIS-DSP | DSP / SIMD 是否启用、int8 算子覆盖 |
| Cortex-M55 / M85 | CMSIS-NN + MVE / Helium | 向量内核、通道形状和数据布局 |
| Nordic nRF52 / nRF53 | TFLM / LiteRT Micro + CMSIS-NN | BLE 低功耗调度与推理唤醒时间 |
| ESP32 / ESP32-S3 | ESP-DL、ESP-NN、ESP-DSP 或平台推理库 | 目标芯片优化库、内存区域和任务调度 |
| STM32 | CMSIS-NN 或 STM32Cube AI Studio | 自动代码生成、目标板验证与性能测量 |
| RP2040 | 纯 C、小型整数模型、双核任务分配 | 无 Cortex-M DSP 扩展,模型简化更重要 |
| Arduino Nano 33 BLE Sense | nRF52840 + Cortex-M4F 优化路径 | 教学模型向 CMSIS-NN 部署迁移 |
Nordic 的 nRF Connect SDK 示例可以通过配置选项启用 TFLM 的 CMSIS-NN 内核。(docs.nordicsemi.com)
Espressif 的 ESP-DL 是面向 ESP 系列芯片的轻量神经网络推理框架,并配套模型量化和运行工具。(Espressif Systems)
STM32Cube AI Studio 可以分析、优化并编译模型,生成面向 STM32 的 C 代码,同时支持在目标板上测量性能和内存占用。(STMicroelectronics)
RP2040 使用双核 Cortex-M0+,不具备 Cortex-M4 那类 DSP 扩展,因此更需要依靠纯 C 优化、整数化、模型精简和合理的双核任务分配。(Raspberry Pi)
18. 一套可直接执行的 TinyML 优化清单
阶段一:建立基线
-
记录模型准确率;
-
记录模型文件大小;
-
记录 Tensor Arena;
-
测量总推理时间;
-
测量前处理和后处理时间;
-
记录功耗和电池工作状态。
阶段二:确认量化
-
使用真实代表性数据校准;
-
比较浮点和 int8 模型准确率;
-
确认输入、输出和中间算子是否真正整数化;
-
检查模型是否仍包含不支持的浮点算子。
阶段三:确认优化库
-
检查 CMSIS-NN 或厂商优化库是否编译;
-
确认目标 CPU 参数;
-
确认 DSP / SIMD / MVE 是否启用;
-
检查是否大量使用 Reference Kernel。
阶段四:分析模型结构
-
找到耗时最高的算子;
-
检查不支持的特殊算子;
-
检查通道数和张量形状;
-
评估是否可替换为更友好的算子;
-
检查中间激活峰值。
阶段五:优化系统
-
使用 DMA 和环形缓冲区;
-
避免串口输出进入计时范围;
-
让采样、推理和通信分任务运行;
-
调整推理频率;
-
减少无意义的无线发送;
-
缩短 MCU 活跃时间。
阶段六:重新验证
-
模型准确率是否下降;
-
新数据上性能是否稳定;
-
推理最坏时间是否满足要求;
-
RAM 是否存在越界风险;
-
设备温度和功耗是否合理;
-
优化后结果是否与原模型一致。
19. 关键概念解释
| 概念 | 通俗解释 | 技术解释 | 本章中的作用 |
|---|---|---|---|
| LiteRT for Microcontrollers | 让 MCU 看懂并运行模型的框架 | 面向微控制器的轻量 C++ 推理运行时 | 负责模型解释与算子调度 |
| CMSIS-NN | Cortex-M 的神经网络高速工具箱 | 针对 Cortex-M 优化的 NN Kernel 集合 | 加速计算密集算子 |
| Reference Kernel | 通用但不一定最快的实现 | 重点保证可移植性与正确性 | 提供算子回退路径 |
| Optimized Kernel | 针对芯片特点写的高速实现 | 使用 DSP、SIMD、MVE 或汇编优化 | 降低算子延迟 |
| Cycle-bound | 算得太慢 | 性能受计算指令数量和吞吐限制 | 需要减少计算或使用并行指令 |
| Memory-bound | 数据送得太慢 | 性能受内存带宽和访问延迟限制 | 需要数据复用和改善布局 |
| SIMD | 一次处理多个数据 | Single Instruction Multiple Data | 加速 int8 / int16 运算 |
| Intrinsic | 用 C/C++ 表示特殊指令 | 编译器提供的架构相关函数 | 比手写汇编更易维护 |
| im2col | 把卷积窗口排成矩阵 | 将卷积转换为矩阵乘法 | 提升计算效率但占用缓冲区 |
| Tensor Shape | 数据张量的维度 | 批次、高度、宽度、通道等维度配置 | 影响内核选择和向量效率 |
| Data Alignment | 数据按合适地址排列 | 满足处理器访问宽度或向量要求 | 避免额外内存访问开销 |
| Tensor Arena | MCU 运行模型的工作内存 | 存放输入、输出和中间张量的静态内存区 | 决定模型能否在 RAM 中运行 |
| Quantization | 用低位宽数字近似浮点值 | 将权重和激活转换为 int8 等格式 | 减小模型并适配整数内核 |
| Profiling | 找出时间花在哪里 | 测量算子延迟、内存和能耗 | 决定优化优先级 |
20. 本章案例复盘:一次完整优化如何发生?
假设有一个多通道 EMG 手势识别模型,初始情况为:
浮点模型
推理时间:120 ms
RAM 占用:420 KB
目标周期:50 ms
可以按照下面的流程优化:
第一步:模型 int8 量化
→ 模型体积和 RAM 下降
→ 推理时间降低到 75 ms
第二步:启用 CMSIS-NN
→ Conv 和 Fully Connected 使用优化内核
→ 推理时间降低到 38 ms
第三步:调整通道数和张量形状
→ 更适合 SIMD 处理
→ 推理时间降低到 30 ms
第四步:检查构建参数
→ 修正目标 CPU 和 Release 优化等级
→ 推理时间降低到 22 ms
第五步:复用滑动窗口缓冲区
→ 减少数据复制
→ 端到端时间降低到 18 ms
这个示例说明:
最终性能改善通常不是来自某一个"神奇按钮",而是来自多层优化的累积。
21. 本章还不能解决的问题
本章说明了优化的整体方法,但还不能直接回答:
-
某个 Edge Impulse 模型是否调用了 CMSIS-NN。
-
某个模型中哪个算子耗时最高。
-
具体开发板应使用多大的 Tensor Arena。
-
哪种编译选项最适合某个工程。
-
某个 int8 模型为什么准确率明显下降。
-
哪些张量维度最适合特定 Cortex-M 核心。
-
某个生理信号模型应使用 CNN、MLP 还是传统模型。
-
如何在真实硬件上精确测量每次推理能量。
-
如何同时优化采样、滤波、推理和 BLE 通信。
-
如何修改 CMSIS-NN 内核或自行编写 SIMD / MVE 算子。
这些问题需要结合具体模型、主控、工具链和测试数据进一步分析。
22. 本章总结
本章最重要的收获是:TinyML 优化是一项全链路协同工作。轻量模型和 LiteRT for Microcontrollers 让机器学习可以进入 MCU,CMSIS-NN 则通过纯 C、DSP / SIMD 和 MVE 等不同实现提高 Cortex-M 上的神经网络效率。但优化库只有在模型数据类型、算子、张量形状、编译参数和目标处理器配置都匹配时,才能发挥真正作用。量化为 int8 只是起点,内存访问、数据复用、im2col、通道布局、Tensor Arena 和完整应用的前后处理同样会决定最终速度。对于 EEG、ECG、EMG、PPG、HRV、GSR / EDA 等项目,优化目标也不能只写成"模型越快越好",而应根据不同信号的采样率、前处理负担、窗口长度和功耗需求,找到真正的系统瓶颈。
23. 参考资料
| 资料名称 | 类型 | 链接 | 与本章内容的关系 |
|---|---|---|---|
| LiteRT for Microcontrollers | Google 官方文档 | 官方页面 (Google AI for Developers) | 说明微控制器推理运行时的定位、内存要求和支持平台 |
| CMSIS-NN Documentation | Arm 官方文档 | 官方页面 (Arm Software) | 说明 CMSIS-NN 的算子类别、目标处理器和量化规范 |
| CMSIS-NN GitHub Repository | GitHub 开源项目 | 官方仓库 (GitHub) | 提供源码、许可证、算子支持和构建配置 |
| CMSIS-NN Current Operator Support | 官方开源文档 | 官方仓库说明 (GitHub) | 说明纯 C、DSP、MVE、int8、int16 和部分 int4 支持情况 |
| CMSIS-NN Convolution Functions | Arm 官方文档 | 官方页面 (Arm Software) | 用于解释 im2col、GEMM 和部分卷积缓冲策略 |
| LiteRT Post-training Quantization | Google 官方文档 | 官方页面 (Google AI for Developers) | 说明训练后量化对模型大小、延迟和内存的影响 |
| LiteRT 8-bit Quantization Specification | Google 官方文档 | 官方页面 (Google AI for Developers) | 说明 int8 的 scale、zero point 和按通道量化 |
| MobileNetV2: Inverted Residuals and Linear Bottlenecks | 经典学术论文 | 论文页面 (arXiv) | 说明轻量神经网络如何降低移动和边缘推理成本 |
| MLPerf Tiny Benchmark | 学术论文 / 行业基准 | 论文页面 (arXiv) | 强调应综合比较准确率、延迟和能耗 |
| MCUNetV2: Memory-Efficient Patch-based Inference | 学术论文 | 论文页面 (arXiv) | 说明按块推理如何降低 TinyML 的峰值内存 |
| TinyEngine | GitHub 开源项目 | 官方仓库 (GitHub) | 展示模型结构和 MCU 推理库协同优化的实现 |
| TensorFlow Lite Micro CMSIS-NN Sample --- Nordic | 官方开发文档 | 官方页面 (docs.nordicsemi.com) | 说明 nRF Connect SDK 中如何启用 CMSIS-NN 内核 |
| ESP-DL User Guide | Espressif 官方文档 | 官方文档 (Espressif Systems) | 补充 ESP 系列芯片的模型量化和优化推理路径 |
| STM32Cube AI Studio | ST 官方工具 | 官方页面 (STMicroelectronics) | 说明 STM32 模型分析、优化、代码生成与目标板验证 |
| RP2040 Documentation | Raspberry Pi 官方文档 | 官方页面 (Raspberry Pi) | 支持 RP2040 纯 C、整数化和双核任务优化分析 |