2、基础知识:嵌入式视觉系统组成、内存类型(SRAM/Flash)与容量限制、典型应用场景
在进入 TinyML 内存受限视觉的实战之前,必须先建立对嵌入式视觉系统硬件底座的清晰认知。许多初学者在模型部署阶段遭遇的“内存溢出”“推理卡死”“帧率过低”等问题,根源往往不在于模型本身,而在于对系统组成、内存层次和容量边界缺乏系统性理解。本章将围绕嵌入式视觉系统的三大核心要素——系统组成、内存类型与容量限制、典型应用场景——展开深入剖析,为后续章节中关于输入尺寸、通道数与 Arena 控制的讨论奠定坚实的工程基础。
上图展示了嵌入式视觉系统的完整数据流与内存层次关系。从图像采集到后处理输出,每个环节都在与内存打交道。理解这条链路中数据如何流动、存储在哪里、何时被释放,是掌握 TinyML 内存优化的第一步。下面我们将逐一拆解每个组成部分的职责与内存特征。
2.1 嵌入式视觉系统的四大核心组成
一个典型的嵌入式视觉系统由图像采集、预处理、推理引擎、后处理输出四个模块构成。每个模块对内存的需求模式截然不同,理解这些差异是进行内存规划的前提。
2.1.1 图像采集模块
图像采集模块负责从物理世界中捕获视觉信息。主流方案包括:
- DVP(Digital Video Port)并行接口:常见于低成本的 OV7670、OV2640 等传感器,通过 8/10 位并行数据线传输,占用 GPIO 较多,但时序简单。
- MIPI-CSI 串行接口:用于更高分辨率的传感器(如 OV5640、IMX219),差分信号传输,抗干扰能力强,但需要 MCU 内置 MIPI 控制器。
采集模块的内存消耗主要体现在帧缓冲(Frame Buffer)上。例如,一个 QVGA(320×240)的 RGB565 图像,单帧占用 320×240×2 = 153,600 字节 ≈ 150KB。如果使用双缓冲(Ping-Pong 机制),则需 300KB。对于 SRAM 仅有 256KB 的 MCU 来说,这已经占据了绝大部分可用内存。因此,输入尺寸的选择直接受限于帧缓冲的分配策略。
2.1.2 图像预处理模块
预处理模块负责将原始图像转换为模型可接受的输入格式。典型操作包括:
- 格式转换:RGB565 → RGB888 → GRAY(灰度),减少通道数以降低计算量。
- 几何变换:缩放(Resize)、裁剪(Crop)、旋转(Rotate),用于对齐模型输入尺寸。
- 数值归一化:将像素值从 [0, 255] 映射到 [0, 1] 或 [-1, 1],或直接进行 uint8 量化。
预处理的内存开销通常为临时缓冲区。例如,将 320×240 的 RGB565 转换为 96×96 的灰度图,中间需要至少一个 96×96×1 = 9,216 字节的临时数组。如果预处理步骤过多,每个步骤都需要独立的缓冲区,内存碎片化问题就会显现。在实际工程中,推荐采用原地操作(In-place)或单缓冲区复用策略,将多个预处理步骤合并到同一块内存区域。
2.1.3 推理引擎模块
推理引擎是 TinyML 系统的核心计算单元。以 TensorFlow Lite for Microcontrollers(TFLite Micro)为例,其内存模型包含三个关键区域:
- 模型权重区:存储在 Flash 中,只读,不占用 SRAM。例如 MobileNetV1 的 96×96×3 输入版本,权重约 1.8MB,需要 2MB 以上的 Flash。
- Tensor Arena:这是 SRAM 中最重要的动态内存区域,用于存放中间激活值、临时张量和推理过程中的所有动态数据。Arena 的大小直接决定了模型能否成功部署。
- 算子工作区:某些算子(如卷积、深度可分离卷积)需要额外的临时缓冲区,这些也在 Arena 中分配。
推理引擎的内存消耗与输入尺寸、通道数呈非线性关系。例如,一个 3×3 卷积层,输入特征图 32×32×16,输出 32×32×32,其激活值内存为 32×32×32 = 32,768 字节。如果输入尺寸翻倍到 64×64,激活值变为 64×64×32 = 131,072 字节,增长了 4 倍。这就是为什么输入尺寸是内存优化的第一杠杆。
2.1.4 后处理与输出模块
后处理模块将推理结果转换为可执行的决策。常见操作包括:
- Softmax 归一化:将 logits 转换为概率分布,需要临时存储所有类别的概率值。
- 阈值判断:例如检测到目标时输出 1,否则输出 0。
- 结果编码:将分类结果编码为 UART 串口数据、LED 控制信号或显示屏刷新数据。
后处理的内存需求通常较小(几 KB 以内),但需要注意输出缓冲区的生命周期管理。如果后处理需要保留多帧结果(例如滑动窗口平均),则需额外分配历史结果缓冲区。
2.2 内存类型与容量限制深度解析
嵌入式系统的内存类型直接决定了数据存储的持久性和访问速度。下表对比了三种主要内存类型的特性:
| 内存类型 | 典型容量 | 访问速度 | 掉电保持 | 主要用途 | 成本特征 |
|---|---|---|---|---|---|
| SRAM(片上) | 16KB ~ 1MB | 极快(单周期) | 否 | 运行时数据、Arena、栈、堆 | 高(每 KB 成本最高) |
| Flash(片上/片外) | 256KB ~ 16MB | 慢(读 50-100ns) | 是 | 代码、模型权重、只读数据 | 中 |
| PSRAM/SDRAM(片外) | 2MB ~ 64MB | 中等(需刷新) | 否 | 大帧缓冲、扩展内存池 | 低(每 MB 成本低) |
在 TinyML 视觉任务中,SRAM 是最稀缺的资源。以 STM32F746 系列为例,其 SRAM 容量为 320KB,Flash 为 1MB。这意味着:
- 模型权重必须存放在 Flash 中,且不能超过 1MB(实际可用约 800KB,需留出代码空间)。
- Arena 大小不能超过 320KB,且需要与帧缓冲、预处理缓冲区共享这 320KB。
- 如果输入图像为 96×96×3(RGB),单帧原始数据为 27,648 字节,加上预处理临时缓冲区,留给 Arena 的空间可能只剩 200KB 左右。
2.3 典型应用场景与内存需求特征
不同的应用场景对内存的需求模式差异显著。下表总结了三种典型场景的内存特征:
| 应用场景 | 输入尺寸 | 模型大小 | SRAM 需求 | 帧率要求 | 典型 MCU 选型 |
|---|---|---|---|---|---|
| 关键词唤醒(KWS) | 10×10×1(MFCC) | 50-200KB | 30-80KB | 实时(<100ms) | Cortex-M4 @ 100MHz |
| 图像分类(简单物体) | 32×32×3 ~ 96×96×3 | 200KB-1MB | 100-250KB | 1-10 FPS | Cortex-M7 @ 400MHz |
| 物体检测(人脸/行人) | 128×128×3 ~ 192×192×3 | 1-3MB | 300KB-1MB | 0.5-5 FPS | Cortex-M7 + PSRAM |
2.3.1 场景一:低功耗智能门铃
一个典型的智能门铃需要实现“人形检测”功能,要求在 1 秒内完成一次推理,且平均功耗低于 10mW。系统约束如下:
- MCU:STM32L4 系列,SRAM 128KB,Flash 512KB。
- 摄像头:QVGA(320×240)灰度传感器,输出 8-bit 灰度图。
- 模型:MobileNetV1 96×96×1 输入,权重 400KB(Flash),Arena 需求 80KB。
内存分配方案:
SRAM 分配(总计 128KB):
- 帧缓冲(单缓冲):320×240×1 = 76,800 字节 ≈ 75KB
- 预处理临时区:96×96×1 = 9,216 字节 ≈ 9KB
- Tensor Arena:80KB
- 栈 + 堆 + 系统保留:约 20KB
- 总计:75 + 9 + 80 + 20 = 184KB > 128KB ❌
上述方案超出 SRAM 容量,必须优化。优化策略:
- 降低采集分辨率:将摄像头配置为 160×120(QQVGA),帧缓冲降至 160×120×1 = 19,200 字节 ≈ 19KB。
- 直接缩放采集:部分传感器支持硬件缩放,直接输出 96×96 灰度图,帧缓冲进一步降至 9,216 字节。
- 调整 Arena 分配:通过模型量化(int8)将 Arena 需求从 80KB 降至 50KB。
优化后:9,216 + 9,216 + 50,000 + 20,000 ≈ 88KB,满足 128KB 限制,且留有 40KB 余量。
2.3.2 场景二:工业视觉缺陷检测
在工业质检场景中,需要在传送带上检测产品表面的划痕。系统要求:
- 分辨率:128×128 RGB 输入,以捕捉细微缺陷。
- 检测精度:F1 分数 ≥ 0.95。
- 节拍:每件产品检测时间 ≤ 200ms。
该场景的内存挑战在于:128×128×3 的输入意味着单帧数据为 49,152 字节(RGB888),如果使用 RGB565 则为 32,768 字节。模型选择 MobileNetV2 128×128×3,权重约 1.2MB(Flash),Arena 需求约 180KB。此时需要选择带有 PSRAM 的 MCU(如 STM32H747 或 i.MX RT1062),将帧缓冲放在 PSRAM 中,SRAM 仅用于 Arena 和关键路径数据。
2.4 常见误区与设计复盘
在嵌入式视觉系统的内存规划中,以下误区最为常见:
误区一:只关注模型大小,忽略激活值内存
许多开发者认为“模型权重 300KB,Flash 有 1MB,肯定够用”。但实际部署时发现 Arena 需要 150KB,而 SRAM 只有 128KB,导致无法运行。激活值内存与输入尺寸、通道数直接相关,必须提前估算。
误区二:帧缓冲使用双缓冲,导致内存翻倍
双缓冲(Ping-Pong)可以提高采集与处理的并行度,但代价是内存翻倍。在 TinyML 场景中,如果推理时间小于帧间隔,单缓冲 + 等待机制通常足够。只有在需要持续采集且推理时间接近帧间隔时,才考虑双缓冲。
误区三:忽略预处理临时缓冲区
预处理步骤(如缩放、格式转换)需要临时存储中间结果。如果每个步骤都分配独立缓冲区,内存碎片化会非常严重。推荐使用内存池复用技术,将多个预处理步骤的临时缓冲区合并为一块。
复盘总结
本章的核心结论可以归纳为以下三点:
- 系统组成决定内存分布:采集、预处理、推理、后处理四个模块各自的内存需求模式不同,需要统一规划。
- SRAM 是硬约束:Flash 容量决定模型大小上限,但 SRAM 决定能否运行。选型时必须同时评估两者。
- 输入尺寸是第一优化杠杆:将输入从 128×128 降至 96×96,激活值内存可减少约 44%,这是最直接有效的内存优化手段。