本节课我们介绍GCN网络的代码实践。
pyG的安装与简介
PyG (PyTorch Geometric)是一个基于pytorch的图神经网络包,安装和pytorch是类似的,也是有下面的可选的安装命令界面。
PyG安装.
其中内置了一些数据集模块和广泛使用的图卷积网络,比如GCN,切比雪夫网络,SAGE等等。
PyG的数据模块
在这里我想专门花时间来讲一讲数据集的构建,可能有些同学没有实践过,当我们使用pytorch去构建数据集的时候,我们不得不将整个数据转换成tensor,这个时候,你会发现如果你数据的维度是不整齐的,你是没法把整个数据转化成tensor的,那么后面数据集的切分训练都非常麻烦,困难很多。而对于图神经网络,我们每个样本是一张图,还有节点组成的特征矩阵,这就麻烦了,图的大小可不一样,节点数目也不一样,上一个样本可能是50个节点,下一个样本可能是80个节点,普通的tensor搞不定,当然你可以用pandas什么的去组件自己的数据集,想办法克服,但是呢,我发现PyG这个数据模块非常的简单方便,还和pytorch兼容,不仅仅是图数据,只要是不规则的数据我们都可以这么去操作。
x: 用于存储每个节点的特征,形状是[num_nodes, num_node_features]。 edge_index: 用于存储节点之间的边,形状是 [2, num_edges]。 pos: 存储节点的坐标,形状是[num_nodes, num_dimensions]。 y: 存储样本标签。如果是每个节点都有标签,那么形状是[num_nodes, *];如果是整张图只有一个标签,那么形状是[1, *]。 edge_attr: 存储边的特征。形状是[num_edges, num_edge_features]。
这里的每个参数不一定要有,也可以没有,根据需要去变化。
我们给一个例子介绍一下,因为这个torch_geometric.data.Data的格式略有点奇怪哈
1
2
3
4
5
6
7
8
9
import torch
from torch_geometric.data import Data
nodes_feature = torch.tensor[[3,4,2],[0,1,2],[1,3,2]]
edge = torch.tensor([[0, 1, 0, 2], [1, 0, 2, 0]], dtype=torch.long) # 边的储存形式有点奇怪,我个人感觉是因为这样比较容易存成torch的稀疏矩阵的形式,具体的我也不清楚原因
label = torch.tensor([[1],[0],[1]], dtype=torch.float)
edge_feature = torch.tensor([[2,4],[2,4],[3,2],[3,2]], dtype=torch.float)
sample = Data(x=nodes_feature, edge_index=edge)
Data.edge_attr = edge_feature
Data.y = label
但是,这并不是torch_geometric.data.Data最方便的一点,最关键的是我们可以去自定义数据。举个例子,
1
Data.myAdj = torch.tensor([[1,0],[0,1]], dtype=torch.long)
所以,我们可以随心所欲的构建自己的数据,这就极大方便了我们构建数据集。而且样本怎么集合成数据集呢,非常容易,只需要用一个python的List就能解决,每次append就可以。
这里还有一点我需要强调,这个PyG自带的定义边集合的方式只能是传给PyG内置的图神经网络,如果你自己的写图神经网络的网络,你需要安装你的需求去改变数据的格式。
GCN网络模型搭建
首先,我们可以根据之前的原理简介,自己去实现一个图卷积层。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class GCN_layer(Module):
def __init__(self, in_features, out_features, dropout=0., act=F.relu):
super(GCN_layer, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.dropout = dropout
self.act = act
self.weight = Parameter(torch.FloatTensor(in_features, out_features))
self.reset_parameters()
def reset_parameters(self):
torch.nn.init.xavier_uniform_(self.weight)
def forward(self, input, adj):
input = F.dropout(input, self.dropout, self.training)
support = torch.mm(input, self.weight)
output = torch.spmm(adj, support)
output = self.act(output)
return output
class GCN(nn.Module):
def __init__(self):
self.GCN_Layer_1 = GCN_layer(64,32)
self.GCN_Layer_2 = GCN_layer(32,1)
def forward(self,x,adj):
out = self.GCN_Layer_1(x)
out = self.GCN_Layer_2(out)
reture out
当然了,你也可以用现成的PyG的包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import troch_geometric.nn import GCNconv
class GCN(nn.Module):
def __init__(self,input_feature,num_classes):
super(GCN,self).__init__()
self.input_feature = input_feature
self.num_classes = num_classes
self.conv1 = GCNconv(self.input_feature,32)
self.conv2 = GCNconv(32,self.num_classes)
self.ac = nn.ReLU()
def forward(self,data):
x, edge_index = data.x, data.edge_index
out = self.conv1(x)
out = self.ac(out)
out = self.conv2(out)
reture out