简介:基于深度学习的滚动轴承故障诊断完整项目包,面向需要完成毕业设计、课程设计或期末大作业的计算机及相关专业学生,也适合对智能故障诊断感兴趣的初学者进阶练习。压缩包共41个文件,含30个MAT格式数据文件、6个Markdown说明文档、4个Python源码脚本和1个使用说明文本,整体大小约34.87MB。目前已有971人学习使用。源码基于CNN与DNN模型实现,提供数据预处理、模型训练、准确率可视化等脚本,并附有预处理后的数据与最后一层特征数据,可对照论文和报告复现实验过程。项目目录按数据、预处理、源码、说明文档分层组织,每层均配有README,使用说明明确标注运行环境与步骤,经过严格调试,下载解压后即可直接运行,是毕业设计或深度学习方法落地的完整参考方案。
1. 深度学习进场之前,滚动轴承故障诊断卡在哪儿
转动机械的故障里,滚动轴承占的比例常年排在前三,但传统诊断方法有一个绕不开的痛点——同一套特征在不同工况下会“翻脸”。一组峭度和包络谱在固定转速下能把内圈故障分得清清楚楚,转速一变、负载一换,阈值全部失效,现场工程师只能靠经验重新调参数。
基于深度学习的滚动轴承故障诊断方法把这个问题改成了一条端到端链路:模型直接从原始振动信号里学习可分性特征,不再依赖人工构造的指标阈值。这个方向对两类人最有用:一是毕业设计需要出实验数据和对比图的同学,想在一个公开数据集上跑通全流程;二是想评估数据驱动方案能不能落地到现场的诊断工程师。先说清楚一点,这类方案对数据分布变化敏感,后面我会把切窗、模型、训练和泛化验证一条线串起来讲。
2. 信号数据要过三关:切窗、标注、归一化,最耗时间的不是训练
2.1 拿到加速度信号先别急着喂网络:三个前置问题
打开一个轴承诊断项目包,最常见的原始数据是加速度传感器采下来的时序振动信号,采样率通常在 10kHz 到 20kHz 之间,一个文件里可能有几十万甚至上百万个采样点。直接把整段序列扔进网络会同时踩中两个坑:一是序列太长,模型计算量和显存占用都兜不住;二是整段信号只有一个标签,样本量太少,统计上没法训练。
我一般会把数据处理拆成三个前置问题来回答,三个答案直接决定后续模型的上限。第一个问题:一个训练样本应该有多长?或者说,一个用于分类的输入窗口要包含多少个振动周期?第二个问题:同一个故障状态能切出多少个样本,样本量够不够网络吃饱?第三个问题:数据要不要做归一化,归一化的统计量应该从哪部分数据里算,测试集会“泄题”吗?
前两个问题是一对矛盾。窗口开得越长,单个样本包含的故障冲击周期越完整,模型越容易学到周期性特征,但样本总数变少;窗口开得越短,样本数变多,但每个样本可能只截到故障冲击的一部分,类别可分性变差。这个取舍没有绝对标准,跟轴承的转速和故障特征频率有关,后面细说。
第三个问题才是真正影响实验结论的暗坑。很多第一次做诊断任务的人会把所有数据先归一化再划分训练集和测试集,这在学术上叫数据泄漏,测试集的信息通过归一化统计量混进了训练过程,最后得到的准确率高得离谱但一换数据就崩。正确做法是先划分集合,再单独在训练集上拟合归一化参数。
2.2 滑窗切样本:重叠率怎么定,样本量怎么算
切窗口的常见做法是滑窗重叠采样,用一个固定长度的窗口沿时间轴滑动,相邻窗口以一定比例重叠。这样做一举两得:既能把一条长信号切出大量样本,又能在相邻样本之间保留一部分连续性信息。
窗口长度选择上,我一般先用转速算出轴承的转频,保证一个窗口至少包含 5 到 10 个完整转轴旋转周期。比如转速 1800 转/分时转频是 30Hz,周期约 33 毫秒,12kHz 采样率下一个周期大约 400 个点,窗口取 1024 点约覆盖 2.5 个周期,取 2048 点约覆盖 5 个周期。对于内圈故障和外圈故障这类有明确特征频率的信号,2048 点的窗口更容易让模型在卷积层里捕捉到周期性的冲击模式,但计算量也翻倍。
重叠率的选择直接影响样本量。重叠率 50% 时,窗口每次前进 512 点;重叠率提高到 75%,每次只前进 256 点,样本量接近翻倍。切出来的样本数量可以用下面这段代码估算,也可以直接跑一遍看结果。
import numpy as np def sliding_window(signal, window_size=2048, overlap_rate=0.5): """ 滑窗切分一维振动信号 signal: 原始加速度序列, 一维 numpy 数组 window_size: 窗口长度, 默认 2048 点 overlap_rate: 重叠率, 0~1 之间, 默认 0.5 """ step = int(window_size * (1 - overlap_rate)) # 计算能切出的窗口总数 valid_len = (len(signal) - window_size) // step + 1 samples = [] for i in range(valid_len): start = i * step samples.append(signal[start:start + window_size]) return np.stack(samples) # 假设已加载好原始信号 raw_signal, 长度约 120000 点 # raw_signal = load_vibration_data("path/to/signal.csv") # samples = sliding_window(raw_signal, window_size=2048, overlap_rate=0.5) # 输出 (58, 2048), 即 58 个样本, 每个样本 2048 个采样点代码里的valid_len计算是常见的边界处理方式:当尾部剩余信号不足一个窗口时直接丢弃,不补零。补零会引入一段毫无物理意义的平坦区域,模型可能把这段“安静”误学成一种故障模式。overlap_rate从 0.5 提到 0.75,样本数会从约 58 个翻到约 115 个,对后面的训练集扩充效果很直观。
我建议在项目里把window_size和overlap_rate两个参数用显式变量声明,并写进实验记录。因为它们对最终准确率的影响通常比换一个网络结构还要大,我见过不少人折腾了几天模型结构,最后发现只是把重叠率从 0.25 调到 0.75,准确率就涨了三个点。
2.3 标注与数据集划分:先分后归一,别让测试集泄题
切窗完成之后,每个窗口的标签继承自它所在的那条原始记录。比如某个振动文件在实验时记录的状态是“内圈故障,直径 0.014 英寸,负载 1 马力”,那么这个文件切出来的所有窗口标签都是这一档。这里有一个关键点:同一个文件的窗口之间高度相关,如果直接随机打乱再划分训练测试集,训练集里很可能混进了和测试集窗口来自同一条原始信号的窗口,测试结果虚高。
正确做法是先把原始文件按故障类型分层划分成训练文件组和测试文件组,再对每个文件组内的窗口做切分。这在故障诊断领域叫“文件级划分”,区别于“样本级划分”。样本级划分适合做演示,但论文和实际项目里建议用文件级划分,结论更可信。
归一化放在划分之后,只在训练集上计算均值和标准差,再应用到验证集和测试集:
from sklearn.preprocessing import StandardScaler # 假设切好的训练样本 X_train, 形状为 (num_samples, window_size) # X_test 同理, 两者已经按文件级划分完毕 scaler = StandardScaler() # 先对每个样本做展开, 拟合统计量 X_train_flat = X_train.reshape(X_train.shape[0], -1) scaler.fit(X_train_flat) X_train_norm = scaler.transform(X_train_flat).reshape(X_train.shape) X_test_flat = X_test.reshape(X_test.shape[0], -1) X_test_norm = scaler.transform(X_test_flat).reshape(X_test.shape)scaler.fit只用了训练集数据,统计量包括每个采样位置的均值和标准差。测试集的归一化用的是训练集的统计量而不是自己的,这一步直接保证了测试结果是“未知数据”上的表现。有些同学会把fit和transform混着用,或者在合并后的全部数据上做fit,这是测试集泄题的常见来源。
最后在送入模型前,记得把数据从二维(样本数, 窗口长度)变形为模型要求的(样本数, 1, 窗口长度),多出来的维度是通道数。加速度信号是单通道,所以填 1。这个维度问题在 PyTorch 里很容易漏掉,一漏就是运行时维度不匹配报错。
3. 模型选型:一维CNN是骨架,注意力模块决定上限
3.1 为什么首选1D-CNN,而不是把原始信号拼成全连接层
把 2048 个原始采样点直接摊平接一个全连接层,输入维度是 2048,假设第一个隐藏层 128 个神经元,那仅是这一层就有 26 万个参数,训练起来很吃力,而且全连接层对输入信号的局部时间偏移完全没有鲁棒性。轴承振动信号里的故障特征,比如外圈故障的冲击脉冲,在波形上表现为特定形状的局部突起——只要形状对,出现在波形的哪个位置并不重要。
一维卷积天然适配这种数据:卷积核在时间轴方向滑动,提取的是局部波形的模式,自动获得了平移不变性。一个 3 长度的卷积核可以看作在学习“当前点和左右邻居的组合模式”,多叠几层之后,感受野扩大,就能覆盖到相邻几个冲击脉冲之间的周期关系。这就是一维 CNN 成为滚动轴承振动信号诊断主流基线的根本原因——它的归纳偏置和信号本身的物理结构是对齐的。
和 2D CNN 的对比也值得一提:有人喜欢先用小波变换或短时傅里叶变换把一维信号变成时频图,再用 2D CNN 做图像分类。这条路本身没有错,但它引入了额外的变换参数——小波基函数、尺度、窗函数类型——这些参数对结果的影响很难解释清楚,调试成本更高。直接对原始波形做 1D 卷积,省掉前处理变换,整个流程的可复现性更好,也更符合毕业设计里“方法改进点和消融实验容易讲清楚”的需求。
3.2 一个可复现的BearingCNN网络结构
下面这个结构是诊断任务里很常见的基线模型,我按“卷积块 + 池化 + 全局平均池化 + 分类头”的套路写,代码可以直接跑通。它的特点是参数量小,单张显卡跑得非常轻松,很适合作为毕业设计的起点模型。
import torch.nn as nn import torch.nn.functional as F class BearingCNN(nn.Module): def __init__(self, in_channels=1, num_classes=4): super(BearingCNN, self).__init__() # 第一个卷积块: 提取局部波形模式 self.conv1 = nn.Sequential( nn.Conv1d(in_channels, 16, kernel_size=3, padding=1), nn.BatchNorm1d(16), nn.ReLU(), nn.MaxPool1d(kernel_size=2, stride=2) ) # 第二个卷积块: 扩大感受野, 捕捉冲击序列的局部节奏 self.conv2 = nn.Sequential( nn.Conv1d(16, 32, kernel_size=3, padding=1), nn.BatchNorm1d(32), nn.ReLU(), nn.MaxPool1d(kernel_size=2, stride=2) ) self.conv3 = nn.Sequential( nn.Conv1d(32, 64, kernel_size=3, padding=1), nn.BatchNorm1d(64), nn.ReLU(), nn.MaxPool1d(kernel_size=2, stride=2) ) # 全局平均池化后接分类层 self.global_pool = nn.AdaptiveAvgPool1d(1) self.classifier = nn.Sequential( nn.Flatten(), nn.Linear(64, 64), nn.ReLU(), nn.Dropout(0.5), nn.Linear(64, num_classes) ) def forward(self, x): x = self.conv1(x) x = self.conv2(x) x = self.conv3(x) x = self.global_pool(x) return self.classifier(x)逐层看参数设计:kernel_size=3配合padding=1让卷积不改变序列长度,三个卷积块之后序列长度只受池化层影响,从 2048 压缩到 256。MaxPool1d的stride=2把序列长度每一步减半,这是下采样和控制计算量的主要手段。AdaptiveAvgPool1d(1)把最后一个维度压成 1,不管前面输入长度是多少,最终都能输出固定维度给分类层,这让模型对输入长度有一定容忍度。
通道数从 16 涨到 32 再涨到 64,遵循的是“分辨率减半、通道翻倍”的经典设计原则,保证信息容量不随空间尺寸缩小而丢失。Dropout(0.5)放在分类层第一层后面,主要防的是最后的线性层过拟合——在样本量只有几百到几千的诊断任务里,分类头是最容易过拟合的部分,Dropout 放在这里性价比最高。
num_classes要看你的具体标注粒度为 4 类还是 10 类:4 类是正常、内圈故障、外圈故障、滚动体故障,10 类是把每种故障再按损伤直径细分。毕业设计里先跑 4 类,把流程调通,再换 10 类做消融对比,是比较稳妥的节奏。
3.3 想让准确率再上一个台阶:加注意力模块或混合LSTM
基线 CNN 跑通之后,通常论文里的改进点会落在两个方向上:一个是在卷积块之间插入通道注意力或时空注意力模块,让模型对故障冲击出现的频带更敏感;另一个是把最后的全局平均池化换成 LSTM 或 GRU 层,显式建模相邻时间步之间的依赖关系。
我一般建议优先加注意力而不是 LSTM。LSTM 在序列建模上确实能捕捉长期依赖,但训练更慢、更容易过拟合,对输入长度也更敏感;而一个轻量的注意力模块改动小,消融实验容易做——你可以把“有注意力 vs 无注意力”作为论文里的一个对比组,红枣逻辑很清晰。如果选注意力,用最基础的通道注意力即可,不需要一上来就上 Transformer 那套重结构。
如果坚持用 LSTM,常见做法是把卷积块输出的特征序列作为 LSTM 的输入,LSTM 输出最后一个时间步的隐状态,再接到分类头。整个过程相当于先用 CNN 做局部特征降维,再用 LSTM 做序列建模,比直接用 LSTM 吃原始波形靠谱很多,因为 CNN 已经大幅缩短了序列长度,LSTM 的优化压力小得多。
4. 训练与评估:把超参、早停、指标三件套配齐,结果才敢写进论文
4.1 损失函数、优化器与学习率:照着一组默认值起步
分类任务的损失函数首选交叉熵,PyTorch 里CrossEntropyLoss自带 Softmax,所以模型最后一层不需要额外激活函数。优化器用 Adam 是主流选择,它对学习率的敏感度比带动量的 SGD 低,默认的betas=(0.9, 0.999)不需要动。
学习率的起点我一般设1e-3。太大会导致损失曲线震荡,太小则模型在 50 个 epoch 内很难收敛到理想精度。训练到一半如果发现验证集准确率停滞,常见做法是引入余弦退火或阶梯式衰减。下面的训练循环覆盖了一个标准流程,包括学习率调度和每个 epoch 的损失记录:
import torch import torch.nn as nn from torch.utils.data import DataLoader def train_model(model, train_loader, val_loader, epochs=50, device="cuda"): model.to(device) criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.5) best_val_acc = 0 for epoch in range(epochs): model.train() train_loss = 0 train_correct = 0 train_total = 0 for xb, yb in train_loader: xb, yb = xb.to(device), yb.to(device) optimizer.zero_grad() outputs = model(xb) loss = criterion(outputs, yb) loss.backward() optimizer.step() train_loss += loss.item() * xb.size(0) train_correct += (outputs.argmax(dim=1) == yb).sum().item() train_total += xb.size(0) scheduler.step() val_acc = evaluate(model, val_loader, device) if val_acc > best_val_acc: best_val_acc = val_acc torch.save(model.state_dict(), "best_model.pth") return best_val_accStepLR每 15 个 epoch 把学习率乘 0.5,在 50 个 epoch 的训练里会衰减两次,适合大多数诊断数据集的收敛节奏。best_val_acc的维护逻辑起一个“模型保存哨兵”的作用:只有验证集准确率刷新历史最高时才保存权重,不会把最后几个 epoch 的过拟合权重写进结果。zero_grad必须在每个 batch 开始前执行,否则梯度会跨 batch 累积,损失曲线会乱跳。
如果你用的显卡显存不够,把batch_size从 128 降到 64 或 32 即可,比改模型结构更快解决问题。学习率是否需要跟着调,要看损失曲线的形态判断,一般小幅调整即可。
4.2 训练中的早停与模型选择:别迷信最后一个epoch
过拟合在轴承诊断任务里出现得比想象中早。样本量只有几千时,模型两三个 epoch 就能把训练集准确率做到 95% 以上,但从第 15 个 epoch 起验证集准确率可能反而往下走。所以我建议训练时监控两条曲线:训练集 loss 持续下降但验证集 loss 开始反弹——这是过拟合的标准信号。
一个可落地的早停逻辑是:连续 10 个 epoch 验证集准确率没有刷新纪录,就终止训练并回滚到历史最优权重。这个“10”是一个经验值,数据集越小、噪声越大,这个窗口就应调大一些。同时把训练过程中每个 epoch 的验证集准确率打印出来,运行结束后核对最优 epoch 的位置,你会对它出现得有多早感到意外。
early_stop_patience = 10 epochs_since_improve = 0 for epoch in range(epochs): # 训练与评估略, 得到当前 val_acc if val_acc > best_val_acc: best_val_acc = val_acc epochs_since_improve = 0 torch.save(model.state_dict(), "best_model.pth") else: epochs_since_improve += 1 if epochs_since_improve >= early_stop_patience: print(f"Early stopping at epoch {epoch}") break实际项目中“训练 50 轮然后取最后一轮权重”的做法在故障诊断里很容易翻车,因为最后一轮可能已经处在过拟合区间。训练过程的打印日志、最优 epoch 位置和验证集准确率建议记录到 CSV 或实验笔记里,方便后续做对比分析。
4.3 评估指标:准确率之外,还要看每一类怎么错了
准确率在类别平衡的数据集上够用,但轴承故障数据即使是从公开数据集切出来的,也不能保证 10 个细分类别样本量完全相等。准确率会掩盖一个事实:模型可能对小样本类别完全失效,但被大类别的高准确率拉平了整体指标。所以评估阶段我习惯把混淆矩阵、精确率、召回率和 F1 分数全部算出来。
from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns import matplotlib.pyplot as plt def evaluate_with_report(model, loader, device="cuda"): model.eval() y_true = [] y_pred = [] with torch.no_grad(): for xb, yb in loader: xb, yb = xb.to(device), yb.to(device) outputs = model(xb) preds = outputs.argmax(dim=1).cpu().numpy() y_pred.extend(preds) y_true.extend(yb.cpu().numpy()) cm = confusion_matrix(y_true, y_pred) # 分类报告包含 precision/recall/f1 以及每类的样本数 print(classification_report(y_true, y_pred, digits=4)) plt.figure(figsize=(8, 6)) sns.heatmap(cm, annot=True, fmt="d", cmap="Blues") plt.xlabel("Predicted") plt.ylabel("True") plt.tight_layout() plt.savefig("confusion_matrix.png", dpi=150)classification_report会把每一个故障类别的精确率、召回率、F1 值一次性列出来,一眼就能看出哪些类别被“牺牲”了。confusion_matrix的热力图也不只是好看,它直接回答一个诊断问题——“内圈故障的样本最常被误判成哪一个类别”,这个信息对数据层面的后续改进非常关键。
如果发现某个类别的召回率明显偏低,常见对策有两个:一是给损失函数里每个类别按样本量的倒加权,让模型更重视小类;二是回到切窗阶段,对该类别的原始信号增加窗口重叠率,让同类别的训练样本更充分。先看混淆矩阵里的误判方向,再决定动数据还是动损失函数,不要一上来就换网络结构。
5. 避坑与常见问题排查:五个高频翻车现场
5.1 训练集准确率 99%,验证集只有 70%
现象:训练曲线一路冲到接近满分,验证集准确率却在一半左右徘徊;或者验证集曲线的抖动幅度肉眼可见地大。
原因:这类现象九成是数据泄漏。前面提到的样品级划分是最大元凶——切窗后不按原始文件分组,随机打乱后同一条信号切出的窗口同时进了训练集和验证集,模型在训练时已经“见过”验证集里几乎同样的波形。另外,归一化统计量先在全部数据上拟合,也等于把测试集的信息提前暴露给了优化过程。
解决:先按文件分组,把整个文件划归到某一个集合,再切窗;归一化只fit训练集;最后检查测试集窗口和训练集窗口有没有“共享原始记录”。修完之后准确率可能掉下来一截,但这才是真实水平。
5.2 换随机种子,结果波动好几个点
现象:同一份代码,只改random_state或torch.manual_seed,模型最终准确率在正负 5 个点之间跳。某些种子下表现得特别好,换一个就“翻车”。
原因:故障诊断数据集的样本总量通常只有几千,网络初始化、样本打乱顺序、Dropout 随机性都会被小数据集放大。尤其当类别不平衡时,一个种子下测试集里天然多几个难样本,准确率就会明显偏低。
解决:固定所有相关随机种子,包括 Python 的random、NumPy 的random和 PyTorch 的 CPU/CUDA 种子。然后把同一组超参数跑 5 次不同种子,报告均值和标准差,而不是只挑最好的一次。这个习惯直接提升实验可信度。
5.3 外圈故障类别总是学不进去
现象:混淆矩阵里其他类别的 F1 都不错,唯独外圈故障这一个类别的召回率明显低于同行。
原因:先检查原始数据的标注范围。外圈故障有时会和其他故障混叠在同一段信号里,或者切窗后大量窗口落在了两个故障冲击之间的“相对安静区”,代表性不足。另外如果这一类别的原始文件只有一两个,样本数量天然处于劣势。
解决:针对该类别单独增加重叠率,比如全数据用 0.5,这个类别用 0.75,重新切窗;或者在损失函数里对该类别加权重。改了数据之后重新训练,再看混淆矩阵该行的召回率有没有改善。若没有,再检查该类别信号在其他类别下的误判分布。
5.4 t-SNE 可视化里,不同故障类别聚成一团
现象:把网络倒数第二层的特征拿出来跑 t-SNE,图上不同类别没有形成清晰的分簇,甚至混在一起分不出边界。
原因:特征提取能力不足或特征层选择不对。t-SNE 画倒数第二层特征时,如果模型还没有充分收敛,或者卷积层感受野不够覆盖完整的冲击周期,特征就会有大量重叠。另一种常见错误是把最后一层的 Logits 拿来画,Logits 已经被分类权重“格式化”了,聚簇效果天然很差。
解决:把可视化对象换成nn.AdaptiveAvgPool1d之后的特征向量,并确认模型用的是验证集准确率最高的权重,而不是最后一个 epoch 的权重。若仍然混叠,说明模型结构容量不够,优先考虑加深最后一个卷积块或加注意力模块。
5.5 训练到一半显存溢出或者卡死
现象:CUDA out of memory报错,或者训练速度慢到没法在可接受时间内跑完一轮。
原因:最常见的是batch_size太大、输入窗口太长或 PyTorch 的 DataLoader 没有合理设置num_workers。输入 2048 点、单通道、batch 128 本来占用不大,但如果模型里接入了 LSTM 或者序列长度被意外地放大,显存压力会急剧上升。
解决:先把batch_size降到 32 看训练是否稳定,再把num_workers从默认值调到 CPU 核心数附近。注意num_workers太高在小数据集上反而增加进程调度开销,4 到 8 通常足够。若清洗代码后显存仍然吃紧,检查输入张量的 shape,常见问题是通道维度写成了(batch, 2048, 1),卷积把它当成多通道长序列处理,参数和中间变量都会膨胀。
6. 验证模型真的“会”诊断:特征可视化和跨工况泛化测试
6.1 用特征分布判断网络学到了什么
训练完成只是个开始。我给一个项目做验收时,第一件事就是让模型跑一遍测试集,把倒数第二层的特征提出来做 t-SNE 可视化。这个方法的特点是能直观看出同一个故障类别的样本是否在特征空间聚拢、不同类别是否明显分离。如果可视化结果混作一团,准确率再高也说明模型在“死记硬背”个别样本,泛化能力堪忧。
特征提取代码很简单:注册forward_hook或者在forward里直接返回global_pool之后的向量。注意要加载验证集上最优的权重,而不是自己默认保存的最后一轮权重——这一点我在最开始的训练流程里就留了接口。
6.2 换负载、换转速,看模型会不会露馅
滚动轴承诊断模型的真正考验在于跨工况泛化。用一个负载下训练好的模型去测试另一个负载下的数据,准确率往往会明显下滑,这是数据驱动方法的已知短板。在完整体验这个流程后,我记得第一次做跨负载测试时准确率直接掉了近 20 个点,那种“整个方案被推翻”的挫败感让人记忆犹新。
跨工况测试的操作方法是:训练数据用 0 马力负载或 1 马力负载的数据,验证和测试全部用 2 马力、3 马力负载的数据。如果准确率下降到不可接受,也不用立刻换模型,先确认训练集中是否包含目标工况的转速范围。没有的话,就要在数据层面补充目标工况的子集做微调,或者用迁移学习做同目标域适配。
6.3 一个值得养成的习惯:固定随机种子并保存完整实验配置
最后落一个具体技巧:每次训练前把随机种子固定,同时把数据切窗参数、模型结构、学习率和 epoch 数一并写入一个实验配置字典,和模型权重一起保存。过了几周再回来看实验时,你会感谢这个步骤——没有它,想复现当初的结果几乎要靠玄学。除了随机种子,还要注意 PyTorch 不同版本之间的算子行为可能有差异,所以把环境版本记录下来同样重要。
现在我做诊断项目时,已经习惯把“固定种子 + 文件级划分 + 最优权重保存”三个动作当作实验的默认前置条件。这些习惯本质上都属于“后悔药”一类的东西,提前准备好,后面会少掉很多重新跑训练的力气。希望这篇内容能帮你在滚动轴承故障诊断的方向上少走弯路。
本文还有配套的精品资源,点击获取