简介这份资源面向机械故障诊断方向的学习者与工程实践者提供一套基于深度学习的完整项目源码帮助理解如何用Python将振动、温度等传感器数据转化为可用的故障识别模型。包内共88个文件以45个py源码与43个pyc编译文件为主压缩包约172KB涵盖数据生成、一维与二维数据集处理、模型定义及训练脚本等模块结构紧凑便于按流程阅读。项目围绕数据预处理、特征工程、CNN与LSTM等模型构建、训练调参、评估验证及部署思路展开适合希望把深度学习落地到工业设备预测性维护的读者参考。目前已有386人学习可作为课程设计、毕业项目或工程原型的起步素材帮助快速搭建实验环境并理解故障诊断的完整链路。1. 从一份振动信号到故障标签这个项目到底在做什么设备维护这行有个反直觉的结论很多故障不是突然发生的而是振动信号里早就埋了伏笔只是人耳和阈值报警抓不住。这个项目就是干这件事的——用深度学习把机械振动信号直接映射成故障类别省掉手工提特征那一步。它适合两类人一类是刚接触工业信号诊断、想找个能跑通的 Python 项目练手另一类是做设备监测的工程师手里有加速度传感器数据想看看 CNN、LSTM 这类模型到底能不能替代传统的包络谱分析。项目主体是Deep_Learning_For_Fault_Diagnosis-main里面把数据生成、1D/2D 数据集构建、模型定义和训练脚本拆得比较清楚不是那种一个 notebook 从头写到尾的玩具。你拿到手之后能顺着generate_dataset.py造数据、用train.py跑训练再改models里的网络结构做对比实验。2. 项目结构拆解从 generate_dataset.py 到 train.py 的数据链路2.1 目录里每个文件在链路里的位置先把Deep_Learning_For_Fault_Diagnosis-main的骨架理清楚不然直接打开train.py会不知道数据从哪来。这个项目的组织方式比较典型按数据流分成四层文件/目录角色输入输出generate_dataset.py造数据入口故障频率、采样率、噪声参数原始振动序列dataset_1d一维信号数据集原始序列定长 1D 样本dataset_2d二维图像数据集原始序列时频图/灰度图utils公共函数配置、路径归一化、切分、可视化models网络定义输入维度、类别数CNN/LSTM 等模型train.py训练主脚本数据集、模型、超参权重文件、日志这个分法有个好处数据生成和模型训练解耦。你换一种故障类型只动generate_dataset.py你换网络只动models和train.py的模型选择部分。常见做法是把配置写进utils里的一个 config 字典避免路径和超参散落在各个文件里。2.2 数据生成用仿真信号替代真实台架真实故障数据不好拿这个项目用仿真信号起步。generate_dataset.py的核心逻辑是按故障特征频率叠加谐波和噪声模拟轴承内圈、外圈、滚动体故障的振动波形。下面是一段典型的实现思路import numpy as np def generate_vibration_signal(fault_freq, fs12000, duration1.0, noise_level0.1): 生成一段含故障特征的振动信号 fault_freq: 故障特征频率(Hz) fs: 采样率 duration: 信号时长(秒) noise_level: 高斯噪声标准差 t np.linspace(0, duration, int(fs * duration), endpointFalse) # 基频载波 故障频率调制模拟冲击成分 carrier np.sin(2 * np.pi * 1000 * t) impact np.sin(2 * np.pi * fault_freq * t) signal carrier * (1 0.5 * impact) # 加入高斯白噪声模拟实际工况干扰 signal noise_level * np.random.randn(len(t)) return signal这段代码里fault_freq是区分故障类型的关键参数内圈、外圈、滚动体各有对应的特征频率计算公式项目里一般会在utils里封装成函数。noise_level控制信噪比调大之后模型难度上升可以用来测试鲁棒性。fs默认 12000 Hz 是旋转机械振动监测里比较常见的采样率如果你手头数据是 25600 Hz改这个参数就行但后续做 FFT 时频率轴要同步改。2.3 1D 与 2D 数据集的分工dataset_1d和dataset_2d不是重复造轮子而是对应两类模型输入。1D 数据集直接把时间序列切成定长片段适合 1D-CNN 和 LSTM2D 数据集把片段做短时傅里叶变换STFT或小波变换转成时频图适合 2D-CNN。项目里同时保留两套是为了让你对比“原始时序”和“时频表示”哪种对当前故障更敏感。切分逻辑上常见做法是滑动窗口窗口长度取 1024 或 2048 点步长取窗口的一半这样既有重叠又不至于样本爆炸。标签按片段所属的故障类型赋值最后按 7:2:1 分训练、验证、测试。注意别把同一段连续信号切出来的窗口同时放进训练集和测试集否则准确率会虚高这是时序任务里最容易翻车的地方。2.4 模型定义models 目录里放了什么models目录通常按网络类型分文件比如cnn1d.py、lstm.py、cnn2d.py。以 1D-CNN 为例结构不会太深三到四个卷积块加全局平均池化就够用import torch.nn as nn class CNN1D(nn.Module): def __init__(self, num_classes4, input_len1024): super().__init__() self.features nn.Sequential( nn.Conv1d(1, 16, kernel_size15, stride2, padding7), nn.BatchNorm1d(16), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(16, 32, kernel_size7, stride2, padding3), nn.BatchNorm1d(32), nn.ReLU(), nn.AdaptiveAvgPool1d(1) # 把时间维压成1输出32维特征 ) self.classifier nn.Linear(32, num_classes) def forward(self, x): x self.features(x) # [B, 32, 1] x x.flatten(1) # [B, 32] return self.classifier(x)kernel_size第一层给 15 是为了覆盖足够的冲击周期第二层降到 7 做更细的特征组合。AdaptiveAvgPool1d(1)替代了展平操作好处是输入长度变化时全连接层不用改。num_classes按你的故障类别数改比如正常、内圈、外圈、滚动体就是 4。如果你要用 LSTM把features换成nn.LSTM(input_size1, hidden_size64, batch_firstTrue)后面接最后一个时间步的输出即可。3. 跑起来环境、命令与训练脚本参数3.1 环境准备与依赖安装项目是纯 Python 技术栈深度学习框架大概率是 PyTorch因为models里的写法更贴近 PyTorch 习惯。建议用 conda 建独立环境避免和系统里的包打架conda create -n fault_diag python3.9 -y conda activate fault_diag pip install torch torchvision numpy scipy scikit-learn matplotlibscipy用来做 STFT 和小波变换scikit-learn用来出混淆矩阵和分类报告matplotlib画时频图和损失曲线。如果你机器有 CUDA装对应版本的 torch 就行没有的话 CPU 也能跑只是训练慢一些。常见做法是在train.py开头写device torch.device(cuda if torch.cuda.is_available() else cpu)后面统一.to(device)。3.2 三步跑通生成数据、训练、看结果第一步先造数据确认generate_dataset.py能正常输出python generate_dataset.py --fault_types inner,outer,ball --samples_per_class 500 --output_dir ./data--fault_types指定要生成哪几类故障--samples_per_class控制每类样本数--output_dir是输出目录。跑完检查./data下有没有按类别分的子文件夹每个子文件夹里是.npy或.csv文件。第二步启动训练python train.py --data_dir ./data --model cnn1d --epochs 50 --batch_size 64 --lr 0.001--model对应models里的网络名--epochs和--batch_size按显存调--lr是学习率。训练过程中会打印每个 epoch 的 loss 和验证准确率最后保存权重到checkpoints/下。第三步评估通常train.py里会带一个--eval开关或者单独有个evaluate.pypython train.py --data_dir ./data --model cnn1d --eval --checkpoint ./checkpoints/best.pth这一步会输出测试集准确率和混淆矩阵重点看哪两类容易混比如内圈和外圈在低转速下特征频率接近混淆是正常的。3.3 关键超参怎么调batch_size从 64 起步显存不够降到 32 或 16但太小会让 BatchNorm 统计不稳。lr用 0.001 配 Adam 是稳妥起点如果 loss 震荡就降到 0.0005。epochs不用一上来给 100先跑 30 看验证集是否已经平了。窗口长度input_len和采样率要匹配1024 点在 12 kHz 下大约 85 ms能覆盖一个完整的冲击周期。如果你把noise_level调到 0.3 以上模型可能需要更深的网络或者更长的训练轮次才能收敛。4. 避坑与排查数据泄漏、维度不匹配和过拟合4.1 验证集准确率异常高测试集却崩了现象是训练日志里验证准确率 99%一换测试集掉到 60%。原因多半是滑动窗口切分时同一段连续信号的重叠窗口被分到了不同集合模型其实见过“邻居”。解决方法是按原始信号段划分训练/验证/测试再在各自集合内部切窗口而不是先切窗口再随机分。这个坑在时序任务里非常常见改完之后指标会回落到真实水平。4.2 报错 Expected input to have X channels现象是train.py跑起来就抛维度错误提示输入通道数不对。原因是 1D-CNN 要求输入形状是[B, 1, L]而你的数据可能是[B, L]或者[B, L, 1]。解决方法是加一句x x.unsqueeze(1)把通道维补上或者在 Dataset 的__getitem__里就返回正确形状。2D-CNN 同理输入应该是[B, 1, H, W]别把通道维和 batch 维搞混。4.3 训练 loss 不降准确率卡在随机水平现象是 loss 一直在 1.38 附近晃四分类的随机水平准确率 25% 左右。原因可能是标签没对齐比如文件名排序和标签映射不一致或者归一化把信号幅度压没了。解决方法是先打印一个 batch 的x.mean()和x.std()确认数据不是全零或全常数再检查label的取值范围是不是 0 到num_classes-1。另外学习率太大也会导致 loss 不降先降到 0.0001 试几个 epoch。4.4 过拟合训练集 100%验证集 70% 就上不去了现象是训练准确率一路涨到 100%验证集早早停在 70%。原因是模型容量相对数据量偏大或者数据增强不够。解决方法是加 Dropout全连接层前加nn.Dropout(0.5)、加权重衰减Adam 的weight_decay1e-4、或者对 1D 信号做随机加噪、随机缩放。如果这些都不管用说明数据本身区分度不够得回到generate_dataset.py调整故障频率的间隔让类别之间更有区分度。4.5 保存的模型加载后预测结果全一样现象是训练时指标正常重新加载权重做推理所有样本预测成同一类。原因通常是保存时只存了state_dict加载时模型结构没对上或者model.eval()忘了调BatchNorm 还在用 batch 统计。解决方法是保存时同时存model.state_dict()和模型配置加载时先实例化同结构模型再load_state_dict推理前固定加model.eval()和torch.no_grad()。5. 二次开发换数据、换模型、上部署的改造思路5.1 换成自己的振动数据项目自带的仿真数据只是让你跑通链路真正要落地得换成实测数据。假设你手里有 CSV 格式的振动信号每行一个采样点文件名里带故障标签。改造点在dataset_1d的 Dataset 类里把读取逻辑从.npy换成pandas.read_csv标签从文件名解析。注意实测数据的采样率、量纲和仿真数据不一样归一化要按通道做 Z-score而不是简单除以最大值。如果实测数据类别不平衡比如正常样本远多于故障样本可以在 DataLoader 里用WeightedRandomSampler做重采样或者在 loss 里给少数类加权。5.2 加一个新模型做对比想试试 Transformer 或者 GRU不用改train.py的主流程只要在models下新建一个文件实现__init__和forward然后在train.py的模型选择字典里注册进去。比如加一个 GRUclass GRUModel(nn.Module): def __init__(self, num_classes4, hidden_size64, num_layers2): super().__init__() self.gru nn.GRU(input_size1, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue) self.fc nn.Linear(hidden_size, num_classes) def forward(self, x): # x: [B, 1, L] - [B, L, 1] x x.transpose(1, 2) out, _ self.gru(x) return self.fc(out[:, -1, :]) # 取最后一个时间步注册时在train.py里加一行gru: GRUModel命令行--model gru就能跑。对比实验建议固定随机种子不然指标波动会让你误以为模型差异很大。我一般会在utils里加一个set_seed(42)每次训练前调一次。5.3 模型轻量化与推理脚本工业现场往往要求模型能跑在边缘设备上参数量不能太大。1D-CNN 本身已经比较轻如果还嫌大可以把通道数从 16/32 降到 8/16或者用深度可分离卷积替换普通卷积。导出方面PyTorch 可以用torch.jit.trace把模型转成 TorchScript脱离 Python 环境推理import torch model CNN1D(num_classes4) model.load_state_dict(torch.load(./checkpoints/best.pth, map_locationcpu)) model.eval() example torch.randn(1, 1, 1024) traced torch.jit.trace(model, example) traced.save(./checkpoints/cnn1d_traced.pt)之后在部署端用torch.jit.load加载输入同样形状的张量就能拿到分类结果。注意 trace 的时候要传一个真实形状的示例输入且模型里不能有依赖输入值的控制流否则 trace 会丢分支。5.4 一个容易忽略的验证习惯改造完之后别只看准确率。我习惯在测试集上额外跑一遍混淆矩阵和每类召回率尤其是故障诊断这种场景漏报比误报代价高。如果某一类召回率明显低先回去看那一类的时频图有没有被噪声淹没再决定是加数据还是改模型。从那以后我每次换数据或换模型都强制走一遍“混淆矩阵 召回率”的检查不再只盯着 loss 曲线。希望帮到你。本文还有配套的精品资源点击获取