初识GCN

1.GCN概述

CNN处理的图像或者视频数据中像素点(pixel)是排列成成很整齐的矩阵
GCN 中的 Graph 是指数学(图论)中的用顶点和边建立相应关系的拓扑图
在这里插入图片描述

GCN的本质目的就是用来提取拓扑图的空间特征

1.1.拉普拉斯矩阵

拉普拉斯矩阵(Laplacian matrix) ,主要应用在图论中,作为一个图的矩阵表示。对于图 G=(V,E),其Laplacian 矩阵的定义为 L=D-A,其中L 是Laplacian 矩阵, D=diag(d)是顶点的度矩阵(对角矩阵),d=rowSum(A),对角线上元素依次为各个顶点的度, A 是图的邻接矩阵。
普通形式的拉普拉斯矩阵
L = D − A L=D-A L=DA
为什么GCN要用拉普拉斯矩阵?

  • 拉普拉斯矩阵是对称矩阵,可以进行特征分解(谱分解)
  • 由于卷积在傅里叶域的计算相对简单,为了在graph上做傅里叶变换,需要找到graph的连续的正交基对应于傅里叶变换的基,因此要使用拉普拉斯矩阵的特征向量。

1.2.相关定义

邻居:一个节点 n 是一个节点 v 的邻居只有在存在一个从 v 到 n 的边时。
邻接矩阵:邻接矩阵 A 为 n×n 矩阵,其中 n 为图中节点数,Aij=1 表示节点 i 和节点 j 之间有边相连
在这里插入图片描述
度矩阵D:D 是对角矩阵,即除了对角线其他元素都为 0,对角值如下计算, D i i D_{ii} Dii表示与节点 i i i 相连的节点数
在这里插入图片描述
节点特征向量矩阵:的节点 v 带有特征向量,用矩阵 X 保存图节点的特征向量,特征向量维度是 d:
在这里插入图片描述
GCN 主要是将卷积操作应用到图结构上,如下图所示,GCN 输入的 chanel 为 C(即节点 Xi 特征向量的维度), GCN 输出的 chanel 为 F,即每个节点 (Zi) 的特征向量维度为 F,最后用节点的特征对节点进行分类预测等:
在这里插入图片描述

1.3.GCN的输入

给定一个图G=(E,V) ,一个GCN的输入包括:

  • 一个输入特征矩阵 X X X,其维度是 N × F 0 N \times F^{0} N×F0 ,其中 N N N是节点的数目, F 0 F^{0} F0是每个节点输入特征的数目
  • 一个 N × N N \times N N×N的对于图结构的表示的矩阵,例如 G G G的邻接矩阵 A A A

2.一个简单的 Propagation Rule

一个最简单的传播规则是:
f ( H i , A ) = σ ( A H i W i ) f(H^{i},A)=σ(AH^{i}W^{i}) f(Hi,A)=σ(AHiWi)
其中Wi是第 i层的权重并且σ是一个非线性激活函数例如ReLU 函数。权重矩阵的维度是 F i × F i + 1 F_{i}×F_{i}+1 Fi×Fi+1也就是说权重矩阵的第二个维度决定了在下一层的特征的数目。如果你对卷积神经网络熟悉,这个操作类似于 filtering operation 因为这些权重被图上节点共享。

H i + 1 = f ( H i , A ) = σ ( A H i W i ) H^{i+1}=f(H^{i},A)=σ(AH^{i}W^{i}) Hi+1=f(Hi,A)=σ(AHiWi)

A A A:(N,N)邻接矩阵
F i F^{i} Fi:一维数值,第 i i i层的特征数目
H i H^{i} Hi ( N , F i ) (N,F^{i}) (N,Fi),每一行都是一个节点的特征表示
X = H 0 X=H^{0} X=H0 ( N , F 0 ) (N,F^{0}) (N,F0),输入向量
W i W^{i} Wi ( f i , F i + 1 ) (f^{i},F^{i+1}) (fi,Fi+1) i i i层的权值矩阵

加入权重和激活函数后完整的计算公式:
在这里插入图片描述

3.一个例子,由浅入深

定义一个图:
在这里插入图片描述

3.1.按照简单的传播规则计算

step 1:这个图的邻接矩阵表示为:

import numpy as np
A = np.matrix([  ##邻接矩阵
    [0,1,0,0],
    [0,0,1,1],
    [0,1,0,0],
    [1,0,1,0]
],dtype=float)

step 2:定义特征向量X:

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

X:

matrix([[ 0.,  0.],
        [ 1., -1.],
        [ 2., -2.],
        [ 3., -3.]])

step 3:计算 A ∗ X A*X AX

A*X

A ∗ X A*X AX

matrix([[ 1., -1.],
        [ 5., -5.],
        [ 1., -1.],
        [ 2., -2.]])

3.2.出现的问题

这时我们会发现一般的传播规则存在如下的问题:

  • A ∗ X A*X AX 的结点表示中,并没有加自己的特征值。一个节点的聚集表示不包括它自己的特征!这个表示只是它的邻居节点特征的聚集。
  • 邻接结点多的结点的特征值会大,少的特征值就小。具有很大度数的节点将会有很大的值在它们的特征表示中,而具有很小度数的节点将会有很小的值。这些可能造成梯度消失或者梯度爆炸。这对于随机梯度下降也可能是有问题的,随机梯度下降通常被用来训练这样的网络,而且对于每个输入特征的值的范围是敏感的。

3.3.自循环

step 4:单位矩阵 I I I

I = np.matrix(np.eye(A.shape[0]))

I I I

matrix([[1., 0., 0., 0.],
        [0., 1., 0., 0.],
        [0., 0., 1., 0.],
        [0., 0., 0., 1.]])

step 5:加入自循环后与特征向量 X X X相乘:

A_hat = A + I
A_hat * X

结果:

matrix([[ 1., -1.],
        [ 6., -6.],
        [ 3., -3.],
        [ 5., -5.]])

3.4.归一化

特征表示可以通过节点的度来进行归一化,方法是将邻接矩阵 A 转换为 A 和度矩阵D的逆的乘积。因此我们简化的传播规则看起来向这样:
step 6:度矩阵:

D = np.array(np.sum(A,axis=0))[0]
D = np.matrix(np.diag(D))  

D D D

matrix([[1., 0., 0., 0.],
        [0., 2., 0., 0.],
        [0., 0., 2., 0.],
        [0., 0., 0., 1.]])

step 7:归一化操作:

D**-1 * A

计算后:

matrix([[0. , 1. , 0. , 0. ],
        [0. , 0. , 0.5, 0.5],
        [0. , 0.5, 0. , 0. ],
        [1. , 0. , 1. , 0. ]])

step 8:归一化之后与特征向量 X X X相乘:

D**-1 * A * X

计算后:

matrix([[ 1. , -1. ],
        [ 2.5, -2.5],
        [ 0.5, -0.5],
        [ 2. , -2. ]])

3.5.加入权重和激活函数

step 9:加入权重:

w = np.matrix([
    [1,-1],
    [-1,1]
])
A_hat = A + I
D_hat = np.array(np.sum(A_hat,axis=0))[0]
D_hat = np.matrix(np.diag(D_hat))

D_hat:

matrix([[2., 0., 0., 0.],
        [0., 3., 0., 0.],
        [0., 0., 3., 0.],
        [0., 0., 0., 2.]])
D_hat**-1 * A_hat*X*w

计算后:

matrix([[ 1., -1.],
        [ 4., -4.],
        [ 2., -2.],
        [ 5., -5.]])

step 10:加入激活函数:

def relu(x):         
    return (abs(x) + x) / 2.0
relu(D_hat**-1 * A_hat * X * w)

计算结果:

matrix([[1., 0.],
        [4., 0.],
        [2., 0.],
        [5., 0.]])

4.空手道案例分析

4.1.案例介绍

Zachary 空手道俱乐部是一个被广泛使用的社交网络,其中的节点代表空手道俱乐部的成员,边代表成员之间的相互关系。当年,Zachary 在研究空手道俱乐部的时候,管理员和教员发生了冲突,导致俱乐部一分为二。下图显示了该网络的图表征,其中的节点标注是根据节点属于俱乐部的哪个部分而得到的,「A」和「I」分别表示属于管理员和教员阵营的节点。

4.2.代码实现

import numpy as np
from networkx import to_numpy_matrix
import networkx as nx      
zkc = nx.karate_club_graph()        # 导入空手道俱乐部的社交网络
order = sorted(list(zkc.nodes()))         #对所有点进行排序 # sorted() 函数对所有可迭代的对象进行升序排序操作。
A = to_numpy_matrix(zkc, nodelist=order)       #邻接矩阵
I = np.eye(zkc.number_of_nodes())         #单位矩阵
A_hat = A + I
D_hat = np.array(np.sum(A_hat, axis=0))[0]     #sum(a, axis = None) : 依给定轴axis计算数组a相关元素之和,axis为整数或者元组 
D_hat = np.matrix(np.diag(D_hat))       #对角线

def plot_graph(G, weight_name=None):
    '''
    G: a networkx G
    weight_name: name of the attribute for plotting edge weights (if G is weighted)
    '''
    import matplotlib.pyplot as plt
    %matplotlib notebook
    
    plt.figure()
    pos = nx.spring_layout(G)     #采用spring布局方式定义一个布局
    edges = G.edges()       #获取边
    weights = None
    
    if weight_name:
        weights = [ int(G[u][v][weight_name] ) for u,v in edges]
        labels = nx.get_edge_attributes(G,weight_name)
        nx.draw_networkx_edge_labels(G,pos,edge_labels=labels)
        nx.draw_networkx(G, pos, edges=edges, width=weights);
    else:
        nodelist1 = []
        nodelist2 = []
        for i in range (34):        #管理员和教员阵营分类
            if zkc.nodes[i]['club'] == 'Mr. Hi':
                nodelist1.append(i)
            else:
                nodelist2.append(i)
        #nx.draw_networkx(G, pos, edges=edges);
        nx.draw_networkx_nodes(G, pos, nodelist=nodelist1, node_size=300, node_color='r',alpha = 0.8)
        nx.draw_networkx_nodes(G, pos, nodelist=nodelist2, node_size=300, node_color='b',alpha = 0.8)
        nx.draw_networkx_edges(G, pos, edgelist=edges,alpha =0.4)
        
plot_graph(zkc)

在这里插入图片描述

#定义权重
#正态分布;loc:正态分布的均值; scale:正态分布的标准差; size(int 或者整数元组):输出的值赋在shape里
W_1 = np.random.normal(loc=0, scale=1, size=(zkc.number_of_nodes(), 4))
W_2 = np.random.normal(loc=0, size=(W_1.shape[1], 2)) 
W_1.shape

(34, 4)

W_2.shape

(4, 2)

def relu(x):          #定义relu激活函数
    return (abs(x) + x) / 2.0

def gcn_layer(A_hat, D_hat, X, W):        #定义 D_hat**-1 * A_hat * X * W公式
    return relu(D_hat**-1 * A_hat * X * W)

#前向传播:
H_1 = gcn_layer(A_hat, D_hat, I, W_1)
H_2 = gcn_layer(A_hat, D_hat, H_1, W_2)
output = H_2  

feature_representations = {
    node: np.array(output)[node] for node in zkc.nodes()}
feature_representations

{0: array([0.3646146 , 0.26904721]),
1: array([0.2848063 , 0.29515183]),
2: array([0.51791888, 0.18827742]),
3: array([0.31797502, 0.23169222]),
4: array([0.2265585 , 0.71748199]),
5: array([0.20798158, 0.54375024]),
6: array([0.23193104, 0.46542201]),
7: array([0.18881706, 0.31602282]),
8: array([0.41123805, 0. ]),
9: array([0.41832314, 0.12669272]),
10: array([0.17721712, 0.6640156 ]),
11: array([0.47274409, 0. ]),
12: array([0.43774438, 0.15015674]),
13: array([0.2456919, 0.261067 ]),
14: array([0.93199074, 0. ]),
15: array([0.9236548, 0. ]),
16: array([0.23525499, 0.37571568]),
17: array([0.25711395, 0.27326112]),
18: array([1.16095606, 0. ]),
19: array([0.28237279, 0.03967677]),
20: array([1.05828531, 0. ]),
21: array([0.22964731, 0.27950972]),
22: array([1.07827656, 0. ]),
23: array([0.97721974, 0. ]),
24: array([1.17417171, 0.0783619 ]),
25: array([1.15124332, 0.07776736]),
26: array([0.7745391, 0. ]),
27: array([0.85109117, 0.05471966]),
28: array([0.75985656, 0.31224247]),
29: array([0.81969178, 0. ]),
30: array([0.4580584, 0. ]),
31: array([0.86383816, 0.19264988]),
32: array([1.24950088, 0. ]),
33: array([1.1516554, 0. ])}

#把运行结果画出来
import matplotlib.pyplot as plt
plt.figure()
plt.xlim(-0.3,1)
plt.ylim(-0.3,1)
for i in range (34):
    if zkc.nodes[i]['club'] == 'Mr. Hi':
        plt.scatter(np.array(output)[i,0], np.array(output)[i,1] ,color = 'r',alpha=0.5,s = 20)  #alpha透明度,s点的大小
    else:
        plt.scatter(np.array(output)[i,0], np.array(output)[i,1] ,color = 'b',alpha=0.5,s = 20)
#plt.scatter(np.array(output)[:,0],np.array(output)[:,1])
plt.show()

在这里插入图片描述

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
GCN(Graph Convolutional Network)是一种用于图数据深度学习模型,它可以对节点和边进行特征学习和预测。GCN在图神经网络领域具有重要的应用价值。 GCN的PyTorch实现可以使用PyTorch Geometric库来实现。PyTorch Geometric是一个专门用于处理图数据的PyTorch扩展库,提供了一系列用于构建和训练图神经网络的工具和函数。 在PyTorch Geometric中,可以使用torch_geometric.nn模块中的GCNConv类来定义GCN层。GCNConv类实现了GCN的前向传播过程,可以根据输入的节点特征和图结构进行特征学习和传播。 以下是一个简单的GCN模型的示例代码: ```python import torch import torch.nn as nn from torch_geometric.nn import GCNConv class GCN(nn.Module): def __init__(self, num_features, num_classes): super(GCN, self).__init__() self.conv1 = GCNConv(num_features, 16) self.conv2 = GCNConv(16, num_classes) def forward(self, x, edge_index): x = self.conv1(x, edge_index) x = torch.relu(x) x = self.conv2(x, edge_index) return x # 构建模型 model = GCN(num_features, num_classes) # 定义损失函数和优化器 criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.01) # 训练模型 for epoch in range(num_epochs): # 前向传播 output = model(x, edge_index) loss = criterion(output, y) # 反向传播和优化 optimizer.zero_grad() loss.backward() optimizer.step() ``` 在上述代码中,GCN类定义了一个简单的两层GCN模型,输入节点特征的维度为num_features,输出类别的数量为num_classes。模型的前向传播过程中使用了两个GCNConv层,并通过ReLU激活函数进行非线性变换。训练过程中使用交叉熵损失函数和Adam优化器进行模型的优化。 希望以上内容对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值