图卷积网络(GCN) 2.3.1入门指南:从图数据到节点分类实战

1次阅读
没有评论

共计 2503 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

为什么需要图卷积网络?

传统深度学习模型(如 CNN、RNN)假设数据是欧几里得空间的规则结构,但现实中的社交网络、分子结构、知识图谱都是非欧几里得的图数据。这类数据有两个核心特点:

图卷积网络 (GCN) 2.3.1 入门指南:从图数据到节点分类实战

  • 节点关系不规则 :每个节点的邻居数量不固定
  • 拓扑信息重要 :连接模式本身包含关键特征

传统方法如手工特征工程或全连接网络难以有效捕捉这些特性,而 GCN 通过邻域聚合机制直接在图结构上操作。

GCN 2.3.1 核心原理

消息传递三要素

  1. 邻居采样 :确定中心节点的 k -hop 邻域范围
  2. 消息函数 :对邻居特征进行线性变换(公式 1):
    $$\text{msg}_j = W \cdot h_j^{(l)}$$
  3. 聚合函数 :常用均值 / 求和 / 最大值聚合(公式 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 空间添加扰动

避坑指南

  1. 邻接矩阵未归一化 :直接使用原始 A 矩阵会导致数值不稳定
  2. 自环遗漏 :忘记添加自连接会丢失节点自身特征
  3. 批量归一化误用 :在图数据上使用 BN 会导致不同图 / 子图间的统计量混乱

延伸思考

  1. 如何处理动态变化的图结构(如社交网络新增关系)?
  2. 当节点特征缺失严重时,如何设计鲁棒的 GCN 模型?
  3. 图注意力机制(GAT)相比 GCN 在哪些场景更有优势?

通过这个实战案例,我们实现了在 Cora 引文网络上的节点分类任务。GCN 的核心优势在于直接利用图结构信息,但实际应用中需要注意层数控制、归一化选择等关键因素。建议下一步尝试在 OGB 标准数据集上测试模型性能。

正文完
 0
评论(没有评论)