1. 先分清图任务的预测对象
| 任务 | 输入 | 预测对象 | 源目录示例 |
|---|---|---|---|
| 节点分类 | 一张或多张图 | 节点标签 | Cora GCN、PPI GAT、DGCN node |
| 图分类 | 多张图 | 每张图的标签 | MUTAG GIN、PROTEINS GMT、DASBM |
| 链路预测 | 图和候选节点对 | 边是否存在/边类别 | Cora link prediction、DGCN link |
| 图表示学习 | 图结构与特征 | 节点或图 embedding | GraphSAGE 无监督训练 |
任务类型决定数据划分、组 batch 方法、模型输出形状和指标,不能只替换最后一个分类层。
2. PyG 的 Data 对象
一张同构图通常表示为:
import torch
from torch_geometric.data import Data
x = torch.tensor(
[[1.0, 0.0], [0.0, 1.0]],
dtype=torch.float32,
)
edge_index = torch.tensor(
[[0, 1], [1, 0]],
dtype=torch.long,
)
data = Data(x=x, edge_index=edge_index)
主要属性:
| 属性 | 典型形状 | 含义 |
|---|---|---|
x |
(num_nodes, num_node_features) |
节点特征 |
edge_index |
(2, num_edges) |
COO 形式的源、目标节点索引 |
edge_attr |
(num_edges, num_edge_features) |
边特征,可选 |
y |
依任务而异 | 节点级、边级或图级标签 |
pos |
(num_nodes, dimensions) |
节点坐标,可选 |
batch |
(total_nodes,) |
多图 mini-batch 中每个节点所属的图 |
图级任务中的 batch 不是普通样本维度。通常需要 global_add_pool、global_mean_pool 等把节点表示聚合成图表示。
3. 消息传递是 GNN 的共同骨架
一层消息传递可抽象为:
flowchart LR
N[邻居节点特征] --> M[构造消息]
E[边与边特征] --> M
M --> A[sum / mean / max / attention 聚合]
S[中心节点特征] --> U[更新节点状态]
A --> U
聚合函数必须对邻居顺序保持不变。堆叠
4. GCN 的归一化传播
经典 GCN 层写为:
其中
使用 PyG 内置 GCNConv:
import torch
from torch.nn import functional as F
from torch_geometric.nn import GCNConv
class GCN(torch.nn.Module):
def __init__(self, in_channels, hidden_channels, num_classes):
super().__init__()
self.conv1 = GCNConv(in_channels, hidden_channels)
self.conv2 = GCNConv(hidden_channels, num_classes)
def forward(self, x, edge_index):
x = self.conv1(x, edge_index)
x = F.relu(x)
x = F.dropout(x, p=0.5, training=self.training)
return self.conv2(x, edge_index)
源 Notebook 还手写了继承 MessagePassing 的 GCNConv,有助于理解 add_self_loops -> 线性变换 -> 计算归一化 -> propagate -> message 的过程。工程代码优先使用官方层,除非确实需要修改消息函数或聚合规则。
5. Cora:单图节点分类
from torch_geometric.datasets import Planetoid
from torch_geometric.transforms import NormalizeFeatures
dataset = Planetoid(
root="data/Planetoid",
name="Cora",
transform=NormalizeFeatures(),
)
data = dataset[0]
为什么 len(dataset) == 1:整个 Cora 引用网络是一张图,样本是图中的节点,不是一篇论文对应一个 Data。
源记录与 PyG 公共划分的关键形状:
| 内容 | 数值 |
|---|---|
| 图数量 | 1 |
| 节点数 | 2708 |
| 节点特征 | 1433 维词袋特征 |
| 类别数 | 7 |
PyG edge_index 条目 |
10556 |
| 训练/验证/测试 mask | 140 / 500 / 1000 个节点 |
边数为什么有两个口径
原笔记开头写了 5429 条引用关系,后面 PyG 输出是 edge_index=[2, 10556]。两者不能直接互换:
- 原始数据描述可能按引用关系或去重关系计数;
- PyG 为无向消息传递通常存储两个方向的边条目,还会处理重复边;
- 代码里真正参与传播的数量应以当前
data.edge_index.size(1)为准; - 写实验报告时必须注明统计的是“关系数”还是“有向 COO 条目数”。
mask 训练
model.train()
optimizer.zero_grad(set_to_none=True)
logits = model(data.x, data.edge_index)
loss = F.cross_entropy(logits[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
评估时分别使用 val_mask 与 test_mask,不能把整张图上的所有标签都加入训练损失。
6. 不同图任务的代码结构
节点分类:PPI + GAT
- 模型:
GATConv; - 任务:多标签节点分类;
- 指标:F1,而不是普通单标签 accuracy;
- 数据:训练、验证、测试由多张图组成。
图分类:MUTAG + GIN
- 每张分子图对应一个标签;
- GIN 在节点层做消息传递;
global_add_pool(x, batch)把节点表示变成图表示;- 图级 logits 与
data.y计算交叉熵。
图分类:PROTEINS + GraphMultisetTransformer
源代码组合 GCNConv 与 GraphMultisetTransformer,说明图级 readout 不只可以使用简单 sum/mean pooling,也可以使用可学习的集合聚合。
链路预测:Cora
- 使用
RandomLinkSplit划分正边; - 训练时进行 negative sampling;
- 编码器生成节点表示;
- 解码器对节点对打分;
- 使用 ROC-AUC 等排序指标。
必须避免把验证/测试正边泄漏进训练图结构或负采样集合。
无监督 GraphSAGE
源代码用 LinkNeighborLoader 生成局部训练样本,通过边目标训练编码器,再用 Logistic Regression 或 SGDClassifier 评估 embedding。这里要分开:
- 表示学习阶段的自监督目标;
- 下游线性评估阶段的标签使用;
- 采样图与评估图的边界。
有向图:DGCN
PYGsgd 下的两个脚本使用 torch_geometric_signed_directed:
dgcn_node.py:半监督节点分类;dgcn_link.py:链接方向/边分类。
有向图不能总是先无向化。入邻居、出邻居、方向特征和任务标签可能都携带信息。
7. 图分类 benchmark 的工程分层
本地 PDF《大模型辅助编程-图分类任务》记录了把已有训练脚本迁入统一 benchmark 的思路,可归纳为:
flowchart TB
C[Config<br/>model / task / data 参数] --> T[Task]
D[Dataset<br/>下载 / 处理 / 划分 / 缓存] --> T
M[Model<br/>可选预处理] --> W[Task Wrapper<br/>图级 pooling + 分类输出]
W --> T
T --> R[direct run / hyperparameter tune]
R --> E[按验证集选模并报告测试结果]
值得保留的工程原则:
- 配置、数据、模型、任务流程分离;
- 数据集负责 raw/processed 缓存和 split;
- 图级任务用 wrapper 统一不同模型的输出;
- 多次运行或调参要保证每个 trial 独立初始化模型;
- 以验证集选择 checkpoint,再记录对应测试指标;
- 记录随机种子、数据划分和调参空间。
PDF 中的代码仍有未完成标记和路径耦合,应视作设计记录,不是可直接复用的最终框架。
8. 两份 GNN 示例目录的关系
源目录同时存在:
GNN训练流程代码阅读-官方github-examples:作为官方示例基线;GNN训练流程代码阅读:本地阅读/运行副本,并包含已下载的 Cora、PPI 数据。
逐文件哈希与 diff 显示:
mutag_gin.py、graph_sage_unsup_ppi.py、两个 DGCN 脚本完全相同;- 其余差异主要是加入
KMP_DUPLICATE_LIB_OK、类型检查注释、设备日志; - 本地副本没有形成大量算法改写。
因此笔记中把它们视为“基线 + 本地运行副本”,不重复归纳成两套知识,也不在未确认前删除任何一份。
9. 图任务验收清单
- [ ] 预测对象是节点、边还是图,输出形状与标签一致。
- [ ]
edge_index的方向、重复、自环和无向化策略明确。 - [ ] 图切分或边切分没有泄漏。
- [ ] mini-batch 图任务正确使用
batch和图级 pooling。 - [ ] 节点任务只在训练 mask 上计算训练损失。
- [ ] 负采样不会采到真实正边。
- [ ] 指标匹配任务:accuracy、F1、ROC-AUC 等口径清楚。
- [ ] 数据预处理缓存与代码版本一致。
- [ ] 大图训练说明是否使用邻居采样及其 fanout。
- [ ] 有向图任务说明是否保留方向信息。
来源映射
PYG\PYG.mdPYG\GCN.md/PYG\GCN.ipynbPYG\Cora数据集加载.mdPYG\pygstudy.ipynbGNN训练流程代码阅读\GNN训练流程代码阅读-官方github-examples\本科benchmark3.14.md大模型辅助编程-图分类任务.pdf- PyG
Data文档 - PyG
GCNConv - PyG 创建消息传递网络
- PyG 数据集速查表