基于重构的无监督/单类时间序列异常检测

只让模型"见过正常",让它把正常规律学得非常熟;测试时,凡是"不符合正常规律"的片段,模型就还原不好,重构误差就会变大,于是判为异常。

这类方法通常叫做基于重构的无监督/单类时间序列异常检测,典型模型包括 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更值得研究。

相关推荐
小宋10211 小时前
大模型成本怎么控制:Token统计、缓存与模型路由实战
人工智能·缓存
阿里云大数据AI技术1 小时前
DataWorks Data Agent 实战课堂(七):数据治理 Agent——AI 驱动的自动化治理
人工智能·agent
知识分享小能手1 小时前
深度学习学习教程,从入门到精通,数值计算 — 知识点详解(4)
人工智能·深度学习·学习
三声三视1 小时前
审计清单函数名写成 def?tri-checklist 的 diff 解析在 Python 改名场景下悄悄翻车
人工智能·ai·skillhub·tri-checklist·tri-skills
嘟嘟嘟95272 小时前
Kubernetes 引入 KYAML:更安全的 YAML 子集
人工智能·架构·开源
智购科技自动售货机厂家2 小时前
2026自动售货机设备清洁效果自动验证:从图像比对到评分算法的工程实践~YH
人工智能·算法·计算机视觉
财迅通Ai2 小时前
光智科技全景透视:一家被“光学元件”标签遮蔽的稀散金属材料平台
大数据·人工智能·科技·光智科技
AI技术新视界2 小时前
失控的认知外包:大语言模型如何像病毒般入侵人类思维与社会生态
人工智能·llm·认知科学
后端小肥肠2 小时前
还在找PPT 生成工具?我集成了 GitHub 高星 Skill,自动匹配最优方案
人工智能·aigc·agent