邻居采样概述

在Colab中打开 GitHub

在之前的教程中,您已经学习了如何通过计算图上所有节点的表示来训练GNNs。然而,有时您的图太大,无法在单个GPU上计算所有节点。

在本教程结束时,您将能够

  • 理解随机GNN训练的流程。

  • 了解什么是邻居采样以及为什么它为每个GNN层生成一个二分图。

消息传递回顾

回想一下,在Gilmer 等人的研究中,消息传递的公式如下:

\[m_{u \to v}^{(l)} = M^{(l)}\left(h_v^{(l-1)}, h_u^{(l-1)}, e_{u \to v}^{(l-1)}\right)\]
\[m_{v}^{(l)} = \sum_{u \in \mathcal{N}(v)} m_{u \to v}^{(l)}\]
\[h_v^{(l)} = U^{(l)}\left(h_v^{(l-1)}, m_v^{(l)}\right)\]

其中DGL调用 - 消息函数: \(M^{(l)}\) - 归约函数: \(\sum\) - 更新函数: \(U^{(l)}\)

请注意,这里的\(\sum\)可以代表任何函数,并不一定是求和。

本质上,单个节点的第\(l\)层表示依赖于同一节点的第\((l-1)\)层表示,以及相邻节点的第\((l-1)\)层表示。这些第\((l-1)\)层表示又依赖于这些节点的第\((l-2)\)层表示,以及它们的邻居。

以下动画展示了2层GNN如何计算节点5的输出:

image1

你可以看到,为了从第二层计算节点5,你将需要其直接邻居的第一层表示(用黄色标记),这又需要它们的直接邻居(即节点5的第二跳邻居)的表示(用绿色标记)。

邻居采样概述

你也可以从前面的例子中看到,计算少量节点的表示通常需要输入大量节点的特征。由于输入特征所需的节点很容易覆盖图的大部分,特别是对于现实世界中的图,这些图通常是无标度的,因此为消息聚合获取所有邻居通常成本太高。

邻居采样通过选择一部分邻居来执行聚合,从而解决了这个问题。例如,要计算 \({h}_5^{(2)}\),你可以选择两个邻居而不是所有邻居来进行聚合,如下面的动画所示:

image2

你可以看到,这种方法在单个小批量的消息传递中使用的节点要少得多。

您还可以在上面的动画中注意到,动画中的计算依赖关系可以描述为一系列二分图。输出节点(称为目标节点)位于一侧,所有必要的输入节点(称为源节点)位于另一侧。箭头表示采样的邻居如何将消息传播到节点。DGL称此类图为消息流图(MFG)

请注意,一些GNN模块,例如SAGEConv,需要使用上一层的目标节点特征来计算输出。在不失一般性的情况下,DGL始终将目标节点本身包含在源节点中。