神经网络在过去的十年里取得了巨大的成功,然而早期的神经网络变体只能使用规则结构的数据或欧几里得数据(Euclidean data)来实现,而现实世界中的大量数据具有底层的非欧几里得(Non-Euclidean)图结构(Graph structures)。图神经网络(Graph Neural Networks)的出现解决了图数据结构的不规则性(Non-Regularity)问题,而图卷积网络 (GCN)就是最基本的图神经网络变体之一。在这篇文章中我们将由浅入深的介绍GCN的实现原理。
图 - Graph
由于图(Graph)的独特功能可以捕获数据之间的结构关系,它被广泛应用于各种领域,从社交网络分析,生物信息学到计算机视觉,许多现实生活中的问题都可以用图来表示,这里列举了2021年最热门的一些图神经网络的应用, 感兴趣的可以了解一下。
什么是图,数据如何通过图来表示?
图(Graph)包含着节点(node)信息,边(edge)信息,全局(global)信息,是一种数据结构,它可以表示一组或多组对象以及对象之间的关系和连接(connection)。图1给出了几个可以用图(Graph)表示信息的例子,图1中红色的图(Graph)可以看作是一个社交网络的表示,其中人物(Peter, Mary...)可以看作是图的节点(Node),人物之间的关系(friend, brothers...)可以看作是图的边(Edge),而全局信息可以是这个社交网络涉及的人数或者关系的类型数量。这些信息集合在一起,形成了一个图(Graph)。而我们的图神经网络就是基于这样的一张图实现的,通过不断学习图的信息来完成任务。
什么样的问题或任务需要用到图(Graph)数据结构?
我们已经知道如何用图来表示信息了,接下来我们需要知道要使用这些图数据来做什么类型的预测任务。当前基于图实现的预测主要分为以下几类:
- 节点分类(Node classification): 预测给定节点的类型以及属性,一个标签对应一个节点
- 关联预测(Link prediction): 预测两个节点是否连通以及节点之间的连接关系
- 社区检测(Community detection): 识别连接紧密的节点集群, 揭示网络聚集行为
- 网络相似性(Network similarity): 两个(子)网络的相似程度
- 图级任务(Graph-level task): 预测整个图的属性,一个标签对应一个图
当前应用比较多的是关联预测(Link prediction),也叫做链路预测。在推荐系统的构建中常常用到它。关联预测也经常在社交网络中用于向用户推荐朋友,除此之外它也经常被用来预测犯罪关联。
图神经网络 (GNN)
要想理解GCN,我们首先需要了解和学习GNN相关的一些基础和原理,因为GCN实际上是基于GNN做了一些改变。文章的开头我们提到很多神经网络如CNN面向的图像数据和RNN面向的文本数据的格式都是固定的。因此面对本身结构、彼此关系都不固定的节点特征,我们必须要借助图结构来表征它们的联系。而GNN面向的输入对象就是这些结构不规则、不固定的数据结构。
对于一张输入的图(Graph),节点信息,边的信息,整张图的全局信息都可以被编码成特征向量,这些特征可以被GNN提取然后用于分类等任务,所以实际上GNN依然会像CNN那样做提取特征的工作,只是方式不同。
邻接矩阵(Adjacency Matrix)
对于图神经网络来说,邻接矩阵是非常重要的一个概念。它可以将图的连通性形象的表示出来,节点与节点之间是否有边相连接,通过这个矩阵我们就可以知道。那么邻接矩阵一般怎么生成呢?
以下图(图2)为例,我们将原始图像(Image)视为具有图像通道的矩形网格(图2中最左)。在图问题中,我们可以将图像(Image)看作是具有规则结构的图(Graph)的另一种方式,其中每个像素代表一个节点,并通过边缘连接到相邻像素(图2中最右)。每个非边界像素恰好有 8 个邻居,每个节点存储的信息是一个 3 维向量,表示该像素的 RGB 值。最终我们就会得到最右边的图(Graph)。需要注意的是,一般问题中生成的图(Graph)不会是如此规则的。有了Graph之后我们就知道了所有节点的连接关系,我们就可以生成图2中间的邻接矩阵。邻接矩阵的大小取决于节点的个数,N个节点,邻接矩阵就是N x N的大小。如果节点间有一条边相连,那么对应的矩阵里的格子就是蓝色,不相连就是白色,一般用1和0表示,1就是相连,0是不相连。
聚合操作 & 特征更新
GNN的输入一般是所有节点的起始特征向量和表示节点间连接关系的邻接矩阵。聚合操作和节点特征更新是图神经网络的核心操作。以图3为例,我们首先考虑A节点,聚合操作会将当前节点A的邻居节点信息乘以系数聚合起来加到节点A身上作为A节点信息的补足信息,当作一次节点A的特征更新。对图中的每个节点进行聚合操作,更新所有图节点的特征。通过不断交换邻域信息来更新节点特征,直到达到稳定均衡,此时所有节点的特征向量都包含了其邻居节点的信息,然后我们就能利用这些信息来进行聚类、节点分类、链接预测等等。不同的GNN有不同的聚合函数,可根据任务的不同自由选择,这里举的只是一个很简单的例子,重点是要明白我们需要用到什么信息需要做什么操作,做这些操作的目的是什么。一次图节点聚合操作和权重学习,可以理解为一层神经网络,后面再重复进行聚合、加权,就是多层迭代了。一般GNN只要3~5层就可以学习到足够的信息,所以训练GNN对算力要求很低。注意, GNN 不会更新和改变输入图(Input Graph)的结构和连通性,所以我们可以用与输入图相同的邻接矩阵和相同数量的特征向量来描述 GNN 的输出图(Output Graph),输出的图只是更新了每个节点的特征。
图卷积网络 (GCN)
论文地址: Semi-Supervised Classification with Graph Convolutional Networks
上一段我们介绍了GNN的原理,实际上在GCN中我们也同样需要进行聚合操作和特征更新,也同样需要用到邻接矩阵,那么GCN和GNN有什么不一样呢?图3中我们知道在聚合邻居信息时需要给邻居的信息乘上一个系数再进行相加,GNN中这些系数(a, b, c...)的设定是没有规则的,是初始随机设定然后在训练过程中不断学习的。但是GCN提出解决了a,b,c这些系数的设定问题,下面我们来看一下GCN的基本思路。
首先,我们先了解一些关于GCN的数学概念:
图中提到的矩阵都是重要的GCN输入,我们需要用它们来提取节点的特征然后做聚合和更新。其中度矩阵我们还没有解释,它实际上表示了每个节点邻居的数量,有多少度数也就是有多少个节点与它相连。例如A节点只有一个邻居,那么它的度就是1,相应矩阵上的值就是1,度矩阵只有对角线上有值。
接下来,我们需要理解A矩阵和X矩阵相乘的含义,因为它们的相乘代表了GCN的聚合操作。以图5为例,观察邻接矩阵的第一行,我们看到节点 A 与 E 有一个连接。相乘之后,结果矩阵的第一行是 E 的特征向量。同样,结果矩阵的第二行是 D 和 E 的特征向量之和。通过将A和X相乘,我们可以得到所有邻居向量的和。
但如果只是简单的这样做来得到邻居信息的聚合,会出现两个问题:
- 我们没有包含节点本身的特征。结果矩阵也应该包含节点本身的特征。
- 我们需要取平均值或者邻居的特征向量的加权平均值,而不是 sum() 函数把这些信息全部加起来。原因是在使用 sum() 函数时,度数高的节点可能会对度数低的节点的更新有很大的影响,而实际上如果一个度数低的节点在特征更新的过程中加入了全部的度数高的节点信息,这是不合理的(图6)。此外,神经网络对输入数据的规模很敏感。因此,我们需要对这些向量进行归一化以消除潜在问题。
对于第一个问题:
对于第二个问题
我们现在得到的就是加权平均值,我们这里做的是对度数低的节点增加权重,减少度数高的节点的影响。这种加权平均的想法是,我们假设低度节点对其邻居产生更大的影响,而高度节点产生的影响较小,因为它们将影响分散在太多的邻居身上。到这一步,归一化已经算完成了,但在论文中作者最后提出的归一化公式其实是对D开了根号并在A两侧都进行了相乘(图10)。但在实际情况的代码中,用到的归一化还是(A)比较多,因为实验发现其实用哪种归一化公式,性能的差别不会太大。
最后我们来看一下GCN的公式
这里的Ã实际上已经是归一化之后的Ã了,也就是说 。同样的,一次聚合更新操作代表GCN的一层。层数是节点特征可以行进的最远距离。例如,使用 1 层 GCN,每个节点只能从其邻居那里获取信息。收集信息过程独立进行,所有节点同时进行。当在第一层之上堆叠另一层时,我们重复收集信息过程,但这一次,邻居已经有了关于他们自己邻居的信息(来自上一步)。因此,根据我们认为节点应该从网络中获取信息的程度,我们可以为设置相应的层数。但一般通过 6-7 层,我们几乎可以得到了整个图,这使得聚合变得不那么有意义。因为节点每更新一次,感受野就变大一些,如果网络太深,那么每个节点就会受无关节点的影响,效果反而下降。
参考文献:
[1] Graph Convolutional Networks (GCN)
[2] A Gentle Introduction to Graph Neural Networks
[3] GNN的理解与研究