由于课题研究需要,这星期看了几篇GCN相关的文章和书籍,并对其进行了代码复现,现将最近学习的内容做一个梳理与总结,用于日后复习巩固。由于能力有限,文章中有错误或者不当之处,还望各位读者多多指出。之后对GCN应用方面相关的论文阅读笔记,也会及时文末跟新。(本文作为笔者的学习笔记,如有错误,希望各位读者批评指正)- - 更新时间:2020年11月1日
[学习笔记(1)]深入浅出了解GCN原理(公式+代码)
[学习笔记(2)]深入浅出了解GNN的几种变体
引言
相信大多数读者在了解GCN(Graph Convolutional Networks)之前,对CNN(Convolutional Neural Network)都是非常熟悉的,我们知道,在连续信号中的卷积是表征函数f与g经过翻转和平移的重叠部分函数值乘积对重叠长度的积分,如下公式(1)。
∫
−
∞
+
∞
f
(
τ
)
g
(
x
−
τ
)
d
τ
(
1
)
\quad\qquad\int_{-\infty}^{+\infty} f(\tau)g(x-\tau)d\tau \qquad\qquad\qquad (1)
∫−∞+∞f(τ)g(x−τ)dτ(1)
对于离散信号而言,离散卷积的本质也是平移叠加之后的加权和,所以在CNN中图像上的卷积,本质上是利用参数共享的过滤器(kernel),通过计算中心像素点以及相邻像素点的加权和来构建成Feature Map,实现空间特征的提取,而加权的系数就是卷积核的权重,这其实在很多传统图像的算法中也有体现,就比如高斯平滑算子,拉普拉斯算子,边缘检测算子(提取边缘特征),包括SIFI(Scale-invariant feature transform)特征点提取,也是一系列的卷积和后处理操作。这些在图像上通过卷积核特征提取的操作,之所以有效很大一部分原因是因为图像本身是结构化数据,它是多个像素点排列整齐的矩阵,而CNN具有平移不变性(即图像如果经过平移,得到的特征图也会相应平移)。然而在真实世界中,还含有很多非欧几里得距离的数据,比如社交网络关系、交通连通图、脑网络连接等等,对于这类具有抽象意义的拓扑图关系的数据,它们是无法保证平移不变性的,这就需要我们有类似cnn的方法,来提取和挖掘有效的空间关系进行建模学习。广义来说,对于任何数据,都可以建立一定的拓扑关联,来进一步挖掘数据内部之间的关联性,所以GCN有很大的应用空间。
GCN发展
GCN真正开始运用和发展是从这篇于2016年提出,2017年发表的文章开始:SEMI-SUPERVISED CLASSIFICATION WITHGRAPH CONVOLUTIONAL NETWORKS ,详细文章内容,读者可以自行阅读原文。
1、基于损失函数的考虑
在2016年以前,就有前人尝试利用正则化约束的方法,通过在损失函数中引入图的拉普拉斯正则项,来对节点分类任务进行半监督学习,如下公式(2).
L
=
L
0
+
λ
L
r
e
g
w
i
t
h
L
r
e
g
=
∑
i
,
j
A
i
j
∣
∣
f
(
X
i
)
−
f
(
X
j
)
∣
∣
2
=
f
(
X
)
T
△
f
(
X
)
.
(
2
)
\mathcal{L}=\mathcal{L}_0+\lambda\mathcal{L_{reg}}\qquad with\quad \mathcal{L_{reg}}=\sum_{i,j}A_{ij}||f(X_i)-f(X_j)||^{2}=f(X)^T\vartriangle f(X). \qquad(2)
L=L0+λLregwithLreg=i,j∑Aij∣∣f(Xi)−f(Xj)∣∣2=f(X)T△f(X).(2)
其中
L
0
\mathcal{L}_0
L0为监督损失(与label定义的损失),
L
r
e
g
\mathcal{L}_{reg}
Lreg为约束项,
f
(
.
)
f(.)
f(.)可以是神经网络可微函数,
X
X
X是节点特征向量
X
i
X_i
Xi的矩阵,
△
=
D
−
A
\vartriangle=D-A
△=D−A是无向图
G
=
(
V
,
E
)
G=(V,E)
G=(V,E)的非标准化拉普拉斯矩阵。这里说明下,拉普拉斯矩阵是用来研究图结构性质的核心对象,其定义为
L
=
D
−
A
L=D-A
L=D−A,其中D是一个对角矩阵,
A
A
A是邻接矩阵,
D
i
i
=
∑
j
A
i
j
D_{ii}=\sum_jA_{ij}
Dii=∑jAij 表示
i
i
i节点的度。拉普拉斯矩阵还有一种正则化的形式(symmetric normalized laplacian)
L
s
y
m
=
D
−
1
2
L
D
−
1
2
=
I
N
−
D
−
1
2
A
D
−
1
2
(
3
)
\qquad L_{sym}=D^{-\frac{1}{2}}LD^{-\frac{1}{2}}=I_N-D^{-\frac{1}{2}}AD^{-\frac{1}{2}} \qquad\qquad\qquad(3)
Lsym=D−21LD−21=IN−D−21AD−21(3),其元素级别的定义如下:
L
s
y
m
[
j
,
j
]
{
1
i
f
i
=
j
−
1
d
e
g
(
v
i
)
d
e
g
(
v
j
)
i
f
e
i
j
∈
E
0
o
t
h
e
r
w
i
s
e
(
4
)
\qquad L_{sym}[j,j]\left\{ \begin{aligned} 1\qquad\quad& &{ if\ i=j\quad}\\ \frac{-1}{\sqrt{deg(v_i)deg(v_j)}} & &{if\ e_{ij} \in E} \\ 0 \qquad\quad& & {otherwise } \end{aligned} \right.{\quad \qquad \qquad \qquad (4)}
Lsym[j,j]⎩⎪⎪⎪⎨⎪⎪⎪⎧1deg(vi)deg(vj)−10if i=jif eij∈Eotherwise(4)
拉普拉斯矩阵的定义源自于拉普拉斯算子,拉普拉斯算子它是
n
n
n维欧式空间种的二阶微分算子,在二维空间的图像中表示就是我们熟悉的边缘检测算子(两者之间的关系这里不多展开,感兴趣的读者可以看看这篇文章 拉普拉斯算子与拉普拉斯矩阵的关系
回到公式(2),从表达式上我们可以清晰的看到,正则部分相当于衡量相邻节点之间的差异性,因为 A i , j A_{i,j} Ai,j是邻接矩阵上的元素,两个节点处于邻接关系时为1,其他为0.这样的正则项,使得拓扑图上相邻节点尽可能相似,物以类聚,这是很自然的想法。从信号的角度上来看,减少该正则项,就是期望经过模型之后的图信号更加平滑。从频域上来看,是对图信号做了低通滤波的处理,但是这样的假设可能会限制模型的表达能力,因为图上边不只包含相似度的信息,还可能包含其他相关信息。
2、从谱图卷积开始
最初标准的第一代GCN出自Spectral Networks and Locally Connected Networks on Graphs,其对于图上的卷积有如下定义:
g
θ
∗
x
=
U
g
θ
U
T
x
(
5
)
\qquad \qquad g_{\theta}*x=Ug_{\theta}U^Tx \qquad\qquad\qquad\quad(5)
gθ∗x=UgθUTx(5)
这里
U
U
U是图的标准化拉普拉斯(Laplacian)矩阵
L
s
y
m
L_{sym}
Lsym(公式3)的特征向量矩阵,因此有
L
s
y
m
=
U
Λ
U
T
L_{sym}=U\Lambda U^T
Lsym=UΛUT,
x
x
x是数据中提取出来的特征,也就是输入,定义
g
θ
=
d
i
a
g
(
h
^
(
λ
l
)
)
g_{\theta}=diag(\hat{h}(\lambda_l))
gθ=diag(h^(λl))是特征值的响应函数,进一步为了类比CNN中的共享卷积核的设计,在神经网络中将其设置为可训练参数的卷积核,如
d
i
a
g
(
θ
l
)
diag(\theta_l)
diag(θl)。而
U
T
x
U^Tx
UTx的本质是将
x
x
x映射到傅里叶空间,
U
U
U是傅里叶空间的一组正交基。对于如何将傅里叶分解推广到图卷积,可以参考这篇The Emerging Field of Signal Processing on Graphs: Extending High-Dimensional Data Analysis to Networks and Other Irregular Domains ,太过复杂的推导和证明这里不过多解释。
对于第一代版本的GCN主要有以下几点弊端:
- 每一层的计算涉及 U d i a g ( h ^ ( θ l ) ) U T Udiag(\hat{h}(\theta_l))U^T Udiag(h^(θl))UT三个矩阵乘法,复杂度为 O ( N 2 ) O(N^2) O(N2),代价较高
- 卷积核具有n个参数,n是L的特征值个数。
- 计算Hermitian Matrix特征值的代价非常昂贵
过高的计算复杂度和过大的计算参数,在实际运用中都是不允许的,于是基于以上两点的考虑,就产生了第二代版本的GCN,详细内容和公式推导可参考论文:Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering
,文中作者将卷积核巧妙地设计成了如下公式:
g
θ
(
Λ
)
=
∑
k
=
0
K
−
1
θ
k
Λ
k
=
(
∑
j
=
0
k
−
1
θ
j
λ
1
j
⋱
∑
j
=
0
k
−
1
θ
j
λ
n
j
)
(
6
)
g_{\theta}(\Lambda)=\sum_{k=0}^{K-1}\theta_k\Lambda^k= \begin{pmatrix} \sum_{j=0}^{k-1}\theta_j\lambda_1^j &&\\ &\ddots&\\ &&\sum_{j=0}^{k-1}\theta_j\lambda_n^j \end{pmatrix}\qquad\qquad(6)
gθ(Λ)=k=0∑K−1θkΛk=⎝⎜⎛∑j=0k−1θjλ1j⋱∑j=0k−1θjλnj⎠⎟⎞(6)
经过这样的设计,原本需要训练n个参数,缩小到了K个,同时将公式(6)带入公式(5)得到公式(7),从公式(7)中不难发现,此时我们不在需要在求矩阵的特征向量了,可直接使用拉普拉斯矩阵进行运算。第二代版本的GCN解决了第一代的2、3两个问题的弊端,但是矩阵乘法的复杂度依旧是
O
(
N
2
)
O(N^2)
O(N2)。
g
θ
∗
x
=
∑
j
=
0
k
−
1
θ
j
L
j
x
(
7
)
\qquad\qquad g_{\theta}*x=\sum_{j=0}^{k-1}\theta_jL^jx \qquad \qquad \qquad\quad(7)
gθ∗x=j=0∑k−1θjLjx(7)
3、切比雪夫卷积核
计算多个大型稠密矩阵的乘法复杂度是很高的,这运用中在实际场景是不被允许的,尤其是计算像社交关系网络这种超大拓扑图的数据,显然是无法实现的,为解决这个问题,我们采用切比雪夫多项式(Chebyshev polynomials)来近似
g
θ
(
Λ
)
g_{\theta}(\Lambda)
gθ(Λ),具体内容的讨论读者可阅读知乎:chevyshev多项式作为卷积核 或Hammond等人对这一问题深入的讨论Wavelets on graphs via spectral graph theory,我们直接给出近似公式:
g
θ
’
(
Λ
)
≈
∑
k
=
0
K
θ
k
′
T
k
(
Λ
~
)
(
8
)
\qquad \qquad g_{\theta^’}(\Lambda)\approx\sum_{k=0}^{K}\theta_k^{'}T_k(\tilde{\Lambda})\qquad\qquad\qquad(8)
gθ’(Λ)≈k=0∑Kθk′Tk(Λ~)(8)
这里
Λ
~
=
2
λ
m
a
x
Λ
−
I
N
\tilde{\Lambda}=\frac{2}{\lambda_{max}}\Lambda-I_N
Λ~=λmax2Λ−IN是对
Λ
\Lambda
Λ的一种缩放,
λ
m
a
x
\lambda_{max}
λmax是
L
L
L的最大特征值,
θ
′
∈
R
k
\theta^{'}\in\mathbb{R}^k
θ′∈Rk是切比雪夫系数向量,切比雪夫的递归式定义为
T
k
(
x
)
=
2
x
T
k
−
1
(
x
)
−
T
k
−
2
(
x
)
T_k(x)=2xT_{k-1}(x)-T_{k-2}(x)
Tk(x)=2xTk−1(x)−Tk−2(x),设
T
0
(
x
)
=
1
T_0(x)=1
T0(x)=1,
T
1
(
x
)
=
x
T_1(x)=x
T1(x)=x,由此就可以的得到一个计算近似特征值的方法,将公式(8)带入之前的卷积定义公式(5),我们有:
g
θ
∗
x
=
∑
k
=
0
K
θ
k
′
T
k
(
L
~
)
x
(
9
)
\qquad\qquad g_{\theta}*x=\sum_{k=0}^{K}\theta_k^{'}T_k(\tilde{L})x \qquad\qquad\qquad(9)
gθ∗x=k=0∑Kθk′Tk(L~)x(9)这里
L
~
=
2
λ
m
a
x
L
−
I
N
\tilde{L}=\frac{2}{\lambda_{max}}L-I_N
L~=λmax2L−IN,这个表达式是局部化的,它是拉普拉斯式的一个K阶多项式,也就是说,它只依赖于距离中心节点(K阶邻域),公式(9)的复杂度是
O
(
∣
ε
∣
)
O(|\varepsilon|)
O(∣ε∣),即计算复杂度取决于图的边的数量。
4、GCN图卷积网络
为了简化问题,同时减轻由于局部节点度过大而导致过拟合的问题,我们设置K=1,即只考虑中心节点的一阶邻近,将 T 0 ( x ) = 1 T_0(x)=1 T0(x)=1, T 1 ( L ~ ) = L ~ T_1(\tilde{L})=\tilde{L} T1(L~)=L~带入公式(9),进一步,我们将尺度变换的 λ m a x \lambda_{max} λmax固定为2。于是我们就得到卷积新的近似表达:
g
θ
∗
x
≈
θ
0
′
x
+
θ
1
′
(
L
−
I
N
)
x
=
θ
(
I
N
+
D
−
1
2
A
D
−
1
2
)
x
.
(
10
)
g_{\theta}*x\approx\theta_0^{'}x+\theta_1^{'}(L-I_N)x=\theta(I_N+D^{-\frac{1}{2}}AD^{-\frac{1}{2}})x.\qquad\qquad(10)
gθ∗x≈θ0′x+θ1′(L−IN)x=θ(IN+D−21AD−21)x.(10)
由盖尔圆盘定理我们知道,公式(10)中
I
N
+
D
−
1
/
2
A
D
−
1
/
2
I_N+D^{-1/2}AD^{-1/2}
IN+D−1/2AD−1/2的特征值范围为[0,2],重复的进行卷积操作,可能会导致数值不稳定,在神经网络中多层的图卷积之后,容易导致梯度消失或者梯度爆炸。为了解决这个问题,我们将其进一步标准化:
I
N
+
D
−
1
2
A
D
−
1
2
→
D
~
−
1
2
A
~
D
~
−
1
2
(
11
)
\qquad \qquad \quad I_N+D^{-\frac{1}{2}}AD^{-\frac{1}{2}}\to \tilde{D}^{-\frac{1}{2}}\tilde{A}\tilde{D}^{-\frac{1}{2}}\qquad\qquad\qquad\qquad(11)
IN+D−21AD−21→D~−21A~D~−21(11)
其中
A
~
=
A
+
I
N
\tilde{A}=A+I_N
A~=A+IN,
D
~
=
∑
j
A
~
i
j
\tilde{D}=\sum_j\tilde{A}_{ij}
D~=∑jA~ij,此时我们就将其特征值规范到了[0,1]之间。可以看到,
A
~
\tilde{A}
A~相当于每个节点增加了自连接关系,直观上来看,就是每个节点的跟新与邻近节点的表征以及节点上一层的表征有关。
将公式(11)带入公式(10)我们的图卷积表达式最终可写成如下形式:
Z
=
D
~
−
1
2
A
~
D
~
−
1
2
X
Θ
(
12
)
\qquad\qquad\quad\qquad Z=\tilde{D}^{-\frac{1}{2}}\tilde{A}\tilde{D}^{-\frac{1}{2}}X\Theta \qquad \qquad\qquad\qquad\qquad\quad(12)
Z=D~−21A~D~−21XΘ(12)
这里
X
∈
R
N
×
C
X\in\mathbb{R}^{N\times C}
X∈RN×C,N表示节点数,C表示节点的特征向量维度如C-dimensional,
Θ
∈
R
C
×
F
\Theta\in\mathbb{R}^{C\times F}
Θ∈RC×F表示可训练的参数矩阵,F表示输出维度,
Z
∈
R
N
×
F
Z\in \mathbb{R}^{N\times F}
Z∈RN×F就是卷积后的信号,这个公式的计算复杂度为
O
(
∣
ε
∣
F
C
)
O(|\varepsilon|FC)
O(∣ε∣FC),由于
A
~
X
\tilde{A}X
A~X可以执行稀疏矩阵乘法运算,所以实际计算速度会很快。
代码设计与实现
在GCN中,将公式(12)写成如下多层传播的形式:
H
(
l
+
1
)
=
σ
(
D
~
−
1
2
A
~
D
~
−
1
2
H
(
l
)
W
(
l
)
)
(
13
)
\qquad\qquad \qquad H^{(l+1)}=\sigma(\tilde{D}^{-\frac{1}{2}}\tilde{A}\tilde{D}^{-\frac{1}{2}}H^{(l)}W^{(l)})\qquad\qquad\qquad \quad(13)
H(l+1)=σ(D~−21A~D~−21H(l)W(l))(13)
代码实现方面非常简单,主要是前期对邻接矩阵的处理,以及图卷积层的构建,这里是一个pytorch实现的代码:
import torch
import torch.nn as nn
import torch.nn.init as init
import torch.nn.functional as F
# 图卷积层
class GraphConvolution(nn.Module):
def __init__(self, input_dim, output_dim, use_bias=True):
"""图卷积:L*X*\theta
Args:
----------
input_dim: int
节点输入特征的维度
output_dim: int
输出特征维度
use_bias : bool, optional
是否使用偏置
"""
super(GraphConvolution, self).__init__()
self.input_dim = input_dim
self.output_dim = output_dim
self.use_bias = use_bias
self.weight = nn.Parameter(torch.Tensor(input_dim, output_dim))#权重
if self.use_bias:
self.bias = nn.Parameter(torch.Tensor(output_dim))
else:
self.register_parameter('bias', None)
self.reset_parameters()
def reset_parameters(self):
init.kaiming_uniform_(self.weight)
if self.use_bias:
init.zeros_(self.bias)
def forward(self, adjacency, input_feature):
"""邻接矩阵是稀疏矩阵,因此在计算时使用稀疏矩阵乘法"""
support = torch.mm(input_feature, self.weight)
output = torch.sparse.mm(adjacency, support)
if self.use_bias:
output += self.bias
return output
def __repr__(self):
return self.__class__.__name__ + ' (' \
+ str(self.input_dim) + ' -> ' \
+ str(self.output_dim) + ')'
# 将邻接矩阵标准化
def normalization(adjacency):
"""计算 L=D^-0.5 * (A+I) * D^-0.5,
Args:
adjacency: sp.csr_matrix.
Returns:
归一化后的邻接矩阵,类型为 torch.sparse.FloatTensor
"""
adjacency += sp.eye(adjacency.shape[0]) # 增加自连接
degree = np.array(adjacency.sum(1))
d_hat = sp.diags(np.power(degree, -0.5).flatten())
L = d_hat.dot(adjacency).dot(d_hat).tocoo()
# 转换为 torch.sparse.FloatTensor
indices = torch.from_numpy(np.asarray([L.row, L.col])).long()
values = torch.from_numpy(L.data.astype(np.float32))
tensor_adjacency = torch.sparse.FloatTensor(indices, values, L.shape)
return tensor_adjacency
更多相关代码,可以从GitHub上下载:
《深入浅出图神经网络:GNN原理解析》配套代码
关于GCN的论文集合:GCN相关论文汇总
总结
从第一个版本到最终图卷积网络,每一次都在前一次的基础上大大减少了计算复杂度,最终才使得GCN的端到端训练成为可能,然而科学是不断进步和发展的,GCN还存在很多问题。
1、谱域卷积
在谱域图卷积中,我们对图的拉普拉斯矩阵进行谱分解,并通过在傅里叶空间特征分解帮助我们理解潜在的子图结构,GCN和ChebNet就是典型的应用。但是对于有向图的邻接矩阵是非对称矩阵,此时不能对拉普拉斯矩阵进行谱分解,需要我们重新定义邻接关系,或者通过其他形式的GCN来挖掘拓扑图上的关系。
2、空域卷积
空域卷积作用在节点的邻域上,我们通过聚合距离中心节点k-hop邻居来得到节点的特征表示。空域卷积相比谱域卷积更加简单和高效,GraphSAGE(Graph SAmple and aggreGatE)和GAT(Graph Attention Network) 是空域卷积的典型代表(GCN变体)。
未来围绕GCN的工作可以从以下几点围绕展开:
1、过度平滑问题
2、下游任务的处理应用
3、可解释性
4、处理有向图
5、inductive任务
…
参考文献
[1] T. N. Kipf and M. Welling, “Semi-supervised classification with graph convolutional networks,” 5th Int. Conf. Learn. Represent. ICLR 2017 - Conf. Tra
[2] M. Defferrard, X. Bresson, and P. Vandergheynst, “Convolutional neural networks on graphs with fast localized spectral filtering,” Adv. Neural Inf. Process. Syst., no. 59, pp. 3844–3852, 2016.
[3] Y. Jin, N. Duffield, P. Haffner, S. Sen, and Z. L. Zhang, “Learning Convolutional Neural Networks for Graphs Mathias,” 2010 22nd Int. Teletraffic Congr. - Proceedings, ITC 22, vol. 1, 2010.
[4] J. Bruna, W. Zaremba, A. Szlam, and Y. LeCun, “Spectral networks and deep locally connected networks on graphs,” 2nd Int. Conf. Learn. Represent. ICLR 2014 - Conf. Track Proc., pp. 1–14, 2014.
[5] 《深入浅出图神经网络:GNN原理解析》刘忠雨,李彦霖,周洋