Part 2: Semi-Supervised Learning with Spectral Graph Convolutions
基于图的机器学习是一项艰巨的任务,因为它非常复杂,而且信息结构也很丰富。这篇文章是有关如何使用图卷积网络(GCN)在图上进行深度学习的系列文章中的第二篇,图卷积网络是一种功能强大的神经网络,旨在直接在图上工作并利用其结构信息。我将简要回顾上一篇文章,但您可以在这里找到该系列的其他部分:
在我之前关于GCN的帖子中,我们看到了一个简单的数学框架,用于表达GCN的传播。简而言之,给定N×F⁰特征矩阵X和图形结构的矩阵表示,例如G的N×N邻接矩阵A,GCN中的每个隐藏层都可以表示为Hⁱ= f(Hⁱ⁻1, A))其中H⁰= X,f是传播规则。每一层Hi对应于一个N×Fi特征矩阵,其中每一行是一个节点的特征表示。
我们可以看到传播规则的形式为:
1:f(Hⁱ,A)=σ(AHⁱWⁱ),和
2:f(Hⁱ,A)=σ(D⁻¹HⁱWⁱ),其中Â= A + I,I是单位矩阵,D⁻¹是Â的逆度矩阵。
这些规则通过应用权重W 1和激活函数σ将节点的特征表示计算为节点邻居的特征表示的集合。我们可以通过将上面的传播规则1和2表示为f(Hⁱ,A)= transform(aggregate(A,Hⁱ),Wi)来使聚合和转换步骤更明确,其中:transform(M,Wⁱ)=σ(MWⁱ),aggregate(A,Hⁱ)=AHⁱ;对应于规则1,aggregate(A,Hⁱ)=D⁻¹Hⁱ对应于规则2。
正如我们在上一篇文章中讨论的那样,规则1中的聚合将节点表示为其邻居特征表示的总和,它具有两个明显的缺点:
节点的汇总表示不包括其自身的特征,并且
具有大度数的节点的特征表示将具有较大的值,而具有小度数的节点的值将具有较小的值,这可能导致爆炸梯度问题,并使得使用诸如对特征缩放敏感的随机梯度下降算法很难训练。
为了解决这两个问题,规则2首先给矩阵A的每个节点添加自环(self-loop),然后使用变换后的邻接矩阵Â= A + I进行汇总。接下来,特征表示通过与逆度矩阵D⁻¹相乘进行归一化,将汇总转化为平均值,其中汇总的特征表示的比例对于节点度不变。
在下文中,我将规则1称为求和规则,将规则2称为均值规则。
Kipf和Welling的最新论文提出了使用频谱传播规则来近似频谱图卷积:
与上一篇文章中讨论的求和和均值规则相比,频谱规则仅在聚合函数的选择上有所不同。尽管它与平均规则有些相似,因为它使用提高到负幂的度矩阵D归一化了聚合,但是归一化是不对称的。让我们尝试一下,看看它能做什么。
我们可以理解到目前为止介绍的聚合函数,它们是加权总和,其中每个聚合规则仅在权重选择上有所不同。首先,我们将了解如何将相对简单的求和和均值规则表示为加权和,然后再继续执行频谱规则。
为了查看如何使用求和规则计算第i个节点聚合特征表示,我们看到如何计算聚合中的第i行:
如上面的等式1a所示,我们可以将第i个节点的聚合特征表示计算为矢量矩阵乘积。我们可以将该向量矩阵乘积公式化为简单的加权和,如公式1b所示,其中我们对X中的N行进行求和。
第j个节点在等式1b中的集合中的贡献由A的第i行的第j列的值确定。由于A是邻接矩阵,所以如果第j个节点是第i个节点的邻居,则该值为1 ,否则为0。因此,等式1b对应于对第i个节点的邻居的特征表示求和。这证实了上一篇文章的直观结论。
总之,每个邻居的贡献仅取决于定义好的邻接矩阵A的邻居。
为了查看均值规则如何聚合节点表示,现在再次使用均值规则来查看聚合中的第i行是如何计算的。为简单起见,我们仅考虑“原始”邻接矩阵上的均值规则,而无需在A和单位矩阵I之间进行相加,后者仅对应于向图添加自环。
从上面的方程式可以看出,现在的推导要稍微长一些。现在,在等式2a中,我们首先将邻接矩阵A与度矩阵D的逆矩阵相乘,以进行变换。在等式2b中,此计算更加明确。逆度矩阵是对角矩阵,其中沿对角线的值是逆矩阵节点的度。位置(i,i)上的值是第i个节点的逆矩阵的度数。
如公式2e所示,我们现在再次对邻接矩阵A中的N行中的每行求和。如在求和规则的讨论中所述,这相当于对第i个节点的邻居进行求和。但是,现在可以保证公式2e中的加权总和中的权重与第i个节点的度之和为1。因此,等式2e对应于第i个节点的邻居的特征表示上的平均值。
求和规则仅取决于邻接矩阵A的邻域,而均值规则也取决于节点的度。
现在,我们有了一个有用的框架来分析频谱规则。让我们继续探索吧!
与均值规则一样,我们使用度矩阵D变换邻接矩阵A。但是,如等式3a所示,我们将度矩阵提高到-0.5的幂,并在A的每边乘以它。如等式3b所示分解。再次回想一下,度矩阵(及其幂)是对角线的。因此,我们可以进一步简化公式3b,直到达到公式3d中的表达式。
公式3d展示了一些非常有趣的东西。在计算第i个节点的集合特征表示时,我们不仅要考虑第i个节点的度,还要考虑第j个节点的度。
与均值规则相似,频谱规则将聚合s.t归一化。聚合特征表示与输入特征大致保持相同的比例。但是,如果频谱规则的度数量较少,则它们在加权总和中的权重会更高,而如果度的数量较多,则其权重较低。当低度邻居比高度邻居提供更多有用的信息时,这可能是比较有用的。
除了频谱规则外,Kipf和Welling还演示了如何将GCN用于半监督分类。在半监督学习中,我们希望同时使用带标签和未带标签的示例。到目前为止,我们已经隐式地假定整个图都是可用的。换句话说,我们知道所有节点,但不是所有节点标签。
在我们看到的所有规则中,我们在节点邻域上进行聚合,因此共享邻居的节点往往具有相似的特征表示。如果图表现出同质性,即连接的节点趋于相似(例如具有相同的标签),则此属性非常有用。同质性发生在许多真实的网络中,尤其是社交网络表现出很强的同质性。
正如我们在前一篇文章中看到的,仅通过使用图结构,即使是随机初始化的GCN也可以在同构图中的节点的特征表示之间实现良好的分离。我们可以通过在标记节点上训练GCN,通过更新在所有节点之间共享的权重矩阵,将节点标签信息有效地传播到未标记节点,来进一步迈出这一步。可以按以下步骤进行:
让我们看看频谱规则是如何使用半监督学习将有标签节点的信息传播到没有标签节点的。与上一篇文章一样,我们将以Zachary的空手道俱乐部为例。
如果要继续学习,可以在此处找到数据集以及Jupyter笔记本,其中包含用于训练和评估GCN的代码。
简而言之,Zachary的空手道俱乐部是一个小型社交网络,其中空手道俱乐部的管理员和教练之间会发生冲突。任务是预测空手道俱乐部每个成员选择他们中的哪一方。可以在下面看到网络的图形表示。每个节点代表空手道俱乐部的成员,成员之间的链接表示他们在俱乐部外进行互动。管理员和教练分别标有A和I。
本文基于MXNet实现频谱规则,MXNet是一个易于使用且高效的深度学习框架。实现如下:
class SpectralRule(HybridBlock):
def __init__(self,
A, in_units, out_units,
activation, **kwargs):
super().__init__(**kwargs)
I = nd.eye(*A.shape)
A_hat = A.copy() + I
D = nd.sum(A_hat, axis=0)
D_inv = D**-0.5
D_inv = nd.diag(D_inv)
A_hat = D_inv * A_hat * D_inv
self.in_units, self.out_units = in_units, out_units
with self.name_scope():
self.A_hat = self.params.get_constant('A_hat', A_hat)
self.W = self.params.get(
'W', shape=(self.in_units, self.out_units)
)
if activation == 'ident':
self.activation = lambda X: X
else:
self.activation = Activation(activation)
def hybrid_forward(self, F, X, A_hat, W):
aggregate = F.dot(A_hat, X)
propagate = self.activation(
F.dot(aggregate, W))
return propagate
现在我们已经实现了频谱规则,我们可以将这些层彼此堆叠。我们使用类似于上一篇文章的两层体系结构,其中第一个隐藏层具有4个单元,第二个隐藏层具有2个单元。这种体系结构使可视化生成的二维嵌入变得容易。它与上一篇文章中的体系结构在三个方面有所不同:
def build_model(A, X):
model = HybridSequential()
with model.name_scope():
features = build_features(A, X)
model.add(features)
classifier = LogisticRegressor()
model.add(classifier)
model.initialize(Uniform(1))
return model, features
我已经将包含图卷积层的网络的特征学习部分划分为特征组件,将分类部分划分为分类器组件,单独的特征组件更容易可视化激活层。 LogisticRegressoras是一个分类层,该层通过对最后一个图卷积层提供的每个节点的特征求和并对其执行sigmoid函数来执行逻辑回归。
您可以在随附的Jupyter笔记本中找到用于构建功能组件的代码和LogisticRegressor的代码。
可以在下面看到用于训练GCN模型的代码。简而言之,我初始化了一个二元交叉熵损失函数cross_entropy,以及一个SGD优化器(训练器)来学习网络参数。然后,针对指定的周期数训练模型,其中针对每个训练示例计算损失,并使用loss.backward()向后传播误差。然后调用trainer.step来更新模型参数。在每个周期之后,由GCN层构造的特征表示都存储在feature_representations列表中,我们将在稍后进行检查。
def train(model, features, X, X_train, y_train, epochs):
cross_entropy = SigmoidBinaryCrossEntropyLoss(from_sigmoid=True)
trainer = Trainer(
model.collect_params(), 'sgd',
{'learning_rate': 0.001, 'momentum': 1})
feature_representations = [features(X).asnumpy()]
for e in range(1, epochs + 1):
for i, x in enumerate(X_train):
y = array(y_train)[i]
with autograd.record():
pred = model(X)[x] # Get prediction for sample x
loss = cross_entropy(pred, y)
loss.backward()
trainer.step(1)
feature_representations.append(features(X).asnumpy())
return feature_representations
至关重要的是,仅标记了教练和管理员的标签,并且网络中的其余节点是已知的,但未标记! GCN可以在图卷积期间找到标记和未标记节点的表示形式,并且可以在训练期间利用两种信息源来执行半监督学习。
具体来说,在GCN中进行半监督学习是因为它通过聚合节点的标记邻居和未标记邻居生成节点的潜在特征表示。在训练期间,我们然后反向传播交叉熵损失,以更新所有节点之间共享的权重。但是,这种损失取决于标记节点的潜在特征表示,而标记节点的潜在特征表示又取决于标记节点和未标记节点。因此,这是一个半监督学习。
如上所述,存储了每个时期的特征表示,这使得我们可以看到训练过程中特征表示的变化。下面,我考虑两个输入特征表示。
在第一个表示中,我们仅使用稀疏的34×34单位矩阵I作为特征矩阵X,即图中每个节点都用 one-hot编码。此表示形式的优点是可以在任何图形中使用,但是会导致网络中每个节点的输入参数需要大量的内存和计算能力才能在大型网络上进行训练,并且可能导致过拟合。幸运的是,空手道俱乐部网络很小。使用此表示,网络训练了5000个周期。
通过对网络中的所有节点进行统一分类,我们可以得出上面所示网络中的错误分布。在此,黑色表示分类错误。尽管将近一半(41%)的节点被错误分类,但是与管理员或教练员(但不是同时存在!)紧密联系的节点往往被正确分类。
如上图所示,我已经说明了特征表示在训练过程中如何变化。这些节点最初紧密地聚集在一起,但是随着训练的进行,教练和管理员被拉开了,并拖着一些节点。
尽管为管理员和教练提供了完全不同的表示形式,但是他们拖曳的节点不一定属于他们的社区。这是因为图卷积在特征空间中将紧密共享邻居的节点嵌入在一起,但是共享邻居的两个节点可能无法平等地连接到管理员和教练。特别地,使用单位矩阵作为特征矩阵导致每个节点有很强的局部表示,即,属于图的相同区域的节点可能紧密地嵌入在一起。这使得网络难以以归纳的方式在远距离之间共享信息。
我们将通过添加两个特定于网络的任何节点或区域的特征来改善表示形式1,这些表示可衡量与管理员和教师的关联性。为此,我们计算了从网络中每个节点到管理员和教练的最短路径距离,并将这两个特征连接到先前的表示形式。
由于我们注入了有关图中每个节点位置的全局信息,因此可能会有点“作弊”的感觉。信息应该被图卷积中的特征组件(理想地)捕获。但是,图卷积层始终具有局部视野,并且捕获此类信息的能力有限。尽管如此,它还是GCN的有用工具。
和以前一样,我们对网络中的所有节点进行了分类,并绘制了上面显示的网络中错误的分布图。这次,只有四个节点被错误分类;对表示1的重大改进!在仔细检查特征矩阵后,这些节点与教练和管理员等距(在最短路径上),或者更接近管理员,但属于教练社区。 GCN使用表示2训练了250个周期。
如上图所示,这些节点最初再次非常紧密地聚集在一起,但是在训练甚至开始之前就被分成了一些社区!随着训练的进行,社区之间的距离越来越大。
在这篇文章中,我对如何在GCN中进行汇总进行了深入的说明,并展示了如何使用均值,总和和频谱规则作为示例将其表示为加权总和。我真诚的希望是,您将发现此框架对考虑在您自己的图卷积网络中进行聚合时可能需要的权重很有用。
我还展示了如何在MXNet中实施和训练GCN,以频谱图卷积和Zachary的Karate Club作为简单的示例网络对图形进行半监督分类。我们看到了仅使用两个标记节点,GCN仍然有可能在表示空间中实现两个网络社区之间的高度隔离。
尽管有更多关于图卷积网络的知识,我希望将来有时间与您分享,但这是(目前)该系列的最后一篇文章。如果您有兴趣进一步阅读,我想以以下论文作为结尾,这些论文我觉得很有趣:
1:Inductive Representation Learning on Large Graphs
汉密尔顿(Hamilton)等人在本文中提出了几个新的聚合函数,例如,使用最大/平均池或多层感知器。此外,他们还提出了一种简单的方法来对GCN进行小批量训练,从而大大提高了训练速度。
2:FastGCN: Fast Learning with Graph Convolutional Networks via Importance Sampling
Hamilton等人提出的小批量方法的一个缺点是,由于递归,批处理中节点的数量在执行的聚合数量中呈指数增长。陈等等人提出了他们的FastGCN方法,该方法通过独立地执行图卷积层的批量训练来解决此缺点。
3:N-GCN: Multi-scale Graph Convolution for Semi-supervised Node Classification
在FastGCN解决训练递归图卷积网络问题的地方,N-GCN挑战了GCN根本需要递归的前提! Abu-El-Haija等。取而代之的是提出一种具有多个(N)个GCN的扁平架构,其输出串联在一起。每个GCN会捕获不同距离的邻居(基于随机游走语义),从而避免了递归聚合。