node classification:基于torch_geometric(PyG)框架搭建简单GCN网络对Cora数据集进行训练测试

参考文章:
GNN的第一个简单案例:Cora分类
PyG文档之二:快速入门

1、Cora数据集

(1)GNN常用的数据集:https://linqs.soe.ucsc.edu/data
(2)Cora数据集是GNN中的一个经典数据集,相当于mnist数据集在CNN中的地位。该数据集是机器学习论文之间的引用网络,共有2708篇论文(即:节点数量)、7类论文(即:节点类别数)、5429条边,每个节点有1433个特征。
node classification:基于torch_geometric(PyG)框架搭建简单GCN网络对Cora数据集进行训练测试_第1张图片

2、torch_geometric框架(PyG)

参考官方文档:https://pytorch-geometric.readthedocs.io/en/latest/notes/introduction.html

PyG框架中使用的数据都是Data对象格式(本文的Cora数据集是在PyG框架中导入下载的,所以是已经预先处理成Data格式的了)

node classification:基于torch_geometric(PyG)框架搭建简单GCN网络对Cora数据集进行训练测试_第2张图片

以上是官方文档直接翻译的,有点晦涩难懂。以下是我的一些补充理解:

(1)data.x:节点特征矩阵。每一行代表一个节点的特征向量,行数=节点数
(2)edge_index:边的连接特征。 COO格式 [[源节点],[目标节点]]
(3)edge_attr:边的特征
(4)data.y:每个节点都有一个特征向量x和一个标签 y(图的节点x可以根据其值进行向量表示)

例子:
node classification:基于torch_geometric(PyG)框架搭建简单GCN网络对Cora数据集进行训练测试_第3张图片

3、GCN原理

提出GCN的论文:《SEMI-SUPERVISED CLASSIFICATION WITH GRAPH CONVOLUTIONAL NETWORKS》,ICLR2017。

这篇论文里面有很多公式,当然我没有看懂……所以只能找了一些讲解的文章看看。我觉得比较通俗的有:
《跳出公式,看清全局,图神经网络(GCN)原理详解》

如果实在看不懂的话,就本博客中搭建简单的GCN网络来说,应该也没什么太大问题……GCN层在PyG框架中已经封装好了,也不需要从0搭建(类似于我们CNN网络中,也是直接调用PyTorch框架中封装好的CNN层)

4、代码实现

以下在Google Colaboratory环境上运行,如果您是在本地电脑上运行,只需要安装torch_geometric库就可以了,不需要第(2)步

(1)安装torch_geometric库,参照官方文档安装教程:https://pytorch-geometric.readthedocs.io/en/latest/notes/installation.html

# 1、查看torch、cuda版本
import torch; print(torch.__version__);
print(torch.version.cuda)

1.10.0+cu111
11.1

# 2、感叹号是在google colab才需要添加
!pip3 install torch-sparse -f https://data.pyg.org/whl/torch-1.10.0+cu111.html
!pip3 install torch-scatter -f https://data.pyg.org/whl/torch-1.10.0+cu111.html
!pip3 install torch-geometric

(2)挂载Google硬盘,存放我们下载的数据

# 挂载Google硬盘
from google.colab import drive
drive.mount('/content/gdrive')
# 切换工作目录,这个看你想在哪个目录下
import os
os.chdir('/content/gdrive/MyDrive/GNN')

(3)至此,环境配置完成。以下是数据集加载、GCN模型构建、训练测试:

# 数据集下载
from torch_geometric.datasets import Planetoid

def get_data(root_dir='GNN_Dataset', data_name='Cora'):
  Cora_dataset = Planetoid(root=root_dir, name=data_name)
  print(Cora_dataset)
  return Cora_dataset

Cora_dataset = get_data()

# GCN模型搭建
# torch_geometric.nn中包含了多种GNN层,GCN、GraphSAGE、GAT等……
import torch.nn as nn
from torch_geometric.nn import GCNConv
import torch.nn.functional as F

class GCN(nn.Module):
  def __init__(self, in_c, hid_c, out_c):
    super(GCN,self).__init__()    # 构造函数

    # 研究表明,GNN层数不宜超过3层
    # 输入特征、输出特征
    self.conv1 = GCNConv(in_channels=in_c, out_channels=hid_c)
    self.conv2 = GCNConv(in_channels=hid_c, out_channels=out_c)
  
  # Data对象存放图形数据,以下是Data对象的属性,但不是必需的
  # 具体查看torch_geometric官方文档
  def forward(self, data):
    x, edge_index = data.x, data.edge_index    # x:节点特征矩阵; edge_index:COO格式的图形连接,维度[2,边的数量],数据:[ [源节点],[目标节点] ]
    # 第一层
    x = self.conv1(x, edge_index)
    x = F.relu(x)
    # 第二层
    x = self.conv2(x, edge_index)
    # 第三层,输出层
    x = F.log_softmax(x, dim=1)

    return x

# 训练,测试
def main():
  device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  model = GCN(in_c=Cora_dataset.num_node_features, hid_c=100, out_c=Cora_dataset.num_classes)
  model = model.to(device)        # GPU训练
  data = Cora_dataset[0].to(device)
  optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=5e-4)  # 学习率衰减

  # train模式:启用BatchNormalization和Dropout
  model.train()
  for epoch in range(500):
    optimizer.zero_grad()
    out = model(data)
    # 交叉熵损失
    loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])       # 负对数似然。 标签,train_mask是训练集部分
    loss.backward()
    optimizer.step()
    print('epoch:',epoch, 'loss:',loss.item())    # python中加号是字符串拼接,要求对象都是字符串。而print时,不同类型的对象直接用逗号隔开就可以了

  # test模式:不启用BatchNormalization和Dropout
  model.eval()
  _, pred = model(data).max(dim=1)  # softmax向量中,取出最大的概率值
  target = data.y   # 标签
  # print('shape of pred:',pred[data.test_mask].shape)    # torch.Size([1000])
  # print('shape of target:',target[data.test_mask].shape)
  correct = pred[data.test_mask].eq(target[data.test_mask]).sum().item()
  acc = correct / int(data.test_mask.sum())  # 计数
  print('accuracy:{:.4f}'.format(acc))

# 程序入口
if __name__ == '__main__':
  main()

(4)程序运行结果

……
epoch: 494 loss: 0.01216048002243042
epoch: 495 loss: 0.012144618667662144
epoch: 496 loss: 0.012128839269280434
epoch: 497 loss: 0.012113094329833984
epoch: 498 loss: 0.012097395025193691
epoch: 499 loss: 0.01208181120455265
accuracy:0.7970

5、GCN的一些挑战

(1)Over Smoothing(过平滑):多层GCN后,每个节点获得的信息趋近于整个图所有节点的信息,导致所有节点的表示会趋近于相同

6、Less Relative

以下内容跟本文没什么关系……

(1)mask:

矩阵A
矩阵B:0、1组成的矩阵
两个矩阵的对应元素相乘后,矩阵A中的某些元素会变为0(对应矩阵B中0元素的位置)
node classification:基于torch_geometric(PyG)框架搭建简单GCN网络对Cora数据集进行训练测试_第4张图片
参考:浅析深度学习中的mask操作

你可能感兴趣的:(GNN,GNN,PyG)