CWRU轴承数据集与1D CNN深度学习故障诊断完整实战
简介面向深度学习故障诊断方向学习者一项基于西储大学CWRU轴承数据集的CNN诊断分析项目覆盖滚动轴承正常、内圈、外圈及滚动体等多种故障状态的识别任务适合课程设计、毕业设计及工业智能运维入门实践。项目已配置TensorFlow 1.7.1与Keras 2.2.4环境附带处理好的.mat数据集和可直接运行的Python预测程序无需调试即可复现完整故障分类流程并梳理了从原始振动信号到特征提取再到模型评估的代码逻辑。资源共117个文件包含45个MATLAB数据文件原始振动信号、Python源码、模型权重文件.pth、TensorBoard训练日志、可视化图片与配置文件等压缩包大小145.86MB目录结构清晰便于按模块学习或替换数据进行扩展实验。已有10383人浏览学习可帮助读者快速掌握CNN在故障诊断中的实战思路同时借助训练日志分析调参细节与模型收敛状态对复现和二次开发均有参考价值。 做深度学习故障诊断绝大多数入门者最后都会绕到西储大学CWRU轴承数据集上来。这个项目就是完整的“数据集 预处理 模型 训练评估”开源流水线第1期先把最核心的主线打通用Python读取CWRU振动信号做滑窗采样和标签制作搭建一维卷积神经网络1D CNN完成轴承内圈、外圈、滚动体、正常四种状态的分类诊断。整套代码在普通CPU机器上就能跑通不需要GPU非常适合刚接触深度学习、准备做故障诊断方向课题或毕业设计、以及想快速建立一条baseline的同学。我直接说结论这条路是故障诊断领域最成熟的入门路径踩坑最少、见效最快。1. 项目整体思路与方案选型1.1 为什么首选西储大学轴承数据集凯斯西储大学Case Western Reserve University轴承数据中心发布的数据集可以说是轴承故障诊断界的“MNIST”。几乎所有做故障诊断的论文都会用它做验证公开时间早、数据标注完整、采样频率和负载工况齐全研究社区里积累了大量可供对比的结果。数据集本身的信号来自SKF 6205-2RS深沟球轴承通过电火花加工在轴承上人为制造不同尺寸的故障点然后用加速度传感器采集振动信号。故障类型分为内圈故障Inner Race、外圈故障Outer Race、滚动体故障Ball/Rolling Element每种故障下又有0.007英寸、0.014英寸、0.021英寸三种损伤尺寸再加上正常状态样本覆盖了旋转机械最典型的轴承失效模式。采样频率提供12kHz和48kHz两种驱动端和风扇端都有传感器数据。选择这个数据集做深度学习诊断项目理由很实在数据量适中完整下载也就几百兆类别标签划分清晰振动信号是一维时序数据不需要额外做图像处理可以把精力全部聚焦在“深度学习怎么做故障诊断”这条主线上。1.2 技术路线选型为什么先用1D CNN故障诊断的深度学习方法大体上有三条路。第一条是把原始振动波形直接送入一维卷积网络做端到端学习第二条是先做FFT变换得到频谱再把频谱送入模型第三条是计算时频图比如小波变换、短时傅里叶变换用二维CNN或ResNet处理图像。第1期我选择“原始时域信号 1D CNN”的组合核心考虑是时域信号保留了最完整的原始信息不需要人工设计特征模型能否自动从波形中提取有效模式直接反映了深度学习的特征自学习能力。1D CNN的参数量比2D CNN小很多训练速度快在少量样本和有限算力下更容易收敛对初学者非常友好。FFT频谱和时频图确实有时能带来精度提升但属于后续优化方向不应该在入门阶段一起堆上来——经验不足时反而会不知道问题出在数据还是模型上。另外从故障机理角度看轴承故障会在振动信号中激起周期性冲击成分不同故障位置产生的冲击频率不同。内圈故障、外圈故障、滚动体故障的特征频率与转频存在特定比例关系。深度模型要做的事情本质上是自动捕捉这些频域和时域上的统计差异。理解这一点有助于你后续分析模型为什么分错、数据划分应该注意什么。2. 数据准备与预处理细节2.1 CWRU数据下载与文件命名规律CWRU数据集可以从官网直接下载也可以在GitHub上找到整理好的镜像仓库。下载后你会看到大量.mat文件文件名和所在目录决定了它的工况和故障信息。这里要特别注意不同的整理版本命名可能稍有差异但核心规律是一致的。以常见的12kHz驱动端数据为例我用了这样一批典型文件故障类型损伤尺寸英寸典型文件编号正常无97, 98, 99, 100内圈故障0.007105内圈故障0.014169内圈故障0.021209滚动体故障0.007118滚动体故障0.014185滚动体故障0.021222外圈故障6点钟方向0.007130外圈故障6点钟方向0.014197外圈故障6点钟方向0.021234外圈故障还分为3点钟、6点钟、12点钟方向其中6点钟方向是载荷区故障响应最明显诊断难度也相对低入门阶段用这一组就够了。需要提醒的是不同分享版本里文件编号可能不完全一致跑之前先打印一下.mat文件的字段确认里面包含DE驱动端加速度计、FE风扇端加速度计、BA基座这几个键。2.2 滑窗采样让有限数据发挥最大价值原始.mat文件里是一整段连续振动信号无法直接作为模型输入。我们需要用滑窗的方式切成很多固定长度的样本。这一步有两个关键参数窗口长度和步长。代码实现大致是这样import numpy as np from scipy.io import loadmat def load_cwru_mat(filepath, channelDE, start0, lengthNone): data loadmat(filepath) for key in data.keys(): if key.startswith(__): continue signal data[key].flatten() if channel.upper() in key.upper(): break if length is not None: signal signal[start:start length] return signal def sliding_window(signal, window_length2048, stride1024): samples [] n len(signal) for i in range(0, n - window_length 1, stride): samples.append(signal[i:i window_length]) return np.array(samples)窗口长度我习惯取2048个采样点。在12kHz采样率下2048点对应约0.17秒的信号如果是转频30Hz左右的工况这个长度能覆盖约5个转频周期足够包含多个故障冲击周期。窗口太大样本数会急剧减少窗口太小单样本包含的故障周期太少模型学不到稳定的冲击特征。这是工程上的一个平衡选择。步长方面我用1024也就是窗口之间重叠50%。重叠滑窗能显著扩充样本量对于CWRU这种每类只有一个.mat文件的场景非常关键。一个120万点的信号用2048长度做滑窗能得到约1170个样本如果不重叠只有约585个样本。深度学习模型对数据饥渴重叠采样是我在这个项目中最重要的数据增强手段效果比在信号上加噪声、做时间拉伸更稳定。2.3 标签制作与数据集划分的核心陷阱标签制作看起来简单正常是0内圈故障是1滚动体是2外圈故障是3。但分类粒度需要提前想清楚。一种做法是只分4类不管损伤尺寸另一种做法是把损伤尺寸也带上做10类分类。第1期我用4类理由是这样每个类别样本量更充足模型更容易收敛也便于评估混淆矩阵。数据划分是这个项目最容易翻车的地方很多人把滑窗后的所有样本直接随机打乱然后按7:3切训练集和测试集结果测试准确率高达99%感觉效果爆炸。但这是典型的“数据泄漏”同一个原始信号切出来的相邻窗口内容高度相似极可能同时出现在训练集和测试集里模型相当于“背过答案”。正确做法是先按原始.mat文件切分或者确保划分时来自同一个原始文件的窗口全部进同一侧。我采用的做法是每个.mat文件生成的所有窗口作为一个整体先放入待分配池再按文件维度随机分配保证训练集和测试集来自不同工况或不同文件。def split_by_file(samples_by_file, train_ratio0.6, val_ratio0.2, seed42): np.random.seed(seed) file_names list(samples_by_file.keys()) np.random.shuffle(file_names) n_train int(len(file_names) * train_ratio) n_val int(len(file_names) * val_ratio) train_files file_names[:n_train] val_files file_names[n_train:n_train n_val] test_files file_names[n_train n_val:] return train_files, val_files, test_files归一化也要注意时序顺序必须先划分、后归一化并且用训练集的统计量均值和标准差去归一化验证集和测试集不能用整个数据的全局统计量否则又是一种信息泄漏。3. 模型搭建与训练实操3.1 一维CNN网络结构设计这个项目用的模型不复杂核心就是Conv1d BatchNorm ReLU MaxPooling 全局平均池化 全连接层。我给出一个经过调参、在CWRU四分类上非常稳定的结构import torch import torch.nn as nn class FaultDiagnosisCNN(nn.Module): def __init__(self, num_classes4): super().__init__() self.features nn.Sequential( nn.Conv1d(1, 32, kernel_size7, stride2, padding3), nn.BatchNorm1d(32), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), nn.Conv1d(32, 64, kernel_size5, stride2, padding2), nn.BatchNorm1d(64), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), nn.Conv1d(64, 128, kernel_size3, stride2, padding1), nn.BatchNorm1d(128), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), ) self.classifier nn.Sequential( nn.AdaptiveAvgPool1d(1), nn.Flatten(), nn.Dropout(0.3), nn.Linear(128, num_classes) ) def forward(self, x): x self.features(x) x self.classifier(x) return x几个设计点解释一下。第一层卷积核设为7是因为轴承故障冲击在时域上表现为窄脉冲较大的感受野有助于捕捉冲击的局部形态后续卷积核逐渐缩小到3是为了在更抽象的层次提取特征。BatchNorm放在卷积之后、激活之前能加速收敛、缓解梯度消失对这些尺度变化大的振动信号尤其重要。全局平均池化替代传统的Flatten全连接既减少参数量也让模型对输入长度不敏感。最后的Dropout比例0.3是经验值太高容易欠拟合太低防过拟合效果不明显。3.2 训练超参数与优化器选择损失函数用交叉熵。有人可能会问故障诊断是不是回归问题不是类别之间没有数值大小关系交叉熵配合Softmax输出概率分布才是分类任务的正解。如果用MSE模型会被迫把不同类别往固定的数值上拟合不仅收敛慢分类边界也不稳定。优化器用Adam学习率初始设为0.001。Adam对超参数不敏感、自带自适应学习率是入门阶段最省心的选择。但Adam不等于不需要学习率调整我在训练中加了余弦退火CosineAnnealingLR前50个epoch学习率从1e-3逐渐降到1e-5让模型先快速下降、后期精细收敛实测比固定学习率稳定不少。训练核心循环criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max50)Batch size我选64在CPU上训练一个epoch大约几十秒跑50个epoch两小时左右能完成。这里有个经验如果发现训练集loss震荡不下降优先尝试把学习率降到1e-4而不是盲目加大模型。很多时候模型不动不是容量不够是步子迈太大在最优解附近反复横跳。3.3 训练过程评估不能只看准确率训练完成后除了整体准确率一定要看混淆矩阵和每一类的精确率、召回率、F1。轴承故障诊断场景中不同故障类别容易被混淆尤其是滚动体故障和外圈故障二者的振动冲击特征在时域上比较接近。单独一个准确率数字会掩盖这些问题。我把混淆矩阵的可视化代码封装好每次训练结束自动输出from sklearn.metrics import confusion_matrix, classification_report import matplotlib.pyplot as plt import seaborn as sns def plot_confusion_matrix(y_true, y_pred, labels): cm confusion_matrix(y_true, y_pred) plt.figure(figsize(8, 6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelslabels, yticklabelslabels) plt.xlabel(Predicted) plt.ylabel(True) plt.savefig(confusion_matrix.png, dpi150) print(classification_report(y_true, y_pred, target_nameslabels))还有一个好用的小技巧把最后一个卷积层输出的特征向量保存下来用t-SNE降到二维做散点图。如果不同类别的特征聚成清晰的簇说明模型学到了有区分度的表示如果混成一团那即使准确率还行模型的鲁棒性也存疑。这一步我强烈建议做它能帮你在可视化层面判断模型是否真的“理解”了故障特征而不是在乱猜。4. 常见问题与排查技巧实录4.1 测试准确率虚高数据泄漏怎么查这个项目里80%的“准确率爆炸”都源于数据泄漏。判断方法其实很简单如果测试准确率明显高得不正常比如超过99%先检查滑窗之间有没有重叠、划分前有没有全局打乱。我自己的排查流程是随机抽一个测试集样本在原始信号里找到它对应的窗口起始位置再看这个窗口的相邻窗口是否出现在训练集里。如果重叠了立刻回到按文件划分的方案。就算按文件划分还有一个容易被忽略的点同一个.mat文件里前后段信号的工况状态可能略有变化如果你的滑窗步长非常小窗口重叠率太高本质上是同一个片段的复制粘贴测试集会包含训练集几乎相同的信息。解决方法是把步长加大或者至少保证不同文件之间完全独立。我实测下来按文件划分后准确率会从虚高的99%降到92%~95%左右这才是真实水平。4.2 Loss不下降的排查顺序Loss一直不降先不要改模型结构按这个顺序排查第一步看输入数据有没有归一化振动信号原始数值通常在小数位波动卷积层初始化权重对输入尺度很敏感不做归一化模型可能半天学不动第二步看标签和样本有没有错位滑窗后保存样本的顺序和标签顺序是否一致是经典的低级错误第三步看类别分布是否均衡CWRU四类基本均衡但如果你自己采集的数据集类别悬殊就要加类别权重第四步看一个batch甚至一个样本能不能过拟合如果单个样本都过拟合不了说明模型表达能力或者代码逻辑有问题这时候再去检查forward里有没有写错维度。我还遇到过一种很隐蔽的问题DataLoader里设置了shuffleTrue但每次迭代都在重新打乱同一个epoch的数据导致验证集分布不稳定表现为验证loss上下剧烈波动。解决办法是固定随机种子或者把shuffle只在每个epoch开始时执行一次。PyTorch的DataLoader默认行为没这个问题但如果你自己写了数据迭代逻辑就要特别小心。4.3 PyTorch环境配置与CUDA坑环境配置是很多新手止步的第一道坎。PyTorch安装时最稳妥的方式是用虚拟环境隔离我习惯用conda创建独立环境。如果你用的是CPU跑安装无CUDA版本即可官网的pip install torch会自动适配。如果你有NVIDIA独立显卡想上GPU安装前先执行nvidia-smi查看CUDA版本再到PyTorch官网选择对应版本的安装命令。这里最容易出的问题是PyTorch版本要求的CUDA版本和本机驱动不匹配安装后torch.cuda.is_available()返回False。这不一定是安装失败很可能是PyTorch编译时的CUDA版本高于驱动支持的版本需要降级安装旧的PyTorch或者升级显卡驱动。国内下载PyTorch和大模型权重慢是常态我通常用镜像源安装比如pip install torch -i指定国内镜像地址速度能快很多。还有个小技巧如果conda慢优先用pip因为conda依赖解析太慢。只要能跑torch.Tensor的运算环境就算通了。注意如果运行时报错RuntimeError: CUDA out of memory最直接的办法不是调小模型而是调小batch size比如从64降到32或者把输入长度从2048降到1024当然这会影响模型精度需要重新评估。项目代码里我默认自动选择CPU或GPUdevice torch.device(cuda if torch.cuda.is_available() else cpu)这样没有GPU也能完整运行。4.4 让实验结果可复现的细节深度学习代码里随机性无处不在模型权重初始化、数据加载顺序、Dropout行为都依赖随机数的产生。如果不固定随机种子同一份代码跑两次结果是不同的给调试和对比带来很大困扰。我在项目开头统一固定所有随机源import random import numpy as np import torch def set_seed(seed42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic True torch.backends.cudnn.benchmark False还有一个小坑cudnn.benchmark默认是True它会动态寻找最优卷积算法导致即使固定了种子两次运行结果也可能不同。设置成False可以保证严格可复现代价是会慢一点点。对于追求复现稳定性的故障诊断实验这个牺牲是值得的。固定随机种子之后我建议每个实验跑3次取平均值报告结果因为单次运行的偶然波动在92%和94%之间不足以说明模型优化有效。魔改网络结构之前先确认基线是否稳定这是做深度学习实验的基本素养。写在最后的一个经验这个项目第1期就做到“能跑通、能复现、能分析”的程度已经算真正迈进了深度学习故障诊断的大门。我个人在实际操作中的体会是数据预处理和实验设计是否严谨比换一个更复杂的网络结构重要得多。你与其上来就试ResNet、Transformer不如先把1D CNN在CWRU上的完整链路吃透跑通数据划分、模型训练、结果评估这几个环节。第1期整体跑下来如果你发现准确率稳定在92%以上接下来再往时频图、注意力机制、迁移学习方向扩展时你会清楚每一个改动的收益到底来自哪里。后期还可以做跨负载迁移实验、加入更多故障尺寸做细粒度分类但那是后面几期的事先把第一条baseline攥在手里。本文还有配套的精品资源点击获取