端侧 AI · 15 天工程路线
目录首页 English
DAY 06

端侧视觉流水线

在内存、带宽与实时约束中把摄像头帧变成稳定事件

建议阅读:约 20 分钟

学习目标

能够为 MCU/NPU 视觉系统计算峰值内存和带宽,定义 frame buffer、几何变换、后处理与所有权契约,并用稳态证据验收。

本章关键词

关键词解释ESP32 工程类比
峰值活跃内存某一时刻同时需要保留的所有 buffer 总量。像任务切换时同时占用的栈与 DMA 描述符。
PSRAM通过外部接口连接的大容量 RAM。像扩展仓库,容量大但访问和 DMA 规则不同。
Stride同一行相邻像素数据在内存中的跨度。像 DMA 行传输的实际步长,不总等于可见宽度。
Letterbox保持比例缩放并填充边缘的 resize 方法。像把不同长度 payload 装进固定帧但保留原比例。

承上:回顾与定位

Day 5 已把非 LLM 模型部署到 MCU;本章把资源账本与摄像头数据链合并,回答它能否在真实帧率、内存和热状态下长期稳定工作。

从源头看今天

历史发展脉络

端侧视觉能力来自轻量网络、内存层级、DMA 与完整前后处理共同演进。峰值算力只有在数据能及时到达、buffer 生命周期正确且输出可还原时才有意义。

2009

Roofline 把算力上限与带宽上限画在一起

Roofline 用运算强度连接峰值计算和可持续内存带宽,使“该优化算术还是减少搬运”成为可以测量和讨论的问题。

UC Berkeley Roofline 原始报告 ↗
2016

Eyeriss 量化了数据移动的能耗代价

Eyeriss 提出 row-stationary 数据流,利用局部存储和处理单元间通信复用权重、激活与部分和,强调少搬数据本身就是加速。

Eyeriss 原始论文页面 ↗
2020

MCUNet 把网络与推理引擎协同设计

MCUNet 用 TinyNAS 在设备约束内搜索网络,并让 TinyEngine 按整图生命周期调度内存,推动模型、runtime 和硬件联合优化。

MCUNet 原始论文 ↗
2012

深层 CNN 与 GPU 训练扩大视觉能力

AlexNet 在 ImageNet 上以深层卷积网络展示显著效果,推动视觉主干快速加深,也让部署侧开始面对更大的算力与内存压力。

AlexNet 原始论文 ↗
2015

YOLO 将检测统一为一次网络前向

YOLO 直接从整图预测边界框和类别概率,把检测从多阶段候选流程推向单阶段实时管线,突出端到端延迟的重要性。

YOLO 原始论文 ↗
现在

视觉模型被封装进完整设备流水线

ESP-WHO 等官方工程把摄像头驱动、图像处理、推理模型和示例应用组合起来,部署关注点从单个网络扩展到端到端链路。

ESP-WHO 官方仓库 ↗
今天为什么仍然重要: 今天应把一帧的每次格式、几何、所有权和存储层级变化写进同一条 trace,并在持续运行中观察内存低水位与时序稳定性。
借熟悉的系统建立直觉

类比图解

晚餐高峰期的一间小餐馆

冷库里食材很多,不代表厨房能同时做很多桌菜。切配台面积决定多少盘子能同时摊开,狭窄过道决定服务员搬菜的速度,专用烤炉虽然很快,却只接收合适的烤盘;每次把菜改盘、送进送出都会消耗时间。

外部冷库 Flash/PSRAM 中容量大但访问代价更高的权重和数据
切配台 内部 SRAM 中同时活跃的输入、输出与 workspace
传菜过道 内存总线、DMA、cache line 与持续带宽
专用烤炉 只支持部分算子、布局与 dtype 的 NPU delegate

类比的边界: 餐馆类比适合解释容量、吞吐和换盘成本,但真实存储层次并非互斥房间:cache 会自动替换,DMA 与 CPU 还可能并发访问同一物理内存。是否需要 flush、invalidate 或对齐,必须以芯片手册和实测为准。

本章讲解

峰值内存来自生命周期重叠,不是文件大小相加

为计算图列出每个 tensor 的产生节点、最后一次消费、大小和内存能力,画出活跃区间后才能求峰值。权重常可留在映射 Flash,激活、累加器和 kernel workspace 却可能在同一层同时存在;相机双缓冲、任务栈和网络包也要纳入系统峰值。规划器能复用生命周期不重叠的区域,但动态 shape、分支与 fallback 会改变计划,必须用运行时 high-water mark 校验静态估算。

用运算强度判断等待的是乘加器还是内存

粗算每个算子执行的 MAC 与从慢层级搬运的字节,得到“每字节做多少运算”的直觉;低运算强度路径更可能受带宽约束。提高主频或增加 NPU 单元只有在计算受限时才直接见效,带宽受限时应优先融合算子、分块复用、避免中间张量落地和改变布局。理论带宽是上限,连续读写、cache miss、总线争用与刷新协议决定可持续值,所以必须用接近真实访问模式的基准测量。

零拷贝是一份所有权协议,不是一处指针转换

让相机 DMA 写入模型输入可省一次复制,但前提是 buffer 的地址能力、对齐、stride、cache 一致性和生命周期都满足双方要求。CPU 在 DMA 完成前不能读取,DMA 复用前推理也必须释放;带 cache 的系统还需在正确方向做同步。建议用明确状态机标记 FREE、FILLING、READY、IN_USE,并把超时与丢帧计数写入日志。没有这些约束的“零拷贝”常变成偶发撕裂或陈旧数据。

先按业务需要选择输出粒度

只需判断“画面中是否有火焰”且目标占据稳定 ROI,可从分类开始;需要位置与数量才使用检测;需要像素级面积、边缘或可通行区域才考虑分割。输出越细,标签成本、后处理和内存通常越高。还要写明最小目标像素、允许遮挡和相机距离,因为输入分辨率决定信息上限。用业务事件回放比较候选方案,而不是拿不同数据集上的单一指标横向排名。

把 frame buffer 当成带描述符的二维存储

一帧不只有 width×height:还包含 RGB565、YUV 或 JPEG 等格式、每行 stride、平面排列、对齐和有效区域。JPEG 必须先解码,YUV 转 RGB 时要确认矩阵与范围;直接把有 padding 的行当连续像素会产生斜纹。相机驱动交出的 buffer 通常由池管理,推理完成前不得归还或覆盖。先用彩条、棋盘格和像素探针验证读取路径,再让模型介入,可快速隔离格式错误。

为每次几何变换保留可逆账本

预处理应记录原图尺寸、ROI 原点、缩放比例、填充宽度和模型输入尺寸。拉伸 resize 会改变物体形状;letterbox 保持比例却引入边缘填充,两者必须与训练配置一致。检测框或分割 mask 回到原图时,按变换逆序先去 padding、再除比例、再加 ROI 偏移,并裁剪到有效边界。用四角标记和已知矩形做单元测试,比肉眼看几个框更能发现半像素与取整偏差。

以分阶段回放验证实时流水线

保存一组可合法分享的原始帧,并为每帧留存模型输入、raw output、NMS 结果和回映射结果作为黄金记录。板端逐阶段计算摘要,与 PC 实现比较;同时记录采集、预处理、推理、后处理和排队耗时。压力测试要改变曝光、帧率和消费者速度,确认队列满时丢哪一帧、buffer 是否总能归还。最终 FPS 取决于最慢阶段和流水并发,并不等于模型单次推理的倒数。

让数据真正跑起来

动态过程演示

一帧图像到一个可信事件

播放器保留每次像素与坐标变换,直观看见候选如何被筛选并跨帧稳定。

步骤 1 / 6

DMA 采帧 · YUV/RGB/JPEG + stride + timestamp

相机填充池中 buffer 并移交所有权

观察点

一帧必须携带格式描述符

循环 / 返回条件: 下一帧回到 DMA 采帧;跟踪状态跨帧保留,而像素 buffer 在发布结果后立即归还相机池,二者生命周期不可混淆。

查看静态全景图
camera DMA → frame buffer → ROI/resize/letterbox → model partition
       ▲ ownership/stride      SRAM↔PSRAM↔NPU         │
       └──────── release ◄── NMS + temporal policy ◄──┘

代码或命令示例

frame = camera_acquire()
input, transform = preprocess(frame)
raw = infer(input)
event = postprocess(raw, transform)
camera_release(frame)
assert peak_live_bytes <= memory_budget

动手实验

选择一块 ESP32 摄像头板,列出 frame buffer、模型权重、tensor arena、临时 resize buffer 和输出的生命周期;计算峰值而非总和。回放一张带目标图片,保存原图、letterbox 后输入、raw output 和 NMS 结果,并验证框坐标可逆映射。连续运行 10 分钟记录 FPS、内存低水位、温度或功耗。
实验记录与导出

工程陷阱

避免误判: 把模型文件大小当峰值 RAM,或在 frame buffer 仍被 DMA/驱动持有时原地改写。资源预算必须按生命周期重叠计算,图像变换必须保存 stride、所有权和可逆几何信息。

核心测试

完成 3 道单选题后提交;提交前不会显示答案。

1. 端侧推理峰值 RAM 预算应至少包含?
2. letterbox 后为什么必须保存缩放和 padding?
3. 相机帧最安全的处理时机是?

一起把本章讲清楚

在 GitHub 上讨论本章

登录 GitHub 后提问、补充实测或分享你的实现;评论会保存在本课程的 GitHub Discussions 中。

评论区需要 JavaScript;也可以直接打开 GitHub 讨论区: 打开 GitHub 讨论区 ↗

延伸阅读

启下:下一章如何使用本章能力

下一章是课程分界点:从传统判别式端侧模型进入 LLM,建立语言模型发展脉络、核心术语和能力边界。

下一天: Day 7 · LLM 基础