本次代码是一个简单的GAN神经网络
代码说明:
一、数据准备:
1.使用Karate Club数据集(小型社交网络)
2.包含34个节点(俱乐部成员)和156条边(社交关系)
3.每个节点有34维特征,分为4个类别
二、模型结构:
1.两层GCN(图卷积网络)
2.第一层:34维输入 → 4维隐藏层
3.第二层保持4维方便可视化
4.使用ReLU激活函数
三、可视化功能:
1.原始图结构可视化(使用networkx)
2.训练损失曲线
3.隐藏层表示的PCA降维可视化
四、训练过程:
1.使用交叉熵损失和Adam优化器
2.训练200个epoch
3.输出训练过程中的损失变化
五、测试功能:
计算节点分类准确率运行结果说明:
1.会显示三个可视化窗口:
Ⅰ.原始图结构(节点颜色表示真实类别)
Ⅱ.训练损失曲线
Ⅲ.隐藏层表示的可视化(不同颜色对应不同类别)
2.终端输出:
Ⅰ.数据集基本信息
Ⅱ.训练过程中的损失变化
Ⅲ.最终测试准确率
六、注意事项:
1.首次运行会自动下载数据集(约1MB)
2.可视化窗口需要关闭当前窗口才能继续执行后续代码
3.准确率可能因随机初始化略有波动(通常在0.85-1.00之间)
# 在PyCharm终端安装依赖(已安装可跳过):
# pip install torch torchvision torchaudio
# pip install torch-geometric matplotlib scikit-learn networkx
import matplotlib.pyplot as plt
# ========== 新增部分:解决中文显示问题 ==========
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统
# plt.rcParams['font.sans-serif'] = ['Songti SC'] # MacOS系统
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
import torch
from torch_geometric.datasets import KarateClub
from torch_geometric.nn import GCNConv
import matplotlib.pyplot as plt
import networkx as nx
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA
import os
os.environ['KMP_DUPLICATE_LIB_OK']='True'
# ================== 可调参数 ==================
LEARNING_RATE = 0.01 # 学习率(建议0.001-0.1)
EPOCHS = 200 # 训练轮数(建议100-500)
HIDDEN_DIM = 12 # 隐藏层维度(建议4-16)
VIS_METHOD = 'tsne' # 可视化方法(tsne/pca)
SEED = 42 # 随机种子(确保可重复性)
# ==============================================
# 设置随机种子保证可重复性
torch.manual_seed(SEED)
# 1. 数据准备与展示
def load_data():
"""加载并展示数据集基本信息"""
dataset = KarateClub()
data = dataset[0]
print("\n数据集信息:")
print(f"• 节点数: {data.num_nodes}")
print(f"• 边数: {data.num_edges}")
print(f"• 特征维度: {data.num_node_features}")
print(f"• 类别数: {dataset.num_classes}\n")
return data, dataset
# 2. GNN模型定义
class GNN(torch.nn.Module):
def __init__(self, input_dim, hidden_dim):
super().__init__()
self.conv1 = GCNConv(input_dim, hidden_dim)
self.conv2 = GCNConv(hidden_dim, hidden_dim)
def forward(self, x, edge_index):
x = self.conv1(x, edge_index)
x = torch.relu(x)
x = self.conv2(x, edge_index)
return x
# 3. 可视化工具集
class Visualizer:
@staticmethod
def draw_graph(data):
"""原始图结构可视化"""
G = nx.Graph()
G.add_edges_from(data.edge_index.numpy().T)
plt.figure(figsize=(10, 6))
nx.draw(G,
node_color=data.y.numpy(),
cmap=plt.cm.tab10,
pos=nx.spring_layout(G, seed=SEED),
with_labels=True)
plt.title("原始图结构(节点颜色表示真实类别)")
plt.show()
@staticmethod
def visualize(hidden_rep, labels, method='tsne'):
"""高维特征可视化(支持t-SNE/PCA)"""
plt.figure(figsize=(10, 6))
# 选择降维方法
if method.lower() == 'tsne':
reducer = TSNE(n_components=2, perplexity=10, random_state=SEED)
title = "t-SNE 可视化"
else:
reducer = PCA(n_components=2)
title = "PCA 可视化"
# 降维并绘制
low_dim = reducer.fit_transform(hidden_rep)
plt.scatter(low_dim[:, 0], low_dim[:, 1],
c=labels, cmap=plt.cm.tab10, edgecolors='k')
plt.title(f"{title}(隐藏层维度={HIDDEN_DIM})")
plt.xlabel("Component 1")
plt.ylabel("Component 2")
plt.colorbar(label="Class")
plt.show()
# 4. 训练与测试模块
class Trainer:
def __init__(self, model, data, lr):
self.model = model
self.data = data
self.optimizer = torch.optim.Adam(model.parameters(), lr=lr)
self.criterion = torch.nn.CrossEntropyLoss()
def train(self, epochs):
"""训练过程带损失曲线"""
losses = []
print("开始训练...")
for epoch in range(epochs):
self.optimizer.zero_grad()
out = self.model(self.data.x, self.data.edge_index)
loss = self.criterion(out, self.data.y)
loss.backward()
self.optimizer.step()
losses.append(loss.item())
# 每10%进度打印一次
if (epoch + 1) % max(epochs // 10, 1) == 0:
print(f"Epoch {epoch + 1:4d}/{epochs} | Loss: {loss.item():.4f}")
# 绘制损失曲线
plt.figure(figsize=(10, 4))
plt.plot(losses)
plt.title(f"学习曲线 (LR={LEARNING_RATE})")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.show()
def evaluate(self):
"""模型评估"""
self.model.eval()
_, pred = self.model(self.data.x, self.data.edge_index).max(dim=1)
correct = (pred == self.data.y).sum().item()
acc = correct / self.data.num_nodes
print(f"\n模型准确率: {acc * 100:.1f}%")
# 主程序
if __name__ == "__main__":
# 初始化
data, dataset = load_data()
# 可视化原始图
Visualizer.draw_graph(data)
# 初始化模型
model = GNN(input_dim=data.num_node_features, hidden_dim=HIDDEN_DIM)
# 训练模型
trainer = Trainer(model, data, lr=LEARNING_RATE)
trainer.train(EPOCHS)
# 评估模型
trainer.evaluate()
# 可视化隐藏层表示
with torch.no_grad():
embeddings = model(data.x, data.edge_index).numpy()
Visualizer.visualize(embeddings, data.y.numpy(), method=VIS_METHOD)