Pytorch中使用Transformer对一维序列进行分类源代码。
本程序中,使用了6层Encoder模块和最终的全连接层进行序列分类,没有使用Decoder模块和Embeddi
ng模块(Embedding模块是用于文本嵌入的,本程序数据是序列,因此不用做嵌入)。
1、加载数据,调整为模型需要的输入格式。原始数据为Excel, 400条1*500的序列 (心电信号),其
中200条正常,200条异常。将每条1*500的信号reshape成10*50,即序列长度10*维度50。 这里也可以
理解成把序列看成了文本,每个样本由10个单词(序列长度10)组成,每个单词是50个数字(维度50
)。这样做是为了满足Transformer的输入格式。
2、构建Transformer 模型。其中包含6层的Encoder层和最终的全连接层。.
3、训练测试
PyTorch中使用Transformer对一维序列进行分类项目介绍
项目名称
PyTorch Transformer for 1D Sequence Classification
项目概述
本项目使用PyTorch实现了一个基于Transformer的模型,用于对一维序列进行分类。具体来说,我们处理的是心电信号数据,每个样本是一个长度为500的一维序列。为了适应Transformer模型的输入格式,我们将每个序列reshape成10*50的形状,即序列长度为10,每个时间步的特征维度为50。模型包含6层Encoder模块和一个最终的全连接层,用于将编码后的特征映射到分类结果。
项目特点
- 数据处理:将原始的心电信号数据从Excel文件加载,并调整为适合Transformer模型的输入格式。
- 模型构建:构建了一个包含6层Encoder的Transformer模型,不使用Decoder模块和Embedding模块。
- 训练与测试:提供了完整的训练和测试流程,包括数据加载、模型训练、评估和预测。
项目结构
transformer_sequence_classification/
├── src/ # 源代码目录
│ ├── data_loader.py # 数据加载器
│ ├── model.py # Transformer模型定义
│ ├── train.py # 训练脚本
│ ├── test.py # 测试脚本
│ ├── utils.py # 辅助函数
├── data/ # 数据目录
│ ├── ecg_data.xlsx # 原始心电信号数据
├── README.md # 项目说明
└── requirements.txt # 依赖库文件
主要模块及功能
-
data_loader.py
- 功能:加载和预处理数据。
- 内容:
load_data
函数:从Excel文件中读取数据。preprocess_data
函数:将数据reshape成适合Transformer的输入格式(10*50)。create_data_loaders
函数:创建训练和验证数据加载器。
-
model.py
- 功能:定义Transformer模型。
- 内容:
TransformerModel
类:包含6层Encoder和一个全连接层。EncoderLayer
类:单个Encoder层。PositionalEncoding
类:位置编码。forward
方法:前向传播过程。
-
train.py
- 功能:训练模型。
- 内容:
train_model
函数:训练模型的主要逻辑。evaluate
函数:在验证集上评估模型性能。main
函数:主入口点,负责调用上述函数并管理整个训练过程。
-
test.py
- 功能:测试模型。
- 内容:
test_model
函数:在测试集上测试模型性能。main
函数:主入口点,负责调用上述函数并管理整个测试过程。
-
utils.py
- 功能:提供辅助函数。
- 内容:
get_device
函数:获取可用的计算设备(CPU或GPU)。set_seed
函数:设置随机种子以保证实验的可重复性。
详细代码示例
1. 数据加载与预处理 (data_loader.py
)
import pandas as pd
from torch.utils.data import Dataset, DataLoader
import torch
def load_data(file_path):
df = pd.read_excel(file_path)
X = df.iloc[:, :-1].values
y = df.iloc[:, -1].values
return X, y
def preprocess_data(X, y):
X = X.reshape(-1, 10, 50) # Reshape to (batch_size, seq_len, feature_dim)
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.long)
return X, y
def create_data_loaders(X, y, batch_size=32, test_size=0.2):
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=test_size, random_state=42)
train_dataset = torch.utils.data.TensorDataset(X_train, y_train)
val_dataset = torch.utils.data.TensorDataset(X_val, y_val)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)
return train_loader, val_loader
2. Transformer模型定义 (model.py
)
import torch
import torch.nn as nn
import math
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000):
super(PositionalEncoding, self).__init__()
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
pe = pe.unsqueeze(0).transpose(0, 1)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:x.size(0), :]
return x
class EncoderLayer(nn.Module):
def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
super(EncoderLayer, self).__init__()
self.self_attn = nn.MultiheadAttention(d_model, nhead, dropout=dropout)
self.linear1 = nn.Linear(d_model, dim_feedforward)
self.dropout = nn.Dropout(dropout)
self.linear2 = nn.Linear(dim_feedforward, d_model)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(dropout)
self.dropout2 = nn.Dropout(dropout)
self.activation = nn.ReLU()
def forward(self, src, src_mask=None, src_key_padding_mask=None):
src2 = self.self_attn(src, src, src, attn_mask=src_mask, key_padding_mask=src_key_padding_mask)[0]
src = src + self.dropout1(src2)
src = self.norm1(src)
src2 = self.linear2(self.dropout(self.activation(self.linear1(src))))
src = src + self.dropout2(src2)
src = self.norm2(src)
return src
class TransformerModel(nn.Module):
def __init__(self, input_dim, d_model, nhead, num_encoder_layers, dim_feedforward, num_classes, dropout=0.1):
super(TransformerModel, self).__init__()
self.input_proj = nn.Linear(input_dim, d_model)
self.pos_encoder = PositionalEncoding(d_model)
encoder_layer = EncoderLayer(d_model, nhead, dim_feedforward, dropout)
self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_encoder_layers)
self.fc = nn.Linear(d_model, num_classes)
self.init_weights()
def init_weights(self):
initrange = 0.1
self.input_proj.weight.data.uniform_(-initrange, initrange)
self.fc.bias.data.zero_()
self.fc.weight.data.uniform_(-initrange, initrange)
def forward(self, src):
src = self.input_proj(src)
src = self.pos_encoder(src)
output = self.transformer_encoder(src)
output = output.mean(dim=0) # Global average pooling
output = self.fc(output)
return output
3. 训练脚本 (train.py
)
import torch
import torch.optim as optim
import torch.nn.functional as F
from data_loader import load_data, preprocess_data, create_data_loaders
from model import TransformerModel
from utils import get_device, set_seed
def train_model(model, train_loader, val_loader, epochs=10, lr=0.001):
device = get_device()
model.to(device)
optimizer = optim.Adam(model.parameters(), lr=lr)
criterion = nn.CrossEntropyLoss()
for epoch in range(epochs):
model.train()
total_loss = 0.0
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = criterion(output, target)
loss.backward()
optimizer.step()
total_loss += loss.item()
avg_loss = total_loss / len(train_loader)
print(f'Epoch {epoch+1}/{epochs}, Loss: {avg_loss:.4f}')
# Evaluate on validation set
model.eval()
correct = 0
with torch.no_grad():
for data, target in val_loader:
data, target = data.to(device), target.to(device)
output = model(data)
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()
accuracy = 100. * correct / len(val_loader.dataset)
print(f'Validation Accuracy: {accuracy:.2f}%')
def main():
set_seed(42)
X, y = load_data('data/ecg_data.xlsx')
X, y = preprocess_data(X, y)
train_loader, val_loader = create_data_loaders(X, y, batch_size=32, test_size=0.2)
model = TransformerModel(input_dim=50, d_model=128, nhead=8, num_encoder_layers=6, dim_feedforward=256, num_classes=2)
train_model(model, train_loader, val_loader, epochs=10, lr=0.001)
if __name__ == '__main__':
main()
4. 测试脚本 (test.py
)
import torch
from data_loader import load_data, preprocess_data, create_data_loaders
from model import TransformerModel
from utils import get_device, set_seed
def test_model(model, test_loader):
device = get_device()
model.to(device)
model.eval()
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()
accuracy = 100. * correct / len(test_loader.dataset)
print(f'Test Accuracy: {accuracy:.2f}%')
def main():
set_seed(42)
X, y = load_data('data/ecg_data.xlsx')
X, y = preprocess_data(X, y)
_, test_loader = create_data_loaders(X, y, batch_size=32, test_size=0.2)
model = TransformerModel(input_dim=50, d_model=128, nhead=8, num_encoder_layers=6, dim_feedforward=256, num_classes=2)
model.load_state_dict(torch.load('model.pth'))
test_model(model, test_loader)
if __name__ == '__main__':
main()
5. 辅助函数 (utils.py
)
import torch
def get_device():
return torch.device("cuda" if torch.cuda.is_available() else "cpu")
def set_seed(seed=42):
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(seed)
使用说明
-
环境准备
- 安装依赖库:
pip install -r requirements.txt
- 安装依赖库:
-
数据准备
- 确保数据文件
ecg_data.xlsx
位于data/
目录下。
- 确保数据文件
-
训练模型
- 运行训练脚本:
python train.py
- 运行训练脚本:
-
测试模型
- 运行测试脚本:
python test.py
- 运行测试脚本:
注意事项
- 数据预处理:确保数据预处理步骤正确无误,特别是reshape操作。
- 超参数调整:根据实际情况调整学习率、批大小等超参数,以获得最佳训练效果。
- 硬件要求:建议使用GPU进行训练,以加快训练速度。如果没有足够的计算资源,可以考虑使用云服务提供商的GPU实例。
- 平衡数据:注意数据集中各类别之间的不平衡问题,可以通过过采样、欠采样或使用类别权重等方式来解决。
通过上述步骤,你可以成功地使用Transformer模型对一维序列进行分类。这个项目不仅适用于心电信号分类,还可以应用于其他类似的一维序列分类任务。希望这个项目能帮助你更好地理解和应用Transformer模型。