> 技术文档 > 滚动轴承故障诊断

滚动轴承故障诊断


前言

今天更新的是多尺度卷积+BiLSTM的故障诊断模型。利用不同大小的卷积核能够提取丰富的特征信息,再经过双向LSTM获取时序特征,增强模型的分类效果。

改进

  • 多尺度卷积块 (self.convs)

    • 我们使用了 nn.ModuleList,这是PyTorch中存储一系列nn.Module的标准容器。

    • 创建了三个并行的 nn.Conv1d 层,它们的kernel_size分别为3, 5, 7,用于捕捉不同长度的模式。

    • padding被设置为 (kernel_size - 1) // 2,这是一个常用的技巧,可以确保卷积操作后序列的长度保持不变,方便后续拼接。

  • 特征拼接 (torch.cat)

    • forward 方法中,我们将三个卷积分支的输出在一个列表 multi_scale_features 中收集起来。

    • torch.cat(multi_scale_features, dim=1) 将这些特征图沿着通道维度(维度1)进行拼接。如果每个分支输出 (N, 32, L),拼接后就得到 (N, 32*3, L),即 (N, 96, L)。这比逐元素相乘保留了更多的原始信息。

  • 特征整合 (self.conv_mixer)

    • 在拼接了多尺度特征之后,我们添加了一个常规的卷积层 (self.conv_mixer)来学习如何组合这些来自不同尺度的信息,并统一输出通道数(例如,减少到64),为后续的LSTM层做准备。

  • 批量归一化 (nn.BatchNorm1d)

    • 在卷积和激活函数之间加入了 nn.BatchNorm1d。这层可以规范化每层的数据分布,使得训练过程更加稳定,通常能带来性能提升。

  • 双向LSTM (bidirectional=True)

    • 这是一个可选但通常很有效的改进。双向LSTM可以同时从过去和未来两个方向学习序列信息,对于很多任务都能提升性能。注意,这会导致全连接层的输入特征维度加倍(hidden_size * 2)。

  • 代码健壮性

    • 去除了硬编码的batch_size,模型现在可以接受任意批次大小的输入。

    • 改用 x.unsqueeze(1) 来增加通道维度,这比 .view() 更安全,因为它不会意外地改变数据布局。

代码

import torchimport torch.nn as nnimport torch.nn.functional as Fclass MultiScaleModel(nn.Module): def __init__(self): \"\"\" 在 __init__ 中不再需要传入 batch_size。 \"\"\" super(MultiScaleModel, self).__init__() # 1. 定义多尺度卷积模块 (Multi-Scale Convolutional Block) # 我们将使用三个并行的卷积层,核大小分别为 3, 5, 7 # 使用 ModuleList 来方便地管理这些层 self.convs = nn.ModuleList([ # 分支1: 小尺度特征 nn.Conv1d(in_channels=1, out_channels=32, kernel_size=3, stride=1, padding=1), # 分支2: 中尺度特征 nn.Conv1d(in_channels=1, out_channels=32, kernel_size=5, stride=1, padding=2), # 分支3: 大尺度特征 nn.Conv1d(in_channels=1, out_channels=32, kernel_size=7, stride=1, padding=3) ]) # 注意: padding = (kernel_size - 1) // 2 可以保持序列长度不变 # 拼接后的通道数是 32 * 3 = 96 # 添加一个后续的卷积层来整合多尺度特征 self.conv_mixer = nn.Conv1d(in_channels=96, out_channels=64, kernel_size=3, stride=1, padding=1) # 添加批量归一化层,可以稳定训练并加速收敛 self.batch_norm = nn.BatchNorm1d(num_features=64) self.pool = nn.MaxPool1d(kernel_size=2) # 2. 定义解码器 (dc) 的层 (与原来保持一致) # LSTM的input_size现在是conv_mixer的输出通道数(64) self.dc_layer1 = nn.LSTM(input_size=64, hidden_size=128, batch_first=True) self.dc_layer2 = nn.LSTM(input_size=128, hidden_size=256, batch_first=True, bidirectional=True) # 尝试使用双向LSTM self.dc_layer3 = nn.Dropout(0.5) # 双向LSTM的输出是 hidden_size * 2 self.dc_layer4 = nn.Linear(in_features=256 * 2, out_features=10) def forward(self, x): # 3. 动态获取 batch_size 并调整输入形状 # 假设输入 x 的 shape: (batch_size, sequence_length), 例如 (32, 1024) # .unsqueeze(1) 比 view 更灵活,它会在第1维增加一个通道维度 x_reshaped = x.unsqueeze(1) # -> (batch_size, 1, 1024) # 4. 多尺度卷积前向传播 # 对每个卷积分支进行计算,并将结果保存在列表中 multi_scale_features = [conv(x_reshaped) for conv in self.convs] # 使用 torch.cat 在通道维度(dim=1)上拼接特征 x_cat = torch.cat(multi_scale_features, dim=1) # -> (batch_size, 96, 1024) # 5. 整合特征并通过后续层 # 使用 ReLU 激活函数替代 tanh x = F.relu(self.conv_mixer(x_cat)) x = self.batch_norm(x) # 应用批量归一化 encoder_outputs = self.pool(x) # -> (batch_size, 64, 512) # 6. 调整维度以匹配 LSTM 的输入格式 # Conv1d 输出: (N, C, L) -> LSTM 输入: (N, L, C) lstm_input = encoder_outputs.permute(0, 2, 1) # 7. 解码器 (dc) 的前向传播 dc, _ = self.dc_layer1(lstm_input) dc, _ = self.dc_layer2(dc) # 8. 获取 LSTM 最后一个时间步的输出 # 对于双向LSTM,我们需要拼接前向和后向的最后一个隐藏状态 # dc shape: (batch_size, seq_len, 256 * 2) # 我们取最后一个时间步的输出 dc = dc[:, -1, :] # 9. Dropout 和全连接层 dc = self.dc_layer3(dc) output = self.dc_layer4(dc) # 10. 输出 # 在使用 nn.CrossEntropyLoss 作为损失函数时,不需要手动应用softmax # 它会内部完成 log_softmax。因此,通常直接返回logits(全连接层的输出)。 return output# --- 如何使用模型 ---# 创建一个模型实例model = MultiScaleModel()# 创建一个假的输入张量来测试# batch_size=32, sequence_length=1024#dummy_input = torch.randn(32, 1024)#output = model(dummy_input)# 打印模型结构和输出形状#print(model)#print(\"Output shape:\", output.shape)