☰
聚类欠采样+孪生自注意力:破解故障诊断中样本极不平衡的实战方案
2026/10/21 17:23:22 网站建设 项目流程

1. 从故障数据说起:不平衡是常态,不是例外

做故障诊断的人都有这种经历:现场采集回来的数据,正常样本动辄几十万条,故障样本可能只有几十条,甚至有些故障类型只有几条样本。真正去做模型时才发现,传统分类器在这一堆数据上训练出来,准确率看着有99%,实际拿故障样本一测,几乎全被当成正常样本放过去了。这不是模型不行,是数据分布本身就把模型带偏了。

这个项目尝试的思路很明确:数据层面用聚类欠采样把多数类(正常样本)重新裁剪,模型层面用孪生自注意力网络去提取真正有判别力的特征,两头发力解决类别不平衡问题。整套方案不依赖复杂的信号处理先验知识,也不需要在现场囤积海量故障数据,核心思路就是“让模型在极少量故障样本下也能学到有用的判别边界”。

这篇内容适合正在做设备故障诊断、工业PHM方向的研究生和算法工程师看。如果你也遇到过“数据集不平衡得离谱、模型一测故障就拉胯”的情况,这里的思路和踩坑记录应该能给你一些启发。

先说一个基本观点:不平衡问题不是“加数据”就能解决的。故障样本就那几条,加噪、滑窗、生成对抗网络,能试的都试过,但生成的样本要么和真实故障形态差太远,要么直接把模型带出一种“假把式”的自信。聚类欠采样加孪生网络的组合,走的是另一条路——不追求增加少数类数量,而是让模型在极不均衡的对比中学会“不一样意味着什么”。

2. 方案选型:为什么偏偏是聚类欠采样加孪生自注意力

2.1 先看清楚常规做法的问题在哪

处理不平衡数据,最常见的三板斧:随机欠采样、随机过采样、SMOTE。

随机欠采样就是从多数类里随机丢掉一部分样本,让两类数量差不多。思路简单,但问题致命:正常样本内部本来就有不同运行工况、不同载荷状态、不同退化程度,你随机删掉一批,很可能把某些工况下的特征信息整段删掉,模型对正常样本的覆盖面一下就窄了。等到现场来一个没见过的正常工况,直接误报成故障。

随机过采样就是把少数类样本复制几遍,让数量跟上多数类。这个做法更应付不了事——复制出来的样本和原样本一模一样,模型看到的“多样性”是假的,训练时反复见同样几个点,过拟合几乎是必然的。

SMOTE在少数类样本之间插值生成新样本,看着聪明一点,但故障信号这东西,插值出来的“中间形态”往往是毫无物理意义的噪声。真实故障是某种确定性的机械异常,你把它和另一个故障样本平均一下,出来的东西既不像故障A也不像故障B,模型学到这种人造形态,现场一点用不上。

2.2 聚类欠采样的核心逻辑

聚类欠采样的思路是:正常样本不是铁板一块,内部有结构。不同转速、不同负载、不同运行阶段对应的振动特征是不一样的,它们天然会形成若干个簇。与其盲目地随机删,不如先用无监督聚类把正常样本分群,然后从每一个簇里按比例抽取样本。

这么做的直接好处有三个。第一,保留正常样本的多样性——每个工况簇都被抽到,不会出现某个正常形态被整体删除的惨案;第二,控制采样比例的时候有了抓手——你可以根据每个簇的样本密度决定抽样数量,密度高的簇多删一点,密度低的簇少删一点;第三,聚类本身会暴露正常样本内部的异常小簇——如果有一些“正常样本”聚合成了一个离群的小簇,往往意味着那是尚未标记的异常状态,值得单独检查。

2.3 孪生自注意力网络的选型逻辑

采样把数据理了一遍,接下来就是模型。这个场景里选孪生网络而不是普通CNN分类器,核心原因是:故障样本太少,直接做多分类是“用最稀缺的数据学最复杂的决策面”,学不动。

孪生网络做的事情不是直接分类,而是判断“两个样本是不是同一类”。这种相似度度量任务的样本对可以自由组合——正常和正常是一对,故障和正常是一对,故障和故障是一对。通过样本对的构造,即使故障样本只有几十条,也能组合出大量训练样本。注意,不是复制几十条,而是“正常-故障”配对就有“大量正常样本×几十条故障样本”这么多种组合,训练数据瞬间就丰富起来了。

自注意力模块在这里解决的是另一个问题:故障信号的关键判别信息往往只集中在整个样本的某一段上。可能是转频的某个倍频处出现边频带,可能是某个冲击周期出现变化,但整个序列很长,真正有效的特征只占一小部分。普通卷积层的感受野有限,堆深了又容易过拟合。自注意力机制能直接计算序列中每个位置和其他所有位置的关系,模型可以自动学会“注意力放在哪个区段”,相当于帮特征提取器装了一个自动对焦的镜头。

所以整套方案的逻辑链是:聚类欠采样解决数据分布问题,孪生结构解决样本稀缺问题,自注意力解决特征定位问题。三个环节各自解决一个具体矛盾,不是简单堆砌技术名词。

3. 聚类欠采样的工程实现细节

3.1 在什么空间做聚类

这是第一个容易踩坑的地方。很多人拿到数据就直接对原始波形做聚类,效果往往很差。原因很简单:原始振动波形是几百上千个时间点,每个样本的相位、幅值、噪声都不同,直接在这个空间算欧氏距离,反映的是“波形对齐程度”而不是“工况相似程度”。

更稳的做法是先做一个轻量级的特征提取,比如提取常用的时域统计量——均方根值、峰值因子、峭度、波形因子、脉冲指标等,再把特征向量喂给聚类算法。也可以先用一个预训练的自动编码器或CNN把样本压成一个低维嵌入向量,再用嵌入向量聚类。实际操作里,时域统计指标加KMeans通常就够用,性价比最高;如果发现聚类结果不稳定,再换成基于自编码器得到的特征嵌入。这一个选择,直接决定后面采样出来的“代表性样本”靠不靠谱。

3.2 聚类簇数K的选择

KMeans需要预先指定簇数K。选多少合适,没有放之四海而皆准的标准答案,但有几个经验做法:

  • 用肘部法画簇内误差平方和曲线,找拐点;
  • 用轮廓系数检查聚类质量,一般取轮廓系数最大的K;
  • 结合现场工况信息——比如你知道设备一共有几个转速档位、几种负载工况,K就取工况数的2到3倍,给每个工况留出内部子状态的余量。

更保险的做法是多跑几组K值,分别在后面模型验证集上试效果,选泛化性能好的那个K。这个做法虽然笨,但可靠性高。聚类本身是手段不是目的,最后还是要以故障诊断的指标论英雄。

3.3 采样比例怎么设计

聚类完成后,每个簇里的样本量通常差别很大。采样时我用的策略是:

  • 先统计每个簇的样本数量N簇;
  • 设定目标总采样数M,M的建议值是故障样本数量的2到4倍,太少则决策边界仍然偏向正常类,太多则会进一步压缩正常样本的信息量;
  • 每个簇的采样数为M乘以权重,权重与该簇样本量占总量的比例相关,同时限制每个簇最少保留一定数量的样本,防止某些小簇被抽空。

这里有个细节:不是每个簇都均匀采样最好。如果某些簇对应的恰好是比较少见的正常工况,这类样本信息量高,应该适当多保留一点,采样权重上调。实际操作可以给每个簇计算平均样本距离(簇越紧凑代表该工况越稳定,越可以少留),或者直接依赖聚类后的异常检测修正权重。

采样完成之后,把多数类子集和少数类故障样本合并成新训练集。合并后建议再跑一次简单的分布检查——比如PCA投影看两类样本在低维空间里是否仍然明显重叠,如果重叠得很厉害,说明故障特征本身太弱或者传感器测点不合适,后面模型训练也得先解决这个前提。

3.4 代码框架参考

整个采样过程用代码实现不算复杂,提供一个我实践过的流程参考:

from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler # 假设X_majority为多数类样本,X_minority为少数类样本 scaler = StandardScaler() X_scaled = scaler.fit_transform(X_majority) # 特征空间上的K聚类 kmeans = KMeans(n_clusters=5, n_init=10, random_state=42) labels = kmeans.fit_predict(X_scaled) # 获取每个簇的索引 cluster_indices = {} for idx, label in enumerate(labels): cluster_indices.setdefault(label, []).append(idx) # 为每个簇分配采样数量 sample_ratio = 0.3 # 整体欠采样后多数类为原始的比例 per_cluster_count = { label: max(20, int(len(indices) * sample_ratio)) for label, indices in cluster_indices.items() } # 按簇采样并合并 sampled_indices = [] for label, indices in cluster_indices.items(): count = per_cluster_count[label] if len(indices) <= count: sampled_indices.extend(indices) else: sampled_indices.extend( np.random.choice(indices, size=count, replace=False) ) X_sampled = X_majority[sampled_indices]

实际工程里,特征列表建议用代码动态计算,不能把特征写好写死——因为你换一个设备、换一组测点,有效的统计特征可能不同。标记、归一化、特征提取器最好都写成可配置模块,为后续迁移留后路。

4. 深度孪生自注意力网络的核心设计

4.1 输入构造:样本对怎么搭

孪生网络吃进去的不是单条样本,而是样本对。样本对的构造直接影响训练信号的质量,这一步值得花时间认真设计。

样本对的构造规则:

  • 正样本对:同一类别内的两条样本。多数类和多数类配对,少数类和少数类配对。注意正样本对里不要混入不同故障类型,如果故障有多个子类,同子类的才配成正对。
  • 负样本对:不同类别的两条样本。主要是正常类和故障类的配对。这类配对数量充足,而且恰恰是故障诊断中最需要区分的组合。
  • 配对比例:建议正常-故障负样本对占大头,大概70%~80%,剩下用正常-正常、故障-故障正样本对补充。如果负样本对全是容易区分的样本,模型学不到难分边界,因此最好在训练中逐步增加困难样本对的比重。

操作层面还有一个关键点:故障样本对必须做数据增强。时间序列的增强手段包括时域加噪、幅值缩放、时间扭曲、随机裁剪拼接,重点在于增强之后不能破坏故障的物理本质。比如尺度变化对某些冲击型故障特征影响不大,但对边频带特征影响很大,所以增强方式最好结合具体的故障形态来选择。

4.2 孪生分支与自注意力子模块

孪生网络的两个分支结构完全相同,并且共享权重。共享权重意味着两个分支使用同一套参数,这样送入的样本对是被同一个特征提取器处理的,最终计算出的相似度才有可比性。

每个分支的典型结构是:

  • 输入层:原始时间序列,做了归一化(或者简单低通滤波);
  • 卷积前嵌入:一维卷积层做初步局部特征提取,配合最大池化降维;
  • 多头自注意力模块:这一步的作用是让模型在整个序列范围内定位判别性区段。实际实现可以加位置编码,也可以不加——振动信号不依赖严格的语序,但位置信息能帮助模型识别周期性模式,建议给序列加上可学习位置编码;
  • 特征聚合法:注意力加权后的特征通过全局平均池化汇总成固定维度的向量;
  • 嵌入输出:用一个全连接层把特征向量映射成最终嵌入向量,推荐维度在64~128之间,太低信息不够,太高容易过拟合。

自注意力模块的算力消耗需要心里有数。如果输入序列很长(比如上万点),直接把一整条序列做全局注意力会非常吃力。可以先用卷积层加池化把序列长度降下来(比如降到原来的1/8到1/16),再做注意力计算。这是一个工程妥协,而且实证下来对性能的损失可以忽略。

分支输出的嵌入向量用欧氏距离或余弦距离度量相似度,距离近的意味着模型认为这两个样本属于同一类,距离远的则是不同类。

4.3 损失函数怎么设计

孪生网络惯用的损失是对比损失(Contrastive Loss):

def contrastive_loss(emb1, emb2, label, margin=1.0): # label=1表示正样本对(同类),label=0表示负样本对(异类) distance = torch.nn.functional.pairwise_distance(emb1, emb2) loss = 0.5 * (label * distance.pow(2) + (1 - label) * torch.clamp(margin - distance, min=0).pow(2)) return loss.mean()

这个损失的含义清晰且适合本场景:同类样本对的距离应该尽量小,异类样本对的距离至少大于一个边界margin。margin的取值会影响模型对“多远才算不同类”的判断,实践里面试从1.0起步,在验证集上看聚类分离度来调整。

一个值得尝试的优化是引入焦点损失(Focal Loss)的思想,给难分的样本对更高的损失权重。具体做法是在对比损失里引入一个权重项——如果两个样本的真实距离在margin附近,说明这个样本对让模型很纠结,这时候应该把它的影响放大,引导模型集中精力去学这些边缘地带的判别能力。

另一个补充是加入辅助分类头。在孪生分支的特征向量后面接一个小型分类器,用交叉熵损失一起优化,相当于多任务学习。这个做法能帮助嵌入向量保留更多与分类相关的判别信息,而不是只优化距离结构。实际测试中,辅助分支确实能有效加速收敛,让嵌入特征的质量更高。

4.4 为什么自注意力比纯CNN更适合这里

CNN在处理故障诊断特征时有几个天生的短板:卷积核的感受野有限,如果要捕获长距离依赖(比如一个冲击事件对后续一段波形的影响),需要堆叠很多卷积层,参数膨胀很快;池化层会丢弃掉部分空间信息,而故障特征往往就藏在细微的时序模式中。

自注意力用注意力权重把整个序列的信息按重要程度加权聚合,天然就能解决长距离依赖问题。它不追求“每一层的感受野大一点”,而是直接让任何两个位置之间可以交互。这里的代价是计算量高,但通过前面说的卷积预降维,可以在实际工程中控制住开销。

还有一个实际考量:CNN对样本量特别敏感,本来就只有几十个故障样本,还去堆十几层卷积,结果一定是过拟合。自注意力机制有更强的表示能力,配合孪生网络本身就相当于一个很大的正则化结构——模型不是直接学一个多分类映射,而是学一个相似度函数,这种约束天然对样本量要求更宽容。

5. 训练策略和评价指标:别被准确率骗了

5.1 训练流程的整体安排

训练孪生网络和训练普通分类器有本质差异:每一个step送入的是一个样本对而不是一条样本,因此训练数据准备的逻辑完全不同。

我的建议流程是:

  1. 完成聚类欠采样,得到均衡后的训练集(多数类子集+少数类全量);
  2. 从训练集中构造样本对,一次性生成好所有配对索引,并确保同一batch内正负样本对比例稳定;
  3. 训练阶段,优先用Adam优化器,初始学习率1e-4附近,mini-batch不要太大,32或64即可,每次迭代后根据验证集上面向不平衡的综合指标决定是否调整学习率或提前停止;
  4. 训练结束后,用全部训练集上的少数类样本作为支持集,对测试集样本逐一计算与支持集样本的相似度,根据最近邻的类别判定测试样本的类标签。

这里说明一下在推理阶段的关键:模型输出的是嵌入向量,而不是类别概率。判定时用K近邻或阈值化距离都行。阈值化有一个独特优势——你可以设定“如果距离所有已知类别都太远,判定为未知故障”,这个能力在生产环境里很实用,能识别没见过的异常类型。

5.2 评价指标怎么定

在类别不平衡的故障诊断场景,准确率几乎没有任何参考价值。一个99%都是正常样本的数据集,你直接全判正常也有99%的准确率,但一个故障都抓不住。这种模型放到现场就是摆设,还会让人产生虚假的安全感。

推荐使用以下指标组合:

指标公式关注点
召回率(故障类)TP / (TP+FN)有多少真正的故障被抓住了,这是最不能妥协的核心指标
精确率(故障类)TP / (TP+FP)报警的里面有多少是真的故障,防止“狼来了”式误报
F1分数2×精确率×召回率/(精确率+召回率)两者兼顾
G-meansqrt(召回率×特异度)多数类和少数类识别效果的几何平均,不平衡场景首选
AUC曲线下面积不依赖阈值,评价模型排序能力

实际项目里,我最看重的是故障类的召回率和G-mean。召回率低直接意味着漏报,漏报的代价是现场设备坏了都没人知道;G-mean则能反映出模型是否真的兼顾了两类样本,单纯压正常类误差而放弃故障类的模型在G-mean上会现出原型。

5.3 一个容易忽略的细节:验证集也要保持原始分布

很多人把数据均衡化之后才划分训练集和验证集,结果验证集也是均衡分布的,模型在验证集上的指标很好,一上现场就拉胯。正确的做法是:训练集用均衡化后的数据,验证集和测试集严格保持原始的不均衡分布,这样验证结果才真实反映模型在真实场景中的表现。

换句话说,数据重采样只应用在训练阶段,验证阶段必须“原汁原味”。我见过太多团队在这个细节上翻车,训练集验证集指标好得不得了,部署之后误报率失控,回头复盘才发现验证集的分布被破坏了。

6. 常见问题与排查技巧实录

6.1 聚类采样后训练集太小,模型欠拟合

欠采样最直接的副作用就是把训练集的体量压小了。如果原始数据100万条正常样本,故障样本200条,你强行采到400条正常样本,训练集一共600条,深模型很难吃饱。

经验解法有两个。一是采样比例不要一刀切,可以尝试多数类样本量为少数类样本量的2到4倍,而不是严格的1:1。类别不平衡不是完全不能容忍,过度均衡反而牺牲多样性。二是模型本身要浅:孪生网络分支的卷积层建议控制在3到4层,注意力头数控制在4到8个,嵌入维度不要超过128,否则小数据集上必然出问题。

6.2 自注意力在短样本上效果不明显

如果样本长度本身就只有几百点,自注意力能捕获的长距离信息有限,优势就体现不出来。这时候不必执着于全局注意力,可以用窗口注意力或者局部自注意力,按固定窗长把序列切开,在窗口内做注意力计算,效果稳定而且计算更快。

判断样本长度够不够有一个简单标准:观察故障特征一个完整周期大概占多少点,如果整个样本还覆盖不了两三个周期,那就优先做数据重采样或插值延长,而不是硬上注意力。

6.3 验证集F1高但现场误报多

最常见的原因是训练样本和现场样本的分布差异过大。聚类欠采样采到的“正常样本”来自生平时段,而现场运行的正常样本可能存在载荷波动、转速漂移、环境噪声变化。建议在构造训练集时,刻意加入多种运行工况下的正常样本,宁可“正常”类复杂一点,也不能让它太“纯粹”。

另外,阈值设定也很关键。推理阶段相似度阈值设置得太宽松,几乎所有样本都会被判定为“同类”,故障样本就不会被判异;设置得太严格,正常的运行波动也会被判为故障。实际项目里可以在阈值附近留一个过渡区间,落在区间里的样本输出“需人工复核”,别急着给结论。

6.4 聚类结果不稳定,换随机种子结果差异很大

这种情况通常说明正常样本的特征空间结构不够清晰。排查顺序是:

  • 先检查特征提取是否合理,时域统计量维度太低,换用频域特征(各频段能量比例、频谱峰值位置)或嵌入特征;
  • 再检查是否需要归一化,KMeans对特征的尺度非常敏感;
  • 还可以尝试多次运行聚类并取平均结果的方式减少随机性,或者改用MiniBatchKMeans提升稳定性和速度。

6.5 训练时损失值剧烈震荡,就是降不下来

这个问题的根源往往不在模型,而在样本对的构造。如果同一个batch里正样本对和负样本对的比例波动很大,比如前一个batch全是简单样本、后一个batch全是困难样本,损失曲线就会剧烈震荡。

解决方法是固定每个batch内正负样本对的比例,并做样本对的难例挖掘。尤其是故障类的负样本对,优先选择当前模型最容易混淆的样本对(距离靠近margin边界的),这能让训练信号更有针对性。难例挖掘的实现在代码上也不复杂:每个epoch先跑一轮前向传播,记录每个样本对的距离,排序后取距离最接近margin的那批样本对加入下一轮的训练集。

7. 实验设计与效果验证建议

如果要在自己的数据集上复现这套方案,可以按以下模板组织实验:

7.1 数据集准备

公开数据集方面,很多团队会用业内常见的轴承故障公开数据作为起步验证集,比如含有正常、内圈故障、外圈故障、滚动体故障振动数据的通用测试集合。建议的做法是用其中一类作为少数类,人为构造不平衡比例(比如1:50,1:100,1:200),验证方法在不同不平衡程度下的退化趋势。

工业合作数据集则要特别注意标签的准确性——振动数据的故障标签有时本身就是模糊的,比如某个样本同时存在早期磨损和润滑不足两种状态,标注为单一故障类型就会给模型注入噪声。

7.2 基线对比

建议至少和以下方法做对比,才能在个人实践中定位这套方案的真实价值:

方案数据层面模型层面
A无处理CNN分类器
B随机欠采样CNN分类器
CSMOTE过采样CNN分类器
D无处理孪生CNN(无注意力)
E聚类欠采样孪生CNN(无注意力)
F(本文方案)聚类欠采样孪生自注意力网络

记录每个方案在故障类召回率、G-mean、F1分数上的差异,重点关注不同不平衡比例下的稳定性。这里的预期是:不平衡比例越高,方案F相对基线的优势越大——因为随机欠采样丢失的多样性信息在不平衡严重时最致命,而孪生网络的结构优势在少数类样本极少时能发挥最大的价值。

7.3 消融实验

消融实验尽量单独做两个:一是去掉聚类欠采样,只保留孪生自注意力网络,观察G-mean怎么变化;二是去掉自注意力模块,只保留聚类欠采样,观察召回率怎么变化。这两个实验直接说明方案中每个模块各自的贡献。

另外,对聚类簇数K和采样比例做一组小规模的敏感性分析。如果K从4变到8,G-mean波动小于2%,说明方案对聚类参数不敏感,稳定性好,值得沿用;如果波动太大,就要考虑固定K值或者在多个K上做集成。

7.4 可视化分析

把训练完成后的嵌入向量用降维算法投影到二维平面上做散点图,观察两类样本是否形成清晰的簇。这个可视化可以做两件事:

  • 判断训练质量:如果两类样本在嵌入空间混成一片,说明模型还没学到判别性特征,需要回看损失函数或样本对比例;
  • 判断未知故障的检测能力:把现场新采集的数据也投影到图上,看它们落在什么位置。如果落在已知类别的分布之外,说明这个样本是未见过的异常——孪生结构天然支持这种“开集识别”,这也是它比普通分类器更适合工业现场的原因之一。

8. 一些想提醒你的实用要点

最后集中列几条我在实际项目里收获的、不在论文里明说的经验。

第一,聚类欠采样和孪生网络的组合不是银弹。如果你的故障样本少到只有几条,再好的结构设计也学不到多少东西——这时候的首要任务不是建模,而是去现场补数据,或者结合机理知识构造物理约束。至少需要几十条以上的故障样本,这套方法才有发挥空间。

第二,做样本对匹配时注意故障样本之间的“内部差异”。同一种故障类型在不同的载荷下特征差异可能非常大,如果把差异过大的两条故障样本硬配成正样本对,损失函数会给出互相矛盾的学习信号,模型训练会变得很不稳定。建议在做配对前先对故障样本做一次内部聚类,差异过大的子类暂时不要互相配对。

第三,推理阶段的阈值不要拍脑袋定死。训练结束后拿一段验证数据跑一遍,看嵌入向量的距离分布,画出来,观察正常-正常对和正常-故障对的距离是否分得开,再在两者的交叠区取阈值。生产环境里,阈值应该是可以在线调整的参数,每过一段时间就拿一批人工复核过的数据重新评估阈值。

第四,注意力机制不是加上就“自动”有效的。如果发现注意力可视化结果乱糟糟的,没有什么规律,先检查输入数据归一化做没做对,再检查序列长度是否需要截断或补零,实在不行就缩减注意力头的数量,多头的优势在小数据集上体现不出来,反而增加过拟合风险。

这套方案在我的多次项目实践中带来一个明确的感觉:不平衡问题被拆成了“可用数据不足”和“特征可分性不够”两个具体问题,再分别用采样策略和模型结构去对症下药。相比直接上复杂模型期待它自带免疫能力,这种拆解式的做法更可解释、更容易调优,也更容易在换一个场景时迁移复用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询