你好,我现在有.mat格式的轨道疲劳裂缝数据,分为初始、扩展和断裂三个阶段,已经按比例分为训练集和验证集,数据是通过传感器获取测试样本上的原始信号得到的,传感器记录了不同测试点,共30000个测试点,每个测试点包含8192个连续的数据点。.mat格式数据中,变量train_x记录训练数据(21000×8192),变量train_y用0和1记录阶段标签(21000×3);变量test_x记录测试数据(9000×8192),变量test_y用0和1记录阶段标签(9000×3)。现在想用深度学习的算法对其进行识别分类的训练和测试,显卡是RTX5090,深度学习环境是pytorch2.7.0+python3.12+CUDA12.8,在此深度学习环境下,请给出RNN、CNN、CNN-LSTM和增加注意力机制的CNN-LSTM共四种网络模型的代码,可分别进行运行。我是一个小白,请给我非常详细的解答,完整且有说明的代码
时间: 2025-07-21 09:54:39 浏览: 0
<think>根据用户要求,我们需要在PyTorch环境下实现四种模型:RNN、CNN、CNN-LSTM和带注意力机制的CNN-LSTM,用于对轨道疲劳裂缝数据进行分类。数据格式为.mat文件,其中训练集包含21000个样本,每个样本有8192个特征(train_x: 21000×8192),标签为3类(train_y: 21000×3);测试集9000个样本(test_x: 9000×8192,test_y: 9000×3)。
由于原始数据是一维时间序列(8192个点),我们将按照以下方式处理:
- RNN:直接输入一维序列,使用RNN处理。
- CNN:将一维序列视为一维信号,使用一维卷积。
- CNN-LSTM:先用一维卷积提取特征,然后将特征输入LSTM。
- 带注意力机制的CNN-LSTM:在CNN-LSTM的基础上,在LSTM的输出上加入注意力机制。
我们首先需要加载.mat文件,然后构建数据加载器,接着定义模型、训练和测试函数。
注意:由于数据量较大,我们将使用GPU进行训练(如果可用)。
步骤:
1. 加载数据:使用scipy.io加载.mat文件。
2. 数据预处理:将数据转换为PyTorch张量,并创建Dataset和DataLoader。
3. 定义模型:分别定义四个模型。
4. 训练和测试:编写训练循环和测试函数。
由于代码较长,我们将分块编写,并尽可能详细注释。
首先,确保安装了必要的库:
```
pip install torch scipy numpy
```
注意:PyTorch 2.0.0及以上版本支持CUDA 12,因此我们使用PyTorch 2.0.0+和CUDA 12.8。
下面开始编写完整代码。由于代码很长,我们将按模型分别编写,但为了可运行,我们将它们整合在一个脚本中,通过命令行参数选择模型。
但是,由于用户要求四种模型,我们将分别实现,并允许通过命令行参数指定模型类型。
代码结构:
1. 导入必要的库
2. 定义配置参数(如批大小、学习率等)
3. 加载数据
4. 定义数据集类
5. 定义四种模型
6. 定义训练和测试函数
7. 主函数,根据选择的模型进行训练和测试
由于代码量很大,我们将分步骤编写。注意:带注意力机制的CNN-LSTM需要自定义注意力层。
注意:由于数据特征长度是8192,我们可能需要通过卷积或降采样降低序列长度,以避免LSTM处理过长的序列。
我们采用以下策略:
- 对于CNN和CNN-LSTM:使用多个卷积层和池化层来降低序列长度。
- 对于RNN:由于序列较长,我们使用两层RNN,并可能使用降采样(如步长为2的卷积)来缩短序列,或者使用GRU/LSTM减少计算量。
考虑到训练时间,我们设置适当的迭代次数(epochs),并验证每个模型。
由于数据量较大,我们使用较大的批处理大小(如128)以加快训练速度。
开始编写代码:</think>以下是在PyTorch 2.7.0 + Python 3.12 + CUDA 12.8环境下实现四种深度学习模型的完整代码,用于轨道疲劳裂缝数据的分类任务:
```python
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from scipy.io import loadmat
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
# 检查CUDA可用性
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")
# 数据加载函数
def load_data(path):
"""加载.mat格式的轨道疲劳裂缝数据"""
data = loadmat(path)
train_x = data['train_x'].astype(np.float32) # 输入数据 (21000, 8192)
train_y = data['train_y'].astype(np.int64) # 标签数据 (21000, 3)
test_x = data['test_x'].astype(np.float32) # (9000, 8192)
test_y = data['test_y'].astype(np.int64) # (9000, 3)
# 将one-hot标签转换为类别索引
train_y = np.argmax(train_y, axis=1)
test_y = np.argmax(test_y, axis=1)
# 创建PyTorch数据集
train_dataset = TensorDataset(torch.tensor(train_x), torch.tensor(train_y))
test_dataset = TensorDataset(torch.tensor(test_x), torch.tensor(test_y))
return train_dataset, test_dataset
# 基础配置
BATCH_SIZE = 128
EPOCHS = 20
LR = 0.001
# 加载数据
train_dataset, test_dataset = load_data("轨道疲劳裂缝数据.mat")
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE)
# ====================== RNN模型 ======================
class RNNModel(nn.Module):
def __init__(self, input_size=8192, hidden_size=128, num_layers=2, num_classes=3):
super(RNNModel, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, num_classes)
def forward(self, x):
# 输入x形状: (batch_size, seq_len, input_size)
x = x.view(-1, 1, 8192) # 重塑为RNN输入格式
# 初始化隐藏状态
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
# RNN前向传播
out, _ = self.rnn(x, h0)
# 取最后一个时间步的输出
out = out[:, -1, :]
out = self.fc(out)
return out
# ====================== CNN模型 ======================
class CNNModel(nn.Module):
def __init__(self, num_classes=3):
super(CNNModel, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv1d(1, 32, kernel_size=5, stride=2, padding=2),
nn.BatchNorm1d(32),
nn.ReLU(),
nn.MaxPool1d(2)
)
self.conv2 = nn.Sequential(
nn.Conv1d(32, 64, kernel_size=5, stride=2, padding=2),
nn.BatchNorm1d(64),
nn.ReLU(),
nn.MaxPool1d(2)
)
self.fc = nn.Sequential(
nn.Linear(64 * 256, 128), # 8192/(2*2*2)=1024 -> 1024/4=256
nn.ReLU(),
nn.Linear(128, num_classes)
)
def forward(self, x):
x = x.view(-1, 1, 8192) # 重塑为CNN输入格式
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1) # 展平
x = self.fc(x)
return x
# ====================== CNN-LSTM模型 ======================
class CNNLSTMModel(nn.Module):
def __init__(self, num_classes=3):
super(CNNLSTMModel, self).__init__()
# CNN特征提取器
self.cnn = nn.Sequential(
nn.Conv1d(1, 32, kernel_size=5, stride=2, padding=2),
nn.BatchNorm1d(32),
nn.ReLU(),
nn.MaxPool1d(2),
nn.Conv1d(32, 64, kernel_size=5, stride=2, padding=2),
nn.BatchNorm1d(64),
nn.ReLU(),
nn.MaxPool1d(2)
)
# LSTM时序建模
self.lstm = nn.LSTM(64, 128, 2, batch_first=True)
self.fc = nn.Linear(128, num_classes)
def forward(self, x):
x = x.view(-1, 1, 8192)
x = self.cnn(x) # 输出形状: (batch, 64, 256)
x = x.permute(0, 2, 1) # 重塑为LSTM输入格式 (batch, seq_len, features)
h0 = torch.zeros(2, x.size(0), 128).to(device)
c0 = torch.zeros(2, x.size(0), 128).to(device)
out, _ = self.lstm(x, (h0, c0))
out = out[:, -1, :] # 取最后一个时间步
out = self.fc(out)
return out
# ====================== 带注意力机制的CNN-LSTM ======================
class Attention(nn.Module):
"""注意力机制模块"""
def __init__(self, hidden_dim):
super(Attention, self).__init__()
self.attention = nn.Linear(hidden_dim, hidden_dim)
self.context = nn.Linear(hidden_dim, 1, bias=False)
def forward(self, x):
# x形状: (batch_size, seq_len, hidden_dim)
attn_weights = torch.tanh(self.attention(x))
attn_weights = self.context(attn_weights).squeeze(2)
attn_weights = torch.softmax(attn_weights, dim=1)
weighted = torch.sum(x * attn_weights.unsqueeze(2), dim=1)
return weighted, attn_weights
class AttentionCNNLSTM(nn.Module):
def __init__(self, num_classes=3):
super(AttentionCNNLSTM, self).__init__()
# CNN特征提取器 (与CNN-LSTM相同)
self.cnn = nn.Sequential(
nn.Conv1d(1, 32, kernel_size=5, stride=2, padding=2),
nn.BatchNorm1d(32),
nn.ReLU(),
nn.MaxPool1d(2),
nn.Conv1d(32, 64, kernel_size=5, stride=2, padding=2),
nn.BatchNorm1d(64),
nn.ReLU(),
nn.MaxPool1d(2)
)
# LSTM时序建模
self.lstm = nn.LSTM(64, 128, 2, batch_first=True, bidirectional=True)
self.attention = Attention(256) # 双向LSTM输出维度*2
self.fc = nn.Linear(256, num_classes)
def forward(self, x):
x = x.view(-1, 1, 8192)
x = self.cnn(x) # 输出形状: (batch, 64, 256)
x = x.permute(0, 2, 1) # 重塑为LSTM输入格式
h0 = torch.zeros(4, x.size(0), 128).to(device) # 双向*2层数
c0 = torch.zeros(4, x.size(0), 128).to(device)
out, _ = self.lstm(x, (h0, c0))
weighted, _ = self.attention(out) # 应用注意力机制
out = self.fc(weighted)
return out
# 训练和评估函数
def train_model(model, train_loader, test_loader, model_name):
model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=LR)
train_losses, test_accs = [], []
print(f"\n训练 {model_name} 模型...")
for epoch in range(EPOCHS):
model.train()
running_loss = 0.0
for inputs, labels in train_loader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item() * inputs.size(0)
epoch_loss = running_loss / len(train_loader.dataset)
train_losses.append(epoch_loss)
# 测试集评估
model.eval()
correct, total = 0, 0
with torch.no_grad():
for inputs, labels in test_loader:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
acc = 100 * correct / total
test_accs.append(acc)
print(f"Epoch [{epoch+1}/{EPOCHS}] - 损失: {epoch_loss:.4f}, 测试准确率: {acc:.2f}%")
# 绘制训练曲线
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(train_losses, label='训练损失')
plt.title(f'{model_name} - 训练损失')
plt.xlabel('Epoch')
plt.ylabel('损失')
plt.subplot(1, 2, 2)
plt.plot(test_accs, 'r-', label='测试准确率')
plt.title(f'{model_name} - 测试准确率')
plt.xlabel('Epoch')
plt.ylabel('准确率 (%)')
plt.tight_layout()
plt.savefig(f'{model_name}_performance.png')
plt.close()
print(f"{model_name} 最终测试准确率: {test_accs[-1]:.2f}%")
return model
# 主函数
if __name__ == "__main__":
# 创建模型实例
models = {
"RNN": RNNModel(),
"CNN": CNNModel(),
"CNN-LSTM": CNNLSTMModel(),
"Attention-CNN-LSTM": AttentionCNNLSTM()
}
# 训练并评估所有模型
results = {}
for name, model in models.items():
trained_model = train_model(model, train_loader, test_loader, name)
results[name] = trained_model
# 保存模型
for name, model in results.items():
torch.save(model.state_dict(), f"{name}_轨道疲劳裂缝分类.pth")
print(f"{name}模型已保存")
```
### 代码说明
1. **数据准备**
- 使用`scipy.io.loadmat`加载.mat格式数据
- 将one-hot标签转换为类别索引
- 创建PyTorch的Dataset和DataLoader
2. **模型架构**
- **RNN模型**:处理原始时序数据,包含两层RNN和全连接层
- **CNN模型**:使用一维卷积提取局部特征,包含两个卷积块
- **CNN-LSTM模型**:CNN提取特征后输入LSTM进行时序建模
- **注意力机制CNN-LSTM**:在LSTM输出上添加注意力层,增强关键特征
3. **训练配置**
- 批大小128,学习率0.001,训练20轮
- 使用Adam优化器和交叉熵损失
- 自动检测并使用CUDA加速
4. **评估与可视化**
- 每轮计算测试集准确率
- 保存训练损失和测试准确率曲线
- 训练后保存模型权重
### 使用说明
1. 将代码保存为`railway_crack_classification.py`
2. 确保数据集文件命名为"轨道疲劳裂缝数据.mat"并放在同目录
3. 安装依赖库:`pip install torch scipy numpy matplotlib`
4. 运行命令:`python railway_crack_classification.py`
5. 训练完成后会生成:
- 每个模型的性能曲线图
- 模型权重文件(.pth)
### 注意事项
1. 根据硬件调整`BATCH_SIZE`,较大批大小需要更多显存
2. 可调整`EPOCHS`控制训练轮数
3. 对于超长序列(8192点),CNN-LSTM模型效率更高
4. 注意力机制可视化可通过保存`attn_weights`实现
### 性能优化建议
1. 数据预处理:添加标准化或归一化
2. 序列降采样:减少序列长度提升效率
3. 学习率调度:添加`lr_scheduler`动态调整学习率
4. 早停机制:防止过拟合
5. 混合精度训练:使用`torch.cuda.amp`加速
[^1]: 轨道疲劳裂缝数据通常包含振动信号特征,深度学习能有效提取其时空特征
[^2]: 注意力机制可增强模型对关键故障特征的捕捉能力,提升分类性能
阅读全文
相关推荐









