GNN Pooling(六):Graph Convolutional Networks with EigenPooling,KDD2019

这真是我读过的最难的一篇图池化了。有些没有理解的地方等日后再来拾遗。
本文作者来自Michigan State University,Pennsylvania State University以及IBM T. J. Watson Research Center。
图池化把节点分组为子图(对应池化之后的超节点),根据这些子图对图进行粗化,然后通过子图中对应的节点生成超节点的特征,将整个图信息简化为粗化图。在对超节点特征进行池化时,通常会忽略这些组节点的结构(局部结构),而采用平均池化或最大池化。但是对于不同的子图来说,子图可能包含不同数量的节点,因此固定大小的池操作符不能适用于所有子图;子图可以有非常不同的结构,这可能需要不同的方法来总结超节点表示的信息。为此,本文提出了一种适应不同子图结构的池化方法——基于傅里叶变换的池化方法,EigenPool,并以此提出了EigenGCN。
github传送门:https://github.com/alge24/eigenpooling

1. EigenPool

在这里插入图片描述
从具体的架构来看,DiffPool比较类似。对于池化的任务,普遍分为两个部分:

  1. 图粗化,即将图划分为一组子图,并将子图视为超节点,从而形成粗化图;
  2. 利用特征池将原始图信号信息转化为粗化图上定义的图信号。

1.1 Graph Coarsening

图粗化的过程是一个子图划分的过程,将原图划分为一组没有重叠节点的一组子图。给定一个图 G G G,包含 K K K个子图 G ( k ) G^{(k)} G(k),使用A∈RN×N表示邻接矩阵,X∈RN×d表示特征, N k N_k Nk表示子图 k k k中的结点数, Γ ( k ) Γ^{(k)} Γ(k)表示子图 G ( k ) G^{(k)} G(k)中的所有结点的列表。定义一个采样操作 C ( k ) ∈ R N × N K C^{(k)}∈R^{N×N_K} C(k)RN×NK

在这里插入图片描述
C ( k ) [ i , j ] C^{(k)}[i,j] C(k)[i,j]表示i,j位置上的元素, Γ ( k ) ( j ) Γ^{(k)}(j) Γ(k)(j)则表示 Γ ( k ) Γ^{(k)} Γ(k)中的第 j j j个元素。首先需要明确 C ( k ) C^{(k)} C(k)是一个比较特殊的矩阵,我们把 i i i视为行,表示 N N N个结点其中的一个, j j j视为列表示结点 i i i属于哪个子图,那么 C ( k ) C^{(k)} C(k)本身就是一个行只能为one-hot向量或者是0向量的矩阵,因为按照本文的定义,一个结点不可能同属两个子图。而对于不同的子图,因为子图的结点数量不同,对应的 C ( k ) C^{(k)} C(k)的大小也不尽相同(对此会有一个补全操作,到特征池那里再说)。
这样,子图 k k k的邻接矩阵 A ( k ) ∈ R N k × N k A^{(k)}∈R^{N_k×N_k} A(k)RNk×Nk就可以表示为:
在这里插入图片描述
由于 C ( k ) C^{(k)} C(k)只表示子图 k k k的采样,因此只有在子图中节点对应的行处才存在非0值,因此计算得出的结果只由每个子图内部的边组成。对其进行逆变换,就可以得到子图在原图中的结构特征,但是由于 C ( k ) C^{(k)} C(k)无法表示跨越子图之间的关系,因此做逆变换(up-sampling):
在这里插入图片描述
之后,得到的 A i n i t A_{init} Ainit仅仅是子图内部结点之间的关系,这样跨越子图的关系也就可以计算: A e x t = A − A i n i t A_{ext}=A-A_{init} Aext=AAinit。这个操作可以理解为:原图的边A-(所有子图之内的边),就得到了子图之间的边。(这部分不好理解,可以试着构建一个K=2的简单矩阵自己推一下
但是此时得到的 A e x t A_{ext} Aext是一个 N × N N×N N×N的矩阵,因此还需要通过assignment matrix(对,就是与DiffPool里的那个assignment matrix差不多)缩放到大小为 N K N_K NK。定义 S ∈ R N × K S∈R^{N×K} SRN×K
在这里插入图片描述
粗化之后的矩阵表示为:
在这里插入图片描述
至此,粗化邻接矩阵的步骤结束。呼,如此麻烦。但是从代码上来看,由于直接采用了封装好的谱聚类方法,所以还是比较好理解。看代码:

	def _coarserning_pooling_(self, adjacency_matrix, pooling_size, normalize=False):
		num_nodes = adjacency_matrix[:,0].shape[0]
		A_dense = adjacency_matrix.todense()
		num_clusters = int(num_nodes/pooling_size)
		if num_clusters == 0:
			num_clusters = num_clusters + 1
		sc = SpectralClustering(n_clusters = num_clusters, affinity= 'precomputed', n_init=10)   # 谱聚类,需要指明cluster的数量
		sc.fit(A_dense)
		clusters = dict()
		for inx, label in enumerate(sc.labels_):   # 从聚类的结果里解析出不同聚类的邻接矩阵
			if label not in clusters:
				clusters[label] = []
			clusters[label].append(inx)
		num_clusters = len(clusters)
		num_nodes_in_largest_clusters = 0
		for label in clusters:
			if len(clusters[label])>=num_nodes_in_largest_clusters:
				num_nodes_in_largest_clusters = len(clusters[label])
		if num_nodes_in_largest_clusters <=5:
			num_nodes_in_largest_clusters = 5
		num_nodes_in_largest_clusters = 5    # 这个最后把最大cluster中的节点数量设置为了5我没咋理解
		Adjacencies_per_cluster = [adjacency_matrix[clusters[label],:][:,clusters[label]] for label in range(len(clusters))]
######## Get inter matrix
		A_int = sp.lil_matrix(adjacency_matrix)
		for i in range(len(clusters)):
			zero_list = list(set(range(num_nodes)) - set(clusters[i]))
			for j in clusters[i]:
				A_int[j,zero_list] = 0
				A_int[zero_list,j] = 0
######## Getting adjacenccy matrix wuith only external links
		A_ext = adjacency_matrix - A_int
######## Getting cluster vertex indicate matrix
		row_inds = []
		col_inds = []
		data = []
		for i in clusters:
			for j in clusters[i]:
				row_inds.append(j)
				col_inds.append(i)
				data.append(1)
		Omega = sp.coo_matrix((data,(row_inds,col_inds)))   # Omega就是公式中的S
		A_coarsened = np.dot( np.dot(np.transpose(Omega),A_ext), Omega)

Eigenvector-Based Pooling

对每个已经划分好的子图,需要通过傅里叶变换提取特征。因为傅里叶变换是以拉普拉斯矩阵为基础的,所以可以说傅里叶变换之后既考虑了结构又考虑了特征。首先,同GCN一样,先定义拉普拉斯矩阵: L = D − A L = D−A L=DA D D D是度矩阵。原文的表示法为(顺便吐槽一下这篇论文写得真是拖泥带水,连简单的度矩阵公式看着都别扭,嗨呀):
在这里插入图片描述
拉普拉斯矩阵对应一组特征向量 { u l } l = 1 N \lbrace u_l \rbrace^N_{l=1} {ul}l=1N以及特征值 { λ l } l = 1 N \lbrace λ_l \rbrace^N_{l=1} {λl}l=1N,给定一个图信号,则对应傅里叶变换为:
在这里插入图片描述
U U U是所有特征向量构成的矩阵。那么傅里叶变换的逆变换为:
在这里插入图片描述
L ( k ) L^{(k)} L(k)为子图k的拉普拉斯矩阵,其对应的特征为 u 1 ( k ) u^{(k)}_{1} u1(k) u N k ( k ) u^{(k)}_{N_k} uNk(k)。通过上采样 C ( k ) C^{(k)} C(k)得到特征在整个图中的表示:
在这里插入图片描述
然后将整个上采样之后的特征向量拼接成矩阵作为池操作符 θ l ∈ R N × K θ_l∈R^{N×K} θlRN×K
在这里插入图片描述
也就是说,不同的子图在 l l l的位置都会对应一个特征,把这个特征拼接起来做成全局的特征。但是,这样又出现一个新的问题,就是每个子图的大小可能不确定,将其补全成最大子图的大小 N m a x N_{max} Nmax,对于那些较小的,则在后边补0向量。最终, l t h l^{th} lth的池化符 θ l θ_l θl下的池化被定义为:
在这里插入图片描述
这里,需要对傅里叶变换的物理意义进行一波理解,我之前也写过这个,但是还是在这里复习一遍。首先,我们就不区分时域和频域,只考虑这样一个事实:傅里叶变换将信号转换为一组正弦波的叠加,每一组正弦波都对应一组特定的基底,在EigenPool中,这个基底就是 θ l θ_l θl。拿Kipf简化之后的GCN来举例,GCN可以理解为一个高通滤波器(也就是让高频率的波通过),在公式中就表示为高频波的基底的叠加。对于GCN来说,只允许零阶和一阶的滤波通过(也就是下面公式里的 θ I θI θI θ L θL θL)。而相比于低通滤波器ChebNet,高通滤波器让更少的波通过却取得了更好的效果,这从物理意义上来理解,就是高通滤波器只聚合邻近的结点的信息,而ChebNet则会让更远的节点的信息参与到卷积的过程中来,后者会造成过平滑。
在这里插入图片描述
那么回到论文中去,在不同的基底作用下的池化就变成了:
在这里插入图片描述
小伙伴们可能会问了,这里也没有基底 θ l θ_l θl啊,那是因为都借助公式(14)转化为X了。而参照GCN对切比雪夫多项式截断的思路,这个 X p o o l e d X_{pooled} Xpooled也可以用一个 H H H阶的截断来代替,也就是下面的公式:
在这里插入图片描述
其中, H < < N m a x H<<N_{max} H<<Nmax,仍然能够保留大量的特征信息(因为高通滤波器)。

THEORETICAL ANALYSIS OF EigenPooling

接下来是对EigenPool进行的原理以及公式的推导,鉴于理解EigenPool已经让我的脑细胞大量死亡,因此这部分留到以后有时间再看。

EXPERIMENT

首先,这几个常用的数据集我也不多说了:
在这里插入图片描述
Baseline:
GCN,GraphSAGE,Set2Set,DGCNN,DiffPool,然后再加上EigenGCN-H, H = 1 , 2 , 3 H=1,2,3 H=1,2,3。对于每个数据集,我们随机将其分为3个部分,即:80%作为训练集,10%作为验证集,10%作为测试集。我们将随机分割过程重复10次,给出10次不同分割的平均性能。运行结果如下:
在这里插入图片描述

  • 在大多数情况下,Diff-pool和EigenGCN框架比那些不使用分层池过程的方法执行得更好。分层聚合节点信息有助于更好地学习图的表示。
  • 提出的框架EigenGCN与GCN、GraphSage和SET2SET使用的是同一个卷积放肆。然而,提出的框架在大多数数据集优于它们。这进一步表明了分层池程序的必要性。换句话说,所提出的特征池确实可以提高图的分类性能。
  • 在大多数数据集中,H越大效果越好。包含更多的特征向量,这表明我们可以在池中保存更多的信息,在大多数情况下可以帮助学习更好的图表示。在一些数据集中,加入更多的特征向量并不会对性能带来任何提高,甚至会使性能变差。理论上,我们可以通过使用更多的特征向量来保存更多的信息。同时,利用较少的特征向量可以对噪声信号进行过滤。

下集预告:基于CRF的池化。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五月的echo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值