基于深度学习的轴承故障诊断:CNN-LSTM架构演进与核心代码逻辑拆解

前言
在设备健康管理(PHM)的实战中,面对凯斯西储大学(CWRU)轴承数据集,直接将几十万个采样点的振动信号塞给模型是行不通的。即使经过切片,纯 LSTM 网络在处理长序列高频噪声信号时也常常面临“梯度崩溃”的窘境。

本文将从整体工程逻辑出发,分段精简拆解数据流转的每一个环节,带你深入理解如何通过 1D-CNN + LSTM 优雅地解决振动信号分类难题。


一、 整体工程逻辑概览

要完成高精度的轴承故障识别,数据与模型的流转通常遵循以下标准化 Pipeline(流水线):

  1. 数据动态提取:由于 CWRU 数据集不同 .mat 文件中变量名不一致,需动态匹配并提取驱动端(DE_time)的一维振动信号。
  2. 滑窗切片(Sliding Window):将超长连续信号截断成固定长度(如 1024)的短序列,构造出带有标签的样本集。
  3. 特征工程与重塑:消除量纲差异(标准化),并将二维数组重塑为深度学习框架要求的 (样本数, 时间步长, 特征通道数) 三维张量。
  4. CNN 降维提特征:利用一维卷积和池化,将 1024 长度的原始时域波形压缩为极短的高级特征序列(如 64 长度)。
  5. LSTM 时序建模与分类:接收浓缩特征,挖掘时序演变规律,最终通过 Softmax 输出 10 分类概率。

二、 核心代码逻辑分段拆解

1. 跨越数据陷阱:动态键名提取

CWRU 数据集的一个著名“坑点”是:105号文件的变量叫 X105_DE_time,118号则叫 X118_DE_time。我们不能硬编码键名,而是需要通过字符串匹配来动态寻址。

import scipy.io as sio

def extract_de_time_signal(mat_file_path):
    mat_dict = sio.loadmat(mat_file_path)
    # 遍历字典的键,动态寻找包含 'DE_time' (驱动端) 的键名
    for key in mat_dict.keys():
        if 'DE_time' in key:
            return mat_dict[key].flatten() # 展平为纯一维数组
    return None

逻辑解析:这一步确保了无论读取哪个状态的 .mat 文件,我们都能准确、鲁棒地剥离出纯粹的振动波形数组,为后续切片做准备。

2. 样本构造的核心:滑窗切片算法

单个 .mat 文件包含约 12 万个采样点,这是单一序列,无法直接训练。我们需要让窗口在时间轴上滑动,通过设置 STEP_SIZE 实现样本重叠(数据扩增)。

# 假设 signal 是上一步提取出的一维振动信号
WINDOW_SIZE = 1024  # 每个样本包含 1024 个点
STEP_SIZE = 512     # 每次滑动 512 个点(50%重叠率)

X_list, y_list = [],[]
for i in range(0, len(signal) - WINDOW_SIZE, STEP_SIZE):
    windowed_data = signal[i : i + WINDOW_SIZE]
    X_list.append(windowed_data)
    y_list.append(current_label) # 赋予当前文件夹对应的故障标签

逻辑解析:这是时间序列分析的灵魂步骤。1024的窗口长度约包含3-4个完整的轴承旋转周期,既保证了包含了足够的物理故障冲击(Impulse),又避免了单样本过于冗长。

3. 数据重塑与标准化:对齐 Keras 输入标准

切片完成后,数据本质上是一个 (样本总数, 1024) 的二维矩阵。为了让模型快速收敛且不报错,需要进行标准化和维度重塑。

from sklearn.preprocessing import StandardScaler

# 1. Z-score 标准化:消除不同故障程度信号的绝对振幅差异,加速梯度下降
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train) 

# 2. 维度重塑:Keras RNN/CNN 要求输入为 3D 张量 (Samples, Time_Steps, Features)
# 对于单通道振动信号,特征数为 1
X_train = X_train.reshape(-1, WINDOW_SIZE, 1) 

逻辑解析:如果没有标准化,突变的极大极小值很容易导致 LSTM 梯度爆炸。重塑为 3D 张量则是明确告诉模型:每次处理 1 个通道的、长度为 1024 的时序数据。

4. 破局关键:CNN-LSTM 联合网络拓扑

这是整个系统的心脏。纯 LSTM 直接吃 1024 长度的序列极易“失忆”和“震荡”。我们用 1D-CNN 作为前置特征处理器。

from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense

# CNN 阶段:大卷积核提取高频冲击,池化层疯狂降维
model.add(Conv1D(filters=64, kernel_size=16, strides=2, activation='relu'))
model.add(MaxPooling1D(pool_size=2)) # 长度大幅缩减
model.add(Conv1D(filters=32, kernel_size=8, activation='relu'))
model.add(MaxPooling1D(pool_size=4)) # 序列长度被压缩到 60 左右

# LSTM 阶段:轻松处理浓缩后的短序列
model.add(LSTM(64, return_sequences=True))
model.add(LSTM(32, return_sequences=False))

# 决策阶段:映射到 10 种故障类型
model.add(Dense(10, activation='softmax'))

逻辑解析

  • Conv1Dkernel_size=16 就像一个低通/高通滤波器,滤除背景噪声,保留冲击尖峰。
  • MaxPooling1D 极其重要!它将 1024 的时间步长极速压缩。送入 LSTM 的序列长度仅剩 60 左右,这恰好落在了 LSTM 最擅长处理的“黄金记忆长度”区间内,训练速度直接起飞。

5. 稳健的训练策略:约束野马

高频振动数据的 Loss 曲面通常非常崎岖(非凸),模型很容易掉入局部最优或发生梯度崩溃。

from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping

# 降低默认学习率,并加入 clipnorm 防止梯度爆炸
optimizer = Adam(learning_rate=0.0005, clipnorm=1.0)
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])

# 加入早停机制,避免过拟合
early_stopping = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)

逻辑解析clipnorm=1.0 是一道保险索。如果反向传播时梯度骤然变大(这在振动信号分析中很常见),它会将其强行截断,保证模型的准确率不会在某一个 Epoch 突然从 90% 暴跌回 30%。


三、 深度解析:模型在“思考”什么?

当上述逻辑串联运行后,模型通常能在测试集上达到接近 100% 的准确率。但如果查看详细的分类报告,我们往往会发现一个有趣的现象:

唯一的微小误判通常发生在 0.014英寸滚动体故障0.021英寸滚动体故障 之间。

这不是模型变笨了,而是物理规律的体现
在实际机械运行中,滚动体(Ball)不仅在自转,还在绕轴心公转。它的故障冲击信号需要穿过内圈或外圈、轴承座等多个介质才能到达传感器,传递路径时刻在变,信号衰减极其严重。这就导致中度(0.014)和重度(0.021)的滚动体损伤,在时域图谱上有时高度重叠。模型能在此处表现出些许“犹豫”,恰恰证明了它真实捕捉到了振动信号的物理特征,而非死记硬背(过拟合)。

四、 进阶与总结

通过拆解代码逻辑,我们可以看出,优秀的深度学习诊断模型绝不是简单地“调包”和“堆叠层数”,而是将信号处理的物理直觉融入网络结构的设计中(如利用 CNN 充当滤波器与降维器)。

五、 代码及数据集获取

关注公众号:“易派森”,输入关键词“凯斯西储大学轴承数据集LSTM故障识别”,获取分析源码及数据集。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐