前阵子一位做智能门锁的客户找到我,要求在他们那块用CR2032纽扣电池供电的主板上跑一个存在检测算法,平均功耗必须低于1mW。说实话,接到需求时我也愣了一下——在MCU上跑模型不难,难的是把整机功耗压到这样一个电池寿命还能撑半年以上的水平。后来我们测得整机运行功耗0.9mW,算法对静态人体的识别F1达到0.92,客户才放心把这套方案拿去量产。这件事让我特别想认真聊一聊:超低功耗Edge AI到底是怎么做到的。
做低功耗边缘AI这几年,我最大的感受是它和云端AI完全是两种物种。云端可以堆GPU、堆电费,边缘设备却要在几平方厘米的板子上用一颗纽扣电池把模型跑起来。这不只是模型压缩问题,而是从算法、硬件、存储、外设到电源策略整个系统的协同优化。这篇文章不会讲太多理论,我会结合自己真实跑过的项目,把超低功耗Edge AI背后那套“为什么”和“怎么做”完整拆开。
1. 为什么“超低功耗”会成为边缘AI的生死线
1.1 边缘AI与云端的本质差异
在云端部署AI,大家关注的是算力、吞吐量和GPU利用率,功耗通常被当作运营成本来统计。但在边缘侧,尤其是不插电的设备上,功耗直接决定产品能否落地。拿一把智能门锁来说,如果用户每开一次门都要等系统花一秒从睡眠唤醒、推理、上报云后台,体验就已经很糟糕了;可如果为了省电把唤醒方式改成“按按钮才识别”,那这“智能”又显得很蠢。超低功耗Edge AI要解决的问题,不是简单地把模型塞进MCU,而是要在有限的电池寿命内,做到你什么时候需要它,它就在什么时候慢慢醒来、快速推理、再安静睡去。
第二个差异是网络。很多边缘场景是在没有稳定Wi-Fi的环境下工作的,比如冷链运输记录仪、资产追踪器、农业传感器。如果每次推理都要把数据传回云端做判断,功耗主要耗在无线传输上,反而是本末倒置。所以把AI推理放到设备本地,目的之一就是降低通信频率,让无线模组只承担异常事件上报的职责。这才是“边缘AI”真正的价值放大器:本地算完,把结果浓缩成一条十几字节的消息传出去,而不是把原始数据一股脑推给云端。
我认为一个合格的边缘AI项目,不能只拿“推理延迟”或“准确率”当指标,还得加上“这次推理花了多少能量”。这两者经常出现冲突:降低延迟可以用高主频跑,但功耗立刻上去;反过来,把频率降到最低,延迟又可能不可接受。真正要平衡的是每帧能耗与响应速度。只有把这个问题想清楚,才不会被花哨的TOPS数带偏。
1.2 功耗预算的四个维度:算力、内存、无线、待机
做低功耗项目的第一步,是先把整机的功耗预算拆开。我一般会在设计阶段就列一张表,把四项核心耗电模块写清楚:
| 模块 | 典型工作电流 | 注意点 |
|---|---|---|
| MCU/SoC推理 | 1-50mA | 与主频、外设、活动系数强相关 |
| 内存/Flash访问 | 0.1-5mA | 低功耗模式时仍需供电刷新 |
| 无线(BLE/Wi-Fi/LoRa) | 5-150mA | 峰值电流极高,但可保持低占空比 |
| 待机(Sleep/RTC/漏电流) | 1-10uA | 直接影响电池寿命的“底座” |
很多人只盯着MCU的睡眠电流,却忽略了线性稳压器自身的静态电流和传感器常开电流。一颗LDO在轻载下如果静态功耗是15uA,那么它甚至比MCU的待机电流还高,整机寿命直接折半。所以我在选择超低功耗方案时,会优先看整套系统的“空载电流”,而不是只看板子上的主控。
这里有一个核心判断:如果边上的无线模组需要每秒钟发一次数据,那么无论模型做得多小,电池都会很快耗尽。所以优先压缩无线广播和同步频率,其次才是推理频率。推理任务能合并就合并,能缓存就缓存,否则一次无线传输所花掉的能量,可能够做几百次本地推理。实际项目里,很多号称“AI功耗太高”的问题,最后查出来其实是无线模块的广播占空比设得太激进。
2. 超低功耗边缘AI的技术栈拆解
2.1 算法侧:从量化到剪枝再到蒸馏
先说模型本身。在MCU级别跑AI,常用到的压缩手段有三个。
第一是量化。把常见的FP32权重压缩成INT8,参数量减少到原来的四分之一,同时乘加操作的带宽也降低不少。对很多CNN来说,INT8量化在精度损失上可以控制在1%以内,这已经有很好的实操收益。再激进一点的INT4甚至二值网络,功耗更友好,但精度波动会明显放大,尤其对回归任务不友好。量化并不是简单的取整,权重分布、激活范围、校准数据集都会影响最终效果,所以我会把它当作一个独立的小工程来做。
第二是剪枝。把权重里绝对值接近0的连接直接移除,稀疏后的模型可以在推理时跳过大量计算。不过MCU上的加速库对稀疏张量的支持不如GPU那么好,所以实际收益要结合算子库评估。我见过一个坏例子:剪枝让模型参数减少50%,但因为没有底层稀疏矩阵库支持,Flash占用没变、功耗也没降,反而因为稀疏索引导致代码路径变大。在MCU上,剪枝更适合用来分析哪些通道是冗余的,再手动改结构,而不是指望模型文件变小就能全自动提速。
第三是知识蒸馏。用大模型当教师,训练出更小的学生模型。蒸馏在小模型上的增益非常明显,比如一个3层卷积网络,直接从零训练准确率可能只有91%,用ResNet50蒸馏后能到93%,模型体量却一模一样。对边缘项目来说,蒸馏是成本最低的提点方式,因为训练阶段在云端/PC完成,部署时不需要额外付出。所以我的标准流程是:先用大模型做教师,蒸馏出一个小模型,再量化到INT8,最后做通道剪枝。顺序不要反,否则每一步的损失会叠加。
2.2 硬件侧:MCU、NPU与异构计算的取舍
硬件选型方面,我通常会分成三档。
第一档是超低功耗MCU,比如Cortex-M4/M33内核,集成低功耗设计,主频几十到一百多MHz,内置几MB Flash和1-2MB RAM。适合跑几百万参数以内的TinyML模型,比如关键词唤醒、手势识别、异常检测。这类MCU在20MHz下跑推理,功耗往往只有几mW,非常耐打。我自己很多项目就是把主频降到刚好满足实时性要求,再配合深度睡眠,整机平均电流能做到几十微安。
第二档是带NPU或DSP加速单元的边缘SoC,比如把低功耗CPU和NPU集成在一起,NPU能做几十GOPS以上,整体功耗几百mW到2W左右。适合跑轻量级YOLO、分割网络、姿态估计这些对算力要求更高的任务。这里要注意,NPU的峰值算力很漂亮,但周围的内存带宽和DDR自刷新才是功耗大户,实际项目里别只看TOPS。
第三档是纯MCU加上外置超低功耗AI加速芯片。这种方案适合项目需求已定的场景,比如在产品开发后期发现主控算力不够,又不想换平台。外置加速芯片通常异步集成,可以让主控长期休眠,只在需要推理时唤醒协处理器,大大降低整机平均功耗。选型时不能只看算力。有一个很反直觉的点:同样是执行一次MobileNetV2推理,高性能MCU在1秒内跑完然后进入深睡眠,可能比低性能MCU用10秒慢吞吞跑完更省电。因为深睡眠电流往往只有几uA,而推理期间则要维持几十mA。所以选型要结合工作负载,计算单次任务的能量,而不是只比较待机功耗。
2.3 工具链:TFLite Micro、Edge Impulse、STM32Cube.AI与Google AI Edge Gallery
工具链成熟度直接决定开发效率。我自己用得最多的是TFLite Micro,因为它的模型转换路径清晰:TF训练模型 -> 转换为TFLite -> 量化 -> 生成C++数组 -> 部署到MCU。它支持的算子有限,所以网络结构要尽量贴着它能跑的分支设计。如果是物联网场景,Edge Impulse这类平台也很方便,从采集数据到训练、部署、测试一条龙,适合团队里缺少嵌入式AI经验的场景。
还有一类厂商工具,比如STM32Cube.AI或NXP eIQ,特点是针对自家MCU做了深层汇编级优化,单个算子的计算更快,内存分配更紧凑。我测试过同一个INT8模型,用Cube.AI生成的代码比TFLite Micro在Cortex-M4上快15%左右,Flash占用也少一些。缺点是和具体芯片绑定,将来换平台要重新走一遍工具链。
最近几年Google也在推动AI Edge工具链,里面有一个面向端侧模型的Gallery模块,提供一组预训练、预量化的视觉和音频典型模型,可以在官方开发环境中直接获取并集成到边缘项目里。我实际体验下来,它的价值在于省掉了前期“找模型-转格式-踩精度坑”的时间,尤其适合快速搭一个POC。不过要注意,这类预置模型一般面向通用场景,真实部署时还是要用目标电域的少量数据做二次校准,否则精度可能偏低。依赖工具链是件好事,但别迷信。无论上游工具怎么优化,你至少得能手动导出每层算子的输入输出张量,学会看量化误差在哪一层开始变大。很多“精度崩了”的问题,最终都要靠debug每一层输出定位。
3. 我实测过的典型超低功耗边缘AI方案
3.1 关键词唤醒(KWS)在Cortex-M4上的功耗实测
先分享一个最经典的案例:关键词唤醒。拿市面上常见的唤醒词“Hey Device”来说,模型我选的是DS-CNN,输入是40维Mel频谱特征,时间窗口20ms,帧移10ms,网络结构是3层卷积加全连接,量化后参数约110KB,Flash占用还不到0.2MB。目标平台是Cortex-M4F @ 80MHz,RAM占用率约35KB。
推理一次的实际耗时我测出来是68ms。这里有个细节:把所有数据搬进局部缓冲区后,让CPU从Sleep状态唤醒执行,主频从1MHz动态切到80MHz,推理结束后再关掉FPU和DMA。用功率分析仪采样,单次推理的能量约68ms×9.6mA×1.8V=1.18mJ。如果设计成每500ms检查一次语音活动检测器,平均功耗大约是1.18mJ/500ms,折算下来大约2.4mW。所以真正部署时,不会让CNN这样定期跑,而是先用一个极低功耗的VAD持续监听环境声音,只有VAD判定可能有人说话,才唤醒CPU跑完整模型。
实际跑出来,VAD工作电流约1.2uA,CNN推理只占10%的唤醒比例,整机平均电流能做到约66uA。用一颗CR2032纽扣电池的可用容量180mAh来算,理论寿命可以到2700小时左右,大约100多天。这个方案已经量产过几次,关键不是模型有多小,而是把“唤醒触发条件”设计好,让CNN根本不需要经常跑。
3.2 人体存在检测:把MobileNetV2改到“面目全非”
第二个案例是人体存在检测,用于当人经过时唤醒室内设备。不要直接用MobileNetV2,那东西在MCU上太大了。我更倾向于用输入32×32的灰度图像,模型是自己搭的5层卷积+2层全连接,参数量约280KB,INT8量化后280KB。由于输入分辨率低,它实际等效于一个非常小的二分类器。我们在某国产Cortex-M33 MCU上跑,主频64MHz,单次推理92ms,工作电流7.8mA,平均能耗约1.29mJ。
客户实际要求是:人进入房间3秒内完成判断,设备环境照度变化也会触发传感器,所以不能只靠帧间差。这里我们做了两段式判断:先用极低分辨率的“帧间差”判断有没有运动,只有运动超过阈值才跑CNN,否则一直处于待机。经实测,在无人房间的动态功耗统计中,平均电流只有15uA,其中传感器+运放占了6uA,MCU睡眠+唤醒调度占了8uA,整机离1mW目标还差很远。后来把传感器调成0.2Hz采样、运放加使能控制,才压到9uA。
这个案例给了一个很关键的教训:模型再小,如果传感器一直以高频率采样并占用总线搬数据,功耗一样很高。要先把整条数据链路都休眠。我们的最终方案里,甚至让传感器平时也进入运动检测模式,只有当传感器自己认为可能有人时才触发MCU去读一次数据,这样才把有人进入3秒内响应的需求,和无人时低功耗的需求真正统一起来。
3.3 设备振动异常分类:零唤醒功耗的极致方案
第三个案例来自工业预测性维护。在一个振动传感器节点上,我们需要对机器正常/异常状态做分类。振动传感器用ADXL362,超低功耗模式,内置FIFO,采样率400Hz。传统思路是把MCU每20ms唤醒读一组数据做FFT,但这样MCU的工作电流太高。这里我采用了一个比较极致的方案:传感器本身的数据就绪中断接到MCU的LPTIM外部事件引脚,当FIFO积累到256个样本后唤醒一次MCU,批量取出数据做特征、跑1D-CNN,分类完毕进入深睡眠。
1D-CNN模型参数只有14KB,推理一次在Cortex-M0+ @ 32MHz上约12ms,平均电流大约4.2mA。因为每次推理间隔可以调到10分钟甚至更长,所以节点平均电流会被拉得很低。实际测试,加上LoRa每半小时上报一次,整机平均电流约28uA,用两节AA电池可以跑两年多。这里的要点是“批量处理”而非“边采边推理”,减少MCU唤醒次数才是降功耗的关键。如果把数据一个个取出来做处理,MCU每20ms醒一次,平均电流可能直接飙到几十倍。
从这三个案例能看出来,超低功耗Edge AI没有一个万能模型,更多是“事件驱动+小模型”的组合。核心思想是让AI在合适的时间做合适的事,而不是像服务器一样一直满负荷运转。
4. 把功耗压到极限的工程细节
4.1 模型量化位宽与精度损失的真实差异
上一节提到的模型都是INT8,但真到了压功耗的后期,你会忍不住想试试INT4甚至二值化。我的建议是:先从INT8开始,把整个链路跑通,再拿真实数据做校准,看精度的边际损失。下面是我在一组室内人体检测数据上做的对比:
| 量化方式 | 模型体积 | 静态准确率 | 单次推理能耗 |
|---|---|---|---|
| FP32 | 1.0x | 98.2% | 3.4mJ |
| INT8 | 0.25x | 97.8% | 1.2mJ |
| INT4 | 0.13x | 96.1% | 0.7mJ |
| 二值化 | 0.03x | 89.5% | 0.3mJ |
INT8是性价比最高的档位。INT4需要底层算子支持,且校准数据必须能覆盖所有典型场景,否则精度可能直接降到不可用。二值化更适合非常简单的模板匹配任务,对于真实图像分类我一般不建议量产。我还发现,INT4在STM32系列上兼容性参差不齐,有些NPU加速单元对INT4是软件模拟,反而更慢更耗电,所以在选低比特量化前,最好先在目标芯片上跑一遍算子profiling。
4.2 内存布局和DMA如何影响总功耗
很多人以为能耗只跟算力有关,但内存访问往往被忽略。对Cortex-M来说,从Flash取指令和数据的功耗明显高于从SRAM读,频繁访问Flash还会拖慢时间。一个很有效的做法是把频繁读取的权重和中间激活数组放到RAM里。但RAM是省功耗的奢侈品,非常有限。我的做法是先用工具统计每层算子的激活内存峰值,再把这层权重预留到RAM,其他仍然留在Flash,通过DMA批量搬运。
DMA的价值在于,它能把数据搬移和CPU计算重叠,让CPU进入wait-for-interrupt状态。比如推理时,先用DMA把下一帧特征搬到内存,CPU计算当前层;等到切换层时,直接使用已就绪的数据,减少CPU空转。我实测过一个10层CNN,加上DMA搬运后,平均电流从8.1mA降到7.3mA,下降了约10%,而延迟还缩短了5%。对于几百毫瓦的系统来说这是毛毛雨,但对于毫瓦级的系统,10%可能就是电池寿命差一个月。另外,把权重按访问频度重新排列,让连续读取命中最快的SRAM,也能一定程度减少Flash取指时间。
4.3 睡眠-唤醒策略:事件驱动与连续推理的取舍
在超低功耗系统里,“何时醒来”比“跑多快”更重要。常见的状态划分是睡眠态、事件检测态、推理态和无线发送态:
| 状态 | 电流 | 持续时间 |
|---|---|---|
| 深睡眠 | 2uA | 无穷大(直到事件) |
| 事件检测(传感器唤醒) | 20uA | 持续 |
| MCU唤醒+推理 | 7-15mA | 10-100ms |
| 无线发送 | 20-80mA | 5-20ms |
设计时,要把无线发送次数作为最优先压缩对象。一次BLE广播20ms、20mA,在3.3V下耗能1.32mJ,这个能量足够执行一次中等规模的CNN推理。所以如果能用“AI”判断出结果正常,不发无线数据,那节省的能量是显著的。这就是我常说的:AI的第一优先级是“过滤掉不需要上报的事件”,而不是“把每个事件都识别得淋漓尽致”。
事件驱动的关键是阈值选择。如果阈值太灵敏,MCU频繁醒,电量消耗和通信次数都增加;太迟钝,又出现漏报。我的经验是先用1-2周真实部署数据做离线回放,根据每周事件数和目标误报率来确定阈值,不要凭感觉调。有时候为了把阈值调准,甚至会让设备进入“影子模式”:AI本地推理,但不上报,只在后台记录结果,跑满一段时间后再统计真实事件率,然后固化阈值。这个方法成本很低,效果却非常明显。
4.4 实时性能指标:每帧能耗与推理时延
最后,给出一套我自己在方案评审时必用的指标计算方法。先测出单次推理的能量E_infer(单位mJ),再估出一段时间内的推理次数N,那么平均推理功耗就是E_infer×N/T_total。如果系统还有无线发送,则加上E_radio×M/T_total,以此类推。
举一个例子:以CR2032纽扣电池,可用容量约180mAh,标称电压3V,折合电能540mWh。如果系统平均功耗是1mW,理想寿命为540小时≈22.5天;如果压到0.5mW,则是45天;如果压到0.1mW,225天。可见要撑半年以上,平均功率必须压到0.2mW以内。这一目标反过来约束了推理次数和无线频率,是很清晰的量化关系。
要注意,电池实际可用容量受放电率、温度、内阻影响,不可能达到标称值。所以我在设计时会把目标寿命乘上1.5-2倍余量,并把低温场景单独测一遍。纽扣电池在低温下容量下降很厉害,而户外设备冬天恰恰是故障高发期。这些因素都要在方案评审阶段就写进文档,否则等测试阶段再发现,改硬件就来不及了。
5. 踩坑记录与避坑建议
5.1 模型太大,Flash塞不下
早期做TinyML时,我曾在选型时只盯着推理时延,忽略Flash密度,导致模型量化后120KB,但MCU片上Flash只有64KB。最后不得不重新设计网络,把输入从64×64改成48×48,参数从120KB降到90KB,同时把几个3×3卷积改用深度可分离卷积,最终Flash占用58KB,但精度也掉了2%。从那以后,我在项目启动前就会把模型大小、RAM峰值、算力需求、外设总线占满等四项指标写进选型表。
另一个常见问题是Flash塞下了,但RAM不够。模型权重可以放Flash,但中间激活数组必须在RAM里,如果RAM峰值超过MCU容量,推理根本跑不起来。解决方法是把部分层改成流式执行,或者用原地计算类操作,但这样会增加代码复杂度。所以选型时千万不要只盯着Flash,RAM峰值可能才是真正的瓶颈。我的经验是:先用脚本跑一遍网络结构,得到每层的激活大小和权重大小,再去找匹配的MCU。
5.2 量化后精度崩盘的五种常见原因
量化是超低功耗边缘AI最常见的翻车点。我总结过五种情况。
第一,校准数据集太小,只有几百张,无法覆盖真实分布,导致量化缩放因子偏差大。第二,网络里有明显的离群权重,压缩后动态范围被少数几个大值拉偏。第三,逐层量化时没有考虑前后层的激活分布,某些通道饱和严重。第四,某些算子(如softmax)被量化后误差被放大,很多框架会强制浮点,但有人手动关掉导致精度丢失。第五,量化后直接部署,没有用目标电域的真实样本做验证,离线测试看起来精度高,上板就崩。
解决方案很简单但费时:先做1000张左右的数据校准,用工具打印每层输出误差,逐步定位;训练时增加量化感知训练,前端加量程限制;推理时对敏感层用浮点混合计算。我发现大部分精度崩盘问题,最后都出在校准数据集和真实场景分布不一致上,而不是模型本身。所以建议在采集数据时,多去几个时间段、几种光线、几种设备位置,让校准集尽量贴近真实环境。
5.3 电池供电下电压跌落导致的复位
低功耗设备最怕“临界复位”。推理开始时主控全速运行,电流骤增,电池内阻和PCB走线电阻产生压降。如果电压掉到MCU掉电阈值以下,系统就会复位,刚算到一半的模型直接丢失。有一次我在做无线节点时,LoRa发射瞬间电流冲到150mA,锂电池瞬时电压从3.7降到3.1V,MCU都复位了。
解决思路有三条。第一,硬件上在电源入口放一个大容量钽电容或超级电容,吸收瞬态压降。第二,用带欠压锁定功能的稳压器,保持输出稳定。第三,软件上把推理和无线发送分时错开,不要在峰值高的时候同时启动。最简单的做法是在启动LoRa之前,先让MCU进入空闲态等2-3ms,再发送,避免叠加电流尖峰。这个问题在纽扣电池场景更明显,因为电池内阻更大,瞬间大电流会把电压拉得非常低,所以一定要预留足够的电源余量。
5.4 调试时感觉功耗高?先检查外设状态
这类问题十次有九次是软件配置问题。有一次我明明把MCU睡到2uA,但整机还有300uA,查到最后是GPIO引脚浮空输入,内部弱上拉没用,外部电平悬空导致半导体泄漏电流。另一次是调试器的SWD接口未隔离,仿真器一直在线,MCU无法真正睡眠。所以设计低功耗设备时,我建议在PCB上预留一个测试电阻,能断开调试器电源;量产固件里把debug接口关闭。还有LED,调试时点亮,量产时如果忘关,几个毫安就飘走了。归根到底,拿到功耗异常后,先用排除法切断传感器、无线模块、指示灯,再逐块检查。
最后再分享一个我在很多项目里屡试不爽的小技巧:别把整个系统当成一个整体去调功耗,先把主控、传感器、无线、稳压器拆成四个独立模块,分别测出待机和峰值功耗,然后填进一张功耗分配表。这样哪怕最终整机功耗超标,也能很快定位是哪个模块拖了后腿。说实话,这些手段单独拿出来都不神秘,难点在于把模型压缩、事件驱动、硬件协同这串动作当成一个整体去做。只要你能把自己方案的单次推理能量和唤醒次数算清楚,功耗自然会被压下来。我个人做项目时,一定会先跑通这张能量账本,再回头调精度和延迟——顺序反了,后面大概率要返工。