由于课题研究需要,这星期看了几篇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真正开始运用和发展是从这篇于2016年提出,2017年发表的文章开始:SEMI-SUPERVISED CLASSIFICATION WITHGRAPH CONVOLUTIONAL NETWORKS ,详细文章内容,读者可以自行阅读原文。
在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.这样的正则项,使得拓扑图上相邻节点尽可能相似,物以类聚,这是很自然的想法。从信号的角度上来看,减少该正则项,就是期望经过模型之后的图信号更加平滑。从频域上来看,是对图信号做了低通滤波的处理,但是这样的假设可能会限制模型的表达能力,因为图上边不只包含相似度的信息,还可能包含其他相关信息。
最初标准的第一代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主要有以下几点弊端:
过高的计算复杂度和过大的计算参数,在实际运用中都是不允许的,于是基于以上两点的考虑,就产生了第二代版本的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)
计算多个大型稠密矩阵的乘法复杂度是很高的,这运用中在实际场景是不被允许的,尤其是计算像社交关系网络这种超大拓扑图的数据,显然是无法实现的,为解决这个问题,我们采用切比雪夫多项式(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(∣ε∣),即计算复杂度取决于图的边的数量。
为了简化问题,同时减轻由于局部节点度过大而导致过拟合的问题,我们设置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还存在很多问题。
在谱域图卷积中,我们对图的拉普拉斯矩阵进行谱分解,并通过在傅里叶空间特征分解帮助我们理解潜在的子图结构,GCN和ChebNet就是典型的应用。但是对于有向图的邻接矩阵是非对称矩阵,此时不能对拉普拉斯矩阵进行谱分解,需要我们重新定义邻接关系,或者通过其他形式的GCN来挖掘拓扑图上的关系。
空域卷积作用在节点的邻域上,我们通过聚合距离中心节点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原理解析》刘忠雨,李彦霖,周洋
[6] 知乎:如何理解 Graph Convolutional Network(GCN)