ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于自注意力与SMOTE的工业时序不平衡异常检测方法

2026/10/8 10:34:10 拓冰建站 浏览量
基于自注意力与SMOTE的工业时序不平衡异常检测方法 工业设备跑起来传感器每秒钟吐出来的数据看着都差不多可真正要命的那几个异常点往往藏在几万条正常记录里占比可能连百分之一都不到。这种时序不平衡异常检测的活儿干过的人都知道有多难受模型训练时正常样本把损失函数压得死死的异常样本的梯度几乎被淹没最后训出来的东西看着准确率挺高实际上一遇到故障就抓瞎。我最近在做一个旋转机械故障预警的项目就撞上了这个经典难题试了几种常规采样方案都不太理想后来把自注意力机制和SMOTE结合起来搞了个可学习的数据增强路子效果比预期好不少。这篇就把这套Deep Attention SMOTE的思路、实现细节和踩过的坑完整捋一遍适合做工业时序异常检测、设备预测性维护、以及任何被类别不平衡折磨过的朋友参考。1. 为什么常规SMOTE在时序异常检测里会翻车1.1 从工业场景的真实数据分布说起先把这个问题的背景交代清楚。工业时序数据的不平衡不是简单的“少数类样本少”它有几个很讨厌的特性。第一是时间连续性传感器采集的是连续信号异常往往表现为一段时间的模式偏移而不是孤立的一个点。第二是类间重叠严重很多异常在早期阶段和正常工况的波形非常接近只是幅值或频率有细微差别。第三是噪声干扰大现场电磁干扰、传感器漂移、工况切换都会产生类似异常的毛刺。我手上这个项目的数据来自一台齿轮箱的振动监测采样频率12.8kHz每段样本截取2048个点做特征提取。正常样本大概有八万多条标注出来的早期磨损异常只有六百多条比例接近130:1。这种量级下任何分类器都会倾向于把所有样本判成正常因为这样损失最小。1.2 标准SMOTE的致命缺陷SMOTE的思路很直观在少数类样本之间做线性插值生成新的合成样本。公式也不复杂对于两个少数类样本 $x_i$ 和其近邻 $x_{nn}$合成样本为$$x_{new} x_i \lambda \cdot (x_{nn} - x_i), \quad \lambda \in [0,1]$$问题就出在这个线性插值上。时序数据里两个异常样本如果在时间维度上处于不同相位直接线性插值出来的“合成异常”在物理上根本不存在。举个具体例子一个异常样本是齿轮啮合频率处出现边频带另一个异常样本是轴承外圈故障特征频率的冲击这两个样本在特征空间里可能距离不远都是异常但插值出来的东西既没有边频带也没有冲击纯粹是一团无意义的数值喂给模型反而引入噪声。更麻烦的是标准SMOTE对近邻的选择是盲目的它只看欧氏距离不考虑时序样本内部各时间步之间的依赖关系。工业时序的异常判别往往依赖于局部模式的突变和长程依赖的断裂这些信息在简单的距离度量下完全丢失了。1.3 可学习增强的核心动机既然固定规则的插值不靠谱那能不能让模型自己学一个增强策略这就是Deep Attention SMOTE的出发点。核心想法是用多头自注意力机制去捕捉时序样本内部的时间依赖结构在这个结构化的表示空间里做样本合成而不是在原始数值空间里瞎插值。同时合成过程本身是可学习的网络会根据下游异常检测任务的反馈来调整增强策略让生成的样本真正对分类有用而不是单纯地“看起来像异常”。这个思路的好处在于它把数据增强从预处理阶段的一个固定操作变成了和检测模型联合优化的一个模块。增强器生成的样本质量直接由检测损失来指导避免了人工设计增强规则时“拍脑袋”的问题。2. Deep Attention SMOTE的整体架构拆解2.1 三个核心模块的协作关系整套方法由三个部分组成时序编码器、注意力引导的样本合成器、异常检测分类头。这三者不是简单的串联而是通过联合训练形成闭环。时序编码器负责把原始的多变量时序片段映射到一个紧凑的表示空间。我用的是一维卷积加位置编码的结构卷积核负责提取局部波形特征位置编码保留时间顺序信息。编码后的表示维度是128每个时间步对应一个128维向量。样本合成器是核心创新点。它接收编码后的少数类样本表示通过多头自注意力计算样本内部各时间步之间的相关性权重然后基于这些权重做加权插值。注意这里的插值不是在整个样本层面做而是在时间步层面做每个时间步的合成系数由注意力权重动态决定。异常检测分类头就是一个简单的全连接网络加softmax输出二分类概率。它的损失函数同时反向传播给编码器和合成器驱动整个系统朝着“生成对分类最有帮助的样本”这个目标优化。2.2 为什么用多头自注意力而不是普通注意力普通注意力只能捕捉一种相关性模式而工业时序数据里的异常模式是多样的。有的异常表现为高频冲击需要关注相邻时间步的局部关系有的异常表现为周期性调制需要关注跨周期的长程关系。多头机制允许模型同时从多个子空间去建模这些不同的依赖模式。具体实现上我用了4个注意力头每个头的维度是32。查询、键、值的投影矩阵都是可学习的。对于长度为L的时序表示序列 $H \in \mathbb{R}^{L \times d}$第 $h$ 个头的注意力计算为$$A^{(h)} \text{softmax}\left(\frac{(H W_Q^{(h)})(H W_K^{(h)})^T}{\sqrt{d_k}}\right)$$其中 $d_k d / num_heads 32$。这个缩放因子很关键维度大了之后点积结果会很大softmax会进入饱和区梯度几乎为零。除以 $\sqrt{d_k}$ 能把方差拉回到合理范围。2.3 合成样本的生成公式有了注意力权重之后合成样本的生成方式是这样的对于两个少数类样本的表示 $H_i$ 和 $H_j$先分别计算它们各自的自注意力矩阵 $A_i$ 和 $A_j$然后用一个可学习的混合系数 $\alpha$ 来融合$$H_{new} \alpha \cdot (A_i H_i) (1-\alpha) \cdot (A_j H_j)$$这里的 $\alpha$ 不是固定的0.5而是由一个小的门控网络根据两个样本的注意力模式相似度动态输出的。如果两个样本的异常模式很接近$\alpha$ 会接近0.5做均匀混合如果模式差异大门控网络会倾向于选择注意力更集中的那个样本作为主导避免生成四不像的样本。这个设计比标准SMOTE的随机 $\lambda$ 高明的地方在于混合系数是有信息依据的它参考了样本内部的时间依赖结构而不是盲目随机。3. 从零实现的关键步骤与参数选择3.1 数据预处理与样本构造工业时序数据的第一步永远是清洗和分段。我的做法是先用滑动窗口把连续信号切成固定长度的片段窗口长度2048步长512保证相邻片段有75%的重叠这样不会漏掉窗口边界处的异常。然后对每个片段做z-score标准化注意这里的均值和方差是用训练集的正常样本统计出来的不能把测试集信息泄露进来。标签方面只要一个窗口内包含至少一个异常标注点就标为异常样本。这里有个取舍窗口太长会导致异常被稀释窗口太短又捕捉不到完整的异常模式。我试过1024、2048、4096三种长度2048在齿轮箱数据上效果最好故障特征频率的完整周期能覆盖到。少数类样本只有六百多条直接拿来做增强肯定不够所以先做了一步基于时间扭曲的粗增强把少数类扩到两千条左右作为Deep Attention SMOTE的输入。这一步是必要的因为注意力机制需要一定数量的样本才能学到有意义的模式样本太少注意力矩阵会退化成均匀分布。3.2 网络结构与超参数配置编码器的卷积层配置是第一层64个卷积核核大小7步长2第二层128个卷积核核大小5步长2第三层128个卷积核核大小3步长1。每层后面接BatchNorm和ReLU。位置编码用的是标准正弦编码最大长度支持512个时间步。合成器的注意力头数设为4前馈网络的隐藏维度是256dropout率0.1。门控网络是一个两层MLP输入是两个样本注意力矩阵的Frobenius范数差和余弦相似度输出一个标量经过sigmoid激活。训练时用了Adam优化器学习率初始3e-4每20个epoch衰减0.5。批次大小64其中正常样本和增强后的异常样本按1:1采样。总共训练了150个epoch在验证集上早停。这里有个关键细节增强器和分类器不能同时从零开始训练。如果一开始就让合成器生成样本它生成的完全是噪声会把分类器带偏。我的做法是前10个epoch只用原始少数类样本训练编码器和分类器让编码器先学到有意义的表示然后再启动合成器并且合成器的学习率设为分类器的十分之一让它慢慢跟上。3.3 损失函数的设计与权重总损失由三部分组成$$\mathcal{L} \mathcal{L}{cls} \beta \mathcal{L}{div} \gamma \mathcal{L}_{reg}$$$\mathcal{L}{cls}$ 是标准的交叉熵损失这是主任务。$\mathcal{L}{div}$ 是多样性损失防止合成器生成大量雷同的样本具体计算是合成样本两两之间的余弦相似度均值我们希望这个值低一些。$\mathcal{L}_{reg}$ 是正则项约束合成样本的表示不要偏离原始少数类样本的分布太远用马氏距离度量。权重方面$\beta$ 设为0.1$\gamma$ 设为0.05。这两个值是我调了大概十几组实验定下来的。$\beta$ 太大会导致合成样本为了追求多样性而失去异常特征太小又会让合成样本高度同质化。$\gamma$ 太大相当于把合成器锁死在原始分布附近失去了增强的意义。4. 实操过程中的坑与排查经验4.1 注意力矩阵退化成均匀分布这是我最开始遇到的最头疼的问题。训练了几十个epoch之后打印出注意力矩阵一看几乎是一个均匀矩阵每个时间步的权重都差不多。这意味着注意力机制根本没学到东西合成器退化成了普通的平均池化。排查下来原因有两个。一是位置编码的幅度太大正弦编码的值域在[-1,1]之间但编码器输出的特征值域大概在[-3,3]位置编码加进去之后反而成了主导注意力全被位置信息带偏了。解决办法是把位置编码乘一个0.1的缩放因子让它作为辅助信息而不是主导信息。二是注意力温度系数没调好。标准的 $\sqrt{d_k}$ 缩放在我的数据上偏大导致softmax输出过于平滑。我改成 $\sqrt{d_k} \times 0.5$ 之后注意力分布明显尖锐了模型开始关注特定的时间步。提示判断注意力是否退化不用等训练完前5个epoch就可以打印注意力矩阵的熵值。如果熵值接近 $\ln(L)$L是序列长度说明已经退化成均匀分布了赶紧调。4.2 合成样本导致的模式崩溃训练到中期的时候我发现检测器在验证集上的召回率突然掉了一大截查了半天发现是合成器开始“偷懒”了。它发现生成某一类特定的异常模式就是那种最明显的冲击特征能让分类损失降得最快于是所有合成样本都往那个方向靠导致其他类型的异常被忽略了。这个问题本质上是生成多样性不足。我加了多样性损失之后有所缓解但还不够。后来又加了一个基于聚类的重采样策略先对少数类样本做K-means聚类合成时强制从不同簇里选样本对保证覆盖到所有异常子类型。这个改动之后召回率恢复了而且对不同故障类型的检测更均衡了。4.3 训练不稳定的梯度问题联合训练增强器和分类器的时候梯度会经过合成样本反向传播到合成器再传到编码器。这条路径很长容易出现梯度消失或爆炸。我遇到过loss突然变成NaN的情况查出来是某几个合成样本的表示值过大经过softmax之后产生了数值溢出。解决办法是在合成器的输出后面加一个LayerNorm把合成样本的表示归一化到合理范围。另外在损失函数里加了一个梯度裁剪最大范数设为1.0。这两个措施之后训练就稳定多了。4.4 常见问题速查表问题现象可能原因排查方法解决措施注意力矩阵均匀位置编码过强或温度系数过大打印注意力熵值缩放位置编码调小温度系数召回率骤降合成样本模式崩溃可视化合成样本分布加多样性损失聚类重采样Loss变NaN梯度爆炸检查合成样本数值范围加LayerNorm梯度裁剪增强无效合成器学习率过高对比增强前后分类指标降低合成器学习率延迟启动过拟合合成样本过多看训练验证曲线差距控制合成比例加dropout5. 效果验证与对比实验5.1 评价指标的选择不平衡场景下准确率是没有意义的我主要看三个指标召回率、F1分数、AUC-PR。召回率反映漏报情况工业场景漏报一个故障的代价远大于误报。F1是召回和精确率的平衡。AUC-PR比AUC-ROC更适合不平衡数据因为它对少数类的表现更敏感。基线方法选了四个不做任何增强的原始训练、标准SMOTE、ADASYN、以及SMOTE结合随机欠采样。所有方法用同一个编码器和分类器结构只改增强部分保证对比公平。5.2 定量结果对比在测试集上的结果如下方法召回率F1分数AUC-PR无增强0.4120.3870.356标准SMOTE0.5830.5210.498ADASYN0.6010.5340.512SMOTE欠采样0.6270.5580.541Deep Attention SMOTE0.7840.7030.692提升还是很明显的。召回率从0.627提到0.784意味着原来漏掉的故障里有将近一半被找回来了。AUC-PR从0.541到0.692说明模型对少数类的排序能力有实质改善。5.3 消融实验分析为了搞清楚每个模块的贡献我做了消融实验。去掉多头机制改成单头注意力召回率降到0.731去掉门控网络用固定0.5混合降到0.712去掉多样性损失降到0.698。三个模块里多样性损失的影响最大说明防止模式崩溃确实是关键。还有一个有意思的发现把注意力换成普通的全连接层相当于在表示空间做线性插值召回率只有0.653比标准SMOTE好一点但远不如注意力版本。这验证了时序内部依赖建模的重要性。6. 工程落地时的实用建议6.1 数据量不足时的处理策略如果少数类样本连一百条都不到直接上Deep Attention SMOTE效果不会好因为注意力机制学不出有意义的模式。这种情况我建议先用基于物理模型的仿真数据做预训练比如齿轮箱的故障可以用动力学方程生成不同故障程度的振动信号拿这些仿真数据预训练编码器再用真实数据微调。仿真数据和真实数据之间肯定有域差异但编码器学到的底层特征提取能力是可以迁移的。另一个办法是迁移学习找同类型设备的公开数据集预训练比如轴承故障有公开的标准数据集可以用。虽然设备型号不同但故障的物理机理是相通的编码器学到的冲击特征、调制特征提取能力能复用。6.2 在线部署的延迟考量工业现场很多场景要求实时检测比如每秒钟要处理几十个窗口。Deep Attention SMOTE的训练阶段可以离线做但推理阶段只需要编码器和分类器合成器可以拿掉。编码器我实测在CPU上单样本推理大概8毫秒GPU上不到1毫秒完全能满足实时要求。如果连编码器的延迟都嫌大可以做模型蒸馏用一个浅层网络去拟合编码器的输出。我试过把三层卷积蒸馏成两层推理速度提升40%召回率只掉了2个百分点性价比很高。6.3 持续学习与模型更新工业设备的工况会随季节、负载、磨损程度变化模型部署后性能会慢慢下降。我的做法是维护一个异常样本缓冲区现场检测到的疑似异常经过人工确认后加入缓冲区定期用新数据重新训练合成器和分类器。注意编码器不要频繁更新否则表示空间一变之前合成的样本就失效了。编码器我一般半年更新一次合成器和分类器每月更新。注意重新训练时一定要保留一部分历史异常样本防止模型只适应新工况而遗忘旧故障模式。这是持续学习里的经典灾难性遗忘问题加历史样本回放是最简单有效的缓解手段。6.4 可解释性的处理工业场景里运维人员不信任黑盒模型你得告诉他为什么判为异常。我在分类头旁边加了一个注意力可视化模块把合成器和编码器的注意力权重叠加到原始振动波形上高亮出模型关注的时间段。实测下来模型关注的位置和故障特征频率出现的位置高度吻合运维人员看到这个对应关系之后就比较放心了。这个可视化还有个额外好处如果模型关注的位置明显不合理比如关注了信号开头的一段空白说明模型学偏了可以及早发现。我遇到过模型关注传感器刚上电时的瞬态响应那明显是数据预处理没做好把启动瞬态当成了异常特征。7. 几个容易被忽略的细节7.1 采样频率与窗口长度的匹配采样频率决定了你能看到多高的频率成分窗口长度决定了频率分辨率。这两个参数必须和你要检测的故障特征频率匹配。齿轮箱的啮合频率一般在几百到几千赫兹轴承故障特征频率在几十到几百赫兹。如果采样频率是12.8kHz窗口2048点频率分辨率是6.25Hz对于轴承故障特征频率来说够用但对于更精细的边频带分析可能不够。我的经验是窗口长度至少要覆盖故障特征频率的5到10个完整周期。轴承外圈故障特征频率如果是100Hz周期10毫秒采样12.8kHz的话一个周期128个点窗口至少640点取2048是留了余量。7.2 多变量通道的对齐问题工业设备往往有多个传感器通道比如三向加速度计。不同通道之间可能存在微小的时间延迟如果不对齐注意力机制会把这些延迟当成异常特征。我的做法是用互相关函数估计通道间的延迟然后做时间对齐。对齐精度要求不高误差在一个采样周期内就行。另外不同通道的量纲可能不同比如振动是加速度单位温度是摄氏度。标准化要分通道独立做不能全局标准化否则量纲大的通道会主导表示。7.3 合成样本的物理合理性检查虽然Deep Attention SMOTE生成的样本在表示空间里是合理的但映射回原始信号空间后还是要做一步物理合理性检查。我用的检查规则包括合成样本的频谱能量分布不能超出原始少数类样本的能量范围合成样本的时域峰值因子不能超过物理极限合成样本的自相关函数要保留故障特征频率的周期性。这些检查不需要很精确设一个宽松的阈值就行主要是过滤掉明显不合理的样本。我实测大概有5%到8%的合成样本会被过滤掉这个比例是正常的不用追求100%通过率。7.4 类别标签的噪声处理工业现场的异常标注往往不精确有时候是事后根据维修记录倒推的时间点可能有偏差。这种标签噪声会严重影响增强效果因为合成器会学到错误的异常模式。我的处理方法是标签平滑把硬标签0和1改成0.05和0.95让模型对标签有一定容错。另外对于标注时间点附近的样本降低其损失权重因为那些样本的标签最不确定。这套方法从数据预处理到模型训练再到工程落地整个链路我都跑通了在齿轮箱和轴承两个数据集上都验证过。核心思想其实不复杂就是把数据增强从固定规则变成可学习模块用注意力机制捕捉时序内部结构让增强服务于检测任务本身。真正花时间的是调参和排查各种训练不稳定的问题这些经验在论文里通常看不到但实际做项目的时候恰恰是最耗精力的部分。如果你也在做类似的工业异常检测项目建议先把基线跑通再逐步加模块每加一个都要做消融验证别一股脑全堆上去不然出了问题都不知道是哪个环节的锅。