- Defferrard 及其团队,在NIPS.2016的上的文章 《Convolutional neural networks on graph with fast localized spectral fiftering》是学习GCN的入门必读文章。文章的核心要点是将谱域GCN的卷积核,使用chebyshev多项式截断,然后经过迭代,绕开了原有对Laplacian的特征分解所需要的大量计算。因此计算复杂度大量下降,加快了卷积的过程。
- 本文针对原文代码,在读入数据时,每个节点仅仅可以读取一个像素值的情况进行修改,以便其可以读入更长的一维向量文中第四部分(Numerical experiments),给出了对于传统图像(欧式数据)转化成graph,这种非欧数据的做法以验证自身提出对GCN改进的有效性。在著名“Hello world”数据集上MNIST上进行了实验。其做法如下:
- 首先,将28x28像素的图像中的每一个像素点,视作graph中的一个节点/顶点(vertex),节点之间的edges的定义来自像素点之间任意两点的欧氏距离,但取前8个最小距离的像素点作为节点的邻接节点(neighborhood)。从这里也能观察出,实际上某一节点的邻接节点,也就是它的八邻域而已,这点和CNN的卷积核(3x3)是相同的作用。有了节点和边(edge)的定义,因此也能很快求得graph的Adjacency matrix和Degress matrix,二者相减即可得到Laplacian。graph定义完毕。(值得注意的是graph的节点由于进行了图粗化,因此得到的Laplacian并不是784x784,而是粗化到了928x928,因此后面输入的数据相应也进行了粗化,不再是784长的像素值,而是928长度的,见下图)
def grid_graph(m, corners=False):
z = graph.grid(m) # 产生一个28*28网格的每个点的坐标
dist, idx = graph.distance_sklearn_metrics(z, k=FLAGS.number_edges, metric=FLAGS.metric)
A = graph.adjacency(dist, idx)
# Connections are only vertical or horizontal on the grid. 网格上的连接只有水平或者垂直
# Corner vertices are connected to 2 neightbors only. 转角处的顶点只与两个邻接点连接
if corners:
import scipy.sparse
A = A.toarray()
A[A < A.max() / 1.5] = 0
A = scipy.sparse.csr_matrix(A)
print('{} edges'.format(A.nnz))
print("{} > {} edges".format(A.nnz // 2, FLAGS.number_edges * m ** 2 // 2))
return A
- 其次,文中也提到了GSP(graph signal processing)的问题,但是在原文代码中,每个节点读入的是其像素值。这也就是说,graph上的每个节点上的signal仅仅是一个数值而已,这限制了特征提取。
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(FLAGS.dir_data, one_hot=False)
train_data = mnist.train.images.astype(np.float32)
val_data = mnist.validation.images.astype(np.float32)
test_data = mnist.test.images.astype(np.float32)
train_labels = mnist.train.labels
val_labels = mnist.validation.labels
test_labels = mnist.test.labels
t_start = time.process_time()
train_data = coarsening.perm_data(train_data, perm)
val_data = coarsening.perm_data(val_data, perm)
test_data = coarsening.perm_data(test_data, perm)
-
图中所示。signal中的值为像素值,对应了定义的graph上vertex的signal。但是一个节点就一个数值实在是难受的一批。
-
如何将signal信号变长,以适应节点有更好的特征,方便我们从数据中获得信息,减少信息丢失。如下图,我们需要的graph的样子。
- 其中红色表示节点间的相互连接,也就是我们得到的邻接矩阵,蓝色竖条为节点signal(这张图上的信号长度各不相同,本博客所针对的是长度相同的信号)。
具体修改工程如下:
1.将model,继承做法去除,直接合并成新的类(neu_gcn)
2.修改model中self.fit()方法 tf的placeholder加一维
3.修改_inference 以适用读入的三维数据的情况(NxMxFin N为batch_size M为节点数量 Fin为signal长度)
4.修改了源码的mnist部分 换用了ABIDE数据(871x116x116),自闭症数据,有871个被试,每个被试拥有116x116的标准脑网络矩阵。另有标准脑脑区位置坐标以便生成连接矩阵。
5.修改了其他辅助函数,删除了本代码没有使用的函数,重写了utils.py和graph.py
详细内容参考,我的github:https://github.com/leesendy/neu_gcn