十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CNN-LSTM轴承故障诊断:从振动信号到端到端深度学习实践

CNN-LSTM轴承故障诊断:从振动信号到端到端深度学习实践 简介本资源是面向人工智能课程设计与机械故障诊断初学者的完整实践项目聚焦滚动轴承9类故障外圈/内圈/滚珠 × 3种直径在3HP负载、1730rpm工况下的振动信号智能识别问题。项目采用CNN-LSTM混合网络建模融合时频特征提取与序列建模能力提供从数据预处理、模型训练、测试评估到结果可视化的全流程Python实现。压缩包共25个文件含4个核心Python脚本含详细中文注释、2个训练好的.pth模型CNN及CNN-LSTM、9个CSV振动数据样本、5张关键流程图如方法框架、重叠采样示意图、1份README.md项目说明及1个Jupyter演示文档整体53.21MB结构清晰、模块解耦、即开即用。已有118人学习下载读者可直接复现故障诊断流程深入理解振动信号处理、深度学习模型搭建与工业场景落地的关键细节。1. 项目整体设计与思路拆解1.1 为什么是CNNLSTM而不是只用其中一种做轴承故障诊断的同行应该都有体会振动信号这玩意儿看起来就是一串数字但里面藏的信息量非常大。早期大家用FFT做频谱分析、用小波包提取能量特征这些方法不是不能用但最大的问题在于特征提取严重依赖人工经验——不同转速、不同负载下有效特征可能完全不同换个工况就得重新调试特征参数非常折腾。深度学习火起来之后很多人直接上CNN或者LSTM做端到端的故障诊断效果确实比传统方法好不少。但我自己实测下来单一模型都有明显短板。CNN擅长提取局部特征卷积核扫过信号片段时能捕捉到局部波形形态但轴承故障信号往往表现出明显的时序依赖性——比如外圈故障时故障冲击会随着转频周期性出现单纯看一个局部窗口很难把握这种长周期的规律。LSTM恰恰擅长处理时序依赖门控机制能记住长时间跨度的信息但对局部细节的敏感度不如CNN。两个模型互补性非常强组合起来做特征提取时序建模的串联结构效果往往优于任意单一模型。这也是这个项目选择CNN-LSTM架构的核心原因。先说一下整体思路CNN部分负责从原始振动信号中提取空间特征把一维信号通过卷积和池化逐步压缩成高维特征序列然后把这些特征序列按照时间顺序输入LSTM让LSTM捕捉特征之间的时序依赖关系最后接全连接层和Softmax完成故障类别的分类。整个模型是端到端训练的不需要额外的人工特征工程。1.2 数据集与预处理的思路项目使用的是标准的凯斯西储大学CWRU轴承数据集这个数据集在故障诊断领域属于基准数据集国内外论文里用得非常普遍。数据采集自电机驱动端和风扇端的轴承包含正常状态和三种故障类型内圈故障、外圈故障、滚动体故障每种故障又分了不同损伤直径0.007英寸、0.014英寸、0.021英寸采样频率有12kHz和48kHz两档。这里有个关键点要先想清楚原始数据是连续的长时域信号直接整段扔给模型训练肯定不行。序列长度太长会导致计算量爆炸而且模型也难以捕捉局部特征。我采用的是滑动窗口切分的方式每个样本截取固定长度的信号段作为输入样本之间有一定重叠。经过切分后每组信号能生成大量样本数据量完全足够训练一个中等规模的深度学习模型。在预处理环节我做了几件比较关键的事归一化把每段信号归一化到[-1, 1]区间消除不同样本之间幅值差异对训练的影响。这里用的是最大最小值归一化因为振动信号的幅值范围是明确的而且归一化后还能保持波形的相对形状。标签编码故障类别做One-Hot编码Softmax输出层和交叉熵损失函数天然匹配。训练集/测试集切分按照数据文件来源切分而不是随机打乱后切分。这么做是因为同一段连续信号切出来的相邻样本高度相似如果随机打乱切分训练集和测试集会存在数据泄漏测试准确率虚高。我实际测试过随机切分时测试集准确率能到99%以上但用文件级切分后准确率会降了几个点这才是真实的泛化水平。1.3 整体技术路线与工具选型整个项目的技术栈是Python配合TensorFlow/Keras框架项目目录里包含了从数据预处理、模型定义、训练脚本到推理预测的完整代码并且每一段代码都有详细注释。模型训练完成后把权重保存成HDF5格式的模型文件后续做推理时直接加载模型文件就行不需要重新训练。选TensorFlow/Keras而不是PyTorch主要原因是这个项目定位是快速复现和实践验证Keras的函数式API写CNN-LSTM串联模型非常直观几行代码就能把模型结构定义清楚。而且Keras训练过程中的回调函数类似早停、模型检查点、学习率衰减用起来非常方便适合做工程实验。如果你更习惯用PyTorch其实核心思路完全一致后续我会在讲解中用代码把网络结构讲清楚方便你迁移到自己熟悉的框架里。2.1 项目目录结构一览拿到项目压缩包后先别急着跑代码熟悉一下目录结构。完整结构如下cnn-lstm-bearing-fault-diagnosis/ ├── data/ │ ├── raw/ # 原始CWRU数据从官网下载后放入 │ ├── processed/ # 预处理后的.npy文件 │ └── split/ # 训练集和测试集的索引 ├── models/ │ ├── cnn_lstm.h5 # 训练好的完整模型 │ ├── cnn_lstm_weights.h5 # 仅权重文件 │ └── training_history.npy # 训练过程的损失和准确率记录 ├── src/ │ ├── config.py # 全局配置参数 │ ├── data_preprocess.py # 数据加载与预处理 │ ├── model.py # CNN-LSTM模型定义 │ ├── train.py # 训练入口 │ ├── evaluate.py # 评估脚本 │ └── predict.py # 推理预测脚本 ├── docs/ │ └── 项目说明.md # 项目说明文档 ├── requirements.txt └── README.md这个目录设计是我个人的习惯数据、模型、代码、文档各归其位互不干扰。config.py集中管理所有超参数这样调参时只需要改一个文件不用到处找魔法数字。train.py和evaluate.py分开训练和评估解耦。2.2 数据加载与预处理模块预处理的核心代码逻辑如下import numpy as np import os from sklearn.preprocessing import StandardScaler def load_raw_data(file_path, sample_rate12000): 加载CWRU原始数据。.mat文件里通常包含多个字段 需要根据实际情况选择对应的信号通道。 # 这里用scipy加载mat文件 from scipy.io import loadmat mat loadmat(file_path) # 根据文件内容选择信号字段 key [k for k in mat.keys() if DE in k][0] signal mat[key].flatten() return signal def sliding_window(signal, window_size1024, step_size512): 滑动窗口切分window_size是每个样本的长度 step_size是滑动步长。重叠率 1 - step_size / window_size。 samples [] signal_len len(signal) for start in range(0, signal_len - window_size, step_size): end start window_size samples.append(signal[start:end]) return np.array(samples)这里有个值得注意的细节window_size的选择直接影响模型性能。窗口太短一个样本里包含的故障冲击周期数太少模型学不到完整的故障规律窗口太长特征维度暴增计算量变大且可能引入无关噪声。我反复实验后12kHz采样率下选择1024个采样点约85ms的振动信号作为窗口长度分类效果和计算效率比较均衡。这个参数是纯工程经验建议你拿到数据后先自己可视化几段不同类型的信号看看故障冲击的周期大概是多长时间再定窗口长度。预处理之后把所有样本拼接成大的numpy数组保存为.npy文件。这里要注意不要用np.save保存list对象多个文件的数据先np.concatenate合并成统一维度的数组再保存否则加载时会出各种奇怪的错误。2.3 CNN特征提取模块模型定义部分是这个项目最核心的代码模块完整结构如下from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Conv1D, MaxPooling1D, LSTM, Dense, Dropout, Flatten, Reshape def build_cnn_lstm_model(input_shape(1024, 1), num_classes4): 构建CNN-LSTM联合模型。 输入是一维振动信号序列输出是故障类别概率分布。 inputs Input(shapeinput_shape) # 第一个卷积模块 x Conv1D(filters64, kernel_size3, activationrelu, paddingsame)(inputs) x MaxPooling1D(pool_size2)(x) # 第二个卷积模块 x Conv1D(filters128, kernel_size3, activationrelu, paddingsame)(x) x MaxPooling1D(pool_size2)(x) # 第三个卷积模块 x Conv1D(filters64, kernel_size3, activationrelu, paddingsame)(x) x MaxPooling1D(pool_size2)(x) # 进入LSTM前保持特征序列的时间维度 # 输入序列长度经过三次池化后变为 1024 / 2^3 128 # 特征维度是64因此LSTM的输入维度是(128, 64) x LSTM(units64, return_sequencesFalse)(x) # 全连接分类层 x Dropout(0.5)(x) x Dense(32, activationrelu)(x) outputs Dense(num_classes, activationsoftmax)(x) model Model(inputsinputs, outputsoutputs) return model很多人在写CNN和LSTM拼接时最容易犯的一个错误是忘记考虑维度匹配。CNN经过池化后特征图的时间长度已经缩水了比如1024个点经过三次步长为2的最大池化后变成了128个点这128个点就是LSTM的timesteps维度而最后一层卷积输出的通道数这里是64就对应LSTM每个时间步的特征维度。所以在设计网络时要提前算好池化带来的时间维度变化否则LSTM层会报维度错误。我在项目里做过一个小实验把LSTM放在CNN之前也就是先用LSTM处理原始信号再进CNN效果明显不如当前方案。原因也很简单原始振动信号是高频时序数据直接在原始信号上做时序建模LSTM很难从中提取稳定的规律。先让CNN做局部特征的抽象和降维LSTM处理的就是更高层、更紧凑的特征序列学习负担小得多。这也是CNN特征提取LSTM时序建模作为主体架构的工程直觉。2.4 训练与评估模块训练脚本中我使用了一些值得注意的配置# 训练核心配置 model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.001), losscategorical_crossentropy, metrics[accuracy] ) # 回调函数 callbacks [ tf.keras.callbacks.EarlyStopping( monitorval_loss, patience15, restore_best_weightsTrue ), tf.keras.callbacks.ModelCheckpoint( filepathmodels/cnn_lstm.h5, monitorval_accuracy, save_best_onlyTrue, verbose1 ), tf.keras.callbacks.ReduceLROnPlateau( monitorval_loss, factor0.5, patience5, min_lr1e-6 ) ] # 训练 history model.fit( X_train, y_train, validation_data(X_val, y_val), batch_size64, epochs100, callbackscallbacks, verbose1 )这里面的经验点比较细我展开说说早停和模型检查点配合使用EarlyStopping的patience设置的是15个epoch意味着如果验证集loss连续15个epoch没有下降就停止训练。ModelCheckpoint保存的是验证集准确率最高的模型而不是最后一个epoch的模型。这两个配合能避免两个问题一是训练时间过长浪费资源二是最后一个epoch的模型因为过拟合而效果变差。很多初学者只保存最后一个epoch的模型结果发现训练集准确率高达99%测试集却表现平平就是这个原因。学习率衰减策略ReduceLROnPlateau会在验证集loss连续5个epoch没有改善时把学习率减半。训练初期用较大的学习率快速收敛后期用更小的学习率精细调节这是深度学习训练的经典策略。如果全程用固定学习率要么初期的收敛速度太慢要么后期在最优点附近震荡跳来跳去降不下去。训练过程中需要关注的关键指标不要只盯着训练集准确率要时刻关注验证集准确率和验证集loss。如果训练集准确率持续上升但验证集准确率停滞甚至下降说明开始过拟合了这时应该增加Dropout比例、降低模型复杂度或增加数据量。我在训练时遇到的一个典型情况是前10个epoch内验证集准确率从85%快速跳到97%之后增长非常缓慢这时不要着急加入学习率衰减后继续训练最终能稳定在99%以上。3. 训练好的模型如何正确使用3.1 模型文件说明与加载方式项目压缩包里的models/cnn_lstm.h5是已经训练完成的完整模型文件包含了网络结构和权重参数。这个文件可以直接用Keras的load_model加载不需要重新定义模型结构。如果用load_weights加载则必须先实例化模型对象且模型结构必须与训练时完全一致包括输入维度、层数、每层的单元数。对初学者来说直接用load_model更省心。from tensorflow.keras.models import load_model model load_model(models/cnn_lstm.h5) model.summary()执行model.summary()后你会看到模型总参数量。这个模型的参数量在几十万级别的规模属于轻量级模型在普通CPU上也能够快速完成推理。如果你将来想把模型部署到嵌入式设备比如用树莓派做一个在线监测系统这个体量是比较合适的。3.2 单样本推理与结果解读模型训练好后核心场景就是对未知振动信号做故障诊断。模拟一个推理流程import numpy as np from tensorflow.keras.models import load_model # 加载模型 model load_model(models/cnn_lstm.h5) # 假设有一段长度为1024的振动信号 # 实际使用时可能是从传感器实时采集的一段数据 signal_segment np.random.randn(1024).astype(np.float32) # 形状调整模型输入要求是(batch_size, 1024, 1) X_input signal_segment.reshape(1, 1024, 1) # 推理 pred_probs model.predict(X_input, verbose0) pred_class np.argmax(pred_probs, axis1)[0] # 类别映射 class_names [正常, 内圈故障, 外圈故障, 滚动体故障] print(f预测类别: {class_names[pred_class]}) print(f置信度分布: {dict(zip(class_names, pred_probs[0]))})注意reshape这一步——模型的输入形状是(batch_size, time_steps, channels)即使只预测一个样本也要构造出batch维度。很多初学者在推理阶段报维度错误问题就出在这里他们直接传入(1024, 1)或者(1, 1024)的形状Keras无法自动推演出预期的维度结构。推理结果不仅给出类别还给出各类别的置信度分布。实际工程中我不建议只看argmax的结果还应关注置信度的分布情况。如果模型对某个样本的预测置信度非常接近比如正常类0.4、内圈故障0.35说明模型对这段信号的特征判断比较模糊这时需要谨慎对待诊断结论。我在实际部署中会根据置信度设置一个阈值低于阈值的样本标记为无法判断触发重新采集或人工复核流程比强行给一个分类结果可靠得多。3.3 批量评估与混淆矩阵分析项目里的evaluate.py脚本做了完整的批量评估核心逻辑如下from sklearn.metrics import classification_report, confusion_matrix, accuracy_score import seaborn as sns import matplotlib.pyplot as plt y_true np.load(data/split/y_test.npy) y_pred np.argmax(model.predict(X_test), axis1) print(f测试集准确率: {accuracy_score(y_true, y_pred):.4f}) print(classification_report(y_true, y_pred, target_namesclass_names)) # 绘制混淆矩阵 cm confusion_matrix(y_true, y_pred) plt.figure(figsize(8, 6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsclass_names, yticklabelsclass_names) plt.xlabel(预测标签) plt.ylabel(真实标签) plt.show()混淆矩阵的价值在于能直观看出模型在哪些类别之间容易混淆。我在实验中发现这个模型最容易混淆的是内圈故障和滚动体故障因为这两种故障的振动特征在某些工况下确实高度相似。这个信息在做工程诊断时非常有用——如果系统连续多次诊断出这两个类别可以考虑引入额外的特征维度比如温度、转速信号来辅助判断。只看准确率数字发现不了这些细节。4. 训练过程与调参实战心得4.1 数据切分与样本均衡性的教训前面提到过训练集和测试集要按数据来源文件切分而不是随机切分。这里再补充一个关于样本均衡性的细节。CWRU数据集里正常工作状态下的样本数量往往远多于故障状态的样本数量。如果不做处理直接训练模型会天然偏向多数类整体准确率看似很高但少数类的召回率会非常差。我测试过正常类的F1值能到1.0但某些故障类只有0.85左右。解决这个问题有两种常见方案。一是对样本量少的类别做过采样复制样本或加噪声生成新样本二是使用类别权重class weight让模型更加关注少数类。我在项目中两种方法都试过使用类别权重的效果更稳定因为它不会引入重复样本导致的过拟合风险。from sklearn.utils.class_weight import compute_class_weight # 计算类别权重 class_weights compute_class_weight( class_weightbalanced, classesnp.unique(y_train_labels), yy_train_labels ) class_weight_dict dict(enumerate(class_weights)) # 训练时传入class_weight参数 model.fit(X_train, y_train, class_weightclass_weight_dict, ...)compute_class_weight设置为balanced时权重会自动按照总样本数 / (类别数 * 该类样本数)计算样本数少的类别权重大样本数多的类别权重小。这个方法在类别不平衡的工业场景里非常实用。4.2 模型参数选择的实验对比在这个项目里模型的几个重要超参数我做了系统的对比实验这里整理成一张表供大家参考参数名测试范围最终选择原因分析输入窗口长度512 / 1024 / 20481024512包含的故障周期太少准确率约低3%2048计算量翻倍但准确率提升不到0.5%卷积核大小3 / 5 / 73小卷积核堆叠可以获得更大的感受野同时参数量更少训练稳定性更好卷积层数2 / 3 / 432层特征提取能力不足4层出现过拟合迹象且训练时间明显增加LSTM隐层单元数32 / 64 / 1286432欠拟合128出现轻微过拟合64综合效果最优Dropout比例0.3 / 0.5 / 0.70.50.3基本不起作用0.7导致拟合不足0.5最平衡批大小32 / 64 / 1286432训练太慢128时梯度更新不稳定64最均衡这些参数的选择不是一蹴而就的我花了不少时间做正交实验。我的建议是不要一次性把所有参数都调一遍那样根本分不清是谁在起作用。正确的做法是固定其他参数只变动一个参数做对比实验每轮实验记录结果最后汇总比较。做实验时把每种配置的结果保存下来包括准确率、训练时间、参数量等方便回溯。4.3 训练过程中的可视化监控训练过程中通过matplotlib把训练曲线画出来能非常直观地判断模型状态。常见的训练曲线有四种形态对应四种不同的问题训练loss和验证loss同步下降后趋于稳定正常训练继续保持。训练loss持续下降但验证loss先降后升过拟合需要增大Dropout或减少epoch。训练loss和验证loss都降不下去欠拟合需要增大模型容量或调整学习率。训练loss震荡厉害学习率过大或数据本身噪声大需要降低学习率或增大batch size。如果项目重新训练我强烈建议把训练过程的可视化脚本保留下来。training_history.npy这个文件记录了训练过程中每个epoch的loss和accuracy用几行代码就能画出完整的训练曲线import matplotlib.pyplot as plt import numpy as np history np.load(models/training_history.npy, allow_pickleTrue).item() plt.figure(figsize(12, 4)) plt.subplot(1, 2, 1) plt.plot(history[loss], label训练损失) plt.plot(history[val_loss], label验证损失) plt.xlabel(Epoch) plt.ylabel(Loss) plt.legend() plt.title(损失曲线) plt.subplot(1, 2, 2) plt.plot(history[accuracy], label训练准确率) plt.plot(history[val_accuracy], label验证准确率) plt.xlabel(Epoch) plt.ylabel(Accuracy) plt.legend() plt.title(准确率曲线) plt.tight_layout() plt.show()4.4 代码注释的风格与作用这个项目里每一段核心代码都配有较详细的注释包括函数的输入输出、关键步骤的作用、参数选择的理由。我个人认为注释的意义不仅是让代码好读更是帮助重建当时为什么这么做的上下文。做过科研项目的人应该都有这种经验过两个月回头翻自己的代码如果没有注释经常想不起来当初为什么写这行逻辑。给注释的时候有几个原则不写废话不注释一句显而易见的x x 1重点注释为什么而不是是什么。比如一个卷积核尺寸选择3注释里应该写使用小卷积核减少参数量并增加非线性而不是这里设置卷积核大小为3。这类解释性注释对阅读者最有价值。5. 常见问题与坑位排查实录5.1 维度匹配报错这个项目代码里最容易出的问题是TensorFlow/Keras版本升级后某些层的默认行为发生了变化。比如在Keras 2.x中LSTM层默认返回最后一层输出return_sequencesFalse如果忘记设置会导致输出形状和期望的不一致。如果运行时报类似ValueError: Input 0 of layer lstm is incompatible with the layer的错误首先检查前一层的输出形状和LSTM的input_shape是否匹配。可以用model.summary()打印每一层的输出形状逐层核对。这类报错的根源在于CNN对输入序列做了池化长度按比例缩小。比如输入1024经过三次pool_size2的池化后变为128。如果不想手动计算可以在LSTM层前面加一个Flatten层再Reshape成指定的形状让Keras自动处理维度变换。不过我个人建议把每一步的维度变化想清楚再写代码靠模型结构推演的方式更清晰也更容易排查问题。5.2 内存不足与训练缓慢原始振动数据经过滑窗切分后样本量会非常大。CWRU数据集中一个数据文件切成1024长度、512步长的窗口能产生数千到上万条样本。如果一次性把所有样本全部加载到内存8GB内存的机器大概率会卡死。我在预处理环节采用了分批处理的方式先按文件逐个切分每个文件的结果直接追加到磁盘上的.npy文件中而不是在内存里拼接后再保存。训练时再用batch_size分批次读入这样内存占用就非常可控了。如果训练速度仍然偏慢优先检查是否用了GPU。model.fit执行时如果TensorFlow检测不到GPU会静默使用CPU训练速度差一个数量级。可以用下面这段代码确认import tensorflow as tf print(GPU 可用:, tf.config.list_physical_devices(GPU))如果没有GPU可以减小输入长度、减少卷积层的通道数、减小批大小来降低计算量。batch_size对训练速度影响也很明显从32调到64训练速度接近翻倍但batch太大容易导致收敛不稳定。5.3 高准确率但实际效果差的陷阱这是深度学习诊断项目最隐蔽的坑。我在初期复现时测试集准确率能做到99.5%以上但把训练好的模型拿到自己采集的新数据上实测时效果大幅下降。当时排查了很久最终发现是数据泄漏导致的假象——我在随机打乱样本时来自同一段连续信号的相邻样本被同时分到了训练集和测试集导致测试集的分布和训练集几乎完全一致模型本质上是在背答案。正确的做法是样本切分后按块切分也就是把所有来自同一个数据文件同一种工况的样本作为一个整体要么全进训练集要么全进测试集。这样模型在测试时面对的是真正未见过的工况。如果你也遇到了训练/测试准确率高但换数据就不行的情况十有八九是这个问题。这个点值得反复强调它是整个项目里最重要的经验之一。另外信号数据在进入模型前要确保归一化参数的一致性。训练的时候用的是训练集的min和max做归一化测试的时候也要用一模一样的min和max不能重新计算测试集的归一化参数。但很多人在预处理时容易忽略这点导致数据分布偏移推理结果打折扣。5.4 模型文件加载失败加载models/cnn_lstm.h5时报错的情况也比较常见。具体来说如果当前环境用的TensorFlow版本和训练时的版本差异较大load_model可能无法解析权重文件里的某些层配置报出Unknown layer或Unable to load weights之类的错误。建议使用requirements.txt中锁定的版本安装依赖或者用tensorflow2.10.0这个相对稳定的版本。2.10是TensorFlow最后一个原生支持GPU的版本2.11之后GPU支持需要额外配置做类似项目用这个版本问题最少。如果实在不想重装环境也可以绕过完整模型加载只加载权重文件cnn_lstm_weights.h5。但这种方式有几个风险一是必须手动把模型结构再搭一遍层顺序、参数设置要和训练时完全一致二是任何细微差异都会导致权重shape不匹配排查起来非常麻烦。所以在条件允许的情况下我宁可使用load_model加载完整模型省事且健壮。5.5 训练结果不可复现如果每次训练跑出来的结果波动很大首先在代码开头设置随机种子import random import numpy as np import tensorflow as tf random.seed(42) np.random.seed(42) tf.random.set_seed(42)设置随机种子后绝大多数情况下训练结果可以复现。但要注意GPU训练时操作顺序不确定性比CPU高所以如果追求严格的复现建议在CPU上跑训练或者使用tf.config.threading设置线程数固定。对于故障诊断这个项目来说模型准确率的微小波动±0.5%其实不影响结论不必过于纠结完全一致的数值。6. 项目扩展与应用落地的可能性6.1 从CWRU到实际工业数据的移植思路CWRU数据集是理想化的数据实际工厂现场采集的轴承振动信号要复杂得多——环境噪音大、转速波动、负载变化、传感器安装位置差异都会影响信号特征。直接拿CWRU上训练的模型去做现场诊断效果会打很大折扣。工程上常用的做法是迁移学习用CWRU数据预训练模型然后用少量现场数据做微调Fine-tuning冻结CNN层权重只训练全连接层和LSTM层。原因很简单CNN层提取的是通用振动形态特征这些特征在实验室数据和现场数据之间是相似的而全连接层和LSTM层学到的是分类边界需要针对现场信号重新校准。微调的数据量要求不高我个人的经验是每个类别准备200-500个样本就能看到明显效果提升。如果现场连这个量级的数据都拿不到可以考虑把模型输出从分类标签改成故障程度评估回归任务这样只需要正常的振动数据就能建立健康基线偏离基线程度作为故障指标。6.2 与自制设备结合做实时在线监测我有的朋友拿到这个项目后自己买了一个USB接口的振动传感器接上树莓派做了个简易的轴承在线监测系统。整个流程是传感器采集加速度信号 → 单片机/树莓派按固定长度截取信号 → 信号送进CNN-LSTM模型推理 → 输出故障类别和置信度。模型推理一次只需要几十毫秒完全满足准实时的需求。这类落地项目最大的难点不在模型本身而是工程问题数据采集的同步与标定、模型量化与边缘部署、通信协议的稳定性等。如果你有兴趣做类似方案建议先从采集-保存-离线分析开始跑通了再升级到在线推理模式一步到位容易翻车。6.3 与其他信号处理方法的融合思路CNN-LSTM组合虽然强大但在实际工业诊断中传统的信号处理方法依然是重要的补充手段。一个比较实用的融合方案是先用包络谱分析提取故障特征频率再用CNN-LSTM做自动分类两者相互验证。比如模型判断为外圈故障而你通过包络谱分析在外圈故障特征频率处发现了明显的峰值谱线那么这个诊断结论的可信度就非常高了。我在实际项目中经常采用这种方式既是模型结果的交叉验证也能在故障早期捕捉到模型可能忽略的微弱特征。另一个方向是引入多个传感器通道的数据例如同时输入加速度信号和声发射信号把多通道数据作为模型的多输入通道类似图像处理里的RGB三通道思路。多传感器信息的融合能显著提升诊断鲁棒性尤其是单一传感器信号受噪声干扰严重时这种互补性尤为重要。7. 最后分享几个实用小技巧整个项目跑通之后有几个小技巧我觉得特别值得分享给正在做类似项目的朋友第一样本切分的重叠率值得认真调。重叠率越高生成的样本数越多模型训练更充分但相邻样本之间的相关性也越高过拟合风险随之增加。我试过0%重叠和50%重叠后者在训练集上的准确率明显更高但验证集上优势很小。如果你用文件级切分这个项目采用的方式重叠率的影响会弱一些因为测试集和训练集没有重叠区域了。第二训练时把模型的输入标准化参数也保存下来。这个项目里我预处理时用的Scaler对象是通过训练集拟合的测试和推理时也必须用同一个Scaler做变换。很多人在预处理时图省事直接对全部数据做标准化这相当于提前让模型看到了测试集的整体分布会导致测试结果虚高。正确做法是先切分数据再在训练集上拟合标准化的参数然后把这个参数保存为本地文件例如用joblib.dump推理时加载同样的参数做变换。第三模型推理前做一次简单的数据质量检查。实际部署时输入模型的信号经常出现各种问题比如传感器掉线导致全零数据、信号被削顶导致幅值饱和等。这类异常数据如果不加甄别直接送入模型模型会给出一个看似合理的诊断结果实际上是垃圾进垃圾出。最简单的检查方法算一下信号的方差方差接近0说明信号异常再算一下峰值如果大量采样点都顶在量程上限说明信号被削顶了。加一道简单的数据质量检查能避免大量误诊断。第四不要迷信单一指标。这个项目里测试集准确率是一个非常直观的指标但在实际场景中你更应该关注混淆矩阵和各类别的召回率。一个模型在总体准确率上表现优秀并不代表每个故障类别都识别得好。有时候为了高整体准确率模型会把少数类样本强行归到多数类这在故障诊断中是致命的——漏报一次轴承故障造成的损失远超误报十次。所以建议在评估模型时把每个类别的精确率、召回率、F1值都打印出来逐项检查。本文还有配套的精品资源点击获取
返回列表