Python深度学习故障诊断实战:轴承振动信号分析与1D-CNN模型实现
发布时间:2026/9/28 2:11:23来源:尧图网络
简介基于Python深度学习的机械设备故障诊断项目资料包面向毕业设计、课程设计及项目开发人群可用于快速搭建故障诊断模型、理解深度学习在工业场景中的落地流程。整套材料围绕TensorFlow框架下的SAE自编码器、RNN与CNN等典型网络展开覆盖数据预处理、模型训练与评估等关键环节适合具备一定Python基础、希望以完整项目作为课题或工程起点的学习者。资源共33个文件以12个py源码文件为核心配套1个docx项目文档另有pyc编译文件、xml与iml工程配置、txt说明等压缩包约135KB。py源码用于模型实现与训练docx用于梳理方案思路配置文件则方便直接导入开发环境整体结构清晰便于按需修改和迁移到轴承、齿轮等设备状态监测场景。目前已有171人学习浏览源码经过测试可放心在此基础上延展二次开发。1. 为什么做机械设备故障诊断要选Python深度学习从一次轴承拆检说起一台离心泵轴承振动连续三天上涨RMS和峰值都贴近报警线但设备没停拆检才发现外圈剥落。基于python深度学习开发的机械设备故障诊断模型解决的就是这种“有异常但说不清故障类型”的难题把振动信号切成样本用卷积网络自动提取特征并输出故障类别。标题里的“源码项目文档”意味着这不是一个单点实验而是可以直接作为毕业设计、课程设计或产线项目开发的完整闭环数据预处理、模型训练、评估脚本以及需求说明和设计文档都齐整。适合正在定题的学生也适合设备维保团队里想做预测性维护但还没接触算法的工程师。下面按选型、数据、训练、踩坑、写文档的顺序把这个项目方向拆透。2. 输入与模型选型时域、FFT谱、时频图到底该把什么喂给网络做故障诊断项目时第一个要定下来的不是网络结构而是输入形式。输入形式决定了后面所有代码的形态。同一个轴承数据集分别用原始时域波形、FFT幅度谱、STFT时频图建模得到的结论和调参路径完全不同。我先说一个通用判断定转速、单一工况下的滚动轴承故障诊断优先选一维输入变转速、强非平稳工况才需要二维时频图。选型顺序应该是输入形式在前模型结构在后训练策略最后才谈。2.1 三类输入形式时域波形、FFT谱与时频图的取舍故障诊断里的输入本质上是振动加速度传感器采集的时间序列。最直接的形式就是把一段原始时域波形喂给模型形状是[window_len]的一维数组。时域信号保留冲击的幅值和相位关系轴承局部故障在每转产生的周期性冲击会直接以“尖峰簇”的形式出现在波形里一维卷积核能学到这种局部冲击模式。这是预处理成本最低的方案也是我给学生项目做默认基线的原因。第二种是FFT幅度谱。对每个窗口做快速傅里叶变换取幅值部分得到一维频谱。频域丢掉了相位但把能量按频率重新分布故障特征频率附近会出现可辨识的谱峰。滚动轴承故障特征频率是一个绕不开的知识点以CWRU数据集常用的6205-2RS轴承为例9个滚动体、节径约39mm、滚子直径约7.9mm在转速1797rpm约30Hz下外圈故障特征频率BPFO约为107Hz内圈BPFI约为162Hz滚动体故障BSF约为70Hz。知道这三个大概值能帮你判断FFT谱里该盯着哪个频段也方便在报告里做物理解释。第三种是时频图用STFT或连续小波变换把一维信号变成[frequency, time]的二维图像再交给二维CNN处理。它同时保留频率和时间信息适合转速变化、启停机过程这类非平稳工况但计算量明显增大且需要足够的样本才能喂饱二维网络。把三类输入放在一起对比更直观输入形式典型模型适用场景预处理成本可解释性原始时域波形1D-CNN定转速、样本充足低中FFT幅度谱1D-CNN / MLP定转速、关注特征频率低高STFT/CWT时频图2D-CNNResNet类变转速、冲击性信号高中如果你是在做课程设计而不是前沿研究我建议直接走“原始时域加一维CNN”这条路。它复现难度最低翻车点最少CWRU这类公开数据上用正确划分方式能做到98%以上准确率足够支撑一篇合格的文档。2.2 模型结构怎么选1D-CNN、2D-CNN与LSTM的适用边界一维卷积网络是目前振动诊断里性价比最高的选择。它的卷积核沿着时间轴滑动参数数量少训练快CPU也能在分钟级跑完小型数据集。一个典型的1D-CNN由三到四个卷积块组成每个块包含Conv1d、BatchNorm1d、ReLU和MaxPool1d最后接全局平均池化和全连接层参数量通常在几万到几十万之间。这里的直觉是振动信号的特征是局部的周期性冲击和频带能量分布卷积核天然适合提取这种局部模式不需要超深网络。二维CNN只有在输入是时频图时才需要。它的优势是能借用ImageNet预训练权重做迁移学习但振动时频图和自然图像的分布差异很大预训练权重帮不了太多更常见的是从零训练一个小型ResNet或VGG类网络。除非你面对的是变速工况否则二维CNN带来的提升非常有限而训练时间和调参成本却翻倍。LSTM在很多教程里被拿来和CNN对比但我的经验是纯LSTM做定转速振动诊断基本是给自己找麻烦。振动信号采样率动辄12kHz一个窗口2048个点LSTM要逐步处理两千多个时间步长程依赖没学到训练速度先拖垮了。更合理的做法是把LSTM放在CNN后面让CNN先做局部特征提取LSTM再对特征序列建模时序关系。这种CNN-LSTM结构确实有效但只有在样本量足够大时才比纯CNN有明显优势。起步项目不要碰它基线永远是一维卷积。2.3 数据集现实CWRU公开数据还是自己采集的现场数据选型绕不开数据来源。公开数据集里最常用的是CWRU美国凯斯西储大学轴承数据中心里面有正常、内圈故障、外圈故障、滚动体故障四类状态故障尺寸分0.007、0.014、0.021英寸三档负载从0到3马力共四档采样率分12kHz和48kHz两档。文件是.mat格式用scipy可以直接读import scipy.io as sio import numpy as np mat sio.loadmat(105.mat) print(mat.keys()) # 查看字段常见有 X105_DE_time 等 de_signal mat[X105_DE_time].flatten() fs 12000 # 驱动端加速度信号采样率48k文件为48000代码逻辑说明CWRU的原始文件里X105_DE_time是驱动端加速度时域信号文件编号105对应0.007英寸内圈故障、0负载工况。读取后先flatten成一维数组后面滑窗时直接基于它切样本。注意DE是驱动端FE是风扇端两者信号差异很大文档里必须写清楚用了哪一端。参数上fs按文件类型取12000或48000这会影响后续FFT频率轴的计算写错会导致特征频率整体偏移。真实项目里没有这么干净的数据。现场信号夹杂噪声、轴系不对中、齿轮啮合干扰而且转速和负载不会恒定。我见过不少同学拿CWRU训出99%的模型放到自采数据上直接掉到75%。所以结论是毕设和课设阶段用CWRU完全没问题但文档里要主动写明“该模型在固定工况公开数据上验证现场部署需要增量微调”这句话能帮你挡掉不少答辩追问如果是实际项目开发数据采集方案比模型结构重要十倍。3. 数据预处理与数据集划分把99%的假准确率打回原形这一章是整个项目的分水岭。模型结构大家都能抄但数据切的水平直接决定结果是真实泛化还是记忆比拼。我要先说一句得罪人的话网上大量故障诊断教程里那种随机打乱滑窗再按8比2划分的做法是在制造假准确率。如果你照着那种流程跑出99%先别高兴大概率是数据泄漏在给你撑腰。3.1 滑窗采样与重叠率把连续振动信号切成训练样本原始振动信号是一条很长的连续序列模型需要固定长度的样本滑窗是最基本的手段。窗口长度怎么定要覆盖至少转子旋转一两圈的完整周期。以12kHz采样、转速1800rpm约30Hz为例一转约400个采样点2048点窗口包含约5转频率分辨率约5.86Hz足以分辨前述的轴承特征频率。1024点窗口样本更多、训练更快但频谱分辨率粗4096点窗口反之。我一般默认2048兼顾频率分辨率和样本数量。重叠率决定样本总量和相邻样本的相关性。50%重叠是常见默认值样本量翻倍训练效果略有提升75%重叠样本更多但相邻窗口几乎只差四分之一个窗口数据泄漏风险随之上升。滑窗代码很短import numpy as np def sliding_window(signal, window_len2048, overlap0.5): step int(window_len * (1 - overlap)) if step 1: raise ValueError(step不能小于1请降低重叠率) samples [] for start in range(0, len(signal) - window_len 1, step): samples.append(signal[start:start window_len]) return np.asarray(samples) # 形状 [n_samples, window_len]逻辑说明step由窗口长度和重叠率共同决定50%重叠时step为1024相邻窗口共享一半数据。代码里先检查step合法性避免有人把重叠率设到0.99导致死循环。这是最基础的版本真实项目里建议用numpy的stride_tricks.as_strided做内存优化或者直接迭代生成后拼接数据量不大时上面这个版本完全够用。归一化放在滑窗之后。标准做法是对每一条原始信号先计算均值和标准差再做z-score然后滑窗避免单个窗口之间的幅值差异影响训练。如果训练集和测试集来自不同天采集的数据各自用各自的统计量归一化即可不要混用mean, std signal.mean(), signal.std() signal_norm (signal - mean) / (std 1e-8)参数说明std加一个小常数是为了防止纯零信号除零报错现场采集偶尔会出现传感器断线导致全零段。归一化的顺序有讲究先归一化再滑窗每个窗口都处于同一幅值尺度如果某个窗口恰好是静默段它会被归一化成全零向量这类样本要在建数据集时剔掉。3.2 从时域样本到频域特征加窗FFT与频率轴对齐如果选频域作为输入在滑窗基础上对每个窗口做FFT。直接对原始窗口做FFT会有频谱泄漏因为窗口边界不连续能量会泄漏到旁瓣。解决方法是先乘窗函数再变换def window_fft(window, fs): n len(window) windowed window * np.hanning(n) # 汉宁窗抑制频谱泄漏 fft_vals np.fft.rfft(windowed) mag np.abs(fft_vals) / n # 幅值归一化 freqs np.fft.rfftfreq(n, d1.0 / fs) return freqs, mag逻辑说明rfft只计算正频率部分输出长度大约是n/2 12048点窗口得到1025个频点。rfftfreq生成对应的频率轴d1/fs是采样间隔秒数。幅值除以n能让谱幅度与信号幅值处于同一量级方便跨样本比较。汉宁窗是故障诊断里的默认选择主瓣宽度和旁瓣衰减的平衡比矩形窗好得多。输入模型的频谱可以只保留有效频带。12kHz采样下奈奎斯特频率是6kHz轴承振动能量绝大多数集中在2kHz以内直接取freqs 2000对应的谱段把1025维降到300多维能显著加快训练且不影响精度。如果做48kHz数据建议先降采样到12kHz再走后续流程高频段对轴承故障诊断的实际增益有限但计算成本翻好几倍。这一步在文档里要写清楚评审看到“原始信号重采样到12kHz”就知道你处理过工程问题。3.3 数据集划分的三条原则分层、分段、分工况这是全篇最需要抄进代码和文档的部分。第一条原则是按段划分而不是按滑窗划分。正确做法是先把原始连续信号切成若干个互不重叠的长段对段做划分再在段内滑窗。如果先把所有窗口堆在一起随机划分相邻窗口共享大量数据训练集和测试集之间等于互相抄答案。一个典型的量化结果这种泄漏可以把测试准确率从真实值的80%抬到99%。from sklearn.model_selection import train_test_split # seg_list: 每项是一整段连续信号来自同一次采集 # label_list: 每项是这一段对应的故障类别标签 seg_train, seg_test, y_train, y_test train_test_split( seg_list, label_list, test_size0.2, stratifylabel_list, # 按类别比例分层采样 random_state42 ) X_train np.vstack([sliding_window(s) for s in seg_train]) X_test np.vstack([sliding_window(s) for s in seg_test])逻辑说明train_test_split作用在段列表上而不是滑窗矩阵上。stratifylabel_list保证每个故障类别在训练和测试里的占比一致避免某一类故障恰好全都落在测试集里。random_state固定住随机种子保证实验结果可复现这是毕设文档里必须交代的问题。划分完之后再滑窗每个段内的重叠窗口必然属于同一边不会跨集泄漏。第二条原则是分层采样。故障数据天然不平衡外圈故障和滚动体故障的样本量往往差好几倍分层能避免小样本类在测试集里被随机种子“抽没”。第三条原则是分工况。CWRU有四档负载严谨的做法是训练集包含其中三档测试集只放没训练过的那一档这个结果才是你真正能对外讲的泛化能力。如果你把四档负载混在一起随机划分测出来的准确率再高也只是“同工况记忆”。提示写文档时把划分方式画成一张示意图原始信号→分割段→划分→滑窗。这张图几乎能消灭一半关于“数据泄漏”的追问。3.4 类别不平衡与样本增强让少数类故障被模型看见真实项目里正常样本永远最多故障样本又少又贵。类别不平衡不解决模型会把多数类预测得特别好少数类直接被吞掉。两个手段配合使用采样权重和增强。PyTorch里的WeightedRandomSampler按样本权重采样让每个batch里少数类出现的概率更高from torch.utils.data import WeightedRandomSampler labels_np np.array(y_train) class_counts np.bincount(labels_np) class_weights 1.0 / class_counts.astype(np.float32) sample_weights class_weights[labels_np] sampler WeightedRandomSampler( weightssample_weights, num_sampleslen(sample_weights), replacementTrue )逻辑说明class_weights是每个类别样本数的倒数样本越少的类别权重越大。WeightedRandomSampler按这个权重有放回抽样每个epoch看到的数据分布更接近均匀变相解决了不平衡问题。代价是有些样本会被重复采样训练收敛节奏要稍微调慢一点。增强要用在划分之后只能对训练集做。振动信号常用的增强手段是加噪、随机平移和幅值缩放。加噪的直观方式是给信号叠加小幅随机噪声x_aug x np.random.randn(n) * 0.02 * x.std()噪声标准差取原信号标准差的1%到5%太小没效果太大改变故障特征。如果在划分之前做增强增强样本和原始样本可能同时落进训练集和测试集又是一种隐蔽的泄漏。这是我踩过的坑做完增强记得回头检查测试集里有没有增强痕迹。4. 用PyTorch实现1D-CNN故障诊断模型从网络定义到训练闭环数据和模型的关系理顺之后实现层面就快了。这一章给出一套可以直接复用的最小工程结构环境准备、网络定义、数据加载、训练循环、评估可视化五部分。如果你还在python入门阶段先把Anaconda环境固定住再装依赖避免后面因为numpy版本冲突折腾半天。4.1 项目结构与环境依赖让源码可被复现一个能让别人跑通的项目目录结构比模型结构更重要。下面这套是我习惯的最小划分也适合直接套进课程设计案例源码里fault_diagnosis/ ├── data_loader.py # 数据读取、滑窗、分割、归一化 ├── model.py # 1D-CNN网络定义 ├── train.py # 训练主脚本含早停与模型保存 ├── evaluate.py # 测试集评估、混淆矩阵、分类报告 ├── requirements.txt # 版本固定的依赖清单 └── docs/ └── project_doc.md # 项目文档按第6章结构写环境安装用conda一步到位。网上python安装教程非常多我简化成固定两句conda create -n fd python3.9然后pip install numpy scipy scikit-learn torch matplotlib。PyTorch的安装命令按官网选操作系统和CUDA版本CPU版本也能跑通本文全部代码只是训练慢一点。requirements.txt里把版本号冻住复制环境时不会翻车。4.2 1D-CNN网络定义尺寸怎么算参数怎么设网络设计遵循一个原则前面卷积层宽、通道数逐级增加最后用全局平均池化把特征压成向量。这样不管输入窗口长度是多少全连接层的输入维度都固定省去手算尺寸的麻烦import torch.nn as nn class FaultCNN1D(nn.Module): def __init__(self, num_classes4): super().__init__() self.features nn.Sequential( nn.Conv1d(1, 16, kernel_size7, stride2, padding3), nn.BatchNorm1d(16), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), nn.Conv1d(16, 32, kernel_size5, stride2, padding2), nn.BatchNorm1d(32), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), nn.Conv1d(32, 64, kernel_size3, stride2, padding1), nn.BatchNorm1d(64), nn.ReLU(inplaceTrue), nn.MaxPool1d(kernel_size2, stride2), ) self.classifier nn.Sequential( nn.AdaptiveAvgPool1d(1), # 把任意长度压成 [B, 64, 1] nn.Flatten(), nn.Linear(64, 128), nn.ReLU(inplaceTrue), nn.Dropout(p0.5), nn.Linear(128, num_classes) ) def forward(self, x): return self.classifier(self.features(x))代码逻辑说明输入形状是[batch, 1, window_len]第一维1代表单通道加速度信号。stride2配合padding让每个卷积层输出长度减半三个卷积块之后长度从2048降到32通道数从16涨到64。AdaptiveAvgPool1d(1)是关键设计它把[batch, 64, 32]直接压成[batch, 64, 1]再接全连接层这样换窗口长度不用改代码。参数设计上第一层kernel_size用7因为轴承冲击宽度通常只有几个采样点太小的卷积核容易漏掉后面卷积核缩到5和3做细粒度特征精修。Dropout放在全连接层取值0.5这是对抗过拟合最直接的手段。这个模型总参数量大约2万对几万条样本的数据集完全够用。你可以加一行print(sum(p.numel() for p in model.parameters()))打印出来写进文档评审喜欢看具体数字。4.3 数据加载器与训练循环早停、学习率调度与模型保存数据加载用PyTorch的Dataset和DataLoader包装。这里有一个细节样本要unsqueeze(0)补上通道维DataLoader训练时shuffleTrue验证时shuffleFalseimport torch from torch.utils.data import Dataset, DataLoader class VibrationDataset(Dataset): def __init__(self, samples, labels): self.samples samples.astype(np.float32) self.labels labels.astype(np.int64) def __len__(self): return len(self.samples) def __getitem__(self, idx): x torch.from_numpy(self.samples[idx]).unsqueeze(0) # 补成 [1, window_len] y torch.tensor(self.labels[idx]) return x, y train_ds VibrationDataset(X_train, y_train) val_ds VibrationDataset(X_val, y_val) train_loader DataLoader(train_ds, batch_size64, shuffleTrue, drop_lastTrue) val_loader DataLoader(val_ds, batch_size128, shuffleFalse)逻辑说明drop_lastTrue丢弃最后一个不完整的batch避免BatchNorm在这种小batch上统计量抖动。batch_size取64到128都可以CWRU量级的数据集显存占用很低CPU训练也不慢。验证集的batch_size可以大一些因为不需要反传梯度只做前向推理。训练循环是整套代码的核心。损失函数用交叉熵优化器用Adam初始学习率1e-3权重衰减1e-4配合早停保存最优模型import torch.nn as nn import torch.optim as optim model FaultCNN1D(num_classes4) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lr1e-3, weight_decay1e-4) scheduler optim.lr_scheduler.ReduceLROnPlateau( optimizer, modemax, factor0.5, patience5 ) best_acc 0.0 patience 12 wait 0 for epoch in range(60): model.train() total_loss 0.0 for xb, yb in train_loader: optimizer.zero_grad() out model(xb) loss criterion(out, yb) loss.backward() optimizer.step() total_loss loss.item() * xb.size(0) model.eval() val_correct 0 with torch.no_grad(): for xv, yv in val_loader: pred model(xv).argmax(dim1) val_correct (pred yv).sum().item() val_acc val_correct / len(val_ds) scheduler.step(val_acc) print(fepoch {epoch:02d} | loss {total_loss / len(train_ds):.4f} | val_acc {val_acc:.4f}) if val_acc best_acc: best_acc val_acc torch.save(model.state_dict(), best_model.pt) wait 0 else: wait 1 if wait patience: break参数说明weight_decay1e-4是L2正则防止权重过大导致过拟合ReduceLROnPlateau在验证准确率连续5个epoch不提升时把学习率减半比固定衰减更省心。早停的核心逻辑是验证准确率不再刷新时就计数连续12个epoch没有提升就停止同时把历史最优权重保存成best_model.pt。这条“后悔药”非常重要训练后期模型可能震荡最后一次epoch的权重往往不如之前某个时刻的权重保存最优权重是标准做法。如果loss降不下去先把学习率降到3e-4试一次。4.4 评估可视化混淆矩阵、分类报告与多窗口投票测试集评估不能只看一个准确率数字。故障诊断关心每一类是否都被正确识别尤其少数类。用sklearn的分类报告和混淆矩阵把结果打出来from sklearn.metrics import classification_report, confusion_matrix model.load_state_dict(torch.load(best_model.pt)) model.eval() y_pred, y_true [], [] with torch.no_grad(): for xt, yt in test_loader: pred model(xt).argmax(dim1) y_pred.extend(pred.numpy()) y_true.extend(yt.numpy()) target_names [Normal, InnerRace, OuterRace, Ball] print(classification_report(y_true, y_pred, target_namestarget_names, digits4)) print(confusion_matrix(y_true, y_pred))逻辑说明classification_report给出每一类的精确率、召回率和F1值。类别不平衡时准确率会骗人F1不会——如果Ball故障只有70%的F1问题一眼暴露。confusion_matrix能看出具体错在哪两类之间比如Ball被误判成Normal还是OuterRace这直接影响后续改进方向。测试时要用model.eval()切到推理模式同时包在torch.no_grad()里否则BN层的统计量和dropout的随机性会污染测试结果。单窗口预测波动很大同一个测试样本切出来的不同窗口可能被分到不同类别。工程里更可靠的做法是多数投票对一个测试段的所有滑窗预测结果做投票取票数最高的类别作为该段的最终诊断from collections import Counter def segment_vote(model, segment_windows): preds [] model.eval() with torch.no_grad(): for w in segment_windows: x torch.from_numpy(w).unsqueeze(0).unsqueeze(0) # [1,1,window_len] preds.append(model(x).argmax(dim1).item()) return Counter(preds).most_common(1)[0][0]逻辑说明unsqueeze两次分别补batch维和通道维。每个窗口独立预测后投票少数窗口的偶然误判被淹没测试准确率通常能提升1到3个百分点。这个技巧在答辩现场演示时特别有用你切一段真实信号投票结果比单窗口预测稳定得多。5. 避坑与排查训练精度高但现场失效的5个常见原因下面这几条是我自己复现公开模型和做产线项目时踩出来的血泪经验按出现频率排序。每一条都按“现象、原因、解决”展开你在训练和部署时对照着查。5.1 数据泄漏测试集里混进了同一段信号的邻居样本现象训练和测试准确率都接近99%换到另一天采集的数据上立刻掉到80%以下。模型在测试集上表现好得像开了挂但在真实数据上原形毕露。原因滑窗之后直接随机打乱再划分重叠窗口把同一段振动的内容泄露进了测试集。相邻窗口共享大部分采样点模型相当于见过测试样本的“邻居”记住的是窗口内容而不是故障规律。这是网上一堆低质量教程里准确率虚高的真正来源。解决回到第三章必须先按连续信号段划分再做滑窗确保测试集里的任何窗口和训练集里的任何窗口之间没有重叠采样点。更严格的做法是训练段和测试段之间留一段没用过的“缓冲信号”彻底切断相关性。你文档里只要写明“按段划分”评审基本不会再揪着数据泄漏问。5.2 过拟合训练集收敛到99%验证集却掉点现象训练损失降到0.01以下验证准确率卡在85%上不去训练和验证的loss曲线从某个epoch开始分离验证集越走越高。原因模型容量过大、样本太少或者dropout没开、权重衰减设成0。CWRU数据干净且模式固定模型背下来训练样本很容易但一遇到验证集的新窗口就露馅。解决先打印模型参数量如果超过50万基本就是容量过剩。把dropout从0.3提到0.5weight_decay设为1e-4再把卷积通道数从64降到32验证准确率经常不降反升。还要检查是不是增强做得不够加噪和随机平移都能提升验证集表现。过拟合是基线模型最常见的问题调这几项之前先别换网络结构。5.3 转速与负载变化后精度骤降训练域和测试域不是一个分布现象CWRU上用0负载数据训练1负载测试准确率从99%掉到85%以下真实产线上更明显换一台同型号设备直接没法用。原因振动特征随转速、负载和安装刚度变化模型学到的是特定工况下的频响模式不是广义的故障物理特征。转速一变特征频率整体偏移卷积核的响应也跟着变。解决训练时混入尽可能多的负载数据并给出跨负载的验证数字比如用0、1、2负载训练只用3负载测试这个准确率才是值得写进结论的泛化指标。进阶做法是用域适应或者先在无标签数据上做自编码器预训练再微调但对毕设而言先把跨工况划分做好比什么都重要。诚实地在文档里写“本模型在固定工况数据上训练跨工况泛化需要进一步微调”这比硬吹99%更有说服力。5.4 训练损失不下降或出现NaN学习率、归一化与标签问题现象4分类任务的loss从初始值1.39附近开始但训练20个epoch还是降不动或者某一轮之后loss突然变NaN后面全部是NaN。原因1.39是4分类随机猜测的交叉熵理论值loss长期停在1.39附近说明输入信号有问题或者模型没在学NaN通常来自学习率过大导致梯度爆炸或者输入里出现极大值。还有一种隐蔽原因标签里有负值或超过类别数的值CrossEntropyLoss直接计算崩溃。解决先检查输入标准化后的均值和标准差确认接近0和1。学习率从1e-3起步不要为了“加速收敛”直接上1e-2。如果NaN出现在某次归一化之后打印一下特征的最大最小值看看是不是出现了inf或NaN。标签问题更简单打印np.unique(y_train)对比num_classes一眼能看出来。5.5 滚动体故障难以识别冲击路径衰减导致的信噪比问题现象混淆矩阵里滚动体故障那类的F1只有70%左右大量被误判成正常或外圈故障。单窗口预测时尤其明显。原因滚动体故障的冲击要经过滚动体、保持架、内外圈多层传递路径才能到达传感器能量衰减严重信噪比最低。单个窗口里故障特征可能完全淹没在背景噪声里模型看不出差别是正常的不是网络结构的问题。解决用上一章的多窗口投票先稳一稳输出再把输入从原始时域换成FFT幅度谱让能量集中到特征频带。要是还不行上包络谱——用希尔伯特变换把高频冲击解调出来再算FFT这是故障诊断里的经典手段from scipy.signal import hilbert envelope np.abs(hilbert(window)) # 包络解调 envelope_spectrum np.abs(np.fft.rfft(envelope)) freqs np.fft.rfftfreq(len(window), d1/fs) band (freqs 50) (freqs 300) # 只看特征频段 feature_vector envelope_spectrum[band]代码逻辑说明hilbert得到解析信号取模得到包络包络的FFT谱里滚动体故障特征频率会更突出。band选50到300Hz是因为前述BPFO、BPFI和BSF都落在这个范围把无关高屏蔽掉模型输入维度也变小了。这个解法在轴承诊断论文里很常见写成对比实验会加分。6. 项目文档与答辩验证设计两组实验把模型价值呈现出来源码能跑只是第一步文档和验证设计决定了毕业设计、课程设计的最终评价。很多同学代码写得好但提交的文档只有“我用了CNN准确率99%”这基本上等于告诉评审你没做过工程验证。文档的核心不是流水账而是让别人能按你的步骤复现出相同结论。6.1 项目文档结构从需求背景到结论的七个部分如果你的学校提供了项目需求说明文档模板先照着模板的章节顺序填比自己另起炉灶快得多。没有模板的话下面这个结构覆盖了最常见的评审关注点文档章节内容要点篇幅建议需求背景为什么用深度学习做故障诊断与传统特征值方法的对比1至2页数据说明数据来源、采样率、故障类型、工况、划分方式1页方法设计信号预处理流程、网络结构图、关键参数表2至3页实验与结果训练曲线、混淆矩阵、逐类F1、消融对比表3至4页讨论与局限数据泄漏防范手段、跨工况泛化不足的诚实说明1页结论三条可读的结论分别对应数据、方法、实验半页附录源码清单、环境依赖、一键运行步骤1页文档里必须有一个“运行说明”小节写清楚从原始数据到最终图表执行哪几条命令。格式化的表格和网络结构图比大段文字有用评审扫一眼就能抓住你的技术路线。6.2 必做的两组验证实验消融实验与跨工况泛化第一组是消融实验把输入从原始时域换成FFT谱对比准确率和F1把dropout去掉对比验证集曲线把CNN换成单层全连接对比特征提取能力。这张对比表直接回答“你的设计贡献在哪里”没有消融实验的深度学习文档在评审眼里约等于没做实验。第二组是跨工况验证训练集和测试集来自不同负载或不同转速把那个真实的泛化准确率写进结论。哪怕只有85%也比99%的假阳性诚实可信。答辩时主动说出“我在跨负载条件下验证过当前准确率还有差距”评审的第一反应通常不是扣分而是觉得你理解模型的边界。6.3 我的一个交付习惯干净环境复现测试我每次交文档前都会做一次“clean-room复现”换另一台干净机器严格按文档里的运行说明从原始数据重新跑到最终图表。跑不通的步骤就是文档没写清楚修复它直到一个陌生环境能一口气跑完。这个习惯帮我避免过好几次“答辩前发现环境对不上”的翻车。项目源码不是越炫越好而是别人拿到后能复现这个复现能力才是毕业设计和课程设计里区分完成度的地方。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网