简介:这是一份面向深度学习与工业智能方向初学者及研究者的故障诊断入门示例,围绕数据预处理、模型搭建与模型训练三大核心环节展开,帮助读者理解如何用神经网络识别和预测复杂设备故障模式。资源包共57个文件,以40个mat数据文件为主体,配合10张png结果图、3个py脚本、2个h5模型权重及2个md说明文档,压缩包约46.13MB,覆盖从原始信号到训练结果的完整链路。内容涉及数据清洗、标准化、特征工程与数据集划分,并对比CNN、RNN/LSTM、自编码器、Siamese网络等模型的适用场景,同时给出初始化、学习率调整、正则化与模型融合等训练策略,以及准确率、F1分数等评估优化思路。目前已有907人学习下载,适合希望快速跑通故障诊断流程、积累实验素材的读者参考。
1. 零基础也能上手的深度学习故障诊断:先搞懂它到底在干什么
你可能听过“深度学习”“人工智能”这些词,觉得它们离自己很远,像是实验室里才用得上的东西。但故障诊断这件事,其实你每天都在做——手机卡顿了,你判断是内存不够还是后台程序太多;家里的风扇声音不对,你猜是轴承缺油还是扇叶变形。区别只在于,人靠经验和耳朵,而深度学习靠数据。
所谓“基于深度学习的故障诊断”,说白了就是:把设备运行时的各种数据(振动、温度、电流等)喂给一个神经网络,让它自己学会分辨“正常”和“异常”,甚至能告诉你具体是哪种故障。它不依赖你手写一堆“如果温度大于80就报警”的规则,而是从大量样本里自动找规律。这套入门示例就是带你走一遍完整流程:数据预处理、模型搭建、模型训练。你不需要先成为数学高手,也不需要买昂贵设备,一台普通电脑加上公开数据集就能跑起来。适合谁?刚接触人工智能、想找一个能跑通的项目练手的学生或转行者,以及工作中需要做设备监测但不知从何下手的工程师。
2. 为什么值得学:从“事后维修”到“提前预警”的思维转变
2.1 传统方法卡在哪里,深度学习又补上了什么
传统故障诊断通常靠两种路子:一是老师傅听声音、摸温度,二是设定固定阈值报警。前者依赖人,经验难复制;后者太死板,设备转速一变、负载一波动,阈值就不准了。更麻烦的是,很多故障在早期非常微弱,等超过阈值时已经晚了。
深度学习的好处是它能从原始信号里自动提取特征。举个例子,轴承内圈有微小裂纹时,振动信号里会出现周期性的冲击成分,但幅值很小,人眼在波形图上根本看不出来。卷积神经网络却能通过多层卷积把这种微弱模式放大并识别出来。你不需要手动设计“冲击间隔”这个特征,网络自己会学。这就是为什么这几年基于深度学习的故障诊断在工业界越来越热——它把“特征工程”这个最耗人力的环节自动化了。
2.2 入门示例为什么选“数据预处理+模型搭建+训练”这条线
很多新手一上来就想搞懂反向传播的数学推导,结果三天就放弃了。这份示例的聪明之处在于,它把整个流程拆成了三段最核心的工程步骤,每一段你都能看到输入和输出,而不是陷在公式里。
- 数据预处理:把原始振动信号切成小段、归一化、划分训练集和测试集。这一步决定了模型能吃到什么“食物”。
- 模型搭建:用几层卷积和池化堆一个简单的网络,不追求花哨结构,先让数据能流过去。
- 模型训练:设置损失函数和优化器,跑几个轮次,观察准确率变化。
你跟着走一遍,就能理解一个深度学习项目从零到一的全貌。之后想换更复杂的模型、换别的数据集,都是在这个骨架上改。
2.3 第一个能跑通的例子:用模拟数据做二分类故障诊断
下面这个例子完全可以在你的电脑上运行,不需要下载任何外部数据集。我们用 numpy 生成两段模拟振动信号:正常信号是正弦波加少量噪声,故障信号是正弦波加周期性冲击。然后搭一个最简单的卷积网络来分类。
先安装依赖(如果还没装):
pip install numpy tensorflow scikit-learn接着是完整代码,每一步都有注释:
import numpy as np from tensorflow.keras import layers, models from sklearn.model_selection import train_test_split # 1. 生成模拟数据:正常信号和故障信号 def generate_normal(n_samples, length=1024): t = np.linspace(0, 1, length) signals = [] for _ in range(n_samples): # 正常:正弦波 + 高斯噪声 sig = np.sin(2 * np.pi * 50 * t) + 0.1 * np.random.randn(length) signals.append(sig) return np.array(signals) def generate_fault(n_samples, length=1024): t = np.linspace(0, 1, length) signals = [] for _ in range(n_samples): # 故障:正弦波 + 周期性冲击 + 噪声 sig = np.sin(2 * np.pi * 50 * t) for pos in range(0, length, 100): sig[pos:pos+10] += 2.0 # 冲击 sig += 0.1 * np.random.randn(length) signals.append(sig) return np.array(signals) # 生成 500 个正常样本和 500 个故障样本 normal_data = generate_normal(500) fault_data = generate_fault(500) # 2. 数据预处理:合并、打标签、归一化、划分 X = np.vstack([normal_data, fault_data]) y = np.hstack([np.zeros(500), np.ones(500)]) # 0 正常,1 故障 # 归一化到均值为0、标准差为1 X = (X - X.mean(axis=1, keepdims=True)) / X.std(axis=1, keepdims=True) # 卷积层需要输入形状为 (样本数, 长度, 通道数) X = X[..., np.newaxis] # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 3. 搭建一个简单的 1D 卷积神经网络 model = models.Sequential([ layers.Conv1D(16, kernel_size=5, activation='relu', input_shape=(1024, 1)), layers.MaxPooling1D(pool_size=2), layers.Conv1D(32, kernel_size=5, activation='relu'), layers.MaxPooling1D(pool_size=2), layers.Flatten(), layers.Dense(32, activation='relu'), layers.Dense(1, activation='sigmoid') # 二分类输出 ]) # 4. 编译和训练 model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy']) history = model.fit(X_train, y_train, epochs=10, batch_size=32, validation_split=0.2) # 5. 在测试集上评估 test_loss, test_acc = model.evaluate(X_test, y_test) print(f'测试集准确率: {test_acc:.4f}')跑完这段代码,你会看到准确率通常在 0.95 以上。这说明网络确实学会了区分“平滑正弦波”和“带冲击的正弦波”。虽然数据是模拟的,但流程和真实项目完全一致。
参数说明:Conv1D(16, kernel_size=5)表示用 16 个长度为 5 的卷积核去扫描信号,每个核会学习一种局部波形模式。MaxPooling1D(pool_size=2)把长度减半,减少计算量并保留最强特征。Dense(1, activation='sigmoid')输出 0 到 1 之间的概率,大于 0.5 判为故障。
提示:如果你运行时报错提示形状不匹配,检查一下
X = X[..., np.newaxis]这行有没有漏掉。卷积层要求输入至少是三维的。
3. 数据预处理:把原始信号变成网络能吃的“营养餐”
3.1 为什么预处理比模型结构还重要
我刚入门时也以为模型越深越好,后来踩坑才发现:如果数据没处理好,再复杂的网络也学不到东西。真实设备采集的振动信号往往包含大量噪声、趋势项和量纲差异。比如一个加速度传感器输出范围是 ±50g,另一个是 ±10g,直接混在一起训练,网络会偏向数值大的那个。
预处理的核心目标有三个:让信号长度一致、让数值范围可比、让训练集和测试集分布一致。这份示例里用到的归一化是最基础的一步,但已经能解决大部分量纲问题。
3.2 三个必做步骤:切分、归一化、划分
第一步,切分。原始信号可能连续采集了几小时,你需要用滑动窗口把它切成固定长度的小段。比如每段 1024 个点,步长 512。这样一条长信号就能变成几百个样本。窗口长度怎么选?一般要覆盖至少 3 到 5 个故障特征周期。如果你不知道周期,先选 1024 或 2048 试试。
第二步,归一化。最常用的是 Z-score 标准化,也就是减均值除标准差。代码里X = (X - X.mean(axis=1, keepdims=True)) / X.std(axis=1, keepdims=True)就是干这个的。注意axis=1表示对每个样本自己归一化,而不是对整个数据集。这样能保留样本之间的相对差异。
第三步,划分。用train_test_split把数据分成训练集和测试集,比例通常是 8:2 或 7:3。如果数据有时间顺序,不能随机打乱,要按时间切分,否则测试集里混入了未来信息,准确率会虚高。
3.3 动手改一改:把窗口长度从 1024 换成 512 会怎样
你可以直接修改上面代码里的length=1024为length=512,同时把模型输入形状改成(512, 1)。重新跑一遍,观察准确率变化。通常窗口太短会丢失低频特征,准确率下降;窗口太长则样本数变少,容易过拟合。这个实验能帮你建立“参数影响直觉”。
# 修改生成函数中的 length 参数 normal_data = generate_normal(500, length=512) fault_data = generate_fault(500, length=512) # 同时修改模型第一层 layers.Conv1D(16, kernel_size=5, activation='relu', input_shape=(512, 1))注意:每次改完参数要重新生成数据,否则形状对不上。
4. 模型搭建与训练:从“黑匣子”到能看懂每一层在做什么
4.1 卷积层到底在信号上“卷”什么
很多人第一次看到“卷积”觉得玄学。你可以这样理解:卷积核就是一个滑动窗口里的权重向量。比如长度 5 的核,它同时看 5 个连续的数据点,把它们加权求和。训练过程中,网络会自动调整这些权重,让某些核专门响应“冲击”,某些核专门响应“高频振荡”。
在故障诊断里,第一层卷积通常学到的是边缘和冲击,第二层组合成更复杂的模式,比如“每隔 100 个点出现一次冲击”。全连接层则把这些模式汇总成分类决策。你不需要手动设计这些特征,但理解每一层的作用能帮你排查问题——比如准确率不涨时,可能是卷积核太小,感受野不够。
4.2 训练过程要看什么:损失和准确率
model.fit返回的history对象里保存了每个轮次的训练损失、训练准确率、验证损失、验证准确率。你可以在训练结束后打印出来:
import matplotlib.pyplot as plt plt.plot(history.history['accuracy'], label='训练准确率') plt.plot(history.history['val_accuracy'], label='验证准确率') plt.xlabel('轮次') plt.ylabel('准确率') plt.legend() plt.show()如果训练准确率一直上升,但验证准确率停滞甚至下降,说明过拟合了。解决办法有:增加数据量、减少模型参数、加 Dropout 层。如果两者都低,说明欠拟合,可以增加层数或训练轮次。
4.3 换一个故障类型:从二分类到多分类
真实场景往往要区分多种故障。你只需要改两处:把标签从 0/1 改成 0/1/2,然后把最后一层改成Dense(3, activation='softmax'),损失函数改成categorical_crossentropy。下面是一个三分类的修改示例:
# 假设生成三种数据:正常、故障A、故障B # y 改为 one-hot 编码 from tensorflow.keras.utils import to_categorical y = np.hstack([np.zeros(500), np.ones(500), np.ones(500)*2]) y = to_categorical(y, num_classes=3) # 模型最后一层 layers.Dense(3, activation='softmax') # 编译 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])这样你就能把入门示例扩展到更接近实际的项目。
5. 避坑指南:新手最容易翻车的五个地方
5.1 现象:准确率一直停在 50% 左右
原因:标签和特征没对齐,或者归一化时把整个数据集一起算了,导致数据泄露。 解决:检查X和y的顺序是否一致;归一化要按样本或按训练集统计量做,不能先用全体数据算均值和方差。
5.2 现象:训练时损失变成 NaN
原因:学习率太大,或者数据里有极端异常值没处理。 解决:把优化器换成Adam(learning_rate=0.0001),并检查数据是否包含 inf 或 nan。可以用np.any(np.isnan(X))排查。
5.3 现象:测试集准确率远高于验证集
原因:测试集和验证集划分时随机种子不同,或者测试集太小。 解决:固定random_state,并确保测试集至少有几百个样本。如果数据本身很少,用交叉验证代替单次划分。
5.4 现象:模型在模拟数据上很好,换真实数据就崩
原因:模拟数据和真实数据的分布差异太大,比如噪声水平、采样率不同。 解决:先对真实数据做同样的预处理,并可视化几个样本对比。如果差异明显,考虑用迁移学习或重新训练。
5.5 现象:训练速度特别慢,风扇狂转
原因:窗口长度太大或批量大小太小,导致计算量爆炸。 解决:把窗口长度从 4096 降到 1024,批量大小从 16 提到 64。如果用的是 CPU,可以换成 Google Colab 的免费 GPU。
6. 下一步学什么:从跑通示例到解决真实问题
你已经跑通了第一个例子,接下来最该做的是换一个真实数据集。比如凯斯西储大学轴承数据集(很多入门教程都用它),或者自己用手机加速度计采集几段晃动数据。不要急着换更深的网络,先把数据预处理流程走扎实。
我建议的学习路径是这样的:
| 阶段 | 目标 | 具体动作 |
|---|---|---|
| 第一周 | 巩固流程 | 把示例代码改成读取 CSV 文件,用真实振动数据训练 |
| 第二周 | 理解评估 | 画混淆矩阵,计算精确率和召回率,而不只看准确率 |
| 第三周 | 尝试改进 | 加 Dropout 层、调整卷积核大小、换用 LSTM 处理时序 |
| 第四周 | 部署思维 | 把训练好的模型保存为 .h5 文件,写一个预测单条数据的脚本 |
保存和加载模型的代码很简单:
# 保存 model.save('fault_diagnosis_model.h5') # 加载 from tensorflow.keras.models import load_model loaded_model = load_model('fault_diagnosis_model.h5') # 预测一条新数据 pred = loaded_model.predict(X_test[0:1]) print('故障概率:', pred[0][0])我第一次做真实数据时,忘了把传感器量纲统一,结果模型把“振动大”直接当成故障,换一个设备就完全失效。从那以后我每次拿到新数据,都强制先画一遍原始波形和频谱图,确认没有量纲和趋势项问题再往下走。希望这份入门示例能帮你少走几个弯路,顺利迈出第一步。
本文还有配套的精品资源,点击获取