ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CNN-SVM轴承故障诊断:从振动信号到故障标签的工程实践

CNN-SVM轴承故障诊断:从振动信号到故障标签的工程实践 简介这份资源面向工业设备健康监测与机器学习入门者聚焦轴承故障诊断这一典型场景提供结合支持向量机与卷积神经网络的完整实践方案。包内共3201个文件以3200张jpg灰度图像和1个py脚本为主压缩包约4.1MB图像用于承载轴承振动信号转换后的故障样本脚本则对应模型训练与诊断流程。已有1739人学习下载说明该方案在故障识别方向具有一定参考价值。读者可借此理解从振动数据到灰度图的预处理思路掌握SVM构建决策边界与CNN逐层提取特征的两类建模路径并对照比较二者在小样本与图像模式识别任务上的表现差异。资源同时覆盖数据标准化、模型训练验证、结果对比与部署预测等环节适合希望将传统机器学习与深度学习方法落地到轴承故障诊断的读者参考。1. 从振动信号到故障标签cnn-svm轴承故障诊断到底在解决什么产线上那台电机最近总在下午三点左右发出周期性异响老师傅拿听音棒顶住轴承座听了几秒说“内圈有伤趁早换”。问题是这种靠耳朵的判断没法写进巡检记录更没法在夜班无人值守时自动报警。cnn-svm轴承故障诊断要解决的就是把“老师傅的耳朵”变成一套能跑在工控机上的自动判别流程先用 CNN 从原始振动信号里自动学出故障特征再用 SVM 做最终分类。它适合手里有振动加速度传感器、采过一批带标签数据、但特征工程做得头疼的设备工程师和算法入门者。相比人工设计峭度、裕度、频谱峰值这些指标CNN 省掉了“猜特征”的环节相比纯 CNN 端到端分类SVM 在小样本上更稳决策边界也更好解释。这条路线在公开轴承数据集上已经被反复验证真正难的是把它落到你自己的台架上。2. 为什么是 CNN 提特征加 SVM 分类而不是二选一2.1 轴承故障诊断的信号特点决定了这个组合轴承故障的振动信号本质上是调制信号滚动体碾过损伤点时产生周期性冲击冲击又调制到系统的高频共振上。外圈故障、内圈故障、滚动体故障的差别藏在冲击的重复频率和调制边带里而这些信息在时域波形上并不直观。传统做法是算包络谱找到故障特征频率再人工比对。问题是转速波动、负载变化、传感器安装位置都会让特征频率漂移人工规则很难覆盖所有工况。CNN 的价值在于它能把“找冲击—算包络—提谱峰”这套流程变成可学习的卷积核。一维卷积核在时域上滑动本质上就是在检测局部冲击模式多层堆叠后它学到的是从低级冲击到高级调制模式的层次特征。这比人工指定“看哪个频段”要鲁棒。但纯 CNN 做分类有个现实问题工业现场标注数据少。一台设备正常样本多、故障样本少故障类型还不均衡。CNN 全连接层在样本少时容易过拟合而 SVM 的结构风险最小化原则在小样本高维特征上表现更稳。所以常见做法是CNN 只当特征提取器把倒数第二层的特征向量拿出来喂给 SVM 做分类。这样 CNN 不需要在少量样本上硬学分类边界SVM 也不需要从原始信号开始处理。2.2 用 Python 搭一个最小可跑的 CNN-SVM 流程下面这段代码用 PyTorch 定义一维 CNN 特征提取器再用 sklearn 的 SVM 做分类。数据假设你已经有了形状为(样本数, 1, 信号长度)的振动信号和对应标签。import torch import torch.nn as nn import numpy as np from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 一维 CNN 特征提取器输入 (batch, 1, 2048) class CNNFeatureExtractor(nn.Module): def __init__(self): super().__init__() self.conv_blocks nn.Sequential( # 第一层大卷积核抓冲击输出通道 16 nn.Conv1d(1, 16, kernel_size64, stride8, padding32), nn.BatchNorm1d(16), nn.ReLU(), nn.MaxPool1d(2), # 第二层中等卷积核抓调制 nn.Conv1d(16, 32, kernel_size16, stride2, padding8), nn.BatchNorm1d(32), nn.ReLU(), nn.MaxPool1d(2), # 第三层小卷积核抓细节 nn.Conv1d(32, 64, kernel_size3, stride1, padding1), nn.BatchNorm1d(64), nn.ReLU(), nn.AdaptiveAvgPool1d(1) # 全局平均池化输出 (batch, 64, 1) ) def forward(self, x): feat self.conv_blocks(x) return feat.view(feat.size(0), -1) # 展平成 (batch, 64) # 假设 X_train_raw 形状 (n, 2048)先转成 (n, 1, 2048) def to_tensor(X): return torch.tensor(X, dtypetorch.float32).unsqueeze(1) # 1. 用 CNN 提取特征这里不训练 CNN随机初始化也能验证流程 # 实际项目需要先用带标签数据训练 CNN 或至少自编码预训练 extractor CNNFeatureExtractor() extractor.eval() with torch.no_grad(): feat_train extractor(to_tensor(X_train_raw)).numpy() feat_test extractor(to_tensor(X_test_raw)).numpy() # 2. 用 SVM 在 CNN 特征上分类 clf make_pipeline(StandardScaler(), SVC(kernelrbf, C10, gammascale)) clf.fit(feat_train, y_train) y_pred clf.predict(feat_test) print(classification_report(y_test, y_pred))这段代码的关键不在网络多深而在三个参数第一层kernel_size64, stride8是为了覆盖轴承冲击的典型宽度2048 点信号里冲击大概占几十到上百点stride8做粗粒度下采样减少计算量同时保留冲击位置信息。第二层kernel_size16对应调制周期比冲击宽度大。最后用AdaptiveAvgPool1d(1)而不是展平全连接是为了让特征对信号平移不敏感——轴承故障的冲击出现在哪个时间点不重要重要的是有没有、以什么节奏出现。SVM 这边C10是正则强度样本少时不要设太大否则每个点都成支持向量gammascale是 RBF 核的宽度特征维度是 64用 scale 自动适配。如果分类报告里某类召回率明显低先别调 SVM回去看 CNN 特征是不是把那一类和其他类混在一起了。2.3 特征提取器怎么训练才不白干上面代码里 CNN 是随机初始化的特征没有意义。实际项目里 CNN 必须训练但训练目标不一定是分类。常见做法有三种第一种是直接用分类损失训练 CNN然后把倒数第二层特征拿出来给 SVM。这种做法简单但 CNN 会偏向于学“容易分类”的特征可能丢掉一些 SVM 能利用的细节。第二种是用自编码器重构损失预训练 CNN让卷积核学会表示冲击波形再拿特征给 SVM。这种做法在故障样本极少时更稳因为重构不需要标签。第三种是联合训练CNN 输出特征后同时接一个 softmax 分类头和 SVM用分类损失加 SVM 的合页损失一起优化。这种做法实现复杂但效果通常最好。我一般会先跑第一种看 SVM 分类报告和纯 CNN softmax 的差距。如果 SVM 比 softmax 高 3 个点以上说明 CNN 特征里确实有线性不可分的信息SVM 的核映射起了作用。如果差不多那可能数据量够大纯 CNN 就够了不必硬上 SVM。3. 从原始振动到模型输入数据切分和标签制作的四个关键决定3.1 采样频率和信号长度怎么定采样频率要覆盖轴承故障的特征频率。轴承故障特征频率一般在几百赫兹到几千赫兹但冲击会激发系统共振共振频率可能在 5kHz 到 20kHz。按照奈奎斯特采样定理采样频率至少是关注最高频率的两倍。工程上常用 12.8kHz、20kHz、25.6kHz 这几档。如果你只关心低频故障特征12.8kHz 够用如果想保留共振带信息建议 20kHz 以上。信号长度决定 CNN 输入尺寸。太短一个样本里可能连一个完整冲击周期都装不下太长计算量大且故障冲击被稀释。常见做法是取 2048 点或 4096 点。以 20kHz 采样为例2048 点对应约 0.1 秒足够覆盖几个冲击周期。如果转速很低比如 300 转/分冲击间隔约 0.2 秒那 2048 点可能不够需要 4096 或 8192 点。3.2 重叠切分能救回不少样本工业现场故障样本少切分时用重叠可以增加样本数。比如 2048 点窗口步长取 1024重叠 50%。这样一段 10 秒的信号能切出约 190 个样本而不是 95 个。重叠的代价是样本间不独立训练时要注意验证集不能和训练集来自同一段原始信号否则准确率虚高。def slice_signal(signal, window2048, step1024): 把长信号切成重叠窗口返回 (n, window) 数组 n (len(signal) - window) // step 1 return np.stack([signal[i*step : i*stepwindow] for i in range(n)]) # 按设备/工况分组切分避免同一段信号同时进训练和验证 # 假设 raw_signals 是 dict: {设备编号: (信号, 标签)} train_X, val_X, train_y, val_y [], [], [], [] for dev_id, (sig, label) in raw_signals.items(): windows slice_signal(sig) # 前 70% 窗口进训练后 30% 进验证 split int(len(windows) * 0.7) train_X.append(windows[:split]) val_X.append(windows[split:]) train_y.extend([label] * split) val_y.extend([label] * (len(windows) - split))这里最关键的是按设备或按时间段分组切分而不是把所有窗口打乱后随机分。同一段信号切出的窗口高度相似随机分会让验证集里出现训练集的“近亲”准确率能到 99%但换一台设备就崩。血泪经验先按设备分再按时间分最后才考虑随机。3.3 标签制作故障类型和故障尺寸要分开公开数据集里标签通常是“内圈故障”“外圈故障”“滚动体故障”但实际诊断中故障尺寸也重要。一个 0.2mm 的早期点蚀和一个 2mm 的剥落处理 urgency 完全不同。如果标签只写故障类型模型学到的可能是“有没有故障”而不是“故障多严重”。建议标签至少两级第一级是故障位置正常/内圈/外圈/滚动体第二级是故障尺寸早期/中期/晚期。如果样本不够至少把正常和故障分开故障内部再按尺寸排序做回归或有序分类。3.4 归一化别用全局均值方差振动信号的幅值受负载和传感器灵敏度影响很大。归一化是必须的但不要用整个数据集的均值和方差。正确做法是每个样本单独归一化或者用训练集的统计量归一化验证集。每个样本单独做 z-score 归一化能消除负载变化带来的幅值差异让 CNN 专注于波形形状。def normalize_per_sample(x): 对每个样本单独做 z-scorex 形状 (n, window) mean x.mean(axis1, keepdimsTrue) std x.std(axis1, keepdimsTrue) 1e-8 return (x - mean) / std注意1e-8是防止除零如果某个窗口信号完全平坦传感器脱落归一化后会变成噪声这种样本应该在预处理阶段就剔除。4. 避坑与排查cnn-svm 轴承故障诊断最常见的五类翻车4.1 验证集准确率 99%换台设备就废了现象训练时验证集准确率很高但把模型用到另一台同型号设备上正常样本被大量判为故障。原因切分时没有按设备分组同一段信号的重叠窗口同时进了训练和验证。模型记住的是这段信号的“指纹”不是故障特征。解决按设备编号或采集时间段分组切分。如果只有一台设备的数据至少按时间先后切用前 70% 时间训练后 30% 验证。更严格的做法是留一台设备完全不做训练只做测试。4.2 SVM 训练报错“收敛失败”或支持向量数等于样本数现象SVM 拟合时警告不收敛或者n_support_接近样本总数。原因CNN 特征没有标准化不同维度量纲差异大或者C设得太大每个样本都成了支持向量。解决在 SVM 前加StandardScaler把特征拉到同一量纲。C从 1 开始试不要一上来就 1000。如果特征维度是 64、样本只有几百C1到C10通常够用。另外检查 CNN 特征是不是有大量常数维度如果有说明 CNN 没训练好或者某层死了。4.3 混淆矩阵里正常和故障分得清但内圈和外圈混在一起现象正常 vs 故障准确率很高但内圈故障和外圈故障互相误判。原因内圈和外圈的冲击重复频率不同但如果信号长度太短一个窗口里冲击次数太少频率信息体现不出来。另外如果 CNN 第一层卷积核太大可能把冲击位置信息抹掉了。解决增加信号长度让一个窗口里至少包含 5 到 10 个冲击周期。或者改用频域输入把 FFT 幅度谱作为 CNN 输入频率分辨率更直接。也可以把 CNN 第一层卷积核改小比如从 64 改成 32保留更多时间细节。4.4 训练损失下降但验证损失上升加 dropout 也没用现象CNN 训练几个 epoch 后训练损失持续降验证损失先降后升典型过拟合。原因故障样本太少CNN 参数量相对样本量太大。或者数据增强没做模型看到的样本多样性不足。解决先减 CNN 参数量把通道数从 64 降到 32层数从 3 层降到 2 层。然后加数据增强对振动信号做时间平移、加高斯噪声、幅值缩放。注意不要做翻转振动信号翻转没有物理意义。如果还不行考虑用自编码器预训练或者直接用 SVM 在手工特征上跑别硬上 CNN。4.5 推理时单样本预测结果和批量预测不一致现象把单个样本喂给模型预测结果和把它放进 batch 里预测不一样。原因CNN 里的BatchNorm在训练和推理时行为不同。推理时用的是训练集统计量如果训练集和推理数据分布差异大结果会偏。另外如果推理时忘了model.eval()BatchNorm 会用当前 batch 的统计量单样本时统计量就是它自己结果自然不同。解决推理前一定调extractor.eval()并用torch.no_grad()包住。如果训练集和现场数据分布差异大考虑用InstanceNorm替代BatchNorm它对 batch 大小不敏感。5. 让 CNN-SVM 真正落地的两个进阶技巧5.1 用 CNN 特征做异常检测解决故障样本极少的问题现场最常见的情况是正常样本一大堆故障样本只有几个。这时候 SVM 分类器根本训不起来。一个实用技巧是只用正常样本训练 CNN 自编码器让重构误差成为异常分数。推理时重构误差超过阈值的判为异常再对异常样本用 SVM 做故障类型细分。class CNNAutoencoder(nn.Module): def __init__(self): super().__init__() self.encoder nn.Sequential( nn.Conv1d(1, 16, 64, stride8, padding32), nn.ReLU(), nn.Conv1d(16, 32, 16, stride2, padding8), nn.ReLU(), nn.Conv1d(32, 64, 3, stride1, padding1), nn.ReLU(), ) self.decoder nn.Sequential( nn.ConvTranspose1d(64, 32, 3, stride1, padding1), nn.ReLU(), nn.ConvTranspose1d(32, 16, 16, stride2, padding8, output_padding0), nn.ReLU(), nn.ConvTranspose1d(16, 1, 64, stride8, padding32, output_padding0), ) def forward(self, x): z self.encoder(x) return self.decoder(z), z # 训练时只用正常样本损失用 MSE # 推理时计算重构误差阈值取正常样本误差的 95 分位数这个做法的好处是正常样本容易获取自编码器训练稳定异常检测和故障分类解耦故障样本少也能先报警。等积累到足够故障样本再用 CNN 特征训练 SVM 做细分。5.2 用交叉验证选 SVM 参数别拍脑袋SVM 的C和gamma对结果影响很大但不要用测试集调参。正确做法是在训练集内部做交叉验证。如果样本按设备分组就用GroupKFold保证同一设备的样本不会同时出现在训练和验证折里。from sklearn.model_selection import GridSearchCV, GroupKFold # groups 是每个样本对应的设备编号 cv GroupKFold(n_splits5) param_grid { svc__C: [0.1, 1, 10, 100], svc__gamma: [scale, 0.01, 0.1, 1] } clf make_pipeline(StandardScaler(), SVC(kernelrbf)) grid GridSearchCV(clf, param_grid, cvcv, scoringf1_macro, n_jobs-1) grid.fit(feat_train, y_train, groupsgroups_train) print(grid.best_params_)scoring用f1_macro而不是准确率因为故障类别通常不均衡。n_jobs-1用满 CPU 核。如果交叉验证最优参数和默认参数差距不大直接用默认的C1, gammascale别为了 0.5 个点过拟合验证集。我自己的习惯是先把 CNN 特征固定住用GroupKFold跑一遍 SVM 参数网格记下最优参数和对应的混淆矩阵。然后换一组 CNN 特征比如换个训练 epoch 的 checkpoint再跑一遍。如果最优参数在不同特征上跳来跳去说明特征本身不稳定回去调 CNN 比调 SVM 更值得。这套流程跑通一次大概半天但能省掉后面反复翻车的后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表