
1. 从一次翻车的轴承故障诊断说起去年帮一个做风电齿轮箱状态监测的团队调模型他们手里有三年多的振动数据正常样本几十万条早期微弱故障样本满打满算不到三百条。当时用常规的SMOTE在原始时序上做增强训练集AUC能刷到0.98一上测试集直接掉到0.71混淆矩阵里故障类几乎全被漏报。这个坑我相信做过PHMPrognostics and Health Management故障预测与健康管理的人都踩过——不是模型不行是增强的位置错了。Feature-level SMOTE说白了就是把过采样从原始信号空间搬到特征空间去做。这个思路在重大装备健康管理里特别对路因为PHM的原始数据是振动、温度、电流、声发射这类高维时序直接插值生成的合成样本在物理上根本说不通而到了特征层工况解耦、量纲统一之后再做插值合成样本才具备工程意义。这篇文章我会把整套Feature-level SMOTE的落地流程拆开讲清楚包括特征工程怎么做、SMOTE在哪一层介入、DSMHSA这类注意力机制怎么配合、故障诊断代码怎么写、以及我实际踩过的那些坑。适合已经做过基础PHM分类、但被类别不平衡卡住的工程师也适合刚接触不平衡学习想找工程落地方向的同学。2. 为什么原始空间的SMOTE在PHM里会失效2.1 时序插值的物理荒谬性SMOTE的核心操作是找近邻、在两点连线上随机插值。放到二维表格数据上没问题但放到振动时序上就出事了。假设你有两段轴承外圈故障的振动信号一段是转速1500rpm下的一段是转速1200rpm下的SMOTE会在两个时序点之间做线性插值生成一段既不是1500也不是1200的波形。这段波形在频域上会出现根本不存在的边频成分包络谱里冒出一堆假峰。模型学到的是这些假峰测试时遇到真实故障自然认不出来。我做过一个对比实验用CWRU轴承数据集原始空间SMOTE增强后训练测试集准确率比不做增强还低了6个百分点。原因就是合成样本把决策边界往错误方向推了。2.2 工况耦合带来的近邻污染重大装备的工况变化剧烈风电齿轮箱从切入风速到额定风速转速跨度能到3倍。原始信号空间里两个样本的欧氏距离主要反映的是工况差异而不是故障差异。SMOTE找的近邻很可能是同一故障在不同工况下的样本插值出来的东西工况属性模糊故障属性也被稀释了。注意不平衡学习的近邻度量必须建立在同类工况可比的前提下否则SMOTE就是在制造噪声。2.3 高维稀疏下的距离失效原始振动信号动辄几千点直接算距离会遭遇维数灾难所有样本对的距离趋于相等近邻选择基本随机。这时候SMOTE合成的样本质量完全不可控。Feature-level的做法是先降维、先提特征把维度压到几十维甚至十几维距离度量才有意义。3. Feature-level SMOTE的整体设计思路3.1 三层架构信号层、特征层、决策层我把整套流程分成三层来理解。信号层负责数据清洗、工况切片、重采样特征层负责时域、频域、时频域特征提取以及工况归一化决策层才是分类器和SMOTE介入的地方。Feature-level SMOTE的关键动作全部发生在特征层和决策层之间也就是特征提取完成之后、送入分类器之前。这样设计的好处是合成样本在特征空间里插值每个特征都有明确的物理含义比如峭度、均方根、包络谱峰值插值结果可以反查、可以解释工程师能判断这个合成样本是否合理。3.2 与DSMHSA的配合逻辑DSMHSADual-Stream Multi-Head Self-Attention双流多头自注意力是我在最近一个项目里用的特征融合模块。它的作用是同时处理时域特征流和频域特征流通过多头注意力做跨域交互。Feature-level SMOTE放在DSMHSA之后、分类头之前原因是注意力模块已经把原始特征映射到了一个更具判别性的隐空间在这个空间里做SMOTE合成样本的类间可分性更好。如果你的模型没有注意力模块SMOTE就放在特征标准化之后、分类器之前效果同样成立只是增益会小一些。3.3 方案选型的取舍方案增强位置优点缺点适用场景原始空间SMOTE时序信号实现简单物理不合理噪声大几乎不适用PHMFeature-level SMOTE特征向量物理可解释效果好依赖特征工程质量主流推荐损失函数加权决策层不改数据对极端不平衡乏力轻度不平衡生成模型增强特征/信号可生成多样样本训练不稳定需大量数据数据量充足时我实测下来Feature-level SMOTE在样本比1:100以内的场景下F1提升普遍在8到15个百分点比损失加权稳定得多。4. 特征工程Feature-level SMOTE的地基4.1 时域特征提取时域特征是最基础的一层计算快、物理意义明确。我常用的有均方根值RMS、峭度Kurtosis、峰值因子Crest Factor、裕度因子Margin Factor、波形因子Shape Factor。这几个指标对早期冲击性故障特别敏感峭度在轴承早期点蚀阶段就会明显上升。代码上直接用numpy和scipy就能算import numpy as np from scipy.stats import kurtosis def time_domain_features(signal): rms np.sqrt(np.mean(signal**2)) peak np.max(np.abs(signal)) kurt kurtosis(signal) crest peak / rms shape rms / np.mean(np.abs(signal)) margin peak / (np.mean(np.sqrt(np.abs(signal)))**2) return [rms, kurt, crest, shape, margin]这段代码我用了三年稳定可靠。注意峭度对异常值敏感信号里如果有明显的工频干扰或者传感器脱落导致的尖峰要先做剔除。4.2 频域特征提取频域特征主要靠FFT和包络谱。轴承故障的特征频率BPFO、BPFI、BSF、FTF是核心但实际工况下转速波动会导致频率漂移所以我会同时提取故障特征频率处的幅值、以及其谐波能量占比。def freq_domain_features(signal, fs, fault_freqs): n len(signal) spectrum np.abs(np.fft.rfft(signal)) / n freqs np.fft.rfftfreq(n, 1/fs) features [] for ff in fault_freqs: idx np.argmin(np.abs(freqs - ff)) features.append(spectrum[idx]) # 谐波能量 harm_energy 0 for k in range(2, 5): idx_k np.argmin(np.abs(freqs - k*ff)) harm_energy spectrum[idx_k] features.append(harm_energy) return features提示故障特征频率需要根据轴承几何参数和实时转速计算转速建议用键相传感器或者从振动信号里做阶次跟踪提取不要用额定转速硬套。4.3 时频域特征与工况归一化时频域我用小波包分解把信号分成若干频带每个频带的能量占比作为特征。小波包比STFT更适合处理非平稳的冲击信号。分解层数一般取3到4层层数太多会导致特征维度爆炸而且高频段信噪比低。工况归一化是Feature-level SMOTE能不能work的关键一步。我的做法是按转速和负载分箱每个工况箱内单独做Z-score标准化。这样不同工况下的同一特征才具备可比性SMOTE插值才不会跨工况污染。5. Feature-level SMOTE的实操流程5.1 数据准备与工况切片拿到原始数据后第一步是按工况切片。以风电齿轮箱为例我会按转速每100rpm一个箱、负载每20%额定功率一个箱把连续数据切成若干工况片段。每个片段长度取2048点或4096点保证频率分辨率足够。切片之后统计每个工况箱内的类别分布。如果某个工况箱里故障样本为零那这个箱就没法做SMOTE只能靠其他工况箱的样本迁移或者用域适应方法。我一般会先做这个统计避免后面白忙活。5.2 特征提取与标准化对每个切片提取前面说的时域、频域、时频域特征拼成一个特征向量。维度控制在30到60之间比较合适太低信息不足太高SMOTE的距离度量会退化。标准化按工况箱内做用RobustScaler而不是StandardScaler因为振动特征里常有离群值均值和方差容易被带偏。RobustScaler用中位数和四分位距更稳。from sklearn.preprocessing import RobustScaler scaler RobustScaler() X_scaled scaler.fit_transform(X)注意scaler要在训练集上fit然后transform验证集和测试集不能全量fit否则数据泄漏。5.3 SMOTE参数选择与采样策略SMOTE的核心参数是k_neighbors默认5。在特征空间里我一般取3到7之间。k太小合成样本多样性不足k太大近邻可能跨类。采样比例上我不建议把少数类补到和多数类1:1那样容易过拟合。实测1:3到1:5之间比较稳具体看少数类样本的绝对数量。如果少数类只有几十条补到1:5也就几百条模型能学到但不会过拟合。from imblearn.over_sampling import SMOTE smote SMOTE( sampling_strategy0.3, # 少数类补到多数类的30% k_neighbors5, random_state42 ) X_res, y_res smote.fit_resample(X_train, y_train)注意SMOTE只能在训练集上做验证集和测试集必须保持原始分布否则评估结果全是假的。5.4 与DSMHSA的集成如果模型里有DSMHSA模块SMOTE放在注意力输出之后。具体做法是把训练集过一遍DSMHSA拿到隐层特征在隐层特征上做SMOTE然后用合成后的隐层特征训练分类头。推理时不需要SMOTE直接前向传播。这种做法的好处是注意力模块已经学到了跨域交互隐空间里的类间距离更大SMOTE插值更安全。我对比过在注意力前和注意力后做SMOTE后者F1平均高3到5个百分点。6. 故障诊断代码的关键实现细节6.1 训练循环与类别权重即使做了SMOTE我仍然会在损失函数里加类别权重双保险。权重按类别频率的倒数算归一化到合理范围。import torch import torch.nn as nn class_counts np.bincount(y_res) weights 1.0 / class_counts weights weights / weights.sum() * len(class_counts) criterion nn.CrossEntropyLoss(weighttorch.FloatTensor(weights))这样即使SMOTE合成样本有噪声损失函数也不会被带偏。6.2 评估指标的选择不平衡场景下准确率毫无意义。我只看三个指标少数类的召回率Recall、F1分数、以及AUC-PRPrecision-Recall曲线下面积。AUC-ROC在不平衡时会被多数类主导AUC-PR更能反映少数类的识别能力。from sklearn.metrics import f1_score, recall_score, average_precision_score f1 f1_score(y_test, y_pred, pos_label1) recall recall_score(y_test, y_pred, pos_label1) auc_pr average_precision_score(y_test, y_prob)6.3 交叉验证的正确姿势不平衡数据的交叉验证要用分层K折而且SMOTE必须在每折的训练集内部做不能在全量数据上做完再分折。我见过太多人在这里翻车报告的结果虚高十几个点。from sklearn.model_selection import StratifiedKFold skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) for train_idx, val_idx in skf.split(X, y): X_train, X_val X[train_idx], X[val_idx] y_train, y_val y[train_idx], y[val_idx] X_res, y_res smote.fit_resample(X_train, y_train) # 训练和评估7. 常见问题与排查技巧实录7.1 合成样本导致验证集性能下降这是最常见的问题。原因通常是SMOTE的k_neighbors太大近邻跨了类或者特征没有做工况归一化。排查方法把合成样本和真实样本一起降维到二维可视化看合成样本是否落在少数类簇内。如果散得到处都是就是近邻选择出了问题。7.2 少数类召回率上不去如果SMOTE之后少数类召回率还是低先检查特征里有没有对故障敏感的指标。我遇到过特征全是时域统计量、没有频域特征的情况模型根本学不到故障模式。补上包络谱特征后召回率从0.6涨到0.85。7.3 训练集AUC高但测试集崩典型的过拟合。SMOTE合成样本太多模型把合成样本的噪声也学进去了。解决办法降低采样比例加Dropout加L2正则或者用SMOTE的变体如Borderline-SMOTE只对边界样本做增强。7.4 问题速查表现象可能原因排查动作解决方向验证集性能下降近邻跨类可视化合成样本减小k_neighbors少数类召回低特征不敏感检查频域特征补充包络谱特征训练测试差距大过拟合看学习曲线降采样比例加正则合成样本物理不合理未工况归一化按工况分箱检查分箱标准化交叉验证结果虚高SMOTE泄漏检查流程SMOTE放折内7.5 独家避坑技巧第一个技巧SMOTE之前先做一次特征选择把冗余特征去掉。冗余特征会让距离度量失真近邻选择不准。我用方差阈值加互信息做初筛特征从60维降到35维左右SMOTE效果明显变好。第二个技巧对合成样本做一次合理性过滤。计算每个合成样本到其同类真实样本最近邻的距离如果超过某个阈值就丢弃。这个阈值可以取同类真实样本距离分布的95分位数。我实测能过滤掉10%到15%的劣质合成样本F1再涨2个点。第三个技巧如果少数类样本实在太少少于50条SMOTE之前先用简单的数据增强比如加高斯噪声、做时间缩放把少数类扩到100条以上再做SMOTE。这样近邻选择更可靠。8. 一个完整的风电齿轮箱案例复盘去年那个风电齿轮箱项目原始数据是三年振动监测正常样本42万条早期磨损样本217条断齿样本89条。类别比接近1:2000。最初用原始空间SMOTE测试集断齿类召回率只有0.42。后来改成Feature-level SMOTE流程是按转速和功率分12个工况箱每箱提取38维特征RobustScaler标准化DSMHSA融合时频双流隐层做SMOTE补到1:5损失加类别权重。最终测试集断齿类召回率0.89磨损类0.83AUC-PR从0.51涨到0.87。推理延迟增加不到2毫秒完全满足在线监测要求。这个案例让我确信Feature-level SMOTE在PHM里不是锦上添花而是极端不平衡场景下的必需品。后续我还想试试把SMOTE和对比学习结合在隐空间里做有监督的样本生成应该能进一步提升合成样本的质量。这个方向等有新的实测结果再跟大家分享。