
只让模型"见过正常",让它把正常规律学得非常熟;测试时,凡是"不符合正常规律"的片段,模型就还原不好,重构误差就会变大,于是判为异常。
这类方法通常叫做基于重构的无监督/单类时间序列异常检测,典型模型包括 AutoEncoder、LSTM-AE、TCN-AE、Transformer-AE、VAE 等。
1. 模型到底在学什么?
假设一个设备正常运行时有时间序列:
X=x1,x2,...,xT X=x_1,x_2,\\dots,x_T X=x1,x2,...,xT
比如燃气调压器可能同时采集:
xt=Pin,Pout,振动,声音 x_t=P_{in},P_{out},振动,声音 xt=Pin,Pout,振动,声音
训练数据全部或绝大多数是正常状态。
把一个正常时间窗口输入自编码器:
X→Encoder→z→Decoder→X^ X \rightarrow Encoder \rightarrow z \rightarrow Decoder \rightarrow \hat X X→Encoder→z→Decoder→X^
模型训练目标非常简单:
minθL(X,X^) \min_\theta L(X,\hat X) θminL(X,X^)
例如均方误差:
L=1T∑t=1T(xt−x^t)2 L=\frac{1}{T}\sum_{t=1}^{T}(x_t-\hat{x}_t)^2 L=T1t=1∑T(xt−x^t)2
模型反复看到正常数据之后,会逐渐学会:
"正常设备的压力应该怎么变化、振动应该是什么形状、不同测点之间应该是什么关系、前后时刻应该如何连续变化。"
因此它实际上学到的是一个正常行为模式空间。
2. 为什么异常数据重构误差会变大?
假设正常情况下出口压力是:
2.00, 2.02, 1.98, 2.01, 2.00 2.00,\ 2.02,\ 1.98,\ 2.01,\ 2.00 2.00, 2.02, 1.98, 2.01, 2.00
模型已经学得很好,所以输入正常数据时:
输入:
X=2.00,2.02,1.98,2.01,2.00 X=2.00,2.02,1.98,2.01,2.00 X=2.00,2.02,1.98,2.01,2.00
重构:
X^=2.01,2.01,1.99,2.00,2.01 \hat X=2.01,2.01,1.99,2.00,2.01 X^=2.01,2.01,1.99,2.00,2.01
误差很小:
E=0.01 E=0.01 E=0.01
但突然发生调压器阀杆卡滞:
Xabnormal=2.00,2.02,2.15,2.40,2.65 X_{abnormal} =2.00,2.02,2.15,2.40,2.65 Xabnormal=2.00,2.02,2.15,2.40,2.65
这种变化模式模型训练时没见过。
模型仍然倾向于按照自己理解的"正常规律"恢复:
X^=2.01,2.01,2.03,2.04,2.05 \hat X =2.01,2.01,2.03,2.04,2.05 X^=2.01,2.01,2.03,2.04,2.05
于是:
∣X−X^∣=0.01,0.01,0.12,0.36,0.60 |X-\hat X| =0.01,0.01,0.12,0.36,0.60 ∣X−X^∣=0.01,0.01,0.12,0.36,0.60
误差突然增大。
所以:
异常程度≈重构误差 \boxed{异常程度\approx重构误差} 异常程度≈重构误差
这就是最核心的原理。
3. 更本质一点:模型学的是"正常流形"
这个概念对你做SCI论文尤其重要。
现实中的时间序列看起来维度很高,例如一个窗口:
X∈R100×20 X\in R^{100\times20} X∈R100×20
100个时间点、20个传感器,相当于2000维。
但设备正常运行实际上并不是随便取2000个数字。
这些变量之间存在大量约束:
Pin→Pout P_{in}\rightarrow P_{out} Pin→Pout
流量↔压力 流量\leftrightarrow压力 流量↔压力
转速↔振动 转速\leftrightarrow振动 转速↔振动
负荷↔温度 负荷\leftrightarrow温度 负荷↔温度
因此正常数据其实只分布在高维空间中的一个很小区域,可以想象成:
text
高维数据空间
异常 ×
× 异常
┌─────────────┐
┌──┘ 正常数据区域 └──┐
● ● ● ● ● ● ● ● ●
● ● ● ● ● ● ●
└─────────┘
× 异常
AutoEncoder通过瓶颈层:
X→Encoderz X\xrightarrow{Encoder}z XEncoder z
实际上是在学习:
正常数据的低维流形 \boxed{\text{正常数据的低维流形}} 正常数据的低维流形
正常样本靠近这个流形,因此可以很好地重构。
异常样本偏离正常流形,因此模型只能把它"投影"回正常空间。
于是:
Reconstruction Error≈样本偏离正常流形的距离 \text{Reconstruction Error} \approx \text{样本偏离正常流形的距离} Reconstruction Error≈样本偏离正常流形的距离
这是比"模型没见过异常所以重构不好"更深一层的理解。
4. 最终怎么判断异常?
模型不是看到误差大就自动知道异常,还需要一个阈值:
Score(X)=1T∑t=1T(xt−x^t)2 Score(X)=\frac{1}{T}\sum_{t=1}^{T}(x_t-\hat x_t)^2 Score(X)=T1t=1∑T(xt−x^t)2
定义阈值:
τ \tau τ
如果:
Score(X)≤τ Score(X)\leq\tau Score(X)≤τ
判为:
Normal Normal Normal
如果:
Score(X)>τ Score(X)>\tau Score(X)>τ
判为:
Abnormal Abnormal Abnormal
也就是:
y={0,E≤τ1,E>τ \boxed{ y= \begin{cases} 0,&E\le\tau\\ 1,&E>\tau \end{cases}} y={0,1,E≤τE>τ
阈值可以用正常验证集误差分布确定,例如:
τ=μE+3σE \tau=\mu_E+3\sigma_E τ=μE+3σE
或者用95%、99%、99.5%分位数:
τ=Quantile(E,0.99) \tau=Quantile(E,0.99) τ=Quantile(E,0.99)
比如正常样本的误差基本都小于0.08:
text
重构误差
正常:
0.01 0.02 0.018 0.03 0.025 0.04 ...
阈值 τ=0.08
│
↓
────────────正常──────│────────异常────────>
│
0.18
0.32
0.70
于是误差超过0.08就产生异常报警。
5. 时间序列为什么不能简单"一个点一个点重构"?
这是时间序列异常检测非常关键的地方。
假设压力:
2.01,2.02,2.00,2.01,2.03 2.01,2.02,2.00,2.01,2.03 2.01,2.02,2.00,2.01,2.03
单独看每个值都正常。
但如果出现:
2.01,2.05,2.15,2.30,2.50 2.01,2.05,2.15,2.30,2.50 2.01,2.05,2.15,2.30,2.50
2.15这个值本身可能还没有越上下限,但上升趋势已经异常。
因此通常不是输入一个点:
xt x_t xt
而是输入滑动窗口:
Xt=xt−w+1,...,xt X_t=x_{t-w+1},...,x_t Xt=xt−w+1,...,xt
例如:
w=60 w=60 w=60
模型实际学习的是:
过去60个时刻应该具有怎样的动态变化规律。
所以它能发现传统阈值报警发现不了的:
- 缓慢漂移;
- 周期异常;
- 波动增大;
- 趋势突变;
- 变量间关系异常;
- 局部形状异常。
6. 多变量时间序列就更有意思了
比如正常调压器存在关系:
Pin↑, Flow↑, Pout≈稳定 P_{in}\uparrow,\ Flow\uparrow,\ P_{out}\approx稳定 Pin↑, Flow↑, Pout≈稳定
这是正常调压关系。
可能某一天:
Pin=正常 P_{in}=正常 Pin=正常
Pout=正常 P_{out}=正常 Pout=正常
Flow=正常 Flow=正常 Flow=正常
单独三个变量都没超限。
但是三者组合关系不正常。
多变量AE学习的是:
Pin,Pout,Flow,Vibration,... P_{in},P_{out},Flow,Vibration,\dots Pin,Pout,Flow,Vibration,...
之间的正常联合分布:
P(X1,X2,...,Xn) P(X_1,X_2,\dots,X_n) P(X1,X2,...,Xn)
所以这类异常叫:
Contextual / Correlation Anomaly \boxed{\text{Contextual / Correlation Anomaly}} Contextual / Correlation Anomaly
这恰恰是工业设备异常检测非常有价值的地方。
7. 但有一个很容易被论文忽略的问题
很多人会说:
"异常没参加训练,因此AE无法重构异常。"
这句话并不完全正确。
一个容量特别大的AutoEncoder可能连异常也重构得很好:
Xabnormal≈X^abnormal X_{abnormal}\approx\hat X_{abnormal} Xabnormal≈X^abnormal
那么:
Eabnormal E_{abnormal} Eabnormal
反而不大,就出现漏报。
这叫异常泛化或过度重构问题。
所以现在高水平时间序列异常检测论文已经不满足于:
AE+MSE AE+MSE AE+MSE
而是在研究:
怎样让正常和异常的异常分数真正拉开 \boxed{\text{怎样让正常和异常的异常分数真正拉开}} 怎样让正常和异常的异常分数真正拉开
例如:
Scorenormal↓ Score_{normal}\downarrow Scorenormal↓
同时:
Scoreabnormal↑ Score_{abnormal}\uparrow Scoreabnormal↑
因此才出现了很多方法:
重构 + 预测
S=αErecon+βEforecast S=\alpha E_{recon}+\beta E_{forecast} S=αErecon+βEforecast
重构 + 潜空间距离
S=αErecon+βD(z,MN) S=\alpha E_{recon}+\beta D(z,\mathcal M_N) S=αErecon+βD(z,MN)
重构 + 对比学习
让正常表示更紧凑:
zN→compact z_N\rightarrow compact zN→compact
异常远离正常区域。
以及 Memory AE、VAE、Diffusion、Transformer、Normalizing Flow、One-class learning 等。
8. 你可以这样理解整个过程
把模型想象成一个只训练过"正常心电图"的医生。
训练阶段:
看了10万张正常心电图。
最终他脑子里面形成了:
"正常心电图应该长什么样。"
测试阶段给他一条曲线,他先尝试按照自己理解的正常规律"画一遍"。
如果:
text
真实曲线 ───╮──╯────
模型重构 ───╮──╯────
两者非常接近:
Error≈0 Error\approx0 Error≈0
就是正常。
如果:
text
真实曲线 ──╭─╯╲╱╲╱────
模型重构 ──╭───────────
差异很大:
Error≫0 Error\gg0 Error≫0
就是异常。
所以它本质上不是:
"学习异常长什么样。"
而是:
"把正常学到足够精确,然后通过偏离正常的程度发现异常。"
9. 这类方法最大的价值
尤其适合工业故障诊断,因为现实中通常是:
正常数据≫异常数据 正常数据\gg异常数据 正常数据≫异常数据
例如设备运行一年:
正常:
99.9% 99.9\% 99.9%
真正故障:
0.1% 0.1\% 0.1%
而且未来会发生什么新故障,你根本不可能提前收集完整。
因此只学习正常样本,可以检测:
已知异常+一定程度上的未知异常 \text{已知异常}+\text{一定程度上的未知异常} 已知异常+一定程度上的未知异常
这也是它比传统监督分类:
Normal/FaultA/FaultB/FaultC Normal/FaultA/FaultB/FaultC Normal/FaultA/FaultB/FaultC
更适合工业现场的一个重要原因。
不过要注意一个概念区别:重构误差首先解决的是"异常检测"------有没有异常;它天然并不能回答"是什么故障、为什么故障"。 要真正做到你说的"异常诊断",通常还要再增加变量级误差归因、故障模式匹配、因果/机理分析。
例如最终可以进一步得到:
异常检测→异常定位→故障诊断 异常检测\rightarrow异常定位\rightarrow故障诊断 异常检测→异常定位→故障诊断
即:
正常建模→重构误差→异常评分→变量贡献度→故障类型 \boxed{ \text{正常建模} \rightarrow \text{重构误差} \rightarrow \text{异常评分} \rightarrow \text{变量贡献度} \rightarrow \text{故障类型} } 正常建模→重构误差→异常评分→变量贡献度→故障类型
"从重构异常检测走到可解释故障诊断"其实比单纯做一个AE更值得研究。