简介这份资源面向深度学习与工业故障诊断方向的研究者和工程师提供一套可直接运行的故障诊断模型代码与配套数据帮助读者跳过从零搭建系统的环节快速进入模型训练与实验验证阶段。压缩包共63个文件约57.74MB以mat数据文件、py源码、xml配置、csv数据集为主另含h5训练权重、png模型结构图及readme说明覆盖数据预处理、模型定义、训练与预测的完整链路。资源中既有基于一维卷积的轴承故障诊断实现也包含LSTM时序诊断脚本并附带训练日志与提交结果文件便于对照复现。目前已有11421人学习下载代码注释较为完整适合作为学术研究或工程实践的入门起点读者可在此基础上调整网络结构、优化器与损失函数或迁移到其他类型的故障诊断任务中。1. 从振动信号到故障标签这套深度学习故障诊断资源到底能跑通什么设备还没坏电流和振动已经先变了。很多做预测性维护的团队卡在同一个地方算法论文看了一堆真到产线上却连一份带标签的故障数据都凑不齐更别说把深度学习模型塞进边缘盒子。这套「基于深度学习的故障诊断模型代码和数据」解决的正是这个断层——它把轴承、齿轮箱这类旋转机械的振动信号从原始时序一路处理到故障分类输出代码和数据配套拿到手就能跑出第一条准确率曲线。它适合三类人刚接触故障诊断、想找个能复现的 baseline 的研究生手里有设备数据但不知道怎么切窗、怎么标注的现场工程师以及需要快速验证某个网络结构在故障分类任务上到底行不行的算法从业者。资源本身不承诺 SOTA它的价值在于流程完整、接口清晰你能顺着它的数据管线换成自己的工况数据而不是从零搭一套预处理框架。下面按「数据长什么样 → 模型怎么搭 → 训练怎么调 → 坑在哪 → 怎么验证」的顺序拆开讲。2. 数据管线拆解从原始振动信号到模型可吃的张量2.1 故障诊断数据集的结构与标签体系这类资源里的数据常见形态是加速度传感器采集的一维时序采样率从几千赫兹到几十千赫兹不等。以轴承故障为例标签通常分三类维度故障位置内圈、外圈、滚动体、故障直径0.007、0.014、0.021 英寸这种分级、以及工况转速、负载。资源里如果用的是公开数据集一般已经按工况分好文件夹每个文件对应一段连续采集的信号。拿到数据第一件事不是急着喂模型而是确认三件事采样率是多少、每段信号多长、标签是怎么编码的。我一般会先写个脚本把目录结构和文件头扫一遍避免后面切窗时长度对不上。下面这段代码就是做这个体检的import os import numpy as np import scipy.io as sio def inspect_dataset(root_dir): 扫描数据集目录输出每个类别的文件数、信号长度和采样率线索 summary {} for label in sorted(os.listdir(root_dir)): label_dir os.path.join(root_dir, label) if not os.path.isdir(label_dir): continue lengths [] for fname in os.listdir(label_dir): fpath os.path.join(label_dir, fname) # 常见格式.mat / .csv / .npy这里以 .mat 为例 if fname.endswith(.mat): mat sio.loadmat(fpath) # 取第一个非元数据的数组作为信号 for k, v in mat.items(): if not k.startswith(__) and isinstance(v, np.ndarray): lengths.append(v.shape[-1]) break summary[label] { file_count: len(lengths), min_len: min(lengths) if lengths else 0, max_len: max(lengths) if lengths else 0, } return summary if __name__ __main__: info inspect_dataset(./data/raw) for k, v in info.items(): print(f{k}: {v[file_count]} files, len {v[min_len]}~{v[max_len]})这段代码的逻辑很直白遍历每个类别文件夹读文件、取信号数组、记录长度。关键参数是root_dir指向你解压后的原始数据根目录。跑完你会得到一张表如果发现某个类别文件数明显偏少或者信号长度参差不齐那后面切窗就得做补齐或截断不能直接按固定长度硬切。2.2 切窗、归一化与训练集划分的实操参数原始信号动辄几十万点不能整段塞进网络。常见做法是滑动窗口切分窗口长度和重叠率是两个核心参数。窗口太短一个故障冲击周期都盖不住太长样本数不够且引入过多正常段。经验值是窗口长度取 1024 或 2048 点重叠率 50%。采样率 12kHz 时2048 点约 170ms足够覆盖一次轴承故障冲击。归一化别用全局均值方差要按每个窗口单独做 z-score否则工况差异会被抹掉。划分训练验证集时务必按「时间段」切而不是随机打乱同一段连续信号切出的窗口如果同时进训练和验证准确率会虚高得离谱这是血泪经验。def sliding_window(signal, window_size2048, overlap0.5): 滑动窗口切分返回 shape(n_windows, window_size) step int(window_size * (1 - overlap)) windows [] for start in range(0, len(signal) - window_size 1, step): seg signal[start:start window_size] # 每个窗口独立 z-score 归一化 seg (seg - seg.mean()) / (seg.std() 1e-8) windows.append(seg) return np.array(windows) def split_by_time(windows, labels, train_ratio0.7): 按时间顺序划分前 70% 训练后 30% 验证 n len(windows) split int(n * train_ratio) return (windows[:split], labels[:split], windows[split:], labels[split:])window_size和overlap是你要根据采样率调的split_by_time里的train_ratio一般 0.7 到 0.8。注意这里没有打乱就是为了防止数据泄漏。如果你做的是跨工况迁移那划分还要按工况来训练用一种转速、验证用另一种这才测得出泛化。3. 模型搭建1D-CNN 与 LSTM 在故障分类上的取舍3.1 网络结构选型为什么时序任务偏爱一维卷积故障诊断的信号本质是局部冲击加周期调制一维卷积核在时间轴上滑动正好能捕捉这种局部模式而且参数量比 LSTM 小、训练快。资源里如果主模型是 1D-CNN通常是几层「卷积 池化 批归一化」堆叠最后接全连接分类。LSTM 适合捕捉更长程的依赖但故障信号经过切窗后窗口内信息已经够用LSTM 的优势不明显反而容易过拟合。我一般会先跑 1D-CNN 做 baseline如果准确率上不去再考虑加残差连接或换成多尺度卷积。下面是一个可直接用的 1D-CNN 结构import torch import torch.nn as nn class FaultCNN(nn.Module): def __init__(self, num_classes10, in_channels1): super().__init__() self.features nn.Sequential( # 第一层大卷积核抓冲击 nn.Conv1d(in_channels, 32, kernel_size15, padding7), nn.BatchNorm1d(32), nn.ReLU(), nn.MaxPool1d(2), # 第二层细化局部模式 nn.Conv1d(32, 64, kernel_size7, padding3), nn.BatchNorm1d(64), nn.ReLU(), nn.MaxPool1d(2), # 第三层高层抽象 nn.Conv1d(64, 128, kernel_size3, padding1), nn.BatchNorm1d(128), nn.ReLU(), nn.AdaptiveAvgPool1d(1) # 全局平均池化输出 (B,128,1) ) self.classifier nn.Linear(128, num_classes) def forward(self, x): # x: (B, 1, window_size) x self.features(x) x x.squeeze(-1) return self.classifier(x)kernel_size15是第一层的关键大核感受野宽能覆盖一个冲击周期后面逐层减小到 7 和 3做特征细化。AdaptiveAvgPool1d(1)把任意长度压成 1这样换窗口长度不用改结构。num_classes按你实际标签数改比如 10 类故障就填 10。3.2 训练循环与关键超参设置训练部分没什么玄学但有几个参数直接影响收敛。学习率用 1e-3 配 Adam批大小 64 或 128轮数看验证集早停。类别不均衡时给 CrossEntropyLoss 加权重权重按类别频率的倒数算。下面是一个最小训练循环from torch.utils.data import DataLoader, TensorDataset def train_model(model, train_x, train_y, val_x, val_y, epochs50, batch_size64, lr1e-3, devicecuda): model model.to(device) train_ds TensorDataset(torch.FloatTensor(train_x).unsqueeze(1), torch.LongTensor(train_y)) val_ds TensorDataset(torch.FloatTensor(val_x).unsqueeze(1), torch.LongTensor(val_y)) train_loader DataLoader(train_ds, batch_sizebatch_size, shuffleTrue) val_loader DataLoader(val_ds, batch_sizebatch_size) # 类别权重频率倒数 class_counts np.bincount(train_y) weights 1.0 / (class_counts 1e-6) weights weights / weights.sum() * len(class_counts) criterion nn.CrossEntropyLoss( weighttorch.FloatTensor(weights).to(device)) optimizer torch.optim.Adam(model.parameters(), lrlr) scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size15, gamma0.5) best_acc 0.0 for epoch in range(epochs): model.train() for xb, yb in train_loader: xb, yb xb.to(device), yb.to(device) optimizer.zero_grad() loss criterion(model(xb), yb) loss.backward() optimizer.step() scheduler.step() # 验证 model.eval() correct total 0 with torch.no_grad(): for xb, yb in val_loader: xb, yb xb.to(device), yb.to(device) pred model(xb).argmax(dim1) correct (pred yb).sum().item() total yb.size(0) acc correct / total if acc best_acc: best_acc acc torch.save(model.state_dict(), best_model.pth) print(fEpoch {epoch1}: val_acc{acc:.4f}) return best_accStepLR每 15 轮把学习率砍半防止后期震荡。best_model.pth只存验证集最好的那次别存最后一轮过拟合的最后一轮往往最差。class_counts那几行是处理不均衡的如果各类样本数差不多可以去掉权重。4. 避坑与排查故障诊断模型训练中最容易翻车的五件事4.1 准确率 99% 但上线就废数据泄漏的三种藏法现象是验证集准确率奇高换一批数据直接掉到随机水平。原因通常是切窗时同一段信号的重叠窗口被分到了训练和验证两边模型记住了这段信号而不是故障特征。解决方法是按时间段或按文件划分确保训练集和验证集的窗口来自完全不同的采集段。还有一种泄漏是归一化用了全局统计量把验证集的信息带进了训练改成每个窗口独立归一化即可。4.2 损失不下降学习率与批归一化的相互作用现象是训练几个 epoch 后 loss 卡住不动或者直接变成 nan。原因常见于第一层卷积核太大配了过高学习率或者 BatchNorm 在批大小太小时统计量不稳。解决办法是把学习率降到 1e-4 试一轮批大小至少 32如果显存不够就改用 GroupNorm。另外检查输入有没有 nan切窗时如果信号里有缺失值归一化会把它放大。4.3 换工况就崩域偏移不是靠加深网络能解决的现象是在实验室数据上 98%换到现场设备直接 60%。原因是训练和测试的转速、负载、传感器位置不同信号分布发生了偏移。解决思路有两个一是做域适应在损失里加 MMD 或对抗项二是更务实的做法把现场数据拿一部分做微调哪怕每类只有几十个样本fine-tune 最后两层就能拉回不少。别指望一个在 A 工况训练的模型直接吃 B 工况。4.4 标签噪声故障分级标注不一致的后果现象是模型在验证集上表现还行但混淆矩阵里某些类别互相混得厉害。原因是标注时故障直径分级边界模糊不同人标的不一样。解决办法是先把混淆最严重的两类合并成一个大类跑一轮确认是不是标注问题如果是要么重新标注要么在损失里用 label smoothing 降低对硬标签的依赖。4.5 显存不够窗口长度和批大小的权衡现象是训练时 OOM。原因是窗口长度 4096 配批大小 128第一层卷积输出维度太大。解决办法优先降批大小到 32其次把窗口长度减到 2048最后才考虑减模型通道数。别一上来就砍模型故障诊断任务里通道数减太多会直接欠拟合。5. 验证与进阶用混淆矩阵和跨工况测试确认模型真的能用训练完只看一个准确率数字是不够的我习惯先画混淆矩阵看哪些类别在互相混。如果某两类混得特别厉害要么是特征太像要么是标注有问题。下面这段代码输出归一化混淆矩阵和每类 F1from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns import matplotlib.pyplot as plt def evaluate(model, test_x, test_y, devicecuda): model.eval() model model.to(device) with torch.no_grad(): xb torch.FloatTensor(test_x).unsqueeze(1).to(device) pred model(xb).argmax(dim1).cpu().numpy() cm confusion_matrix(test_y, pred, normalizetrue) plt.figure(figsize(10, 8)) sns.heatmap(cm, annotTrue, fmt.2f, cmapBlues) plt.xlabel(Predicted) plt.ylabel(True) plt.savefig(confusion_matrix.png, dpi150) print(classification_report(test_y, pred, digits4)) return cmnormalizetrue是按真实类别归一化对角线是召回率。classification_report给出每类精确率、召回率和 F1比总准确率有用得多。如果某类 F1 低于 0.7回去看那一类的信号是不是本身信噪比就差。进阶用法上我建议做一次跨工况验证用一组转速的数据训练另一组转速的数据测试看准确率掉多少。掉 5 个点以内说明特征学得比较稳掉 20 个点以上就得考虑域适应或者加工况标签做条件训练。另外可以试试把时域信号转成时频图用 2D-CNN 跑一遍和 1D-CNN 对比有时候时频图对变工况更鲁棒。资源里的代码和数据足够你把这条链路完整走一遍换成自己的数据时重点盯住切窗划分和归一化这两步别让数据泄漏毁了整个评估。从那以后我每次跑故障诊断实验都强制先出一张混淆矩阵再谈准确率希望帮到你。本文还有配套的精品资源点击获取