尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于一维CNN的轴承故障诊断:从数据处理到工程部署

基于一维CNN的轴承故障诊断:从数据处理到工程部署 简介一份基于卷积神经网络的轴承故障诊断算法模型研究项目源码面向计算机及相关专业学生完成期末大作业、课程设计或毕业设计参考。项目已通过导师评审并获96分以上评价代码经严格调试可确保运行。压缩包共53个文件以40个.mat轴承振动数据文件为主体涵盖0HP、1HP、2HP、3HP等不同负载工况3个.py脚本分别实现数据预处理、模型训练与主流程控制并配有.xml配置、训练日志、模型结构图及说明文档整体包体大小45.24MB。目前已有467人学习下载。源码清晰划分数据加载、特征提取、卷积网络构建与评估模块附带运行环境依赖清单方便快速复现实验。结合WDCNN模型的可视化结果能帮助读者直观理解CNN在旋转机械故障识别中的完整流程是深度学习期末项目的高分范本。1. 基于卷积神经网络的轴承故障诊断项目到底在解决什么问题滚动轴承是旋转机械中出现故障概率最高的部件。基于卷积神经网络的轴承故障诊断项目核心目标是让模型直接分辨内圈、外圈、滚动体损伤等故障类型。这个思路在公开数据集上精度已经很高但源码里真正决定成绩的不是网络有多深而是数据怎么切、标签怎么对齐、训练和验证如何避免数据泄漏以及模型能不能从“跑通”走向“高可用”。这个项目源码对应的学习路径就是当前机械故障诊断最主流的一维卷积神经网络方案。对做课程设计和毕业设计的读者来说它提供了一个完整可复现的算法模型基准对想从传统信号处理转向深度学习的工程师也能看清数据预处理、网络搭建和工程落地的衔接点。下面的内容不依赖某个特定数据集的特殊性换到自己的振动数据上流程同样成立。2. 从一维振动信号到训练样本CNN输入怎么构造CNN最早出名是在图像领域而轴承故障诊断的原始数据是时序信号。如果直接把一段振动加速度波形当成“一行像素”喂给模型要做的第一件事不是定网络结构而是先确定输入片段和物理过程的对应关系。这是源码项目里最容易拉开质量差距的地方。2.1 先算轴承故障诊断机理里的特征频率再定窗口长度轴承故障诊断机理中外圈和内圈故障会在振动信号里产生周期性冲击冲击间隔与转频、滚动体数量、接触角之间存在确定关系。窗口长度的下限应该由这个间隔决定而不是随便取个1024或2048了事。import numpy as np def bearing_fault_freq(rpm, n_ball, ball_d, pitch_d, contact_angle0.0): fr rpm / 60.0 bpfo n_ball / 2.0 * fr * (1 - ball_d / pitch_d * np.cos(contact_angle)) bpfi n_ball / 2.0 * fr * (1 ball_d / pitch_d * np.cos(contact_angle)) return bpfo, bpfi这段代码计算外圈故障特征频率BPFO和内圈故障特征频率BPFI两个值是后续所有窗口设置的基础。以CWRU数据集中常见的6205轴承为例1500rpm下BPFO约在107Hz附近BPFI约在178Hz附近25.6kHz采样率下1024点对应约40ms能覆盖2到4个外圈故障冲击周期。这个长度足以让第一层卷积核看到完整的“冲击-衰减”形态又不至于让单样本包含过多工况变化。窗口短于一个故障周期时模型看到的是冲击间歇期卷积极容易把背景噪声当特征表现就是训练集准确率虚高、验证集波动剧烈。反过来窗口取到4096点以上也不是不行只是样本数量会成比例减少训练时间明显拉长在样本量本就不大的故障诊断项目里收益有限。2.2 原始时域波形 vs 手工特征为什么一维CNN能省掉特征工程传统诊断流程里需要对每段信号计算均值、峰值因子、峭度、裕度等统计量再用FFT提取频域幅值组合成高维特征向量交给SVM或随机森林。这套流程中的峭度和峰值因子对早期微弱故障有一定敏感性但对接触角变化、负载波动等工况变化也很敏感而且手工筛选特征在不同数据集之间几乎不可迁移每换一台设备就要重新做一轮特征工程。一维卷积神经网络1D-CNN的思路完全不同。卷积核是自动学习的滤波器第一层会形成类似带通滤波响应的权值深层会把不同频带的局部响应组合成冲击间隔、共振冲击这类抽象模式。这也是为什么源码项目里通常看不到复杂的EEMD或小波降噪步骤只做简单滑窗切分和幅度归一化剩下的特征提取工作全部交给CNN在训练中完成。def normalize_signal(signal): signal signal - np.mean(signal) std np.std(signal) if std 1e-8: signal signal / std return signal这段函数按单个样本独立做零均值化再除以标准差。按样本归一化而不是按整个数据集归一化是因为部署阶段拿到的实时数据同样可以按这个方式处理不需要保存训练集的全局统计量也不受新数据分布漂移的影响。2.3 数据集划分先按文件再切样本避免时间邻居泄漏公开数据集中每种故障下包含多段连续记录每段记录来自不同的损伤直径和负载工况。如果直接对切片后的样本做随机split同一段连续信号的一部分滑进训练集、另一部分滑进验证集验证集准确率会虚高几个百分点因为相邻片段的噪声形态高度相似本质上这是一种时间邻居泄漏。from sklearn.model_selection import train_test_split file_names sorted(set(s[source_file] for s in all_samples)) train_files, val_files train_test_split( file_names, test_size0.2, random_state42 ) train_samples [s for s in all_samples if s[source_file] in set(train_files)] val_samples [s for s in all_samples if s[source_file] in set(val_files)]第一行从所有样本里取出源文件名集合第二行在文件维度做划分后面两行再按文件归属收集样本。这个顺序比直接对切片样本做train_test_split慢但它保证了同一连续信号的片段不会同时出现在两个集合里。对时间序列类的诊断任务这一步直接决定验证分数的可信度。窗口长度点数适用场景典型问题256512高转速、冲击次数密集样本独立性差单样本信息量不足10242048常规1500rpm附近转速需要配合1/4窗长步长增加样本量4096及以上低转速、早期微弱故障样本数下降训练时长上升表里的重叠滑窗指stride小于窗口长度。窗口1024、stride256时样本数量大约变为原来的4倍同时保持相邻窗口之间的连续语义这是源码里最常见的一组参数搭配。3. 用PyTorch搭一个能跑通的一维CNN轴承故障诊断模型选PyTorch做算法模型搭建主要因为故障诊断类项目经常要看中间特征图、做梯度可视化动态图机制调试起来直观。TensorFlow也能实现但在这种定制化网络结构上改一处卷积核尺寸就要重新审视数据流麻烦很多。3.1 卷积神经网络结构图适合轴承信号的通道和卷积核设置卷积神经网络结构图里决定性能的不是网络有多少层而是每一层的卷积核大小和通道数是否匹配信号本身的物理尺度。第一个卷积层建议用较大的卷积核比如64或128而不是图像任务里默认的3。一维振动信号中单个故障冲击的持续时间通常是几十个采样点大核能一次性覆盖整个冲击波形让第一层就捕获冲击的整体轮廓。import torch.nn as nn class BearCNN(nn.Module): def __init__(self, num_classes4): super(BearCNN, self).__init__() self.features nn.Sequential( nn.Conv1d(1, 16, kernel_size64, stride4, padding30), nn.BatchNorm1d(16), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), nn.Conv1d(16, 32, kernel_size5, padding2), nn.BatchNorm1d(32), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), nn.Conv1d(32, 64, kernel_size3, padding1), nn.BatchNorm1d(64), nn.ReLU(inplaceTrue), nn.AdaptiveAvgPool1d(1), ) self.classifier nn.Linear(64, num_classes) def forward(self, x): x self.features(x) x x.view(x.size(0), -1) return self.classifier(x)1024点输入经过第一层stride4的大卷积后长度变成256再经过两次池化降到64最后由AdaptiveAvgPool1d(1)把每个特征通道压缩成一个值再接全连接分类。AdaptiveAvgPool1d省去了手动计算展平维度的麻烦让模型对输入长度有一定宽容度这是比FlattenLinear更稳妥的收尾方式。层序号操作输出长度作用输入原始信号1024与采样率匹配第1层Conv1d(64) BN ReLU256覆盖单个冲击脉冲第2层MaxPool128保留峰值位置降采样第3层Conv1d(5) BN ReLU128学习局部时序模式第4层MaxPool64序列进一步压缩第5层Conv1d(3) BN ReLU64特征精修第6层AdaptiveAvgPool每通道1点聚合全局特征分类层Linear类别数输出分类logits通道数按16到32到64递增是参数量和表达能力的平衡点。直接用64通道起步在小样本数据集上提前过拟合的概率明显上升按倍数递增则能在每一层逐步提升抽象能力同时控制训练时间。3.2 训练配置损失函数、优化器与批次大小故障诊断是标准的多分类任务损失函数用交叉熵。CWRU数据集各类别样本量接近不需要设置类别权重但自己采的数据如果正常样本远多于故障样本就要考虑给损失函数传入class_weight。优化器优先选择Adam初始学习率1e-3就能在多数情况下跑出不错的结果。Adam对学习率的敏感度比SGD低尤其适合振动信号这种含噪数据。import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset model BearCNN(num_classes4) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lr1e-3) train_loader DataLoader( TensorDataset(train_x, train_y), batch_size64, shuffleTrue )batch_size取64是CPU和GPU都适用的中间值。批量太小会让梯度估计噪声偏大训练曲线上下抖动批量太大单次更新过于平滑收敛变慢。20到30个epoch在这个配置下通常足够看到明显的平台期继续堆epoch不搭配调度策略收益只会越来越小。3.3 训练循环与验证指标准确率之外还要看每类召回率训练阶段用model.train()开启BatchNorm和Dropout的统计更新验证阶段用model.eval()切换到运行均值。这个切换不能省略否则验证误差会被系统性地低估或高估。验证时用torch.no_grad()关闭自动求导可以省掉不必要的计算和显存占用。def train_one_epoch(model, loader, criterion, optimizer): model.train() for xb, yb in loader: optimizer.zero_grad() out model(xb) loss criterion(out, yb) loss.backward() optimizer.step() def evaluate(model, loader): model.eval() preds, labels [], [] total_correct 0 with torch.no_grad(): for xb, yb in loader: out model(xb) pred out.argmax(dim1) total_correct (pred yb).sum().item() preds.extend(pred.tolist()) labels.extend(yb.tolist()) return total_correct / len(loader.dataset), preds, labelsargmax(dim1)在模型输出的各个类别logits里取最大值的下标这就是最终的预测类别。返回的preds和labels先保留后续用于混淆矩阵和分类报告。准确率能说明总体水平但轴承诊断里外圈故障往往比内圈和滚动体故障更易区分只看整体准确率会掩盖局部性能洼地答辩或项目验收时被追问哪个类别效果差容易答不上来。4. 从90分提到95分学习率调度、正则化与特征可视化模型能跑到90%准确率之后再往上走就不再是单纯堆层数的问题。这个阶段要处理的是训练平台期、过拟合以及“模型到底靠什么把两个相近故障区分开”这三个问题。源码质量的高低往往从这一部分开始分化。4.1 学习率调度与早停让模型在第20轮之后继续进步固定学习率1e-3训练到第20轮左右验证损失通常进入平台期。此时继续用原学习率更新参数会在极小值附近来回振荡。解决思路是让学习率在检测到平台期后自动缩小PyTorch里的ReduceLROnPlateau可以直接承担这个职责。scheduler optim.lr_scheduler.ReduceLROnPlateau( optimizer, modemin, factor0.5, patience5 ) for epoch in range(50): train_one_epoch(model, train_loader, criterion, optimizer) val_loss compute_val_loss(model, val_loader, criterion) val_acc, _, _ evaluate(model, val_loader) if val_acc best_acc: best_acc val_acc torch.save(model.state_dict(), best_model.pt) scheduler.step(val_loss)modemin表示监控量是验证损失patience5意味着连续5个epoch损失没有下降才缩小学习率factor0.5表示每次缩小为原来的一半。scheduler.step要放在整个epoch计算完之后而不是batch循环内部否则一个epoch里学习率会被多次修改训练过程不稳定。配合早停时有一个细节验证集准确率最高的模型参数和最后一个epoch的参数往往不完全一样。训练后期模型大概率开始过拟合保存验证准确率最高时的state_dict再在测试时重新加载通常比直接用最后一版参数高出一到两个百分点。4.2 Dropout、批归一化与数据增强的正确用量Dropout在故障诊断网络里的位置比Dropout率本身更重要。放在最后全连接层之前效果最明显放在卷积层之间要谨慎因为卷积特征图相邻位置之间存在强空间相关性强行打乱会破坏局部结构语义。self.classifier nn.Sequential( nn.Dropout(p0.5), nn.Linear(64, num_classes) )p0.5是这类任务常用的起始值。如果训练集只有几千样本Dropout能明显抑制过拟合如果样本上万Dropout对准确率影响变小但依然能降低对训练集噪声的过拟合。信号数据增强和图像数据增强的规则差异很大。对一维振动信号有效且物理可解释的方式是加小幅高斯噪声、随机缩放幅度、随机时间拉伸无效的方式是时间轴反转它会把冲击方向反转制造出物理上根本不会出现的样本。常见做法是把增强逻辑写进Dataset的__getitem__不必提前离线生成全部增强样本否则内存占用会随增强倍数线性上涨。现象常见原因排查方向训练损失下降但验证准确率波动大数据泄漏或窗口过小检查文件级划分增大窗口混淆矩阵对角线偏低通道数不足或卷积核过小增大第一层卷积核到64t-SNE聚类模糊特征提取深度不够增加通道数或加深一层4.3 混淆矩阵与t-SNE可视化判断模型到底学到了什么可视化不是答辩装饰而是定位模型短板的工具。混淆矩阵能直接看出两个类别之间是否系统性互相误判这种误判通常发生在不同损伤直径但同一故障位置的组合里。from sklearn.metrics import confusion_matrix import matplotlib.pyplot as plt cm confusion_matrix(labels, preds) fig, ax plt.subplots(figsize(6, 5)) im ax.imshow(cm, cmapBlues) ax.set_xticks(range(cm.shape[0])) ax.set_yticks(range(cm.shape[0])) ax.set_xlabel(predicted) ax.set_ylabel(true) for i in range(cm.shape[0]): for j in range(cm.shape[0]): ax.text(j, i, cm[i, j], hacenter, vacenter) plt.tight_layout() plt.savefig(confusion_matrix.png, dpi200)imshow画出的矩阵行是真值、列是预测值。对角线上的数字越大越好非对角线上的大数字就是下一步需要定点优化的位置。如果某两类频繁混淆可以尝试为这两个类别单独增加一维统计特征作为辅助输入或增加第二层卷积的通道数而不是盲目把整个网络加深。t-SNE图用来观察最后一层特征的聚类结构。t-SNE保持的是近邻关系而不是全局距离聚类变清晰只能说明模型学到了训练数据上可分的特征不能直接当作物理故障机理的证明。提示t-SNE样本量超过3000时会非常慢先对特征做随机采样再跑并固定random_state保证结果可复现。5. 从离线诊断到实时部署的具体落地技巧训练和验证做完项目源码才算完成一半。这一章的内容是把离线模型变成能在连续数据上工作的诊断模块同时把泛化能力量化出来这部分是很多高分项目拉开差距的地方。5.1 推理时的滑动窗口重叠策略推理阶段面对连续信号流窗口长度要和训练完全一致推理间隔可以比训练时更小。比如训练用stride256推理时可以用stride128让相邻两次诊断之间的时间间隔更短报警响应更快。这里有一个必须提前确认的模型约束如果网络最后用了AdaptiveAvgPool输入长度可以上下浮动不一定是固定值如果用了Flatten连接全连接层长度必须和训练输入完全一致。拿到别人的项目源码以后第一件事就是确认模型收尾用的是哪种方式否则换一段长度不同的数据喂进去形状错误会直接在forward阶段抛出来。5.2 用ONNX导出并替换第一层大卷积核模型训练完只保存了state_dict还不够导出时要用实际数据形状走一遍。torch.onnx.export里的dynamic_axes参数可以把batch维度设为弹性方便服务端按不同批次大小做推理。model.eval() dummy torch.randn(1, 1, 1024) torch.onnx.export( model, dummy, bear_cnn.onnx, input_names[signal], output_names[logits], dynamic_axes{signal: {0: batch}, logits: {0: batch}} )export时model必须处于eval模式否则BatchNorm的统计量会把训练时的均值和方差带进来导出的模型在推理时行为不一致。如果部署目标是CPU第一个卷积层的kernel_size64是主要的延迟瓶颈可以尝试把它拆成两个级联的kernel_size9卷积感受野依然覆盖冲击宽度参数量和计算量大幅下降代价是需要从头训练一次。5.3 跨工况验证用负载条件的变化检验泛化能力最后一个值得写进项目文档的实验是跨工况验证。以CWRU数据集为例它包含0到3马力四组负载数据可以做一组很干净的实验只用负载0训练在负载1、2、3上分别测试量化模型在数据分布偏移后的准确率变化。跨工况测试的准确率通常比同工况测试低3到8个百分点。如果完全一样反而要警惕训练和验证切分存在数据泄漏。缓解分布偏移的一个基础手段是保存训练集的均值和标准差在推理时用同一组参数做标准化让模型看到的数据分布更接近训练分布。具体操作是在项目文档里单独建一个表格记录不同负载下的准确率、召回率和F1值再描述所用的标准化策略和是否尝试过随机缩放增强。这样评估者能在几分钟内看清泛化差距和对应的缓解手段而不是只看到一个孤零零的总准确率。本文还有配套的精品资源点击获取
返回列表