基于深度学习的振动信号故障诊断:1D-CNN全流程实现方案
简介这是一份面向深度学习初学者的故障诊断入门示例资源覆盖数据预处理、模型搭建、模型训练三个核心阶段适合希望快速掌握神经网络在设备故障识别中应用的工程师或研究人员。压缩包共57个文件包含40个mat格式的振动/信号数据、3个Python训练脚本、2个h5格式的已训练模型、10张可视化结果图以及2个Markdown说明文档整体大小46.13MB目录结构清晰便于按步骤对照学习。已有908人学习。资源以卷积神经网络CNN为例代码中完整展示了数据清洗、Z-score标准化、训练集/验证集划分、模型层数设计与Adam优化器调参等环节说明文档还对LSTM、自编码器等备选模型做了适用场景对比帮助读者理解不同架构在故障诊断中的差异。读者既可基于自带数据一键运行也可替换为自己的传感器数据进行迁移实验快速上手并延伸应用。1. 基于深度学习的故障诊断方案一套能跑通数据到诊断的完整流程设备坏了才去修永远是成本最高的选择。真正的工业现场老师傅靠耳朵听轴承异响、靠手感摸机身振动这套经验很难复制而且等听出问题的时候往往已经造成了不小的停机损失。深度学习在这类场景里能做的事是把“振动物理信号→故障特征→类别判断”这条链路自动化用加速度传感器采振动数据预处理后交给卷积网络自动提取特征直接输出“正常、内圈故障、外圈故障、滚动体故障”这样的判别结果。这篇文章就是一套可以直接照着搭的入门完整方案从数据预处理到模型搭建、训练调参、效果验收都覆盖到适合正要交深度学习课程设计、或者刚接触故障诊断方向的学生直接参考。2. 需求分析与技术选型为什么振动信号配一维卷积网络是入门首选方案2.1 故障诊断任务本质一个带噪声的时序分类问题把故障诊断抽象成机器学习问题它本质上是“给定一段振动信号判断设备当前处于哪种健康状态”。这里有几个关键难点决定了技术选型方向。首先是数据形态工业传感器采集的是按时间排列的连续波形本质是时序数据而不是图像那样的二维结构其次是样本量工业场景很难拿到大量故障样本一个正常工况的数据可能是故障工况的几十倍类别极不平衡再就是噪声干扰现场信号里混着工频干扰、随机冲击和环境噪声模型必须有足够强的抗干扰能力。这三条约束放在一起就解释了一个很反直觉的选型结论入门项目不选循环神经网络RNN而选一维卷积神经网络1D-CNN。原因很直接——RNN按时间步逐个处理长序列训练慢且容易梯度消失而一维卷积可以直接在整段序列上滑动提取局部模式天然适合捕捉振动信号里的周期性冲击特征。轴承故障产生的冲击在时域波形里呈现为周期性脉冲频域上又有对应的特征频率卷积核在序列上扫描正好能抓住这类局部模式。2.2 技术栈与版本选型把环境成本降到最低这类入门项目最怕的不是算法难而是环境装到一半装崩了。我的建议是直接用目前资料最全、社区踩坑最少的一套组合Python 3.8 搭配 TensorFlow 2.10 或 PyTorch 1.13主要数据处理库用 NumPy 和 SciPy画图用 Matplotlib。两个框架选哪个都行考虑到故障诊断入门案例在网上流传的代码大部分是基于 TensorFlow 写的跟随主流能少踩很多版本兼容性的坑。硬件方面普通笔记本的 CPU 就能跑通整套流程。原因是振动信号采样率一般在 12kHz 到 25kHz 之间单样本截取 1024 到 2048 个点就足够包含多个故障冲击周期单条样本数据量很小。真正吃显存的是图像类任务但一维振动信号的单样本体量远小于图像CPU 训练一个简单卷积网络通常在十几分钟到一小时内能完成一轮完整实验这对课设和毕设场景来说是完全可以接受的。另外要注意一点故障诊断里千万不要直接拿原始长序列整段丢给网络训练而是要做滑窗截断这个细节直接影响模型能不能收敛。3. 总体架构设计从振动信号到诊断结论的四层处理链路3.1 系统整体框架与数据流向一套完整的基于深度学习的故障诊断方案不管用什么框架实现处理链路都逃不开四个模块信号采集与预处理、数据集构造、模型搭建与训练、诊断结果输出与评估。这个分层方式和图像分类的流程完全不同——图像任务拿到的是现成的像素矩阵而故障诊断拿到的是连续的电压时间序列中间隔着采样、截断、去均值、归一化这些物理信号处理步骤任何一个环节处理不当后面的模型效果都会大打折扣。信号采集层负责把传感器输出的模拟电压信号转成数字序列采样率一旦定下来就不建议随意改动因为后续所有特征频率计算都依赖这个参数预处理层执行去除直流分量、幅值归一化、滑窗截断等操作把原始波形变成模型能吃的样本集模型层基于 TensorFlow 的 Sequential API 堆叠 Conv1D 层、池化层和全连接层最后的评估层计算准确率、召回率和混淆矩阵判断模型是真正学到了故障特征还是仅仅记住了训练集。3.2 卷积网络的层次设计与每层作用针对振动信号的 1D-CNN 结构不需要太复杂以分类 4 种状态为例一个典型的网络配置是输入层接收 1024 到 2048 个点的单通道序列第一层用 32 个大小为 3 的卷积核提取短时冲击特征第二层用 64 个卷积核进一步组合成中层模式每层卷积后跟最大池化做降采样最后压平后接入两个全连接层末端接 Softmax 输出四个类别的概率。这个设计里最关键的两条经验是卷积核尺寸不要超过 7太大会把冲击特征抹平池化尽量用最大池化而不是平均池化因为最大池化对冲击峰值更敏感能保留“故障瞬间幅值突增”这个最具判别力的信息。提示故障诊断网络不是越深越好。工业样本量往往只有几千条堆到 10 层以上很容易过拟合。入门方案控制在 3 到 4 个卷积块即可重点放在数据预处理是否合理而不是网络层数。3.3 训练策略与关键超参数的确定训练阶段的几个超参数决定了这个方案能不能稳定收敛。损失函数用交叉熵这是多分类任务的标准选择优化器推荐 Adam初始学习率 0.001每训练若干轮后如果损失不再下降就把学习率乘以 0.5 做衰减批次大小取 32 到 64单批次太小会让梯度震荡明显太大会让模型陷入尖锐极小值导致泛化能力变差。训练轮数不是硬性规定的我的判断标准是观察验证集准确率——连续 5 轮准确率不再上升就提前停止这个方法比拍脑袋定一个固定轮数要可靠得多。这里要专门说明一下数据集划分的严谨性问题。很多入门代码直接用train_test_split随机划分样本这在故障诊断里是不严谨的。正确的做法是按“实验工况”划分某几次采集的全部样本作为训练集另外几次采集的样本全部作为测试集。原因是同一段连续采集的相邻样本之间高度相关随机划分会造成数据泄漏模型在测试集上的表现会被严重高估这个细节拿去答辩时提到会非常加分。4. 数据预处理与模型搭建的关键实现4.1 振动信号预处理去直流、滑窗与归一化预处理是整套流程里最“出效果”的环节。现场采集到的原始振动信号第一个问题是存在直流偏置——传感器在没有振动时输出也不是 0而是某个恒定电压。这种直流分量不除掉卷积网络学到的第一层特征就会被这个偏置主导故障引起的微小波动反而被掩盖。处理办法很直接对每条样本减去该段信号的均值即可。import numpy as np def preprocess_signal(raw_signal, sample_rate12000, window_size1024, stride512): # 去除直流分量减去整段均值消除传感器偏置影响 signal_detrended raw_signal - np.mean(raw_signal) # 幅值归一化把信号幅值缩放到 [-1, 1] 区间 max_abs np.max(np.abs(signal_detrended)) signal_normalized signal_detrended / max_abs # 滑窗截断将长信号切成固定长度的短样本 samples [] num_windows (len(signal_normalized) - window_size) // stride 1 for i in range(num_windows): start i * stride end start window_size samples.append(signal_normalized[start:end]) return np.array(samples)这段代码的逻辑和参数选择是有讲究的。窗口大小取 1024 意味着在 12kHz 采样率下每条样本覆盖约 85 毫秒的振动信号这个时长足够包含多次轴承故障冲击周期步长取 512 让相邻窗口有 50% 重叠相当于做了数据增广缓解故障样本不足的问题。归一化直接用最大值做缩放而不是标准化因为振动信号的分类依据是冲击形态和频率分布保留相对幅值关系比强行拉成标准正态分布更有意义。4.2 用 TensorFlow 搭建一维卷积诊断模型模型搭建的代码非常简洁。重点在于理解每一层为什么这样配置。第一层卷积的输入形状是 (1024, 1)代表 1024 个时间点、单通道振动幅值后面的卷积层不断增加卷积核数量对应从“局部冲击”到“组合模式”的特征抽象过程。输出层的神经元个数等于故障类别数使用 Softmax 激活将输出转换为概率分布。from tensorflow.keras import Sequential from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout def build_fault_cnn(input_length1024, num_classes4): model Sequential([ # 第一卷积块32个卷积核感知短时冲击特征 Conv1D(filters32, kernel_size3, activationrelu, input_shape(input_length, 1)), MaxPooling1D(pool_size2), # 第二卷积块64个卷积核组合中层时序模式 Conv1D(filters64, kernel_size3, activationrelu), MaxPooling1D(pool_size2), # 第三卷积块128个卷积核提取抽象故障特征 Conv1D(filters128, kernel_size3, activationrelu), MaxPooling1D(pool_size2), # 展开接入分类头 Flatten(), Dropout(0.5), Dense(128, activationrelu), Dense(num_classes, activationsoftmax) ]) model.compile(optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy]) return model这个模型结构是经过实践检验的几个设计细节值得仔细琢磨。卷积核全部用 3在 1024 点的一维信号上叠加 3 层卷积后感受野大约是 21 个点既能捕捉单次冲击的波形形态又不会把多个冲击周期混叠在一起。Dropout 加在全连接层之前概率取 0.5目的是防止全连接层参数过多导致过拟合——卷积层的参数是共享的参数量不大真正容易过拟合的是 Flatten 之后的全连接部分。训练时如果发现验证集准确率远低于训练集优先检查 Dropout 的配置和全连接层的神经元数量。4.3 训练流程与可视化诊断曲线训练部分的代码重点是加入模型检查点和提前停止两个回调。这个做法解决的问题是训练过程中模型表现最好的轮次不一定在最后一轮如果没有检查点回调很可能丢失最优模型权重。from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint # 提前停止验证损失连续 5 轮不下降就终止训练防止浪费时间 early_stop EarlyStopping(monitorval_loss, patience5, restore_best_weightsTrue) # 模型检查点每轮结束后保存当前最优权重防止训练中断丢进度 check_point ModelCheckpoint(filepathbest_fault_model.h5, monitorval_accuracy, modemax, save_best_onlyTrue) history model.fit( X_train, y_train, batch_size64, epochs50, validation_data(X_val, y_val), callbacks[early_stop, check_point], verbose1 )这段代码里 BatchSize 取 64 而不是 32原因是振动样本较短且模型不大64 的批次能更稳定地估计梯度方向缩短训练时间。Epochs 虽然写了 50但实际上 EarlyStopping 大概率会在 20 轮左右截停这是正常的。训练完成后用matplotlib画出训练集和验证集的准确率曲线、损失曲线这个图在课程设计答辩里是必看的展示材料它直观说明模型收敛情况和过拟合程度。5. 避坑指南故障诊断环节最容易翻车的 5 个细节5.1 数据泄漏随机划分样本导致成绩虚高的“假准确率”我第一次做这个方案时犯了所有新手都会犯的错误直接用 sklearn 的train_test_split打乱全部样本后随机划分模型准确率跑到了 99%当时还觉得效果惊人。后来在复现实验时发现同一个连续采集段里相邻样本高度相似随机划分等于让模型在“开卷考试”——测试集里每一道题都在训练集里见过近似的。正确做法是按采集文件或工况维度划分数据集保证同一次采样的数据只出现在训练集或测试集中一个集合里。这个坑在答辩时被导师一眼看穿从此我每做一个诊断项目第一件事就是检查划分代码是按样本还是按实验。5.2 故障样本类别不平衡准确率虚高的另一大来源工业现场正常样本可能占了 90% 以上如果直接拿原始比例去训练模型会学成“永远猜正常”——整体准确率照样很高但故障样本一个都识别不出来。解决办法不是简单删掉正常样本而是对少数类做滑窗叠加采样或者用类别权重让模型加大对少数类错误分类的惩罚。判断模型是不是被类别不平衡带偏了不能只看准确率一定要看混淆矩阵里每一类各自的召回率特别是故障类别之间的混淆情况。5.3 一维卷积核尺寸与池化方式的玄学选择卷积核尺寸从 3 改成 7 或者 9故障诊断的效果会有肉眼可见的差别。现象是卷积核过大时测试集准确率明显下降。原因是工业振动信号的故障特征频率通常在几百赫兹到几千赫兹之间过大的卷积核相当于做了一次低通滤波把高频冲击细节直接抹掉了。池化层同理工厂实地测试时我用平均池化替换最大池化准确率掉了接近 3 个百分点因为平均池化会稀释掉短时冲击峰值这个最关键的判别信息。这类参数没有统一最优解换一个数据集就要重调建议把卷积核尺寸和池化方式做成一行配置项而不是写死在模型里方便后续对比实验。5.4 模型表现好但实际部署不生效对齐训练与推理的预处理训练时对信号做了去均值、归一化和滑窗截断推理时如果只滑窗没归一化输入分布差异会让模型输出完全不可信的结论。这个问题在纯跑通流程的课设里不会被发现但在真实测数据上验证时立刻现原形。解决的思路是把预处理逻辑封装成一个独立函数训练和推理共用同一个入口不要训练写一遍、推理再复制一遍。我在交付方案时习惯把预处理函数单独放到一个模块文件里并在函数注释里写清参数含义避免自己三个月后回来看不记得当时为什么取 1024 这个窗口。5.5 训练曲线震荡不收敛先查学习率再查数据训练时 loss 曲线忽高忽低最常见的原因按概率排序是学习率过大、批次过小、数据顺序没有打乱。我当时的血泪经验是这些因素导致的“震荡”有一个叠加判断法——先把学习率从 0.001 降到 0.0003如果曲线仍然剧烈震荡再检查是否在训练前对数据集做了 shuffle 操作如果还没解决看是不是同一个故障类别连续排在一起导致梯度方向单一。这三步走完80% 的训练异常都能定位。还有一个容易忽略的点是标签编码sparse_categorical_crossentropy要求标签是整数编码如果误用了 one-hot 编码模型能训练但不报错只是准确率上不去而且报错信息非常隐蔽。6. 方案验收与答辩导演怎么向导师证明你的故障诊断方案真正有效6.1 用混淆矩阵和召回率而不是准确率验收课程设计答辩现场导师最常问的一个问题是“你这个模型准确率 98%它到底学会了什么”如果只展示一个准确率数字这个回答是立不住的。我建议准备一张三乘三或四乘四的混淆矩阵图把每一个真实类被预测成什么类别逐项列出来。验收时先看对角线上的数值是不是明显高于非对角线再看故障类之间的混淆是否集中在物理上容易混淆的类别——比如滚动体故障和保持架故障特征频率接近模型偶尔分混是可以接受的但如果正常样本被大量误判为故障这套方案在实际现场是不可用的。6.2 准备一张模型输入输出对照图来应对“黑匣子”质疑答辩最怕被问“神经网络就是个黑匣子你怎么解释它的判断依据”这个问题有现成的应对素材——准备一张原始振动波形、预处理后波形和故障特征频率标注三合一的对比图。展示的正常信号波形应当无明显周期性冲击而外圈故障信号的波形应当有规律间隔的冲击脉冲时间间隔恰好对应故障特征频率的倒数。这张图配合说明“模型在时域上捕捉到的就是这种周期性冲击模式的差异”就能从整体上证明模型学到的是物理有意义的特征而不是数据噪声。更进一步的做法是用 Grad-CAM 类方法输出卷积层的注意力位置但入门方案里这三张对比图已经足够应付大多数提问。6.3 设计一组对照实验证明选型的合理性验收时有一个加分项是准备“备选方案对比表”——拿同一份数据分别用 1D-CNN 和 2D-CNN把信号转成频谱图输入跑一遍对比准确率和训练时间。这个实验的预期结果是一维卷积在时域原始信号上表现略优于二维卷积在频谱图上的表现而且训练时间少一半。这个结果的解释是时域原始信号保留了完整的相位信息和幅值动态范围而转频谱图会损失时序信息同时二维卷积要求的参数量更大小样本条件下更容易过拟合。准备这张表的意义在于它从实验层面回应了“为什么这样设计”的问题比空谈理论有说服力得多。从这个角度说故障诊断虽然套的是深度学习的壳但内核还是信号处理和对比实验的工程思想——从那以后我做这类项目都强制自己把“划分方式是否泄漏、是否做过对照实验、推理能不能复用预处理”这三个问题写在项目开头先把验收标准想清楚再动工希望这个习惯也能帮到你。本文还有配套的精品资源点击获取