gnta架构 gcn架构优缺点_归一化


GCN(Graph convolution Network)是Convets在图结构上的自然推广。卷积神经网络是采用局部感知区域、共享权值和空间域上的降采样,相对于位移、缩放和扭曲,具有稳定不变的特性,能够很好的提取图像的空间特征。图结构不具备图片的平移不变性,传统的卷积方式不适用于图结构。图中每个节点的邻域节点数目不一致,无法用同样尺寸的卷积核进行提取特。

gnta架构 gcn架构优缺点_gnta架构_02

而GCN的本质就是提取图的结构特征,关键在于如何定义局部接受域(receptive field),主要有两种方式:

  • Spatial approach 如何定义局部感受域或者是邻居和节点的顺序 比如给节点的边指定方向
  • Spectral approach 通过图的拉普拉斯矩阵的特征值和特征向量对图结构进行处理。

简单的理论



gnta架构 gcn架构优缺点_gnta架构_03

gnta架构 gcn架构优缺点_图结构_04 gnta架构 gcn架构优缺点_特征向量_05是节点的集合,就是上图的V=[0,1,2,3,4,5] E是连接节点的边集合[1->2,2->4 …] 定义gnta架构 gcn架构优缺点_归一化_06 为节点度的对角矩阵。GCN公式为
gnta架构 gcn架构优缺点_图结构_07 其中gnta架构 gcn架构优缺点_图结构_08
上图一共有6个节点,可以通过下面代码生成

import networkx as nx
g=nx.random_graphs.watts_strogatz_graph(6,3,0.3)
colors = [1, 2, 3, 4, 5, 6]
nx.draw_kamada_kawai(g,with_labels=True,node_color=colors,alpha=0.7,node_size=600,font_size =18)

gnta架构 gcn架构优缺点_特征向量_09是图的邻接矩阵。

A=nx.adjacency_matrix(g).todense()
#
matrix([[0, 0, 0, 1, 0, 1],
        [0, 0, 1, 0, 0, 0],
        [0, 1, 0, 1, 1, 0],
        [1, 0, 1, 0, 0, 1],
        [0, 0, 1, 0, 0, 0],
        [1, 0, 0, 1, 0, 0]], dtype=int64)

gnta架构 gcn架构优缺点_图结构_10是节点的信息。现实中每个node都有自己的特征,在之家网站中,你可以把每个节点想象成user 或者 session,特征可以简单的理解为user 产生pv ,或者浏览时长等等。我们生成一些简单的feature ,方便大家更好的验证

X = np.matrix([
            [i, -i]
            for i in range(A.shape[0])
        ], dtype=float)
        
matrix([[ 0.,  0.],
        [ 1., -1.],
        [ 2., -2.],
        [ 3., -3.],
        [ 4., -4.],
        [ 5., -5.]])

我们看一下 gnta架构 gcn架构优缺点_特征向量_11 gnta架构 gcn架构优缺点_gnta架构_12

A*X
matrix([[ 8., -8.],
        [ 2., -2.],
        [ 8., -8.],
        [ 7., -7.],
        [ 2., -2.],
        [ 3., -3.]])



gnta架构 gcn架构优缺点_图结构_13

很容易看出$AX$只是对邻接域节点进行sum. - 简单的sum对特征提取具有关于节点度的倾向性即节点度越大,聚合的信息就越大. - $A$中不存在self-loop 提取的信息不包含节点本身的信息

我们可以通过gnta架构 gcn架构优缺点_归一化_14 解决self-loop问题
gnta架构 gcn架构优缺点_gnta架构_15 通过节点信息进行归一化
最终的对X的转换操作为
gnta架构 gcn架构优缺点_图结构_16

I=np.matrix(np.eye(A.shape[0]))  #单位矩阵
A_hat=A+I
matrix([[  8.,  -8.],
        [  3.,  -3.],
        [ 10., -10.],
        [ 10., -10.],
        [  6.,  -6.],
        [  8.,  -8.]])
        
D=np.matrix(np.diag(np.array(A_hat.sum(axis=0))[0]))
matrix([[3., 0., 0., 0., 0., 0.],
        [0., 2., 0., 0., 0., 0.],
        [0., 0., 4., 0., 0., 0.],
        [0., 0., 0., 4., 0., 0.],
        [0., 0., 0., 0., 2., 0.],
        [0., 0., 0., 0., 0., 3.]])
D**-1*A_hat

matrix([[0.33333333, 0.        , 0.        , 0.33333333, 0.        ,
         0.33333333],
        [0.        , 0.5       , 0.5       , 0.        , 0.        ,
         0.        ],
        [0.        , 0.25      , 0.25      , 0.25      , 0.25      ,
         0.        ],
        [0.25      , 0.        , 0.25      , 0.25      , 0.        ,
         0.25      ],
        [0.        , 0.        , 0.5       , 0.        , 0.5       ,
         0.        ],
        [0.33333333, 0.        , 0.        , 0.33333333, 0.        ,
         0.33333333]])

我们得到了特征提取的公式
gnta架构 gcn架构优缺点_归一化_17
当然你也可以尝试其他的归一化方式比如对称归一化$D^{-1} A \rightarrow D^{-\frac{1}{2}} \hat{A} D^{-\frac{1}{2}} $
gnta架构 gcn架构优缺点_图结构_18

而谱图理论所操作的对象是图的Laplacian矩阵gnta架构 gcn架构优缺点_特征向量_19 或者标准化Laplacian gnta架构 gcn架构优缺点_归一化_20
gnta架构 gcn架构优缺点_图结构_21半正定矩阵有三个性质:

  • 对称矩阵一定具有n个线性无关的特征向量
  • 半正定矩阵的特征值一定非负
  • 对称矩阵的特征向量相互正交即所有特征向量构成的矩阵为正交矩阵

gnta架构 gcn架构优缺点_gnta架构_22 gnta架构 gcn架构优缺点_归一化_23gnta架构 gcn架构优缺点_图结构_21的特征值,gnta架构 gcn架构优缺点_特征向量_25是特征向量矩阵。 gnta架构 gcn架构优缺点_图结构_26是对gnta架构 gcn架构优缺点_归一化_27的图傅立叶变换。

将图的卷积操作定义为 gnta架构 gcn架构优缺点_图结构_28gnta架构 gcn架构优缺点_图结构_29 其中 gnta架构 gcn架构优缺点_gnta架构_30
gnta架构 gcn架构优缺点_特征向量_31
特征分解复杂度较高,Kipf通过切比雪夫多项式gnta架构 gcn架构优缺点_gnta架构_32直到第k阶的阶段来展开近似gnta架构 gcn架构优缺点_归一化_33来降低计算量

gnta架构 gcn架构优缺点_特征向量_34

gnta架构 gcn架构优缺点_gnta架构_35 gnta架构 gcn架构优缺点_归一化_36gnta架构 gcn架构优缺点_图结构_21的最大特征值 gnta架构 gcn架构优缺点_图结构_38是切比雪夫系数向量
切比雪夫多项式被定义为gnta架构 gcn架构优缺点_图结构_39
因此可以有如下的表达式
gnta架构 gcn架构优缺点_gnta架构_40
其中$\hat{L}=\frac{2}{\lambda_{max}}L-I_N $ 函数复杂度为gnta架构 gcn架构优缺点_特征向量_41

层次的线形模型

图卷积神经网络的模型可以由堆叠多层公式(5)形式的卷积层构成。先将卷积层限制在k=1即
gnta架构 gcn架构优缺点_归一化_42
现在取近似gnta架构 gcn架构优缺点_图结构_43 则有
gnta架构 gcn架构优缺点_gnta架构_44
进一步通过约束参数的数量来避免过拟合,同时最小化每一层的操作数,得到如下:
gnta架构 gcn架构优缺点_特征向量_45
即令(4)中$\theta =\theta^\prime_0 = - \theta^\prime_1 $ 但是gnta架构 gcn架构优缺点_gnta架构_46的特征值的范围是gnta架构 gcn架构优缺点_gnta架构_47在深度神经网络模型中,这个运算的复杂操作有可能导致数值的不稳定和梯度爆炸或者消失,为了解决这个问题,引入了再归一化gnta架构 gcn架构优缺点_gnta架构_48其中gnta架构 gcn架构优缺点_归一化_49

Demo

gnta架构 gcn架构优缺点_图结构_50

下面我们实现一个基于karate_club网络GCN demo



gnta架构 gcn架构优缺点_归一化_51

from networkx import karate_club_graph,to_numpy_matrix
import numpy as np
# step1: Data preparation
zkc=karate_club_graph()
order=sorted(list(zkc.nodes()))

NODE_SIZE=len(order)
#Adjacency matrix
A=to_numpy_matrix(zkc,nodelist=order)

#identity matrix
I=np.eye(zkc.number_of_nodes())

node_label = []
for i in range(34):
        label = zkc.node[i]
        if label['club'] == 'Officer':
                node_label.append(1)
        else:
                node_label.append(0)
                
# step2:  Parameter Settings             
NODE_SIZE = 34
NODE_FEATURE_DIM = 34
HIDDEN_DIM1 = 10
num_classes = 2
training_epochs = 100
step = 10
lr=0.1

# step3: network define
X = tf.placeholder(tf.float32, shape=[NODE_SIZE, NODE_FEATURE_DIM])
Y = tf.placeholder(tf.int32, shape=[NODE_SIZE])
label = tf.one_hot(Y, num_classes)
Y_enc = tf.one_hot(Y, 2)

adj = tf.placeholder(tf.float32, shape=[NODE_SIZE, NODE_SIZE])
weights = {"hidden1": tf.Variable(tf.random_normal(dtype=tf.float32, shape=[NODE_FEATURE_DIM, HIDDEN_DIM1]), name='w1'),
           "hidden2": tf.Variable(tf.random_normal(dtype=tf.float32, shape=[HIDDEN_DIM1, num_classes]), 'w1')}
D_hat = tf.matrix_inverse(tf.matrix_diag(tf.reduce_sum(adj, axis=0)))
# GCN layer1
l1 = tf.matmul(tf.matmul(tf.matmul(D_hat, adj), X), weights['hidden1'])
# GCN layer2
output = tf.matmul(tf.matmul(tf.matmul(D_hat, adj), l1), weights['hidden2'])

# step4:define loss func and train
loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=Y_enc, logits=output))
train_op = tf.train.AdamOptimizer(learning_rate=lr).minimize(loss)
init_op = tf.global_variables_initializer()
feed_dict = {adj: A, X: I, Y: node_label}
with tf.Session() as sess:
        sess.run(init_op)
        # dynamic display
        plt.ion()
        for epoch in range(training_epochs):
                c, _ = sess.run([loss, train_op], feed_dict)
                if epoch % step == 0:
                        print(f'Epoch:{epoch} Loss {c}')

                represent = sess.run(output, feed_dict)
                plt.scatter(represent[:, 0], represent[:, 1], s=200, c=g.node_label)
                plt.pause(0.1)
                plt.cla()

模型效果如下

gnta架构 gcn架构优缺点_图结构_52


gnta架构 gcn架构优缺点_gnta架构_53


gnta架构 gcn架构优缺点_图结构_54


gnta架构 gcn架构优缺点_归一化_55

GCN 能够充分的整合节点的信息,借鉴PinSage,可以将item_id进行嵌入embedding,根据邻居节点的信息实现的嵌入会更加的准确和强大,能够发现文章、视频、图片之间的潜在语义关系,而不仅仅只是内容上的相似。