
做了这么多年嵌入式我明显感觉到圈子里的话风变了。以前聊AI总觉得那是云端那群人的事跟单片机八竿子打不着。直到这几年越来越多产品开始要求“本地智能”大家才慢慢反应过来AI嵌入式并不是把大模型硬塞进板子而是把模型压缩到足够小部署到边缘端去解决实际问题。这个方向业内叫TinyML也就是边缘微型机器学习。这篇文章想讲清楚一件事在典型单片机上TinyML到底能做什么。我不打算列一堆理论而是拆三个自己实际接触过的典型用例来聊——离线语音唤醒、旋转机械的振动异常监测、低功耗图像识别。每一个都会从场景取舍、数据怎么处理、模型怎么训练一路聊到部署到MCU上会踩哪些坑。适合正在做智能硬件、物联网产品想给设备端加“判断力”的嵌入式工程师。1. 先把“单片机跑大模型”这件事说透1.1 为什么一定要把模型放到边缘很多人第一反应是数据传云端不是挺好吗服务器性能强什么模型都能跑何必为难单片机这个想法放在十年前没错可放到真实的物联网场景里就会撞上四堵墙。第一堵墙是实时性。语音唤醒这种交互从喊出唤醒词到设备响应延迟超过几百毫秒人就会觉得“卡”。工业设备做故障保护要求在几十毫秒内对异常振动做出判断把原始波形发到云端再等推理结果回来黄花菜都凉了。第二堵墙是带宽和成本。一个振动监测节点以2kHz采样一秒钟就产生几千字节的原始数据。现场布几十个节点连续上传的话通信流量很快爆炸云端的存储和计算费用也跟着涨。边缘推理只需要把“正常”或“异常”这种结果传出去数据量从KB级降到Byte级。第三堵墙是功耗。无线节点如果每时每刻都在采样上传电池寿命只能按天算。换到边缘推理后MCU大部分时间处于睡眠状态只有检测到事件才醒来跑模型功耗能直接降两个数量级。第四堵墙是隐私。麦克风采集的语音、摄像头拍到的画面、振动数据背后反映的设备状态这些数据很多用户并不希望传到外部服务器。本地推理意味着原始数据不出设备只输出结论产品在合规和信任上的压力都会小很多。你会发现这四个约束只要占两条以上TinyML就是比“云端”更合理的架构。1.2 你以为的“大模型”和MCU上的模型不是一回事每次看到“单片机上部署大模型”这种说法总有人抬杠单片机连个像样的操作系统都跑不动跑大模型不是在开玩笑吗这里的“大模型”确实不是指在MCU上直接跑出参数量百亿的大模型。它指的是“从大模型技术栈压缩下来、能够在边缘运行的模型”。具体做法是先在服务器上训练一个表达能力强的模型——可能是几千万甚至上亿参数——然后用蒸馏、剪枝、量化三步把模型压成几十KB到几百KB的INT8定点模型再部署到MCU上。打个比方总部的大专家团队把所有场景研究透然后从里面提炼出一套适合嵌入式硬件的小技能交给精简后的学生模型继承。学生模型体积小了千万倍但在特定任务上能力保留得还不错。所以TinyML长期被误解本质上是很多人把“训练”和“推理”混为一谈了。大模型负责训练阶段的高成本高精度MCU只负责推理阶段的低功耗低成本。明白了这一点后面很多选型决策就顺了。1.3 三个硬指标决定模型能不能跑在MCU上做AI选型之前先算三笔账也就是三个硬指标。硬指标常见量级影响Flash存储256KB~1MB决定模型参数和代码能否放得下RAM内存64KB~256KB决定中间特征图能不能装下是最大瓶颈算力几十MHz~几百MHz决定推理延迟和能否做连续推理功耗预算待机uA级推理mA级决定推理频率和传感器策略从经验上看振动监测这类信号维度低、模型参数少对RAM和算力最友好语音唤醒次之卷积网络参数量中等但特征图不算大视觉识别最难激活缓冲区随输入分辨率快速膨胀RAM常常成为压死项目的最后一根稻草。所以真正动手之前先画一张“算力—内存—存储”的三角表能筛掉一半不切实际的方案。2. 第一类用例离线关键词唤醒2.1 场景与为什么必须本地响应智能音箱的“你好某助手”、智能门锁的语音开门、儿童玩具的语音指令这类产品几乎都有同一个要求唤醒词必须本地响应。原因很简单如果连唤醒都要联网设备断网就成了废铁而且唤醒这种高频操作如果每次都走云端延迟和流量都受不了。语音数据本身也敏感很多用户不愿意自己的录音被传出去做分析。把唤醒词模型放在MCU上语音信号从麦克风到模型推理全在本地完成产品在隐私层面会更有说服力。这些因素叠加在一起让“离线关键词唤醒”成了TinyML落地最成熟的用例之一。2.2 从麦克风信号到模型输入从声音到模型输入中间有一条完整的信号链。先说采样唤醒词场景通常用16kHz采样率、16bit位深这对人类语音来说足够也不会给MCU带来过大的数据压力。拿到原始PCM数据之后要做的是分帧加窗。一般取25~30毫秒作为一帧相邻帧之间重叠10~20毫秒保证特征不丢失。每一帧先乘一个窗函数然后做FFT再把频谱用梅尔滤波器组映射到梅尔刻度取对数后做离散余弦变换得到MFCC特征。常见做法是每帧提取10~13维MFCC系数。把连续20~40帧的MFCC拼在一起就构成了一张二维的“时频图”。对模型来说它看到的不是声音波形而是这张图。为什么选CNN而不是RNN来处理这种输入原因很简单CNN在MCU上没有时序依赖推理路径固定量化也更友好RNN的循环状态在定点运算里很容易积累误差处理起来麻烦得多。实际项目里常用的结构是两层普通卷积或深度可分离卷积再接一个全连接层输出唤醒词和非唤醒词的概率。参数量通常只有一两万INT8量化之后模型体积在25KB左右非常契合MCU的Flash空间。2.3 部署实测与两级唤醒架构我拿一个模拟项目的数据做个参考这个项目用的是常见M内核MCU主频约80MHz。项目数值输入40帧 × 13维MFCC模型大小INT8量化后约25KB激活RAM约14KB单次推理耗时约10ms唤醒前平均功耗几百uA~几mA量级这里有个特别值得说的设计两级唤醒。系统平时只跑一个极小的语音活动检测模型它的任务不是识别唤醒词而是判断当前有没有人在说话。一旦小模型检测到语音活动再启动完整的唤醒词识别模型。两级唤醒的价值在于小模型更小、更快可以一直挂机运行功耗极低大模型只在需要时才被唤醒整个系统的平均功耗被压得很低。这个逻辑在MCU上用状态机很容易实现是目前低功耗语音产品的主流做法。2.4 这个用例最容易踩的三个坑第一个坑是特征计算不一致。训练环境里用的MFCC参数比如帧长、帧移、滤波器个数必须和MCU端C代码实现完全一致。很多人在PC上跑模型效果很好部署到板子上一塌糊涂查到最后发现是特征代码的窗函数类型不同。第二个坑是麦克风增益和噪声。不同板子上的麦克风模拟增益不一样同一颗芯片在不同PCB上的底噪也不同。模型训练时一定要加入环境噪声增强、不同音量增强最好是拿真机录一段数据回灌训练集否则实际误唤醒率会高到你怀疑人生。第三个坑是误唤醒抑制。单帧模型的输出概率容易有毛刺一秒前的噪声可能突然触发一个高概率输出。工程上至少要做连续两帧概率都超过阈值才触发再加上一次短时静默检查误唤醒率才能压到可用水平。3. 第二类用例振动与声音异常检测3.1 为什么预测性维护是非主流但回报极高的TinyML场景相比语音唤醒振动监测在消费电子产品里没那么显眼但在工业场景里回报极高。电机、泵、皮带机这类旋转设备发生故障之前振动波形会先出现微妙变化。如果能提前捕捉就能避免停机检修和产线损失。传统做法是布网关把振动数据集中上传做分析。这种方案在厂区里施工成本高、维护麻烦而且很多老旧产线根本没有稳定的网络环境。TinyML的好处在于每个传感器节点本身就是一个判断单元正常时静默工作异常时本地产生告警事件远端只接收少量告警信息。数据不出现场模型不依赖网络部署和运维都简单得多。3.2 数据切片、频域特征与自编码器振动监测的模型设计和语音唤醒完全不同。语音是“判断这是什么词”振动监测更多是“判断这个状态正不正常”。数据层面加速度计或麦克风以1kHz~20kHz采样每次取1024或2048个采样点作为一片窗口。窗口加窗后做FFT把时域信号变换到频域。为什么一定要转频域因为频域对相位漂移、基线漂移不敏感而且旋转设备的异常往往集中出现在特定频段频域特征更稳定。接下来把关注的频段划分成几十个区间比如0~2kHz分成48个频带统计每个频带的能量作为模型的输入向量。模型结构我推荐用自编码器而不是传统的分类网络。自编码器是一个“输入—编码—解码—重建”的结构。训练时只用正常数据目标是在输出端重建出和输入一致的向量。推理时如果输入数据偏离正常分布重建误差就会变大。误差超过阈值就认为设备状态异常。为什么选自编码器因为故障样本太稀有故障类型又千奇百怪很难收集到足够的故障数据去练一个分类器。自编码器只需要正常样本就能学到“正常长什么样”这是它在工业场景里最实用的原因。这个模型的参数量通常只有几KINT8量化之后不到20KB。3.3 部署行为设计每一次推理都要算能耗振动监测节点在现场往往是电池供电所以部署时的核心原则是周期性采集按需推理绝不连续跑。实际的状态机大概是这样节点进入低功耗睡眠定时器按设定周期唤醒唤醒后给传感器供电采集一个窗口的数据DMA搬运完成MCU用几十毫秒做完FFT和模型推理输出结果之后立刻再次进入休眠。推理频率不需要过高。旋转机械的故障发展时间尺度通常以分钟计每5秒采一次数据、跑一次模型已经能捕捉绝大多数早期故障。把这个频率降到每5秒一次节点平均电流能做到1mA量级电池寿命从“月抛”变成“季抛”甚至“年抛”。告警逻辑也值得单独设计。单次推理的重建误差超过阈值不代表设备立即坏了可能的偶发干扰也会触发。工程上我会加一个防抖连续3个周期都超过阈值才上报告警。宁可晚几秒不能频繁误报。3.4 这个用例的坑基线漂移和傅里叶前端这个场景最容易翻车的地方不在模型本身而在数据分布。第一个坑是传感器安装位置。同一个设备轴承座顶上和侧面壳体上采集到的振动频谱差别非常大。模型训练数据必须覆盖实际安装位置否则现场很可能一片误报。第二个坑是设备之间的基线差异。同型号电机新出厂和运行五年的正常状态下的频谱能量都不一样。自编码器的重建阈值不能跨设备硬套部署后需要在每台设备上做一段正常数据采集用本地数据重新标定阈值。第三个坑是FFT前端。MCU上通常用定点FFT实现浮点模拟和定点实现之间的数值误差虽然小但在某些频带能量很低的场景会被放大。建议在板子上写一个自检程序把FFT输出和PC端对数看两者之间的误差是否在可接受范围避免把工具链的数值问题当成模型问题排查。4. 第三类用例低功耗视觉识别4.1 视觉上MCU的适用边界如果说前两类用例是“TinyML的舒适区”视觉识别就是“挑战区”。MCU上的视觉能做的事包括图像分类、物体存在性判断、简单场景识别不适合做高帧率连续检测、复杂目标分割。适合MCU的视觉场景有共同点目标相对静止、识别频率低、环境可控。比如智能门锁的摄像头判断有没有人靠近、电表箱里的表盘读数识别、野外昆虫监测相机等。这些场景的共同策略是“事件触发”平时CPU和摄像头都休眠被传感器唤醒后抓拍一帧推理完马上又睡。4.2 网络结构怎么压缩才能塞进去视觉模型不能在MCU上照搬MobileNet全家桶哪怕MobileNet已经算轻量直接跑M内核MCU也扛不住。要主动做结构裁剪。第一步降分辨率。输入图像从224x224降到64x64~160x160通常优先用灰度或单通道输入。80x80灰度图比224x224彩色图的数据量小一个数量级识别精度在受限场景里依然够用。第二步替换卷积结构。用深度可分离卷积替代普通卷积把计算量降一个量级。第三步尽早下采样。网络前两层就做池化把特征图快速缩小。我常用的一种轻量结构大概长这样层输出尺寸说明输入80×80×1灰度图Conv 3×3, 1680×80×16激活缓冲约25.6KB池化40×40×16DepthwiseConv 3240×40×32池化20×20×32DepthwiseConv 6420×20×64池化10×10×64全局平均池化64替代全连接省参数全连接输出10类这里最关键的一点是把尾部全连接层替换成全局平均池化。全连接层的参数量巨大但换成GAP之后模型权重能小一个量级对精度的影响却很小。4.3 事件驱动架构与实测数据MCU视觉的功耗大头往往不是推理本身而是摄像头和补光灯。一片图像传感器的功耗可能是MCU跑模型的几倍甚至几十倍所以视觉系统的架构必须是事件驱动的人体红外传感器或振动传感器先判断“有没有目标”确认有目标后才给摄像头供电拍一帧图像通过DMA转入SRAM然后MCU才跑推理。推理结束立刻断电回到睡眠状态。我跑过的一个视觉分类Demo输入80×80灰度图INT8量化模型权重几十KB单帧推理耗时约1到2秒。这个延迟对门锁、表计这类场景完全可接受因为用户感知等待的时间主要来自门锁机械结构而不是识别本身。4.4 视觉用例最大的坑视觉是三类用例里坑最多的我按出现频率排个序。第一是光照。真实世界的亮度变化极大同一件物体在白天和夜间拍出来在模型眼里可能是两种东西。训练数据必须做亮度扰动、对比度扰动最好直接把真实场景不同时间段拍摄的图像放进去否则现场效果会惨不忍睹。第二是量化敏感。视觉特征的激活分布往往带有长尾PTQ量化后精度回退比语音场景明显。遇到这种情况要转QAT也就是在训练过程中引入伪量化算子让模型适应低精度表示。第三是图像质量。很多团队把精力都花在调模型精度却忽略了摄像头对焦、镜头脏污、红外滤光片带来的偏色。这些图像前端的问题靠模型根本“救”不回来排查时要先怀疑成像链路。第四是目标检测场景。MCU上不要跑NMS这类复杂后处理直接在图像上用滑窗方式跑分类模型输出各个窗口的类别概率和位置把原始结果交给上位机去做框选。省内存又省算力实际效果还不错。5. 从模型到MCU完整落地流程与工程工具链5.1 实践下来的五步流水线很多初次接触TinyML的人以为模型训练完直接用工具转换就行。实际项目里我一般按这五步走第一步在通用深度学习框架里训练一个尽量准的浮点模型。这个阶段的目标是验证任务本身的可行性数据够不够、特征表达够不够、结构能不能收敛。第二步做模型极小化。用剪枝把不重要的通道去掉再用蒸馏把大模型的知识迁移到小模型把参数量压到目标范围。第三步转换并且校验。用芯片原厂的MCU工具链把模型转换成INT8定点格式。这一步要特别注意算子支持情况某些结构在原厂工具链里不支持会直接报错。第四步工程集成。写设备驱动、特征计算、推理运行时调用、电源管理逻辑把模型真正嵌进嵌入式工程。第五步真机回测。在板子上批量跑真机采集的数据把浮点模型在PC上的输出、定点模型在板子上的输出逐条对比。这一步能发现很多工具链报告不出来的问题。这一步看着多但每一步都不难难的是坚持把每步做扎实尤其是最后一步。5.2 PTQ与QAT怎么选量化是TinyML绕不开的话题INT8定点量化可以把模型体积压缩到原来的四分之一推理速度也能提升不少。PTQ也就是训练后量化流程很简单模型浮点训练好之后收集200到500条有代表性的校准数据统计每层激活值的分布范围算出缩放因子把权重和激活都转成INT8。这种方法时间成本低多数场景下够用。QAT也就是量化感知训练是在训练过程中就加入伪量化算子让模型提前适应低精度的“粗糙感”。它会允许梯度和参数一点点修正量化误差精度明显更稳代价是训练时间和调参成本上来了。我的建议是先做PTQ拿一个及格版本如果精度掉点超标再对敏感层做QAT或者混合精度。校准集的选择比量化方法本身更重要它必须覆盖真实场景的分布比如现场噪声、不同光照条件而不是随便拿训练集里的几百张图糊弄。5.3 内存的工程经验内存是MCU上跑模型最大的硬约束这里有几条实战经验值得分享。第一模型参数一定要放到Flash常量区不要放在RAM里。有些工具链默认把模型数据放到可读写段RAM水涨船高改一下段属性就能省出十几KB。第二优先选择支持共享激活缓冲区的推理运行时。早期很多方案是每层动态分配内存激活缓冲区一个叠一个RAM占用按倍数膨胀。改成共享缓冲之后所有层复用一块内存RAM占用能降到原来的三分之一。第三如果模型实在太大有一个技巧把模型放在外部SPI Flash里推理时按层把权重搬到内部RAM再计算算完一层就释放。虽然会慢一些但理论上可以跑比内部Flash大得多的模型。第四大工程建议用一个内存映射表格把每个缓冲区、每个模型的段地址都登记清楚。这个习惯在排查问题时能节省大量时间比临时用调试器看变量靠谱得多。5.4 部署后精度变差先查什么模型转换完上板精度回退是家常便饭。这时候不要急着怀疑量化先按这个清单排查预处理和特征提取的数值类型是否一致。固定点数格式、均值方差归一化参数是否原样搬到了C代码里。数据通路是否丢帧或错位。DMA缓冲是否覆盖了一整帧数据中断抢占了其他内存会不会污染输入。校准集分布是否偏离真实场景。校准用的是白噪声真机上是空调噪声怎么量化都会掉点。算子映射是否存在隐式替换。原厂工具链可能把一个算子映射成精度稍低的实现需要查看转换日志。中断和任务的并发问题。推理时数据被另一个任务改写这种问题日志根本看不出只能靠代码审查。我的经验是大多数TinyML项目部署后精度下降根本轮不到INT8量化背锅八成是前后处理没对齐。把这条清单走一遍往往能找到真凶。6. 三类用例之外我更想提醒大家的几件事6.1 先回答“为什么是TinyML”看完三类用例你会发现TinyML并不是万能的。如果产品网络稳定、数据不敏感、功耗没有极端的约束云端方案其实更灵活模型可以随便换、随时升级。TinyML的价值集中在五个约束上延迟、带宽、成本、功耗、隐私。只有当其中至少两条成为产品的硬需求时才值得把AI挪到MCU上。这听起来像在劝退但实际上是在帮你做取舍。拿着“别人都在做边缘AI”这样的理由立项项目大概率会中途返工。拿着真实的延迟和功耗需求去立项每一行代码才有方向。6.2 模型小不等于工程简单“唤醒模型只有25KB”“视觉权重只有几十KB”听起来很轻巧但背后是音频前端的联调、图像链路的校准、量产一致性的验证。模型压缩只是整个项目的一小段真正的工程量在传感器、驱动和现场环境适配。我见过太多团队在模型结构上死磕却在工程集成阶段被一个DMA缓冲对齐问题卡两周。模型小只代表算力门槛低不代表系统复杂度低。6.3 给正在入坑的人三个执行建议第一从“端到端最小切片”开始。哪怕精度一般也要先让数据从传感器流到模型再流到输出。这条链路一断后面每一步都会踩坑。第二尽早建立回测工具。在板子上写一个自动化脚本批量输入验证集数据同时输出模型推理结果和PC端结果对比。没有回测工具你根本无法判断一次改动是变好了还是变差了。第三提前对原厂工具链做算子测试。把自己的网络结构拆成最小算子逐个验证不要等部署时才发现某个常用操作不被支持。至少在我接手过的几个项目里只要把这三条放在最前面踩坑密度能下降一半以上。