引言
图(Graph)是一个常见的数据结构,现实世界中有很多很多任务可以抽象成图问题,比如社交网络,蛋白体结构,交通路网数据,以及很火的知识图谱等,甚至规则网络结构数据(如图像,视频等)也是图数据的一种特殊形式。针对graph的研究可以分成三类:
1.简单的graph算法:如生成树算法,最短路算法,复杂一点的二分图匹配,费用流问题等等;
2.概率图模型:将条件概率表达为图结构,并进一步挖掘,典型的有条件随机场等;
3.图神经网络:研究图结构数据挖掘的问题,典型的有graph embedding,graph CNN、GNN等。
在前面几篇笔记中,我介绍了DeepWalk、LINE、SDNE、node2vec、struc2vec五种graph embedding算法,这其中有用网络结构进行优化的,也有直接从概率统计上接入NLP的skip-gram进行嵌入的,这里回顾一下embedding的含义,就是将一个空间的点映射到另一个空间,通常是从高维抽象的空间映射到低维的具象空间。本质上是一种映射函数,具体的可以参考我之前写的deepwalk和node2vec介绍,都是在开头重提了embedding的作用以及原因。
node2vec:CS224W课程学习笔记(四):node2vec算法原理与说明
deepwalk:CS224W课程学习笔记(三):DeepWalk算法原理与说明
以及我上一篇中的链接3,这些在Stanford的助教笔记中,都是被叫做浅层编码器,即虽然他们都基于前者解决了一些问题,但都有共同的局限性,即:
- 浅编码器无法缩放,因为每个节点都有唯一的嵌入。
- 浅层编码器具有固有的传导性。它只能为单个固定图生成嵌入。
- 不考虑节点的特征。
- 不能将浅层编码器推广到具有不同损失函数的训练中。
而自2017年推出的GCN(Graph convolutional Networks,图卷积网络)解决了这种限制。
课程笔记与工具
课程链接与相关工具介绍
斯坦福原版视频 |
https://www.youtube.com/watch?v=F3PgltDzllc&list=PLoROMvodv4rPLKxIpqhjhPgdQy7imNkDn&index=17
https://www.youtube.com/watch?v=tutlI9YzJ2g&list=PLoROMvodv4rPLKxIpqhjhPgdQy7imNkDn&index=18
…
https://www.youtube.com/watch?v=buzsHTa4Hgs&list=PLoROMvodv4rPLKxIpqhjhPgdQy7imNkDn&index=25
一直到26,如果只是理论,那就是23。
本节课预学习资料与工具 |
SEMI-SUPERVISED CLASSIFICATION WITH
GRAPH CONVOLUTIONAL NETWORKS:https://arxiv.org/pdf/1609.02907.pdf
Convolutional Neural Networks on Graphs
with Fast Localized Spectral Filtering:https://arxiv.org/pdf/1606.09375v3.pdf
Spectral Networks and Deep Locally Connected
Networks on Graphs:https://arxiv.org/pdf/1312.6203.pdf
同济子豪兄的GCN论文批注:
GCN论文精读-同济子豪兄批注.pdf
课程助教笔记:
https://snap-stanford.github.io/cs224w-notes/machine-learning-with-networks/graph-neural-networks
GNN(图神经网络)
图和神经网络
图神经网络是一种神经模型,我们可以直接将其应用于图,而无需事先了解图中的每个组件。GNN 为节点级、边缘级和图级预测任务提供了一种便捷的方法。那么它是如何嵌入网络的?
具体的我这里参照(https://distill.pub/2021/gnn-intro/) 该篇进行讲解。
我们通常将图像视为带有图像通道的矩形网格,将它们表示为数组(例如,244x244x3 float)。另一种将图像视为具有规则结构的图形,其中每个像素代表一个节点,并通过边缘连接到相邻像素。每个无边界像素正好有8个邻居,存储在每个节点上的信息是一个三维向量,表示像素的RGB值。
但这是图像可以这样做,或者说是图像信息更加的密集,对比现在的智能手机已经上了一亿像素,但很多人觉得还是不够,未来肯定还会向着2亿发展。这里博文里举了个例子,即位于25像素的一个笑脸,可以看见如下图所示的中间节点2-2同样是有八个邻居,将这个图像(image)转化为另外两种格式,邻接矩阵以及图(graph),很明显能看到,邻接矩阵的表示形式是稀疏的,而图更能表明图的结构信息:
然后文章中间举了大量的例子去说明图的概念,比如说分子结构的图关系,奥德赛小说以及跆拳道数据集,同样是展开论述上述的三种图,之后以奥德赛人物关系图为例,因为邻接矩阵其实是对称矩阵,那也就是说明改变当前点的关系,那矩阵还是对称的,甚至进一步说,图数据可没有固定的顺序,改变图中节点的位置对最后的图关系没有影响。
上述为改变了奥德赛的一些人物关系位置,但像素点还是相同的,并且依然还是两张相同的邻接矩阵图,可能第一眼觉得此图复杂,于是博文中又引出了以下所有包含 4 个节点的小图的每个邻接矩阵。
那其实正是这种关系,因此提出了GNN。
GNN介绍
GNN 是对图的所有属性(节点、边、全局上下文)的可优化转换,它保持了图对称性(排列不变性)。这里我们可以构建一个最简单的GNN模型,此GNN在图的每个组件上使用单独的多层感知器(MLP),即分别对图的点、边和全局三个向量分别做一次MLP,用不同的映射函数,如下图所示:
但现实是往往很难直接拿到完整的点或者边的信息,可能我们可以获取到所有的边,而缺少了一些点的数据,我们最终的目标是对节点进行预测,所以需要一种方法来从边缘收集信息并将其提供给节点进行预测。这里GNN中提出了和CNN中一样的方式,为pooling,但我看李沐讲解的时候,将该单词说成是聚合,事后查资料的时候,也发现它们语义上是不同的:
- 池化函数一般用在卷积神经网络中,它可以对特征图进行下采样,减少参数数量,防止过拟合,提高模型泛化能力。 池化函数有多种类型,常见的有最大池化(Max Pooling)和平均池化(Average Pooling),它们分别是取某个区域内的最大值或平均值作为输出。
- 聚合函数一般用在图神经网络中,它可以对节点的邻居信息进行聚合,更新节点的特征,实现图卷积。 聚合函数也有多种类型,常见的有求和(Sum)、求平均(Mean)、求最大值(Max)等。
所以有了pooling方法后,我们就可以根据相邻节点的信息与权重算出该点信息:
上述虚线表示哪条边,加上的柱状图表示每个节点存在的权重,通过边的加权,就能知道节点node的特征了。然后再次用GNN做预测,如下图所示:
那其余的全局向量和边的向量也能使用pooling进行聚合,然后同样进行预测,那么对以上内容汇总,整个GNN的过程可以如下图所示:
输入端是一个graph,经过了GNN blocks后,变成了transformed graph,然后拿着这个转换图加一个分类器,这里可以简单加一个FC层的二分类,最后加一层softmax就作为了输出。
但在这个最简单的GNN公式中,我们根本没有在GNN层内使用图的连通性。每个节点都是独立处理的,每个边以及全局上下文也是如此。我们仅在汇集信息进行预测时使用连接性。那我在预测边的时候,能不能学习到点的信息呢?这自然跟CNN都一样,在各个部分加入传递函数,通过pooling聚合当前信息,然后通过更新函数传递,这是目前主流的做法:
上述这种直接加权一次性加入 N + 1 N+1 N+1层,此操作序列是最简单的消息传递GNN层类型。通过将传递GNN层的消息堆叠在一起,节点最终可以合并来自整个图的信息:在三层之后,节点拥有距离它三步之遥的节点的信息。
而因为有传递函数的加入,那么我们也可以将点、边或者全局的特征向量加入各自的下一层进行学习,比如说下图中直接混合调用,那点学到了边,边也学到了点:
所以,以上关于GNN的内容介绍,可以根据wiki的介绍,总结为,通用 GNN 的架构实现了以下基本层:
- Permutation equivariant: Permutation equivariant(置换等变层)将图的表示映射为同一图的更新表示。一般来讲,置换等变层是通过图节点之间的成对消息传递实现的。直观地,在消息传递层中,节点通过聚合从其直接邻居接收的消息来更新它们的表示。因此,每个消息传递层都会将 GNN 的感受野增加一跳。(PS:我去翻了下原文,就wiki上提出这个词的文献中,其实就是上图的layer N+1)
- Local pooling: 局部池化层(local pooling layer,我还是无法将pooling视作聚合…)通过下采样使图形变粗。局部池化用于增加GNN的感受野,其方式类似于CNN中的池化层。例子包括 k-nearest neighbours pooling(k-最近邻池),top-k pooling,和self-attention pooling。(PS:这里可选的方案还有很多,如果去打一场kaggle比赛的话这里只是举个例子)
- global pooling:全局池化层,也称为读出层,提供整个图形的固定大小表示。全局池化层必须是排列不变的,以便图节点和边的顺序排列不会改变最终输出。 例子包括逐元素总和、平均值或最大值。
以上就是一个GNN原理的简单介绍,我基本是在跟着google research这篇文章再一步步递进,因为没有公式,所以原文里做了非常多的图去帮助理解。如果没有读过的话,非常建议去体验一下,会对GNN的发展历程有一个比较清晰的认知。但是深度学习肯定是没那么简单的,或者说cs224w不简单(PS:毛子老师的这口流利的俄式英语听得我毫无感觉,emmm),GNN作为2007年提出来的网络,在2017年,对其进行了完善。再另一篇同样是由google research所写的文章中,提出了主题是——Modern Graph Neural Networks。
图卷积网络(GCN)
GCN其实早在2017年前就有很多的论文对其进行研究了,只不过还没有被统称为GCN,我是直接上手了《Spectral Networks and Deep Locally Connected Networks on Graphs》该篇,发现除了introduction,后面的很多概念都比较模糊,有很多约定俗成的东西,作为一个该方向可能还没入门的人来说,就需要更多的资料去佐证了,于是就回头把原理过了一遍,包括说推导傅里叶和拉普拉斯,但是理解有限,感觉没一定的经验,现在除了抄,写的话可能会把一个简单的东西弄复杂,那跟我写博文的初衷相悖了,所以这里先Mark一下,等真在这领域深耕一段时间了再回头整理一下,下面的内容可能偏向于个人记录,以及我觉得可以标记的一些感受野。
如果要彻底弄懂2017年的论文,那么这里我看到有一个时间线,参考【GNN】万字长文带你入门 GCN
图卷积网络,说白了还是参考CNN卷积这种操作,但我们知道CNN要求的输入为网格结构,并且要求数据在网格中具有平移不变性,这也造就了它的两大特性,为局部连接 + 权值共享(共享卷积核)
,但是在图网络中,很多任务并不是网格结构,即顶点的邻居数量是不固定的。(PS:看上一节中的奥德赛小说图,图种类多样,但都是一种图)
所以因为这个原因的影响,GCN应运而生,在图结构上扩展了卷积的概念并给出了两种构建方式:
- 基于空域的卷积构建
Spatial Construction
:直接在原始图结构上执行卷积。即由图像像元组成的空间。在图像空间中以长度(距离)为自变量直接对像元值进行处理称为空间域处理。 - 基于谱域的卷积构建
Spectral Construction
:对图结构进行傅里叶变换之后,在谱域进行卷积。即以频率(即波数)为自变量描述图像的特征,可以将一幅图像像元值在空间上的变化分解为具有不同振幅、空间频率和相位的简振函数的线性叠加,图像中各种频率成分的组成和分布称为空间频谱。这种对图像的频率特征进行分解、处理和分析称为频率域处理或波数域处理。
如果对上述两种域比较感兴趣的可以参考《数字图像处理》,以及我上面那篇文章,这里就不再引述,我觉得两种方式比较明显的区别就是,空域变换可以直观地显示信号或图像的形状和位置,但不容易分析它们的周期性和频率成分,频域变换可以显示信号或图像的频率分布和振幅,但不容易显示它们的形状和位置,所以很多数字增强方式都是在频域上推导,如图像恢复、图像重建、辐射变换、边缘增强、图像锐化等等。
这里GCN为了引用卷积的性质,也做了很多尝试,比较经典的就是如下三篇论文:
-
第一代图卷积:《Spectral Networks and Deep Locally Connected Networks on Graphs》
-
第二代图卷积:《Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering》
-
第三代图卷积:《Semi-supervised Classification with Graph Convolutional Networks》
下面进行简单介绍。
GCN:Spectral CNN
在最初的空域中,其实不好进行卷积,原因是空域卷积算非常直接的借鉴了图像里的卷积操作,也实现了CNN的权重共享和局部不变性的特点,但却很难实现权重共享,具体的可以看我最后推荐的知乎链接里的推导过程,这里不再引述,那既然很难实现卷积计算,能不能将图转化到另一个空间(频域)来实现卷积操作呢?根据卷积定理,在空域(时域)中的卷积等于在频域中直接相乘:
f
∗
G
g
=
F
−
1
(
F
(
f
)
⋅
F
(
g
)
)
f *_{G} g=F^{-1}(F(f) \cdot F(g))
f∗Gg=F−1(F(f)⋅F(g))
这里 F F F 和 F − 1 F^{-1} F−1 是傅里叶变换和傅里叶逆变换, f ( n ) f(n) f(n)表示空域输入信号, g ( n ) g(n) g(n)表示空域卷积核。我们需要找到一组傅里叶变换的基,将图从空域转到这组基所表示的频域空间。我们通过构建拉普拉斯矩阵来找到一组傅里叶变换的基。其实拉普拉斯矩阵就是下图的拉普拉斯算子:
如图所示,我们构造这样两个矩阵。
度数矩阵
D
D
D (Degree matrix):
D
(
i
,
j
)
=
{
d
i
if
i
=
=
j
0
otherwise
D(i, j)=\left\{\begin{array}{ll} d_{i} & \text { if } \quad i==j \\ 0 & \text { otherwise } \end{array}\right.
D(i,j)={di0 if i==j otherwise
邻接矩阵
A
A
A (Adjacency matrix):
A
(
i
,
j
)
=
{
1
if
i
∈
N
δ
[
j
]
0
otherwise
A(i, j)=\left\{\begin{array}{ll} 1 & \text { if } i \in N_{\delta}[j] \\ 0 & \text { otherwise } \end{array}\right.
A(i,j)={10 if i∈Nδ[j] otherwise
那么拉普拉斯矩阵
L
L
L 就是上述度矩阵与邻接之差,从图中的例子也很容易看出,即:
L
=
D
−
A
L = D - A
L=D−A
那么为什么会选择用拉普拉斯算子去表示呢?或者说作为特征函数。
拉普拉斯算子(Laplacian operator) 的物理意义是空间二阶导,准确定义是:标量梯度场中的散度,一般可用于描述物理量的流入流出。比如说在二维空间中的温度传播规律,一般可以用拉普拉斯算子来描述。
传统的傅里叶变换公式为:
f
^
(
t
)
=
∫
f
(
x
)
exp
−
2
π
i
x
t
d
x
\hat{f}(t)={\int}f(x){\exp}^{-2{\pi}ixt}dx
f^(t)=∫f(x)exp−2πixtdx
这里引用参考文献中一个很“简单”的证明。信号 f ( t ) f(t) f(t) 是与基函数 exp − 2 π i x t {\exp}^{-2{\pi}ixt} exp−2πixt 的积分,在数学上, exp − 2 π i x t {\exp}^{-2{\pi}ixt} exp−2πixt,是拉普拉斯算子 △ \triangle △的本征函数(满足本征方程), ω \omega ω就和特征值有关。
那为什么是特征函数呢?众所周知,特征向量需要满足的定义式是:对于矩阵 A A A,其特征向量满足的条件应是矩阵与特征向量 x x x 做乘法的结果,与特征向量乘标量 λ λ λ 的结果一样,即满足如下等式:
A x = λ x Ax={\lambda}x Ax=λx
稍微推导一下即可知道,拉普拉斯算子作用在 exp − 2 π i x t {\exp}^{-2{\pi}ixt} exp−2πixt 确实满足以上特征向量的定义:
∆ exp − 2 π i x t = ∂ 2 ∂ t 2 exp − 2 π i x t = − 4 π 2 x 2 exp − 2 π i x t ∆{\exp}^{-2{\pi}ixt}=\frac{{\partial}^2}{{\partial}t^2}{\exp}^{-2{\pi}ixt}={-4{\pi}^2x^2}{\exp}^{-2{\pi}ixt} ∆exp−2πixt=∂t2∂2exp−2πixt=−4π2x2exp−2πixt
这里的原理可以参考【机器学习中的数学】基函数与函数空间
但其实还有另一种证明方式,就是用特征方程上来抽象理解。
将拉普拉斯矩阵 L L L 的 n n n 个非负实特征值,从小到大排列为 λ 1 ≤ λ 2 ≤ ⋯ ≤ λ n \lambda_1 \le \lambda_2 \le \cdots \le \lambda_n λ1≤λ2≤⋯≤λn ,而且最小的特征值 λ 1 = 0 \lambda_1=0 λ1=0,因为 n n n维的全1向量对应的特征值为0。
那可得:
L
(
1
1
⋮
1
)
=
0
→
L\left(\begin{array}{c} 1 \\ 1 \\ \vdots \\ 1 \end{array}\right)=\overrightarrow{0}
L
11⋮1
=0
得证。从本征方程的数学理解来看:
L
u
=
λ
u
L u=\lambda u
Lu=λu
在由Graph确定的维空间中,越小的特征值 λ l \lambda_l λl表明:拉普拉斯矩阵 L L L其所对应的基 u l u_l ul上的分量、“信息”越少,那么当然就是可以忽略的低频部分了。
其实图像压缩就是这个原理,把像素矩阵特征分解后,把小的特征值(低频部分)全部变成0,PCA降维也是同样的,把协方差矩阵特征分解后,按从大到小取出前K个特征值对应的特征向量作为新的“坐标轴”。
那回到正题,上述图中 L = D − A L = D-A L=D−A,即:
A = { 0 1 0 0 1 0 1 0 1 0 1 0 0 1 0 1 0 0 0 0 1 0 1 1 1 1 0 1 0 0 0 0 0 1 0 0 } , D = { 2 0 0 0 0 0 0 3 0 0 0 0 0 0 2 0 0 0 0 0 0 3 0 0 0 0 0 0 3 0 0 0 0 0 0 1 } , L = D − A = { 2 − 1 0 0 − 1 0 − 1 3 − 1 0 − 1 0 0 − 1 2 − 1 0 0 0 0 − 1 3 − 1 − 1 − 1 − 1 0 − 1 3 0 0 0 0 − 1 0 1 } \mathrm{A}=\left\{\begin{array}{llllll} 0 & 1 & 0 & 0 & 1 & 0 \\ 1 & 0 & 1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 & 1 & 1 \\ 1 & 1 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 \end{array}\right\}, \mathrm{D}=\left\{\begin{array}{llllll} 2 & 0 & 0 & 0 & 0 & 0 \\ 0 & 3 & 0 & 0 & 0 & 0 \\ 0 & 0 & 2 & 0 & 0 & 0 \\ 0 & 0 & 0 & 3 & 0 & 0 \\ 0 & 0 & 0 & 0 & 3 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \end{array}\right\}, \mathrm{L}=\mathrm{D}-\mathrm{A}=\left\{\begin{array}{cccccc} 2 & -1 & 0 & 0 & -1 & 0 \\ -1 & 3 & -1 & 0 & -1 & 0 \\ 0 & -1 & 2 & -1 & 0 & 0 \\ 0 & 0 & -1 & 3 & -1 & -1 \\ -1 & -1 & 0 & -1 & 3 & 0 \\ 0 & 0 & 0 & -1 & 0 & 1 \end{array}\right\} A=⎩ ⎨ ⎧010010101010010100001011110100000100⎭ ⎬ ⎫,D=⎩ ⎨ ⎧200000030000002000000300000030000001⎭ ⎬ ⎫,L=D−A=⎩ ⎨ ⎧2−100−10−13−10−100−12−10000−13−1−1−1−10−130000−101⎭ ⎬ ⎫
因为我们使用的是无向图,所以
L
L
L 是对称矩阵。因此
L
L
L 可以按照如下公式进行分解:
L
=
U
Λ
U
−
1
=
U
Λ
U
T
L=U \Lambda U^{-1}=U \Lambda U^{T}
L=UΛU−1=UΛUT
其中特征向量 U = [ u 1 , u 2 , … , u n ] U=\left[u_{1}, u_{2}, \ldots, u_{n}\right] U=[u1,u2,…,un]. 就是我们要找的一组傅里叶变换的基,也因为是实对称矩阵,根据性质,一定可以用正交矩阵进行正交相似对角化。
而特征值 Λ = ∣ λ 1 … 0 … … … 0 … λ n ∣ \Lambda=\left|\begin{array}{ccc} \lambda_{1} & \ldots & 0 \\ \ldots & \ldots & \ldots \\ 0 & \ldots & \lambda_{n} \end{array}\right| Λ= λ1…0………0…λn . 是对应的特征向量所占的比重。
通过这组傅里叶变换的基,我们可以将输入
x
i
x_{i}
xi 从空域转到频域为
F
(
x
i
)
=
U
T
x
i
F(x_{i}) = U^{T}x_{i}
F(xi)=UTxi,因此,图的卷积公式,从空域转换到频域,可以表示为:
x
i
∗
G
F
i
,
j
=
U
(
U
T
x
i
⋅
U
T
F
i
,
j
)
=
U
(
U
T
F
i
,
j
⋅
U
T
x
i
)
x_{i} *_{G} F_{i, j}=U\left(U^{T} x_{i} \cdot U^{T} F_{i, j}\right)=U\left(U^{T} F_{i, j} \cdot U^{T} x_{i}\right)
xi∗GFi,j=U(UTxi⋅UTFi,j)=U(UTFi,j⋅UTxi)
这里可以将
U
T
F
i
,
j
U^{T} F_{i, j}
UTFi,j 整体看成一个可以学习的卷积核,记为
F
i
,
j
θ
F_{i, j}^{\theta}
Fi,jθ,因此最终的卷积公式可以表示成:
x
i
∗
G
F
i
,
j
=
U
F
i
,
j
θ
U
T
x
i
x_{i} *_{G} F_{i, j}=U F_{i, j}^{\theta} U^{T} x_{i}
xi∗GFi,j=UFi,jθUTxi
加入通道和激励函数后,第 k k k 层卷积可以写成:
o k , j = h ( ∑ i = 1 f k − 1 U F k , i , j θ U T x k , i ) = h ( U ∑ i = 1 f k − 1 F k , i , j θ U T x k , i ) o_{k, j}=h\left(\sum_{i=1}^{f_{k-1}} U F_{k, i, j}^{\theta} U^{T} x_{k, i}\right)=h\left(U \sum_{i=1}^{f_{k-1}} F_{k, i, j}^{\theta} U^{T} x_{k, i}\right) ok,j=h(i=1∑fk−1UFk,i,jθUTxk,i)=h(Ui=1∑fk−1Fk,i,jθUTxk,i)
这就跟第一篇GCN论文中所提公式一样了。当然上述卷积公式很多人喜欢写成更通用的方式:
( f ∗ g ) y = U ( ( U T g ) ⊙ ( U T f ) ) (f * g)_{y}=U\left(\left(U^{T} g\right) \odot\left(U^{T} f\right)\right) (f∗g)y=U((UTg)⊙(UTf))
⊙ \odot ⊙表示hadamard product(哈达马积),对于两个向量,就是进行内积运算;对于维度相同的两个矩阵,就是对应元素的乘积运算。
为什么要在这里提一嘴通用形式,是因为我上述推导尽量走的简化路线,关于傅里叶和拉普拉斯的推导都没有详细展开了,而下节的GCN第二部分即是优化的这个点。
GCN:ChebNet
这是时间线上的第二篇论文,ChebNet的作者指出原始的频谱图卷积有两大缺点:
- 图卷积核是全局的且参数量大 (卷积核大小与输入信号相同,参数量与图节点数相同)
- 图卷积运算的复杂度高 (运算过程涉及高计算复杂度的特征分解)
于是ChebNet作者在论文中做出了改进,将 g ^ ( λ l ) \hat g(\lambda_l) g^(λl) 巧妙地设计成了 ∑ j = 0 K α j λ l j \sum_{j=0}^K \alpha_j \lambda^j_l ∑j=0Kαjλlj(原始定义为: g ^ ( λ l ) = ∑ i = 1 N g ( i ) u l ∗ ( i ) \hat{g}(\lambda_l)=\sum_{i=1}^{N}{g(i) u_l^*(i)} g^(λl)=∑i=1Ng(i)ul∗(i))
然后利用矩阵乘法,再以同种方式推一遍(PS:不想推了,也懒得抄了,emmm),上面原输出,即上一小节末尾的式子可以写为:
y
output
=
σ
(
U
g
θ
(
Λ
)
U
T
x
)
y_{\text {output }}=\sigma\left(U g_{\theta}(\Lambda) U^{T} x\right)
youtput =σ(Ugθ(Λ)UTx)
经过这么一设计,变为了:
U ∑ j = 0 K α j Λ j U T = ∑ j = 0 K α j U Λ j U T = ∑ j = 0 K α j L j U \sum_{j=0}^{K} \alpha_{j} \Lambda^{j} U^{T}=\sum_{j=0}^{K} \alpha_{j} U \Lambda^{j} U^{T}=\sum_{j=0}^{K} \alpha_{j} L^{j} Uj=0∑KαjΛjUT=j=0∑KαjUΛjUT=j=0∑KαjLj
简化完后,带回output,为:
y output = σ ( ∑ j = 0 K α j L j x ) y_{\text {output }}=\sigma\left(\sum_{j=0}^{K} \alpha_{j} L^{j} x\right) youtput =σ(j=0∑KαjLjx)
其中 ( α 1 , α 2 , ⋯ , α K ) ({\alpha_1},{\alpha_2},\cdots,{\alpha_K}) (α1,α2,⋯,αK) 是任意的参数,通过初始化赋值然后利用误差反向传播进行调整。上式优势在于:
- 卷积核只有 K K K 个参数,一般 K K K 远小于 n n n ,参数的复杂度被大大降低了。
- 矩阵变换后,神奇地发现不需要做特征分解了,直接用拉普拉斯矩阵 L L L 进行变换。然而由于要计算 L j L^{j} Lj,计算复杂度还是 O ( n 2 ) \mathcal{O}(n^2) O(n2)
然后针对以上第二条缺点,作者利用了Chebyshev多项式递归计算卷积核,来进一步优化结果。即Chebyshev Polynomial,公式为:
g
θ
(
Λ
)
≈
∑
k
=
0
K
−
1
β
k
T
k
(
Λ
~
)
g_{\theta}(\Lambda) \approx \sum_{k=0}^{K-1} \beta_{k} T_{k}(\tilde{\Lambda})
gθ(Λ)≈k=0∑K−1βkTk(Λ~)
其中 β ∈ R K \beta\in \mathbb{R}^{K} β∈RK 表示一个切比雪夫向量, β k \beta_k βk 是Chebyshev多项式的系数(标量); T k ( Λ ~ ) T_k(\tilde{\Lambda}) Tk(Λ~) 是取 Λ ~ = 2 Λ / λ m a x − I \tilde{\Lambda}=2\Lambda/\lambda_{max}-I Λ~=2Λ/λmax−I 的Chebyshev多项式,进行这个shift变换的原因是Chebyshev多项式的输入要在 [ − 1 , 1 ] \left[ -1,1\right] [−1,1] 之间。
由Chebyshev多项式的性质,递推公式为:
T k ( Λ ~ ) x = 2 Λ ~ T k − 1 ( Λ ~ ) x − T k − 2 ( Λ ~ ) x T 0 ( Λ ~ ) = I , T 1 ( Λ ~ ) = Λ ~ \begin{array}{c} T_{k}(\tilde{\Lambda}) x=2 \tilde{\Lambda} T_{k-1}(\tilde{\Lambda}) x-T_{k-2}(\tilde{\Lambda}) x \\ \\ T_{0}(\tilde{\Lambda})=I, T_{1}(\tilde{\Lambda})=\tilde{\Lambda} \end{array} Tk(Λ~)x=2Λ~Tk−1(Λ~)x−Tk−2(Λ~)xT0(Λ~)=I,T1(Λ~)=Λ~
我们将上述多项式带入原卷积公式中,可得:
g
θ
(
Λ
)
∗
x
≈
U
∑
k
=
0
K
β
k
T
k
(
Λ
~
)
U
T
x
=
∑
k
=
0
K
β
k
U
T
k
(
Λ
~
)
U
T
x
=
∑
k
=
0
K
β
k
T
k
(
L
~
)
x
g_{\theta}(\Lambda) * x \approx U \sum_{k=0}^{K} \beta_{k} T_{k}(\tilde{\Lambda}) U^{T} x=\sum_{k=0}^{K} \beta_{k} U T_{k}(\tilde{\Lambda}) U^{T} x=\sum_{k=0}^{K} \beta_{k} T_{k}(\tilde{L}) x
gθ(Λ)∗x≈Uk=0∑KβkTk(Λ~)UTx=k=0∑KβkUTk(Λ~)UTx=k=0∑KβkTk(L~)x
此时,我们计算图卷积运算就不需要再乘上特征向量矩阵 U U U,由递推公式得到的 k k k 阶卷积不再有矩阵乘积了,这样就避免了进行特征分解,而我们可以事先计算好 L k L^{k} Lk,只需要计算矩阵与向量的乘积即可。计算一次 T k ( Λ ~ ) x T_k (\tilde{\Lambda})x Tk(Λ~)x 的复杂度是 O ( ∣ E ∣ ) \mathcal{O}(\left| E \right|) O(∣E∣), E E E 是图中边的集合,则整个运算的复杂度是 O ( K ∣ E ∣ ) \mathcal{O}(K\left | E \right|) O(K∣E∣) 。当Graph是稀疏图的时候,计算加速尤为明显,这个时候复杂度远低于 O ( n 2 ) \mathcal{O}(n^2) O(n2)
GCN:Graph Convolutional Networks
这篇是GCN从GNN进入到现代化的开端,同时也是以这篇为基础,之后还出现了Graph Attention Networks (GAT 2018年),Graph Sample and Aggregate (GraphSAGE 2018年) 和 Graph Isomorphism Network (GIN)等等,相比于上一篇GCN的切比雪夫表示,它改进了:
- 简化了图卷积的定义,从基于傅里叶变换的谱域,变成了基于邻接矩阵的空间域方法。即提出了一种基于图卷积网络(GCN)的半监督学习方法,可以直接在图结构数据上进行高效的卷积运算,而不需要显式地计算图的傅里叶变换或者切比雪夫多项式。
- 减少了参数数量,基于局部化的一阶近似,设计了一种简单而有效的卷积滤波器,可以捕捉图上节点之间的相关性,并且可以通过反向传播和随机梯度下降进行端到端的训练。
那是怎么做到的呢?
论文开篇的introduction就指出,在2016年以前,就有前人尝试利用正则化约束的方法,通过在损失函数中引入图的拉普拉斯正则项,来对节点分类任务进行半监督学习,而在上节的ChebNet论文中的Graph Fourier Transform 小节中也有提到,只不过是用normalized definition 引述了一下,而非主导。而我感觉到非常眼熟,是因为上篇推SDNE图嵌入算法的创新点就是将一阶相似度和二阶相似度做了一个融合,其一阶相似度一样使用的正则化方式,对应上了该篇,那直接引入该式为:
L
=
L
0
+
λ
L
reg
,
with
L
reg
=
∑
i
,
j
A
i
j
∥
f
(
X
i
)
−
f
(
X
j
)
∥
2
=
f
(
X
)
⊤
Δ
f
(
X
)
\mathcal{L}=\mathcal{L}_{0}+\lambda \mathcal{L}_{\text {reg }}, \quad \text { with } \quad \mathcal{L}_{\text {reg }}=\sum_{i, j} A_{i j}\left\|f\left(X_{i}\right)-f\left(X_{j}\right)\right\|^{2}=f(X)^{\top} \Delta f(X)
L=L0+λLreg , with Lreg =i,j∑Aij∥f(Xi)−f(Xj)∥2=f(X)⊤Δf(X)
根据上一节利用Chebyshev多项式简化的目标函数:
g
θ
(
Λ
)
≈
∑
k
=
0
K
−
1
β
k
T
k
(
Λ
~
)
g_{\theta}(\Lambda) \approx \sum_{k=0}^{K-1} \beta_{k} T_{k}(\tilde{\Lambda})
gθ(Λ)≈k=0∑K−1βkTk(Λ~)
这里还能继续做迭代,即考虑对前面定义的频域拉普拉斯矩阵进行归一化从而得到归一化的拉普拉斯矩阵。这里通常有两种形式的归一化。
-
第一种是 L s y s = D − 1 / 2 L D − 1 / 2 = I − D − 1 / 2 A D − 1 / 2 L^{sys}=D^{-1/2}LD^{-1/2}=I-D^{-1/2}AD^{-1/2} Lsys=D−1/2LD−1/2=I−D−1/2AD−1/2,定义Symmetric normalized Laplacian ,之后的GCN论文基本都是采用该种形式,它里面元素的计算方式为:
L i , j sym : = { 1 if i = j and deg ( v i ) ≠ 0 − 1 deg ( v i ) deg ( v j ) if i ≠ j and v i is adjacent to v j 0 otherwise. L_{i, j}^{\text {sym }}:=\left\{\begin{array}{ll} 1 & \text { if } i=j \text { and } \operatorname{deg}\left(v_{i}\right) \neq 0 \\ -\frac{1}{\sqrt{\operatorname{deg}\left(v_{i}\right) \operatorname{deg}\left(v_{j}\right)}} & \text { if } i \neq j \text { and } v_{i} \text { is adjacent to } v_{j} \\ 0 & \text { otherwise. } \end{array}\right. Li,jsym :=⎩ ⎨ ⎧1−deg(vi)deg(vj)10 if i=j and deg(vi)=0 if i=j and vi is adjacent to vj otherwise. -
第二种是 L r w = D − 1 L L^{rw}=D^{-1}L Lrw=D−1L,定义 Random walk normalized Laplacian ,我们发现该种方式求出来的拉普拉斯不是对称矩阵,而它的元素计算为:
L i , j r w : = { 1 if i = j and deg ( v i ) ≠ 0 − 1 deg ( v i ) if i ≠ j and v i is adjacent to v j 0 otherwise. L_{i, j}^{\mathrm{rw}}:=\left\{\begin{array}{ll} 1 & \text { if } i=j \text { and } \operatorname{deg}\left(v_{i}\right) \neq 0 \\ -\frac{1}{\operatorname{deg}\left(v_{i}\right)} & \text { if } i \neq j \text { and } v_{i} \text { is adjacent to } v_{j} \\ 0 & \text { otherwise. } \end{array}\right. Li,jrw:=⎩ ⎨ ⎧1−deg(vi)10 if i=j and deg(vi)=0 if i=j and vi is adjacent to vj otherwise.
这两种都能看作是特殊的频域滤波器,可以将图上的信号映射到一个低维空间,并保持图上节点之间的相似性。具体证明可以看我上一篇总结SDNE算法的时候引出的2013年那篇论文,我就不提了,因为推导量有点恐怖,看了半刻钟,我发现,能用就行,emmm。
那这里为什么选第一个呢?主要是当ChebNet一阶近似时,考虑到每层都会逐点进行非线性叠加,直接选取了 K = 2 K = 2 K=2,也就是说得到了一个拉普拉斯算子的二阶近似函数。这样我们既可以对网络进行卷积操作,又不会引入太多的切比雪夫系数。
另外,归一化的拉普拉斯矩阵的特征值区间为 [0, 2],进一步近似
λ
m
a
x
=
2
\lambda_{max} = 2
λmax=2,所以我们有新的表达式:
g
θ
∗
x
≈
θ
0
x
+
θ
1
(
L
−
I
N
)
x
=
θ
0
x
−
θ
1
D
−
1
2
A
D
−
1
2
x
g_{\theta} * x \approx \theta_{0} x+\theta_{1}\left(L-I_{N}\right) x=\theta_{0} x-\theta_{1} D^{-\frac{1}{2}} A D^{-\frac{1}{2}} x
gθ∗x≈θ0x+θ1(L−IN)x=θ0x−θ1D−21AD−21x
这里如果没有看过拉普拉斯论文的,还能有另一种解释理解上式,我是在唐宇迪的图神经网络GCN章节中学到的,一个很容易理解的例子。
根据前面信息,我们知道邻接矩阵与特征矩阵进行乘法操作,表示聚合邻居信息,但这种聚合是需要进行平均的,也就是说要对各个节点的度进行平均,根据逆矩阵的性质,那度矩阵为 D = D − 1 D = D^{-1} D=D−1.
再带回原来的公式 D − 1 A x D^{-1}Ax D−1Ax,根据交换律,可以为 ( D − 1 A ) x (D^{-1}A)x (D−1A)x,这样就完成了矩阵scale,但左行右列,我对行进行了缩放,那列呢?这时候如果再右乘一个 D − 1 D^{-1} D−1,我们发现对整个输入做了两次归一化,那显然不符合常理,这就像去网吧上网被抓了,回家先被我爸打了一顿,然后又被我妈打了一顿,打的位置同样,但是分时打的,那岂不是我很亏?于是,我可以在他们打之前,先说好了,一人打我一边,或者一个打,一个说就好了,最不济那就混合双打,但也不至于两次打得一模一样好。
那么因为各取一半,我觉得才算一顿毒打,归一化公式变为了:
−
1
deg
(
v
i
)
deg
(
v
j
)
=
D
~
−
1
/
2
A
~
D
~
−
1
/
2
X
-\frac{1}{\sqrt{\operatorname{deg}\left(v_{i}\right) \operatorname{deg}\left(v_{j}\right)}}=\tilde{D}^{-1 / 2} \tilde{A} \tilde{D}^{-1 / 2} X
−deg(vi)deg(vj)1=D~−1/2A~D~−1/2X
这同样是让特征值区间分布在了 [0, 2]。
那么回到上述表达式中,上述 θ 0 \theta_{0} θ0 和 θ 1 \theta_{1} θ1 为切比雪夫系数的向量,是仅有的两个参数。
在实际训练过程中,我们需要规范化参数来避免过拟合,所以我们令
θ
=
θ
0
=
−
θ
1
\theta = \theta_{0} = -\theta_{1}
θ=θ0=−θ1,从而有:
g
θ
∗
x
≈
θ
(
I
N
+
D
−
1
2
A
D
−
1
2
)
x
g_{\theta} * x \approx \theta\left(I_{N}+D^{-\frac{1}{2}} A D^{-\frac{1}{2}}\right) x
gθ∗x≈θ(IN+D−21AD−21)x
然后作者为了预防梯度爆炸,又做了 「renormalization trick」 ,以及将公式从标量推广到矩阵,作者又举了个例子:
但这个例子可能就是为了说明,卷积后的
Z
Z
Z 向量,时间复杂度变为了
O
(
∣
E
∣
F
C
)
\mathcal{O}(|E|FC)
O(∣E∣FC). 因为我没看到后面有引用了。
所以,加入传播激活函数后,多层图卷积网络的传播规则为:
H
(
l
+
1
)
=
σ
(
D
~
−
1
2
A
~
D
~
−
1
2
H
(
l
)
W
(
l
)
)
H^{(l+1)}=\sigma\left(\widetilde{D}^{-\frac{1}{2}} \widetilde{A} \widetilde{D}^{-\frac{1}{2}} H^{(l)} W^{(l)}\right)
H(l+1)=σ(D
−21A
D
−21H(l)W(l))
其中:
- A ~ = A + I N \widetilde{A}=A+I_{N} A =A+IN , A A A 为邻接矩阵, I N I_{N} IN 为单位矩阵,所以 A ~ \widetilde{A} A 为添加自连接的邻接矩阵;
- D ~ i i = ∑ i A ~ i j \widetilde{D}_{i i}=\sum_{i} \widetilde{A}_{i j} D ii=∑iA ij , D ~ \widetilde{D} D 为节点的度数矩阵;
- W ( l ) W^{(l)} W(l) 为神经网络第 l l l 层的权重矩阵, σ ( . ) \sigma(.) σ(.) 是激活函数;
- H ( l ) ∈ R N × D H^{(l)} \in R^{N \times D} H(l)∈RN×D 是第 l l l 层的激活矩阵,并且 H ( 0 ) = X H^{(0)} = X H(0)=X, X X X 是由节点 x i x_{i} xi 的特征向量组成矩阵。
推导完毕。
最后,作者举了个例子,用了一个两层的GCN为图,以Relu为激活函数:
它呈现的一个效果为:
由于我们知道了 GCN 的传播规则,所以我们有最终的结果:
Z = f ( X , A ) = Softmax ( A ^ ReLU ( A ^ X W ( 0 ) ) W ( 1 ) ) Z=f(X, A)=\operatorname{Softmax}\left(\hat{A} \operatorname{ReLU}\left(\hat{A} X W^{(0)}\right) W^{(1)}\right) Z=f(X,A)=Softmax(A^ReLU(A^XW(0))W(1))
其中, W ( 0 ) W^{(0)} W(0) 是输入层到隐藏层的权重, W ( 1 ) W^{(1)} W(1) 是隐藏层到输出层的权重;
作者采用了交叉熵作为损失函数:
L
=
−
∑
l
∈
y
L
∑
f
=
1
F
Y
l
f
ln
Z
l
f
L=-\sum_{l \in y_{L}} \sum_{f=1}^{F} Y_{l f} \ln Z_{l f}
L=−l∈yL∑f=1∑FYlflnZlf
有了代价函数后,我们可以通过梯度下降来更新网络的参数并完成一次完整的训练。
结尾
本篇大概写了三四天,中间工作上的事情也打乱了很多思路,另外就是刚开始搞不清楚频域和空域,因为我没学过信号与系统,最后找到了很多很好的文献帮我弄清楚了GNN的时间线,本篇碍于篇幅,下一篇我也将根据找到的这些文献去复现一下他们的内容或者代码。那么下面是我有参考或者非常推荐看的,而我在文中没有提到的引用,提到的就不会再标注了。
参考与推荐
[1]. Understanding Convolutions on Graphs
[2]. https://en.wikipedia.org/wiki/Graph_neural_network
[3]. 图卷积网络 GCN Graph Convolutional Network(谱域GCN)的理解和详细推导
[4]. 图卷积神经网络
[5]. 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络模型 (二)
[6]. 目前看的GNN论文的一些总结