在机器学习与深度学习领域,模型的选择与对比是优化算法性能的关键环节。本文将基于 Python 和 PyTorch 框架,结合torch_geometric
库,详细展示图卷积网络(GCN)、图注意力网络(GAT)、视觉 Transformer(ViT)以及混合模型(Hybrid)的完整实现过程。从数据加载、模型定义、训练评估到结果保存,每一步都提供可复用的代码,适合算法研究、学术论文写作和工程实践参考。
数据参考(注意:直接用链接中的数据替换):https://download.csdn.net/download/lestatlu/90690594
一、环境配置与基础库导入
在开始代码编写之前,需要导入必要的库,并完成设备选择(优先使用 GPU 加速)。
import time
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import pandas as pd
from torch_geometric.nn import GCNConv, GATConv
from torch_geometric.data import Data
from sklearn.neighbors import kneighbors_graph
from sklearn.metrics import accuracy_score, classification_report, recall_score, precision_score, cohen_kappa_score
from torch.nn import TransformerEncoder, TransformerEncoderLayer
# 设备选择
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")
start_time = time.time()
上述代码中,torch.device
用于自动检测并选择可用的计算设备(GPU 或 CPU),time.time()
用于记录程序运行总时长,方便后续性能评估。
二、数据加载与预处理
数据是模型训练的基础,本案例假设已有预处理好的特征数据和标签数据,需进行划分和格式转换。
# 加载数据
X_all_samples = np.load(r'your_path/X_all_samples.npy')
y_all_samples = np.load(r'your_path/y_all_samples.npy')
train_indices = np.load(r'your_path/global_train_indices.npy')
test_indices = np.load(r'your_path/global_test_indices.npy')
# 创建训练集和测试集
X_train = X_all_samples[train_indices]
y_train = y_all_samples[train_indices]
X_test = X_all_samples[test_indices]
y_test = y_all_samples[test_indices]
y_train = y_train.astype(np.int64)
y_test = y_test.astype(np.int64)
num_classes = np.max(y_train.astype(np.int64)) + 1
# 验证类别数一致性
assert np.max(y_train) + 1 == num_classes, "类别数不一致"
# 转换为Tensor
x_train = torch.tensor(X_train, dtype=torch.float32, device=device)
y_train_tensor = torch.tensor(y_train, dtype=torch.long, device=device)
x_test = torch.tensor(X_test, dtype=torch.float32, device=device)
y_test_tensor = torch.tensor(y_test, dtype=torch.long, device=device)
关键步骤解析:
- 使用
np.load
加载本地保存的 Numpy 数组数据,你需要将your_path
替换为实际的数据存储路径。 - 通过索引划分训练集和测试集,并将标签数据类型转换为
np.int64
,确保与 PyTorch 的torch.long
类型兼容。 - 将 Numpy 数组转换为
torch.Tensor
,并移动到选定的计算设备(GPU 或 CPU)上。
构建图结构
对于 GCN 和 GAT 模型,需要构建图结构数据,这里采用 K 近邻算法生成邻接关系。
# 构建图结构
knn_graph = kneighbors_graph(x_train.cpu().numpy(), n_neighbors=5, mode='connectivity', include_self=True)
edge_index = torch.tensor(knn_graph.nonzero(), dtype=torch.long).to(device)
train_data = Data(x=x_train, edge_index=edge_index)
knn_graph_test = kneighbors_graph(x_test.cpu().numpy(), n_neighbors=5, mode='connectivity', include_self=True)
edge_index_test = torch.tensor(knn_graph_test.nonzero(), dtype=torch.long).to(device)
test_data = Data(x=x_test, edge_index=edge_index_test)
核心逻辑:
kneighbors_graph
函数根据特征数据计算每个样本的 K 近邻关系(这里n_neighbors = 5
表示每个样本连接 5 个最近邻)。- 将邻接关系转换为
torch.Tensor
格式,并与特征数据封装成torch_geometric.data.Data
对象,满足图神经网络输入要求。
三、模型定义
3.1 图卷积网络(GCN)
class GCNModel(nn.Module):
def __init__(self, input_dim, output_dim, hidden_dim=256, num_layers=3):
super().__init__()
self.convs = nn.ModuleList([GCNConv(input_dim, hidden_dim)])
for _ in range(num_layers - 1):
self.convs.append(GCNConv(hidden_dim, hidden_dim))
self.fc_out = nn.Linear(hidden_dim, output_dim)
def forward(self, data):
x, edge_index = data.x, data.edge_index
for conv in self.convs:
x = conv(x, edge_index).relu()
return self.fc_out(x)
模型架构:
- 通过
nn.ModuleList
堆叠多个GCNConv
层,逐步提取图数据的特征。 - 最后由全连接层
fc_out
输出分类结果。
3.2 图注意力网络(GAT)
class GATModel(nn.Module):
def __init__(self, input_dim, output_dim, hidden_dim=256, heads=4, num_layers=3):
super().__init__()
self.convs = nn.ModuleList([GATConv(input_dim, hidden_dim, heads=heads)])
for _ in range(num_layers - 1):
self.convs.append(GATConv(hidden_dim * heads, hidden_dim, heads=heads))
self.fc_out = nn.Linear(hidden_dim * heads, output_dim)
def forward(self, data):
x, edge_index = data.x, data.edge_index
for conv in self.convs:
x = conv(x, edge_index).relu()
return self.fc_out(x)
关键特性:
GATConv
层引入注意力机制,增强模型对图结构中节点关系的捕捉能力。- 多头注意力机制(
heads
参数)进一步提升特征表达能力。
3.3 视觉 Transformer(ViT)
class ViTModel(nn.Module):
def __init__(self, input_dim, output_dim, hidden_dim=256, num_layers=3, num_heads=4):
super().__init__()
self.proj = nn.Linear(input_dim, hidden_dim)
self.pos_embed = nn.Parameter(torch.randn(1, hidden_dim))
encoder_layer = TransformerEncoderLayer(hidden_dim, num_heads, hidden_dim * 4)
self.transformer = TransformerEncoder(encoder_layer, num_layers)
self.fc_out = nn.Linear(hidden_dim, output_dim)
def forward(self, data):
x = self.proj(data.x) + self.pos_embed
x = x.unsqueeze(1).permute(1, 0, 2)
x = self.transformer(x)
return self.fc_out(x.squeeze(0))
设计要点:
proj
层将输入特征映射到 Transformer 所需的维度。pos_embed
添加位置编码,弥补 Transformer 对序列顺序信息的缺失。TransformerEncoder
层通过多头注意力和前馈网络进行特征提取。
3.4 混合模型(Hybrid)
class HybridModel(nn.Module):
def __init__(self, input_dim, output_dim, cnn_dim=64, trans_dim=128, num_heads=2, num_layers=3):
super().__init__()
self.cnn = nn.Sequential(
nn.Conv1d(1, cnn_dim, 3, padding=1),
nn.ReLU(),
nn.MaxPool1d(2),
nn.Conv1d(cnn_dim, cnn_dim * 2, 3, padding=1),
nn.ReLU(),
nn.MaxPool1d(2)
)
self.cnn_out_dim = cnn_dim * 2 * (input_dim // 4)
self.proj = nn.Linear(self.cnn_out_dim, trans_dim)
encoder_layer = TransformerEncoderLayer(trans_dim, num_heads, trans_dim * 4)
self.transformer = TransformerEncoder(encoder_layer, num_layers)
self.fc_out = nn.Linear(trans_dim, output_dim)
def forward(self, data):
x = data.x.unsqueeze(1)
x = self.cnn(x).view(x.size(0), -1)
x = self.proj(x).unsqueeze(1).permute(1, 0, 2)
x = self.transformer(x)
return self.fc_out(x.squeeze(0))
创新融合:
- 结合 1D 卷积神经网络(CNN)和 Transformer,先通过 CNN 提取局部特征。
- 再利用 Transformer 进行全局特征学习,实现优势互补。
四、训练与评估函数
def train_evaluate(model, model_name, train_data, test_data, y_train, y_test):
optimizer = optim.Adam(model.parameters(), lr=0.001)
criterion = nn.CrossEntropyLoss()
# 训练循环
model.train()
for epoch in range(1000):
optimizer.zero_grad()
out = model(train_data)
loss = criterion(out, y_train)
loss.backward()
optimizer.step()
# 评估
model.eval()
with torch.no_grad():
pred = model(test_data).argmax(dim=1).cpu().numpy()
true = y_test.cpu().numpy()
metrics = {
"OA (%)": accuracy_score(true, pred) * 100,
"AA (%)": recall_score(true, pred, average='macro') * 100,
"Kappa": cohen_kappa_score(true, pred),
}
pa = precision_score(true, pred, average=None) * 100
for i, p in enumerate(pa):
metrics[f"PA_Class_{i} (%)"] = p
return metrics
核心流程:
- 使用 Adam 优化器和交叉熵损失函数进行模型训练。
- 训练完成后,在测试集上进行评估,计算总体精度(OA)、宏平均召回率(AA)、Kappa 系数以及每个类别的精度(PA)。
五、主流程与结果保存
model_classes = [
("GCN", GCNModel),
("GAT", GATModel),
("ViT", ViTModel),
("Hybrid", HybridModel)
]
results = {name: [] for name, _ in model_classes}
# 训练评估所有模型
for name, model_cls in model_classes:
model = model_cls(
input_dim=x_train.shape[1],
output_dim=num_classes
).to(device)
fold_metrics = train_evaluate(model, name, train_data, test_data, y_train_tensor, y_test_tensor)
results[name].append(fold_metrics)
del model
torch.cuda.empty_cache()
# 结果统计与保存
final_results = []
for model_name, metrics_list in results.items():
df = pd.DataFrame(metrics_list)
mean = df.mean()
std = df.std()
result_row = {"Method": model_name}
for col in df.columns:
result_row[f"{col} Mean"] = round(mean[col], 2)
result_row[f"{col} Std"] = round(std[col], 2)
final_results.append(result_row)
results_df = pd.DataFrame(final_results)
results_df.to_excel("all.xlsx", index=False)
print("\n结果已保存至 all.xlsx")
print(f"总运行时间: {time.time() - start_time:.2f}秒")
执行逻辑:
- 循环遍历所有模型类,实例化模型并进行训练和评估。
- 统计每个模型的评估指标均值和标准差,并保存到 Excel 文件中。
- 打印总运行时间,方便对比不同模型的训练效率。
数据参考(注意:直接用链接中的数据替换):https://download.csdn.net/download/lestatlu/90690594