常见图神经网络模型:GCN、GAT、GraphSAGE

我们做 ADMET 预测时,分子的拓扑结构是核心信息。怎么把这种结构塞进神经网络?图神经网络(GNN)就是答案。GCN、GAT、GraphSAGE 这三个模型,基本覆盖了八成以上的实用场景。

我个人习惯把 GNN 理解成「消息传递」框架。每个原子就是节点,化学键就是边。节点不断从邻居那收集信息,更新自己的特征。说起来简单,但不同的模型在「怎么聚合邻居信息」上各有各的招。下面我按自己的实践经验,一个一个拆开讲。

4.1 GCN:最经典的“平均池化”

GCN(图卷积网络)是最早被广泛使用的 GNN 模型。它的核心操作就是:把邻居节点的特征取个加权平均,然后跟自身特征合并,再做个非线性变换。

这里有个关键的细节:邻接矩阵的归一化。如果不做归一化,度大的节点(也就是相连原子多的)特征会变得特别大,训练很容易崩。GCN 用了对称归一化的拉普拉斯矩阵,保证节点特征在传播时数值稳定。

在 ADMET 里,我一般把 GCN 当作基线模型。原因是它速度快、参数少,对于小分子数据集(比如几百到几千个分子)基本够用。

我的经验
如果你刚接触图神经网络,先跑一个 GCN 热身。我用它预测过水溶性(logS),两层 GCN + 全局池化,效果就已经超过传统指纹方法了。

下面是 PyTorch Geometric (PyG) 的一个简单 GCN 层示例:

import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv

class GCNModel(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels):
        super().__init__()
        self.conv1 = GCNConv(in_channels, hidden_channels)
        self.conv2 = GCNConv(hidden_channels, out_channels)

    def forward(self, x, edge_index):
        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)
        x = self.conv2(x, edge_index)
        return x

4.2 GAT:学出来的“加权”

GCN 的聚合权重是固定的(根据度计算),但 GAT(图注意力网络)让模型自己去学每个邻居的重要性。这就是注意力机制。

每个节点对邻居的关注度不一样。比如在分子里,某个官能团的原子可能对活性起决定性作用,GAT 能自动给这些原子更高的权重。

我记得有一次项目里,用 GAT 预测 Caco-2 细胞渗透性,它比 GCN 高了 2-3 个百分点的 AUC。为什么?因为渗透性主要取决于分子表面的极性和氢键位点,GAT 学会把注意力集中在这些关键原子上。

避坑指南
我曾经在一个 5 万分子的数据集上训练 GAT,发现 loss 死活不降。查了半天,原来是学习率设得太高,注意力权重在 0 和 1 之间来回震荡。后来把学习率从 0.01 降到 0.001,训练就稳了。

GAT 代码也非常简洁。PyG 里用 GATConv 替换 GCNConv 就行:

from torch_geometric.nn import GATConv

class GATModel(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels, heads=8):
        super().__init__()
        # 多头注意力:每个头学不同关注模式
        self.conv1 = GATConv(in_channels, hidden_channels, heads=heads)
        self.conv2 = GATConv(hidden_channels * heads, out_channels, heads=1)

    def forward(self, x, edge_index):
        x = self.conv1(x, edge_index)
        x = F.elu(x)
        x = self.conv2(x, edge_index)
        return x

4.3 GraphSAGE:能搞定新分子的“归纳”

GCN 和 GAT 都是直推式模型——训练时得知道整个图的结构。但实际中我们经常遇到新分子,它在训练集里没见过。GraphSAGE 专为此设计。它通过采样 + 聚合的方式,对每个节点只采样固定数量的邻居,然后用 Mean、LSTM 或 Pooling 来聚合。

说白了这个模型可以对任意新分子直接做预测,不需要重新训练。这对于高通量 ADMET 筛选非常实用。

我用它做过肝毒性预测,模型规模从 10 万分子扩展到 100 万,只需要重新采样邻居,模型参数完全复用。而 GCN 要重新构建整个邻接矩阵,内存吃不住。

PyG 的 SAGEConv 用法类似:

from torch_geometric.nn import SAGEConv

class GraphSAGEModel(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels):
        super().__init__()
        self.conv1 = SAGEConv(in_channels, hidden_channels)
        self.conv2 = SAGEConv(hidden_channels, out_channels)

    def forward(self, x, edge_index):
        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = self.conv2(x, edge_index)
        return x

4.4 三模型对比

你想想看,真到选模型时,最头疼的就是该用哪个。我根据多年的踩坑经验,整理了一个对比表:

模型聚合方式是否可归纳适用场景典型ADMET任务
GCN度归一化平均否(直推)全图已知的小数据集水溶性、logP
GAT自学习的注意力权重否(直推)需要关注关键原子渗透性、毒性位点
GraphSAGE采样后聚合(均值等)是(归纳)大分子库、增量预测肝毒性、代谢稳定性

4.5 选择建议

嗯,这里要注意:没有万能模型。如果你的数据规模小(<5000分子),GCN 就够了。如果想解释哪些原子对活性贡献大,优先 GAT。如果数据量很大或者需要实时预测新分子,GraphSAGE 是首选。

我个人最常用的搭配是:先用 GCN 做快速原型验证,然后用 GAT 做精细化调优,最终部署时切到 GraphSAGE 以支持增量数据。这套流程在很多工业项目中都跑通了。

核心要点总结
  • GCN:简单、稳定、适合基线
  • GAT:自动学习邻居权重,可解释性好
  • GraphSAGE:归纳式学习,适合大规模动态图
  • 代码层面:PyG 的 Conv 接口统一,换模型只需改一个构造函数
三种图神经网络核心流程对比 GCN: 邻居平均 每层:h_v ← σ(W·mean(h_u)) GAT: 注意力加权 每层:α_uv = softmax(LeakyReLU(...)) GraphSAGE: 采样+聚合 h_v ← σ( W·[h_v, agg(h_N(v))] ) 公共输入:X (原子特征) + edge_index 输出:节点嵌入(用于分类/回归)

你看这个图就清楚了。GCN 和 GAT 是全局一次性传播,GraphSAGE 是采样局部子图。在 ADMET 项目里,我会根据数据量和推理延迟需求在这三者之间切换。