共计 2503 个字符,预计需要花费 7 分钟才能阅读完成。
为什么需要图卷积网络?
传统深度学习模型(如 CNN、RNN)假设数据是欧几里得空间的规则结构,但现实中的社交网络、分子结构、知识图谱都是非欧几里得的图数据。这类数据有两个核心特点:

- 节点关系不规则 :每个节点的邻居数量不固定
- 拓扑信息重要 :连接模式本身包含关键特征
传统方法如手工特征工程或全连接网络难以有效捕捉这些特性,而 GCN 通过邻域聚合机制直接在图结构上操作。
GCN 2.3.1 核心原理
消息传递三要素
- 邻居采样 :确定中心节点的 k -hop 邻域范围
- 消息函数 :对邻居特征进行线性变换(公式 1):
$$\text{msg}_j = W \cdot h_j^{(l)}$$ - 聚合函数 :常用均值 / 求和 / 最大值聚合(公式 2):
$$h_i^{(l+1)} = \sigma\left(\sum_{j \in \mathcal{N}(i)} \frac{1}{\sqrt{d_id_j}} \text{msg}_j\right)$$
层间传播公式
考虑自环和归一化的经典实现(公式 3):
$$H^{(l+1)} = \sigma\left(\tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2}H^{(l)}W^{(l)}\right)$$
其中 $\tilde{A}=A+I$ 是带自环的邻接矩阵,$\tilde{D}$ 是度矩阵。
PyTorch Geometric 实战
环境准备
import torch
import torch.nn.functional as F
from torch_geometric.datasets import Planetoid
from torch_geometric.nn import GCNConv
数据加载与预处理
dataset = Planetoid(root='/tmp/Cora', name='Cora')
data = dataset[0]
# 自动处理对称邻接矩阵并添加自环
# 原始特征已存储在 data.x 中
print(f'节点数: {data.num_nodes}, 边数: {data.num_edges}')
print(f'特征维度: {data.num_node_features}, 类别数: {dataset.num_classes}')
模型定义(关键注释版)
class GCN(torch.nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super().__init__()
# 第一层将输入维度降到 hidden_dim
self.conv1 = GCNConv(input_dim, hidden_dim, cached=True)
# 第二层输出类别概率
self.conv2 = GCNConv(hidden_dim, output_dim, cached=True)
self.dropout = 0.5
def forward(self, x, edge_index):
# 第一层 GCN + ReLU
x = F.relu(self.conv1(x, edge_index))
# 防止过拟合
x = F.dropout(x, p=self.dropout, training=self.training)
# 第二层直接输出 logits
return self.conv2(x, edge_index)
训练流程
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = GCN(
input_dim=dataset.num_node_features,
hidden_dim=16,
output_dim=dataset.num_classes
).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)
data = data.to(device)
for epoch in range(200):
model.train()
optimizer.zero_grad()
out = model(data.x, data.edge_index)
# 仅使用有标签的节点计算损失
loss = F.cross_entropy(out[data.train_mask], data.y[data.train_mask])
loss.backward()
optimizer.step()
# 验证集评估
model.eval()
with torch.no_grad():
_, pred = out.max(dim=1)
correct = pred[data.val_mask].eq(data.y[data.val_mask]).sum().item()
acc = correct / data.val_mask.sum().item()
print(f'Epoch: {epoch:03d}, Loss: {loss:.4f}, Val Acc: {acc:.4f}')
关键调优技巧
层数选择陷阱
- 2- 3 层足够处理 Cora 这类小图
- 深层 GCN 会出现过平滑(over-smoothing)问题
归一化方案对比
| 方法 | 公式 | 适用场景 |
|---|---|---|
| 对称归一化 | $D^{-1/2}AD^{-1/2}$ | 大多数同构图 |
| 随机游走归一化 | $D^{-1}A$ | 有向图 |
| 边权缩放 | $A_{ij}/(d_id_j)^{\alpha}$ | 异构图(α 可调) |
小样本增强策略
- 特征增强:添加节点度等统计特征
- 拓扑增强:通过随机游走生成虚拟边
- 对抗训练:在 embedding 空间添加扰动
避坑指南
- 邻接矩阵未归一化 :直接使用原始 A 矩阵会导致数值不稳定
- 自环遗漏 :忘记添加自连接会丢失节点自身特征
- 批量归一化误用 :在图数据上使用 BN 会导致不同图 / 子图间的统计量混乱
延伸思考
- 如何处理动态变化的图结构(如社交网络新增关系)?
- 当节点特征缺失严重时,如何设计鲁棒的 GCN 模型?
- 图注意力机制(GAT)相比 GCN 在哪些场景更有优势?
通过这个实战案例,我们实现了在 Cora 引文网络上的节点分类任务。GCN 的核心优势在于直接利用图结构信息,但实际应用中需要注意层数控制、归一化选择等关键因素。建议下一步尝试在 OGB 标准数据集上测试模型性能。
正文完
发表至: 未分类
近两天内
