2、TinyML与异常检测基础:TinyML特点、资源约束、常见异常检测方法(统计、距离、机器学习)概述
TinyML 是机器学习与嵌入式物联网系统交叉融合的前沿领域,其核心目标是在毫瓦级甚至微瓦级功耗预算下,将深度学习、经典统计模型或信号处理算法部署到 MCU(微控制器)、DSP 或极低功耗 AI 加速器上。与云端训练、边缘推理的常规 ML 流程不同,TinyML 异常检测系统必须在 内存(RAM/Flash)、算力(MACs/周期)、功耗(电池寿命)和实时性 四重约束下完成数据采集、特征提取、推理和决策。理解这些约束是设计阈值、平衡误报与漏报的前提——因为资源限制直接决定了你能运行多复杂的模型、能缓存多长的历史窗口、能以多高的频率采样。
上图展示了 TinyML 异常检测系统的整体框架:左侧是硬件资源约束边界,右侧是可选算法谱系,底部是数据从采集到阈值判定的完整链路。值得注意的是,阈值设计并非独立环节,它贯穿于特征提取、模型推理和决策输出的全过程。在 TinyML 场景下,由于无法像云端那样存储大量历史数据或运行复杂网格搜索,阈值往往需要结合离线预标定与在线自适应两种策略。下面我们从 TinyML 的核心特点出发,深入剖析资源约束如何影响异常检测方法的选择与阈值设计。
2.1 TinyML 的核心特点与资源约束
TinyML 设备通常指那些面向特定任务、功耗极低、计算能力有限的嵌入式系统。与通用边缘计算设备(如树莓派、Jetson)相比,TinyML 设备具有以下显著特点:
- 极低功耗预算:整机功耗通常控制在 1mW~100mW 之间,电池供电场景下要求待机电流低至微安级,工作电流不超过数十毫安。这意味着异常检测算法不能持续全速运行,往往需要采用事件驱动或占空比调度策略。
- 有限的计算资源:MCU 主频通常在 80MHz~240MHz,且多数不具备硬件浮点单元(FPU),整数运算和定点量化是主流。一次乘法累加(MAC)操作可能需要多个时钟周期,因此算法复杂度必须控制在每秒几万到几百万次操作以内。
- 内存与存储瓶颈:RAM 大小从 16KB 到 512KB 不等,Flash 存储通常为 128KB~2MB。模型参数、中间特征图、滑动窗口缓冲区都需要精打细算。例如,一个 128 维的浮点特征向量占用 512 字节,若缓存 100 个历史样本则需要 50KB RAM,这已经占用了中端 MCU 的 1/4 内存。
- 实时性与确定性:工业异常检测往往要求毫秒级响应,且系统行为必须可预测。这意味着算法执行时间不能有大的抖动,动态内存分配(malloc/free)应尽量避免,递归调用和复杂数据结构也需要谨慎使用。
2.2 常见异常检测方法概述
在 TinyML 资源约束下,并非所有异常检测算法都适用。我们需要根据算法的时间复杂度、空间复杂度以及可解释性进行筛选。下表对比了三大类方法的 TinyML 适配性:
| 方法类别 | 典型算法 | 计算复杂度 | 内存需求 | TinyML 适配性 | 阈值设计特点 |
|---|---|---|---|---|---|
| 统计方法 | 3σ、EWMA、CUSUM | O(n) 极低 | 极低(仅需均值/方差) | ★★★★★ 非常适合 | 阈值可解析计算,易在线更新 |
| 距离方法 | kNN、LOF、马氏距离 | O(n²) 高 | 需存储训练样本集 | ★★☆☆☆ 受限(需压缩样本) | 阈值依赖距离分布,需离线确定 |
| 机器学习 | 孤立森林、SVM、小型MLP | O(n·log n) 中等 | 模型参数较大 | ★★★☆☆ 需量化压缩 | 阈值基于模型输出分数,需校准 |
从上表可以看出,统计方法在 TinyML 中占据主导地位,因为它们几乎不消耗额外内存,且阈值具有明确的统计含义。然而,统计方法对非平稳信号(如设备老化、环境温度漂移)的适应性较差,这时需要引入滑动窗口自适应阈值或轻量级在线学习机制。
2.2.1 统计方法:从 3σ 到 EWMA
最基础的统计异常检测假设数据服从正态分布,当新样本偏离均值超过 k 倍标准差时判定为异常。在 TinyML 中,我们通常使用递推公式在线更新均值和方差,避免存储全部历史数据:
// 在线更新均值与方差(Welford算法)
float count = 0, mean = 0, M2 = 0;
void update(float x) {
count += 1;
float delta = x - mean;
mean += delta / count;
float delta2 = x - mean;
M2 += delta * delta2;
float variance = M2 / count;
float stddev = sqrt(variance);
// 阈值判断: |x - mean| > k * stddev
}
然而,3σ 方法对趋势性变化不敏感。更稳健的做法是使用 EWMA(指数加权移动平均),它给予近期数据更高权重,能更快反映均值漂移:
// EWMA 异常检测
float lambda = 0.2; // 平滑因子
float ewma = 0, ewma_var = 0;
void ewma_update(float x) {
float diff = x - ewma;
ewma += lambda * diff;
ewma_var = (1 - lambda) * (ewma_var + lambda * diff * diff);
float threshold = 3 * sqrt(ewma_var);
if (fabs(x - ewma) > threshold) {
// 触发异常
}
}
2.2.2 距离方法:内存受限下的样本压缩
距离方法(如 kNN)在原始形式下需要存储大量训练样本,这在小内存 MCU 上不可行。实际工程中常采用两种变通方案:
- 原型压缩:使用聚类算法(如 K-Means)将训练数据压缩为 k 个簇中心,在线检测时计算新样本到最近簇中心的距离。例如,将 10000 个正常样本压缩为 16 个原型向量,每个向量 8 维,仅需 512 字节存储。
- 马氏距离:考虑特征相关性,但需要存储协方差矩阵的逆。对于 d 维特征,矩阵大小为 d×d,当 d=8 时仅需 256 字节,可接受;但 d=32 时需 4KB,已接近内存上限。
距离方法的阈值通常设定为“最大正常距离”或“距离分布的 95% 分位数”。由于 MCU 无法存储完整分布,我们可以在离线阶段计算好阈值,并将其作为常量写入 Flash。
2.2.3 机器学习方法:量化与剪枝后的轻量模型
当统计方法无法捕捉复杂非线性异常模式时,可以考虑小型机器学习模型。在 TinyML 中,最常用的是:
- 孤立森林:通过随机切割特征空间来隔离异常点。模型由多棵决策树组成,每棵树深度有限(通常 3~5 层),推理时只需沿树路径比较特征值。一个 10 棵树、深度 4 的孤立森林,每棵树约 15 个节点,总参数约 600 个整数,Flash 占用小于 2.5KB。
- 小型自编码器:将高维输入压缩到低维瓶颈再重建,重建误差作为异常分数。一个输入 8 维、隐藏层 4 维、输出 8 维的自编码器,权重参数约 80 个浮点数,量化后仅 320 字节。但自编码器需要乘法累加操作,在无 FPU 的 MCU 上需使用定点数模拟。
- 线性 SVM:对于线性可分问题,SVM 退化为一个权重向量和偏置,计算量极小。但实际工业数据往往非线性,需要核函数映射,这会显著增加计算量,因此 TinyML 中较少使用核 SVM。
2.3 案例拆解:振动监测中的方法选型与阈值初设
我们以一个实际的工业电机振动监测项目为例,说明如何在 TinyML 约束下选择异常检测方法并设计初始阈值。
背景与约束:某工厂需要在 50 台电机上部署无线振动传感器,每台电机配备一个 STM32L4 系列 MCU(Cortex-M4 @ 80MHz,无 FPU,RAM 64KB,Flash 512KB),使用加速度计以 800Hz 采样率采集振动信号,每 10 秒进行一次 1 秒窗口的 FFT 分析。电池容量为 2400mAh 锂亚电池,要求续航 2 年以上。系统需检测轴承磨损和不对中故障。
初始现象与目标:电机正常运行时,振动频谱在 1x 转频(约 25Hz)处有稳定峰值,幅值在 2~4 m/s² 之间;轴承早期磨损时,2x~4x 频段会出现边带。目标是在不误报的前提下,尽可能早地检测到轴承退化。
关键输入数据与参数:
- 特征提取:从 1 秒窗口的 FFT 中提取 4 个特征——1x 幅值、2x 幅值、高频段(500-800Hz)能量、波形峰度。
- 内存预算:特征缓冲区最多存储 200 个历史样本(每个样本 4 个 float,共 3.2KB),用于在线统计。
- 功耗预算:每次 FFT+特征提取约消耗 12mA 电流,持续 80ms,平均功耗约 0.96mAh/天,加上无线传输,总功耗需控制在 3mAh/天以内。
分析判断过程:由于特征维度低(4 维),且已知正常工况相对稳定,我们首先尝试统计方法。但发现 1x 幅值会随负载变化而波动,单纯 3σ 方法在负载波动时误报率高达 15%。于是改用 EWMA 对每个特征单独建模,并设置两个阈值:
// 特征1: 1x幅值,使用EWMA
float ewma_1x = 3.0; // 初始均值
float ewma_var_1x = 0.5;
float lambda = 0.15;
// 阈值: 3倍EWMA标准差
float thresh_1x = 3 * sqrt(ewma_var_1x); // 约1.5 m/s²
// 特征2: 高频能量,使用滑动窗口分位数
#define WINDOW_SIZE 100
float energy_buffer[WINDOW_SIZE];
// 每10秒更新一次,计算95%分位数作为阈值
实际操作步骤:
- 离线采集 3 台正常电机各 24 小时的数据,计算每个特征的 EWMA 初始均值和方差。
- 在 MCU 上实现 EWMA 更新逻辑,每 10 秒更新一次均值和方差,并动态调整阈值。
- 对于高频能量特征,由于它不服从正态分布,改用滑动窗口的 95% 分位数作为阈值,窗口大小 100 个样本(约 16.7 小时)。
- 设置两级报警:当 1 个特征超阈值时触发“关注”级别,当 2 个及以上特征同时超阈值时触发“报警”级别。
结果对比与复盘:部署 3 个月后,系统成功检测到 2 起轴承早期磨损(在振动加速度超标前 2~3 周预警),误报率为每台电机每月 0.3 次,低于预期的 1 次/月。但发现一个问题:当环境温度变化超过 15°C 时,1x 幅值的 EWMA 均值发生缓慢漂移,导致阈值自适应过宽,灵敏度下降。复盘后,我们在 EWMA 更新中加入了温度补偿系数,并将 λ 从 0.15 调整为 0.08,降低了温度漂移的影响。
2.4 常见误区与总结复盘
在 TinyML 异常检测的工程实践中,以下误区值得特别注意:
- 误区一:盲目追求复杂模型。在资源受限设备上,一个精心调参的 EWMA 往往比一个压缩后的深度网络更可靠。复杂模型不仅占用内存,还会引入量化误差和推理延迟,反而降低系统实时性。
- 误区二:忽略数据分布的非平稳性。工业设备存在磨损、温度漂移、负载变化等自然退化过程,固定阈值必然失效。必须设计阈值自适应机制,但自适应速度要慢于异常演化的速度,否则异常会被“自适应”掉。
- 误区三:阈值设定只关注误报率。在维护场景中,漏报的代价往往远高于误报——一次漏报可能导致设备损坏、产线停机,损失可能是误报成本的百倍。阈值设计应基于代价矩阵,而非单纯追求准确率。
- 误区四:在线更新阈值时忽略数值稳定性。在 MCU 上使用浮点数模拟时,方差可能因舍入误差变为负数,导致 sqrt 出错。建议使用 Welford 算法或定期重置统计量。