ARTICLE DETAIL

资讯详情

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

深度学习驱动的滚动轴承故障诊断:从CWRU数据集到一维CNN实践

深度学习驱动的滚动轴承故障诊断:从CWRU数据集到一维CNN实践 简介面向机械故障诊断与深度学习应用人群的一份完整项目资料聚焦滚动轴承故障诊断场景基于卷积神经网络、循环神经网络以及LSTM、GRU等模型实现振动信号的自动特征提取与故障分类有效弥补传统人工经验和统计模型在噪声干扰下的局限。压缩包共40个文件约34.86MB其中30个mat文件为CWRU等公开轴承数据集4个py脚本覆盖数据预处理、模型训练与可视化分析6个md文档提供项目说明与使用指引。目前已累计260人学习下载适合作为算法复现、课程设计或工程验证的参考。目录结构清晰包含pre_data、last_layer_data等中间数据模块读者可以借助完整代码与数据集快速跑通DNN、CNN等故障诊断流程并结合可视化脚本分析特征提取效果为后续研究或实际项目落地提供支撑。1. 为什么滚动轴承故障诊断要转向深度学习滚动轴承是旋转机械里最容易出问题的部件之一它的失效模式往往不是突然发生的而是从微弱的冲击脉冲慢慢演化为磨损、剥落甚至抱死。传统诊断思路依赖人工提取特征比如时域的均方根值、峰值因子频域的包络谱特征频率这套方法对稳定工况有效但面对变转速、强噪声、多故障耦合时就容易失灵。原因是手工特征本质上是人对信号的先验压缩一旦工况偏离假设特征与故障的映射关系就失效了。深度学习路线图则完全不同它把「特征设计」这件事交给网络自己完成。以 CWRU 轴承数据集为例只需要把原始振动信号切成固定长度片段喂给一维卷积网络或全连接网络模型就能自动学到不同故障部位和损伤程度在波形上的判别性模式。如果你手里正好有Fault_Diagnosis-master这个项目包里面就是一套完整可跑的 CNN 与 DNN 诊断流程适合两类人一是刚入门故障诊断、想用公开数据集验证深度学习流程的研究生和工程师二是已经在用传统特征方法、想对比深度学习基线效果的设备健康管理从业者。2. CWRU 数据集理解与预处理creat_data.py 的信号切片逻辑2.1 CWRU 数据为什么是故障诊断的「MNIST」CWRU凯斯西储大学滚动轴承数据中心是故障诊断领域使用最广泛的公开基准数据。实验台由电机、扭矩传感器、编码器和测功机组成通过电火花加工在轴承上人为制造单点故障故障位置分为滚动体、内圈、外圈三类损伤直径有 0.007、0.014、0.021 英寸三档加上正常状态总共构成 10 类工况。信号采样频率有 12kHz 和 48kHz 两档载荷从 0 到 3 马力对应转速大约 1730 到 1797 rpm。项目文件名里的 1750、1730、1772 就是不同负载下的实际转速这一点在后续划分训练集和测试集时必须留意——不同转速下同一故障的振动特征会有差异如果把不同转速数据混在一起又不做处理模型的泛化能力会被高估。# 以 12kHz 采样率、负载 1 马力约 1772 rpm为例 import scipy.io as sio mat sio.loadmat(1772_12k_DR.mat) # 内圈故障0.014 英寸 key [k for k in mat.keys() if DE in k][0] vibration mat[key].flatten() print(f采样点数: {vibration.shape[0]}对应时长: {vibration.shape[0] / 12000:.2f}s)这段代码读取的是驱动端加速度计数据DE 通道实际项目中通常只用 DE 通道就够了。需要注意.mat文件里同一个键名可能对应多组数据比如内圈故障文件里包含多个转速段的信号需要根据实际转速筛选对应片段。2.2 滑窗切片的两个关键参数窗口长度与步长深度学习模型不能直接消化几秒甚至几十秒的连续振动信号所以要做滑窗切片。窗口长度的选择有讲究太短一个窗口里包含的冲击周期数不够模型学不到完整的故障特征太长样本数量减少而且一个窗口里可能混入转速波动或其它干扰。对于 12kHz 采样率下的轴承外圈故障特征频率通常在 100Hz 到 300Hz 之间一个窗口至少要包含 2 到 3 个冲击周期我一般取 1024 或 2048 个采样点。def sliding_window(data, window_size1024, step512): samples [] for start in range(0, len(data) - window_size, step): samples.append(data[start:start window_size]) return np.array(samples) # 对每类故障生成样本 X sliding_window(vibration, window_size1024, step512) print(f单类样本数: {X.shape[0]}单样本长度: {X.shape[1]})步长决定了相邻窗口的重叠程度。步长等于窗口长度时样本之间无重叠信息利用率最低但独立性最好步长取窗口长度的一半时相邻样本有一半重叠相当于做了数据增强训练样本量翻倍。CWRU 每个文件大约 12 万到 48 万个采样点不加重叠也能切出上百个样本10 类工况合计几千个样本对 DNN 和 CNN 来说完全够用。2.3 train/test 划分的坑先切片再划分否则信息泄漏这是我见过的初学者最容易犯的错误之一。如果先对整个连续信号做 train/test 划分再去切片那么测试集里的某些窗口和训练集里的某些窗口在时间上是重叠的模型等于见过测试数据最终准确率会虚高到 99% 以上。正确做法是先切片、再做随机划分或者按时间段划分——用前 70% 时间段的样本做训练后 30% 时间段的样本做测试。在实际的工业场景中我更推荐按时间段划分因为设备运行数据是流式采集的模型需要面对的是未来时刻的数据而不是与训练数据同时段的重复样本。from sklearn.model_selection import train_test_split # 先切片获得 X_all, y_all再划分 X_train, X_test, y_train, y_test train_test_split( X_all, y_all, test_size0.3, stratifyy_all, random_state42 )stratifyy_all保证每个故障类别在训练集和测试集中的比例一致避免某一类故障样本过少导致模型根本没学会它的特征。CWRU 数据本身类别均衡但加上这个参数可以在后续扩展自己的数据集时少踩一个坑。3. 模型构建从 DNN 到一维 CNN 的完整实现3.1 DNN 基线全连接网络处理振动信号的上限在哪里项目里的dnn.py提供了一个全连接网络基线。它的思路是把 1024 个采样点直接展平成一维向量然后接若干层全连接层。这种做法的优点是实现简单、训练速度快缺点是忽略了振动信号的局部结构——波形相邻点之间的相关性没有被显式建模。但对于 CWRU 这类信噪比很高的数据DNN 往往也能达到 95% 以上的准确率这恰恰说明基线的价值在于给后续更复杂的模型提供对比参照而不是追求极致的精度。import torch.nn as nn class DNN(nn.Module): def __init__(self, input_dim1024, num_classes10): super().__init__() self.net nn.Sequential( nn.Flatten(), nn.Linear(input_dim, 512), nn.ReLU(), nn.Dropout(0.3), nn.Linear(512, 128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, num_classes) ) def forward(self, x): return self.net(x)网络结构遵循一个朴素的规律每一层神经元的数量逐级递减从 1024 压缩到 512 再到 128最后映射到 10 个类别。Dropout的作用是随机丢弃一部分神经元防止全连接层把训练集中的噪声细节也背下来。输入维度 1024 必须与切片窗口长度一致如果你在creat_data.py里改了窗口大小这里也要同步修改。3.2 一维 CNN用卷积核捕捉振动冲击的局部模式卷积神经网络在故障诊断中的优势在于参数共享和局部感受野。一维卷积核沿着时间轴滑动每个卷积核相当于一个模板匹配器——有些模板学到的可能是外圈故障冲击的周期性形态另一些可能学到的是内圈故障调制产生的包络变化。相比 DNN 需要学习每一对输入输出之间的连接权重CNN 的卷积核参数在所有时间位置上共享参数量大幅减少同时归纳偏置更贴合振动信号的局部相关特性。import torch.nn as nn class CNN1D(nn.Module): def __init__(self, num_classes10): super().__init__() self.features nn.Sequential( nn.Conv1d(1, 16, kernel_size64, stride8, padding28), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(16, 32, kernel_size32, stride4, padding14), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(32, 64, kernel_size16, stride2, padding7), nn.ReLU(), nn.AdaptiveAvgPool1d(1) ) self.classifier nn.Linear(64, num_classes) def forward(self, x): # x: (batch, 1024) x x.unsqueeze(1) # (batch, 1, 1024) feat self.features(x) # (batch, 64, 1) feat feat.squeeze(-1) # (batch, 64) return self.classifier(feat)第一层卷积核宽度设为 64对应的物理含义是一次性观察 64 个连续采样点在 12kHz 采样率下大约是 5.3 毫秒的波形。这个长度足以覆盖一个冲击响应的上升沿和衰减过程但又不会长到把多个不同冲击混在一起。stride8表示卷积核每次滑动 8 个点输出特征图的长度约为输入长度的 1/8这是一种朴素的降采样方式。padding的计算公式是(kernel_size - stride) // 2用于保证卷积输出的长度能整除后续的池化操作。最后的AdaptiveAvgPool1d(1)把每个通道的特征图压缩成一个标量相当于取整个特征图在时间维度上的平均值从而抹平了输入长度差异带来的维度问题。3.3 训练脚本的通用骨架优化器、损失函数与评估指标无论 DNN 还是 CNN训练流程都是由四个步骤反复循环构成前向传播计算损失、反向传播计算梯度、优化器更新参数、周期性评估验证集指标。项目里的两个训练脚本遵循同样的骨架不同之处只在于传入的模型对象和输入维度。def train(model, train_loader, val_loader, epochs50, lr1e-3): optimizer torch.optim.Adam(model.parameters(), lrlr) scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size15, gamma0.5) criterion nn.CrossEntropyLoss() for epoch in range(epochs): model.train() for x, y in train_loader: pred model(x) loss criterion(pred, y) optimizer.zero_grad() loss.backward() optimizer.step() model.eval() with torch.no_grad(): val_acc (model(x_val).argmax(1) y_val).float().mean().item() print(fepoch {epoch1}: loss{loss.item():.4f}, val_acc{val_acc:.4f})优化器选择 Adam 而不是传统的 SGD原因是 Adam 自带自适应学习率对初始学习率的敏感度低很多在没有精细调参的前提下通常十几轮迭代就能收敛到较好的精度。StepLR每 15 轮把学习率减半作用是让模型在训练后期做更精细的权重调整。CrossEntropyLoss内部已经包含了 Softmax 操作所以模型最后一层不需要额外加 Softmax 激活函数。4. 实验设计与结果对比训练配置、评估维度与绘图脚本4.1 标签映射与类别组织CWRU 数据整理后的标签体系需要特别明确。一个典型的 10 分类设置是1 类正常9 类故障3 种位置 × 3 种损伤直径。但在实际项目里你也可以只做 4 分类正常、内圈、外圈、滚动体忽略损伤直径的差异。两种设计各有用武之地10 分类任务更细粒度对模型的区分能力要求更高适合评估特征表达的质量4 分类任务更贴近工业现场的决策逻辑因为运维人员首先关心的是「哪个部件坏了」其次才关心「损伤有多严重」。# 标签编码示例 label_map { normal: 0, inner_007: 1, inner_014: 2, inner_021: 3, outer_007: 4, outer_014: 5, outer_021: 6, ball_007: 7, ball_014: 8, ball_021: 9 } # 划分后建议用 Counter 检查每类样本量 from collections import Counter print(Counter(y_train.tolist())) # 确认每类都有足够样本在训练之前检查类别分布是一个好习惯。CWRU 数据的每个文件可以切出数百个样本但如果某个文件在读取时出现了故障比如 mat 文件损坏对应的类别可能只有几十个样本这会导致模型在该类上的表现明显低于其它类。4.2 训练过程中的收敛行为与参数调整用 DNN 跑 CWRU 数据常见的收敛曲线是这样的前 5 轮训练集准确率快速冲到 90% 以上验证集准确率同步上升但略有滞后到 15 轮以后训练集准确率接近 100%验证集准确率在 95% 到 99% 之间波动。如果验证集准确率始终比训练集低好几个百分点说明模型过拟合了此时优先调整 Dropout 的概率从 0.3 提高到 0.5或者缩小网络中间层的神经元数量。如果验证集准确率在 20 轮后还在明显上升说明训练轮数不够可以继续增加epochs并观察是否进入平台期。CNN 的训练收敛通常比 DNN 更快这是卷积核参数共享带来的直接收益。但同时 CNN 对 batch size 更敏感batch size 太小会导致梯度估计噪声大、训练不稳定batch size 太大会让每个 epoch 的迭代次数减少模型整体收敛速度反而变慢。我一般从 32 起步显存不够就降到 16只影响训练速度不影响最终精度。4.3 用 plot_scatter.py 检验模型学到了什么项目里的plot_scatter.py配合last_layer_data目录使用目的是把最后一层隐藏层的输出也就是模型对每个样本提取的高维特征降维到二维平面并可视化。PCA 适合观察的全局分布结构t-SNE 更适合观察局部聚类关系。如果不同故障类别在二维图上形成清晰的簇说明模型的中间层特征确实学到了具有判别性的表示反之则说明特征表达不足或数据划分有问题。from sklearn.manifold import TSNE import matplotlib.pyplot as plt # features: (N, 64) 模型最后一层输出, labels: (N,) 类别标签 tsne TSNE(n_components2, perplexity30, learning_rateauto) emb tsne.fit_transform(features) plt.figure(figsize(8, 6)) for i in range(10): mask labels i plt.scatter(emb[mask, 0], emb[mask, 1], s5, labelfclass {i}) plt.legend() plt.savefig(tsne_result.png, dpi150)perplexity参数控制 t-SNE 中每个点考虑的邻居数量取值通常在 5 到 50 之间样本量大时可以适当调大。如果发现图中各类簇纠缠严重先不要急着换模型结构检查训练集和测试集的分布是否有差异——比如训练集中某一故障类型的损坏程度与测试集中的不同模型自然会把它们映射到不同的分布区域。5. 从 CWRU 到工业现场迁移学习的边界与落地建议5.1 用last_layer_data做小样本诊断的迁移基线CWRU 数据上训好的模型直接部署到现场设备通常会失效——现场轴承的型号、转速、负载、传感器安装位置都与实验台不同振动信号的幅值和频谱分布会整体偏移。一个行之有效的做法是把预训练模型当作特征提取器冻结前面的卷积层只微调最后的全连接层。具体的做法是加载 CWRU 上训练好的模型权重替换最后一层分类器然后用现场采集的少量标注数据比如每类故障 50 到 100 个样本做几轮训练。# 加载预训练模型并冻结特征层 model CNN1D(num_classes10) checkpoint torch.load(cnn_cwru.pth, map_locationcpu) model.load_state_dict(checkpoint[model_state_dict]) # 替换分类头为现场工况的类别数 model.classifier nn.Linear(64, 4) # 现场只区分正常/内圈/外圈/滚动体 for param in model.features.parameters(): param.requires_grad False # 冻结特征提取层 # 只训练分类头学习率可以调大一些 optimizer torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr1e-2)这里把分类头从 10 类改成 4 类是因为现场诊断不需要区分 CWRU 的三种损伤直径。冻结特征层之后反向传播只更新最后一层权重训练数据量需求大幅降低几十个标注样本就足以得到一个可用的分类模型。如果现场数据与实验室数据差距太大冻结层微调效果不佳可改为冻结前两层卷积、微调后一层卷积和全连接层让高层的表达对现场数据的分布做进一步的适配。5.2 模型验证的三重维度模型训练完成后除了准确率还需要观察几项指标。混淆矩阵可以告诉你哪些类别之间容易互相混淆这里最常见的是外圈故障和滚动体故障——因为两者的冲击特征频率比较接近而且传感器的传递路径可能把外圈故障的信号调制得和滚动体故障相似。精确率与召回率在故障诊断中比准确率更有价值因为误报和漏报的成本是不对称的漏报一次可能导致设备停机甚至事故误报一次只是增加一次不必要的停机检查。实时推理性能也需要验证。在 CPU 上运行 1024 点窗口的一维 CNN单次推理耗时通常不到 1 毫秒完全满足在线监测的实时性要求。可以用以下脚本做吞吐量测试import time, torch model.eval() x torch.randn(1, 1, 1024) with torch.no_grad(): # 预热 10 次排除第一次的初始化开销 for _ in range(10): model(x) start time.time() for _ in range(1000): model(x) elapsed time.time() - start print(f单次推理平均耗时: {elapsed / 1000 * 1000:.2f} ms)5.3 现场落地的数据流组织思路工业现场的振动信号采集是连续的诊断流程可以按「滑动窗口 周期推理」的模式组织。传感器以 12kHz 或更高频率采集信号每次攒够 1024 个采样点就触发一次推理相邻窗口之间可以设置 50% 重叠以提升时间分辨率。推理结果通过多数投票聚合到分钟级别只有连续多个窗口都判定为同一故障类型时才触发报警这个简单的去抖策略能极大地减少由瞬时冲击或电磁干扰引起的误报。这项工作的核心价值在于把「调参经验」沉淀为「可复现的代码与数据流程」。CWRU 数据只能证明模型在实验条件下的表现真正实现工业落地还需要采集现场数据、标注故障类别并持续迭代。从现在开始建议你先把项目里的creat_data.py跑通确认数据切片逻辑与自己的理解一致再依次运行 DNN 和 CNN 的训练脚本最后用plot_scatter.py记录下每类故障的特征分布图——这三步做完整条深度学习诊断流水线就已经在你手里了。本文还有配套的精品资源点击获取
返回列表