第1章:层数与深度——GNN过平滑问题的根源
说实话,我刚接触图神经网络那会儿,踩过最大的坑就是——层数堆得越多,效果反而越差。
我当时接了一个社交网络节点分类的任务。直觉告诉我,层数越多,模型能看到的邻居信息越广,效果应该越好。结果呢?3层以内效果稳步提升,到了第4层开始下滑,第5层直接崩了。所有节点的表示几乎一模一样,分类器完全没法区分。
这就是我们今天要聊的核心问题——过平滑(Over-smoothing)。
1.1 什么是过平滑?
过平滑,说白了就是:随着GNN层数增加,不同节点的特征表示变得越来越相似,最终趋于一致。
为什么会这样?
你想想看,GNN每一层都在做消息传递——每个节点聚合邻居的信息。一层聚合1跳邻居,两层聚合2跳邻居。当层数足够多时,每个节点都能看到整个图的信息。如果图是连通的,所有节点的感受野最终会覆盖全图,它们的表示自然就趋同了。
核心结论:过平滑不是bug,是GNN消息传递机制的必然结果。层数越深,节点区分度越低。
我在一个分子性质预测项目里遇到过类似情况。当时用了一个6层的GCN,结果所有分子的表示几乎一样,模型完全学不到结构差异。后来我把层数降到3层,效果反而提升了15%。
1.2 过平滑的数学直觉
咱们不搞太复杂的公式,我直接说直觉。
GNN每一层的更新可以简化为:
h_v^(k+1) = σ( W * MEAN( h_u^(k) for u in N(v) ∪ {v} ) )
每一层都在做平滑操作——把节点自身的特征和邻居的特征做平均。一次平均还好,两次也还行,但十次八次平均下来,所有节点都长得差不多了。
这就像你往一杯咖啡里加牛奶,加一次还能尝出咖啡味,加十次就变成牛奶了。
我的经验:对于大多数图数据集,2-3层GNN已经足够捕获局部结构信息。超过4层,过平滑风险急剧上升。
1.3 残差连接——给深层GNN续命
残差连接(Residual Connection)最早来自ResNet,后来被引入GNN。它的思路很简单:
每一层的输出,不只是当前层的计算结果,还要加上前一层的输入。
h_v^(k+1) = GNNLayer( h_v^(k) ) + h_v^(k)
这样做的好处是什么?
- 保留原始特征:即使深层做了大量平滑,节点仍然保留了一部分初始特征
- 梯度流通:反向传播时,梯度可以直接跳过中间层,缓解梯度消失
我记得有一次做蛋白质结构预测,用了5层GNN,不加残差连接时训练loss死活降不下去。加上残差连接后,loss直接腰斩。嗯,这个技巧真的很实用。
注意:残差连接不是万能的。它只能延缓过平滑,不能完全消除。当层数超过10层时,即使有残差连接,过平滑依然会出现。
1.4 跳跃连接——让浅层信息直达深层
跳跃连接(Skip Connection)比残差连接更进一步。它不只是连接相邻层,而是把前面所有层的输出都拼接到当前层。
常见的做法有两种:
- Concatenation方式:把前面所有层的表示拼起来,作为当前层的输入
- 加权求和方式:给每一层分配一个可学习的权重,然后加权求和
# 跳跃连接的伪代码示例
def forward(self, x, adj):
h = [x] # 保存每一层的输出
for layer in self.layers:
x = layer(x, adj)
h.append(x)
# 把前面所有层的输出拼起来
x = torch.cat(h, dim=-1)
return x
跳跃连接的好处很明显:浅层的局部信息可以直接传递到深层,避免了中间层的过度平滑。我在做图分类任务时,用跳跃连接后,模型对图结构的敏感度明显提升了。
1.5 DeepGCN策略——把CNN的经验搬到GNN上
DeepGCN是2019年提出的一套策略,核心思想是:把CNN中成功的深度网络设计经验,迁移到GNN上。
它主要包含三个组件:
| 组件 | 作用 | 我的评价 |
|---|---|---|
| 残差连接 | 缓解梯度消失,保留初始特征 | 基础必备,建议所有深层GNN都加 |
| 密集连接 | 每一层都连接到后面所有层 | 效果很好,但显存消耗大 |
| 膨胀卷积 | 扩大感受野,不增加参数量 | 适合图结构稀疏的场景 |
DeepGCN最让我印象深刻的是,它能把GNN堆到56层而不出现过平滑。这在以前是不敢想的。
我曾经在一个点云分类任务上试过DeepGCN,56层的模型比3层的模型准确率高了将近8个点。当然,训练时间也长了10倍。这是个trade-off,你得自己权衡。
1.6 知识体系总览
下面这张图,是我梳理的本章知识结构。你可以把它当作一个快速索引:
1.7 避坑指南
最后,分享几个我踩过的坑,希望能帮你少走弯路:
- 不要盲目堆层数:我曾经以为层数越多越强大,结果被过平滑狠狠教育了一顿。先试2-3层,效果不够再加。
- 残差连接不是银弹:它只能延缓过平滑,不能根治。超过10层该崩还是崩。
- 跳跃连接注意显存:把所有层的输出都拼起来,显存消耗是线性增长的。大图上要谨慎。
- DeepGCN适合特定场景:点云、分子图这类任务效果好,但社交网络这种稠密图不一定。
我的建议:刚开始做GNN项目时,从2层起步,用验证集调参。如果发现深层效果反而变差,先检查过平滑,再考虑加连接策略。别一上来就上56层,那是给有经验的人玩的。
好了,这一章的内容就到这里。层数与深度这个话题,说白了就是平衡——平衡感受野和区分度,平衡深度和过平滑。下一章我们会聊另一个让GNN头疼的问题:过拟合与正则化。到时候见。
公众号:蓝海资料掘金营,微信deep3321