PyG使用入门(完整详细)

目录

一. 图的表示

二. 常见基准数据集

三. 小批量

四. 数据转换

五.实现第一个图神经网络

参考文章


一. 图的表示

对于一个具有三个节点和四个边的无权无向图的示例:

 由于边的定义有紧凑表示和元组表示两种,所以上图定义也有两种:

        方式一:

import torch
from torch_geometric.data import Data

edge_index = torch.tensor([[0, 1, 1, 2],
                           [1, 0, 2, 1]], dtype=torch.long)
x = torch.tensor([[-1], [0], [1]], dtype=torch.float)

data = Data(x=x, edge_index=edge_index)
>>> Data(edge_index=[2, 4], x=[3, 1])

        方式二:

import torch
from torch_geometric.data import Data

edge_index = torch.tensor([[0, 1],
                           [1, 0],
                           [1, 2],
                           [2, 1]], dtype=torch.long)
x = torch.tensor([[-1], [0], [1]], dtype=torch.float)

data = Data(x=x, edge_index=edge_index.t().contiguous())
>>> Data(edge_index=[2, 4], x=[3, 1])

说明:

  • x是一个形状为[3, 1]的张量,表示图中有3个节点,每个节点有一个特征。这里,每个节点的特征是一个单一的浮点数。节点0的特征是-1,节点1的特征是0,节点2的特征是1。
  • edge_index是一个形状为[2, 4]的张量,表示图中有4条边。方式一的edge_index的第一行包含起点节点的索引,第二行包含终点节点的索引。方式二则是将各边分开表示。
    • 具体来说,这4条边分别是:
      • 从节点0到节点1
      • 从节点1到节点0
      • 从节点1到节点2
      • 从节点2到节点1

    二. 常见基准数据集

    ​PyG包含大量常见的基准数据集,例如所有 Planetoid 数据集(Cora、Citeseer、Pubmed)、 TUDatasets的所有图分类数据集及其清理版本、QM7 和 QM9 数据集,以及少量 3D 网格/点云数据集,如 FAUST、ModelNet10/40 和 ShapeNet。

    • 初始化化数据集Demo1——ENZYMES 数据集(由 6 个类别中的 600 个图表组成):
      from torch_geometric.datasets import TUDataset
      # 下载指定数据集到本机D:/PyCharmProjects/tmp
      dataset = TUDataset(root='D:/PyCharmProjects/tmp/ENZYMES', name='ENZYMES')
      print(len(dataset)) # 600   数据集大小
      print(dataset.num_classes)  # 6 类别数量
      print(dataset.num_node_features)    #   3   节点特征数量
      
      print(dataset[0])   # Data(edge_index=[2, 168], x=[37, 3], y=[1])   第一个图包含 37 个节点,每个节点有 3 个特征。有 168/2 = 84 条无向边,并且该图被分配到恰好一个类
      print(dataset[0].is_undirected())   # True  数据对象恰好包含一个图级目标
      
      # 创建 90/10 的训练/测试分割
      train_dataset = dataset[:540]
      print(train_dataset)    # ENZYMES(540)
      test_dataset = dataset[540:]
      print(test_dataset) # ENZYMES(60)
      dataset = dataset.shuffle() # 不确定在拆分之前数据集是否已被打乱,您可以通过运行以下命令随机排列它
    • 初始化化数据集Demo2——Cora 数据集:
      from torch_geometric.datasets import Planetoid
      # 下载指定数据集到本机D:/PyCharmProjects/tmp
      dataset = Planetoid(root='D:/PyCharmProjects/tmp/Cora', name='Cora')
      print(len(dataset)) # 600   数据集大小
      print(dataset.num_classes)  # 6 类别数量
      print(dataset.num_node_features)    #   3   节点特征数量
      
      data = dataset[0]
      print(data)   #  Data(edge_index=[2, 10556], test_mask=[2708],train_mask=[2708], val_mask=[2708], x=[2708, 1433], y=[2708]) 10556/2条无向边,长度为2078的测试集、训练集、测试集
      print(data.is_undirected())   # True  数据对象恰好包含一个图级目标
      
      print(data.train_mask.sum().item()) # 140   表示针对哪些节点进行训练(140 个节点)
      print(data.val_mask.sum().item())   # 500   表示使用哪些节点进行验证,例如执行早期停止(500 个节点)
      print(data.test_mask.sum().item()) # 1000   表示针对哪些节点进行测试(1000 个节点)
      

    PS:上面两个数据集由于网络原因,可能会下载失败,网上也有很多解决方法(如配置host文件等)。


    三. 小批量

    神经网络通常以批量方式进行训练。 PyGedge_index通过创建稀疏块对角邻接矩阵(由 定义)并在节点维度上连接特征和目标矩阵,实现小批量的并行化。此组合允许在一个批次中的示例上使用不同数量的节点和边:

    PyG包含其自己的torch_geometric.loader.DataLoader,它已经处理了这个连接过程。让我们通过一个例子来了解它:

    from torch_geometric.datasets import TUDataset
    from torch_geometric.loader import DataLoader
    
    dataset = TUDataset(root='D:/PyCharmProjects/tmp/ENZYMES', name='ENZYMES', use_node_attr=True)
    loader = DataLoader(dataset, batch_size=32, shuffle=True)
    
    for batch in loader:
        print(batch)    # 返回当前批次中的图的总数  eg.DataBatch(edge_index=[2, 4388], x=[1221, 21], y=[32], batch=[1221], ptr=[33]) 这里的数据也是所有图的总和
    
        print(batch.num_graphs) # 当前批次中有多少个图    32

    torch_geometric数据。批处理继承自torch_geometric.data。并包含一个名为batch的附加属性。

    batch是一个列向量,将每个节点映射到批次中的相应图:

    例如,使用它来分别计算每个图的节点维度中节点特征的平均数:

    
    from torch_geometric.utils import scatter
    from torch_geometric.datasets import TUDataset
    from torch_geometric.loader import DataLoader
    
    dataset = TUDataset(root='D:/PyCharmProjects/tmp/ENZYMES', name='ENZYMES', use_node_attr=True)
    loader = DataLoader(dataset, batch_size=32, shuffle=True)
    
    for data in loader:
        print(data) # DataBatch(batch=[1082], edge_index=[2, 4066], x=[1082, 21], y=[32]) 一个包含图数据的批处理对象,批次中节点的总数是1082,有4066/2=2033条无向边,y=[32] 表示32个图的标签
    
        print(data.num_graphs) # 32 当前批处理数据中图的数量
    
        x = scatter(data.x, data.batch, dim=0, reduce='mean')    # 用 scatter 函数,将每个图的节点特征通过求均值的方式聚合成图的特征
        print(x.size()) # torch.Size([32, 21]) # 32个图,每个图有21个特征
    

    您可以详细了解内部批处理流程PyG例如,如何修改其行为,参见此处。有关散射操作的文档,可以参阅torch_scatter 文档


    四. 数据转换

    torchvision变换是转换图像和执行增强的常用方法。
    PyG带有自己的转换,它接受一个Data对象作为输入并返回一个新的转换Data对象。可以使用转换链接在一起torch_geometric.transforms.Compose,并在将处理后的数据集保存到磁盘(pre_transform)之前或在访问数据集中的图表(transform)之前应用转换。

    • Demo1——在 ShapeNet 数据集上应用变换(包含 17,000 个 3D 形状点云和来自 16 个形状类别的每个点标签):
      from torch_geometric.datasets import ShapeNet
      
      dataset = ShapeNet(root='D:/PyCharmProjects/tmp/ShapeNet', categories=['Airplane'])
      
      print(dataset[0])   # Data(x=[2518, 3], y=[2518], pos=[2518, 3], category=[1])
      
    • Demo2——通过变换从点云生成最近邻图,将点云数据集转换为图形数据集:
      import torch_geometric.transforms as T
      from torch_geometric.datasets import ShapeNet
      
      # 使用 force_reload 强制重新加载数据
      dataset = ShapeNet(root='D:/PyCharmProjects/tmp/ShapeNet', categories=['Airplane'],
                         pre_transform=T.KNNGraph(k=6), force_reload=True)
      
      # 获取第一个数据
      data = dataset[0]
      print(data) # Data(x=[2518, 3], y=[2518], pos=[2518, 3], category=[1], edge_index=[2, 15108])

    这里需要安装torch-cluster依赖。而且使用pre_transform来转换数据,然后再将其保存到磁盘(从而缩短加载时间)。下次初始化数据集时,即使您没有传递任何转换,它也已经包含图形边缘。如果pre_transform与已处理数据集中的不匹配,将会显示warn。

    • Demo3——使用transform参数随机地增强一个Data对象,例如,将每个节点位置平移一个小数:
      import torch_geometric.transforms as T
      from torch_geometric.datasets import ShapeNet
      
      dataset = ShapeNet(root='D:/PyCharmProjects/tmp/ShapeNet', categories=['Airplane'],
                          pre_transform=T.KNNGraph(k=6),
                          transform=T.RandomJitter(0.01))
      
      print(dataset[0])   # Data(x=[2518, 3], y=[2518], pos=[2518, 3], category=[1], edge_index=[2, 15108])
      

    五.实现第一个图神经网络

    使用一个简单的 GCN 层并在 Cora 引文数据集上复制实验。有关 GCN 的高级解释,请查看其博客文章

    1. 创建GCN_load.py:写如下代码,用于加载数据集
      from torch_geometric.datasets import Planetoid
      
      dataset = Planetoid(root='D:/PyCharmProjects/tmp/Cora', name='Cora')
    2. 创建GCN.PY
      1. 代码:实现一个两层 GCN
        import torch
        import torch.nn.functional as F
        from torch_geometric.nn import GCNConv
        
        from GCN_load import dataset
        
        
        class GCN(torch.nn.Module):
            def __init__(self):
                super().__init__()
                self.conv1 = GCNConv(dataset.num_node_features, 16)
                self.conv2 = GCNConv(16, dataset.num_classes)
        
            def forward(self, data):
                x, edge_index = data.x, data.edge_index
        
                x = self.conv1(x, edge_index)
                x = F.relu(x)
                x = F.dropout(x, training=self.training)
                x = self.conv2(x, edge_index)
        
                return F.log_softmax(x, dim=1)
      2.  说明:构造函数定义了两个GCNConv层,它们在我们的网络的前向传递中被调用。因为非线性并未集成在conv调用中,因此需要在之后应用(这在所有运算符中都是一致的)。在这里,我们选择使用 ReLU 作为我们的中间非线性,并最终输出类数上的 softmax 分布
    3. 创建GCN_train.py:在训练节点上训练这个模型 200 个 epoch 
      import torch
      
      from GCN import GCN
      from GCN_load import dataset
      import torch.nn.functional as F
      
      device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
      model = GCN().to(device)
      data = dataset[0].to(device)
      optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)
      
      model.train()
      for epoch in range(200):
          optimizer.zero_grad()
          out = model(data)
          loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])
          loss.backward()
          optimizer.step()
    4.  创建GCN_evaluate.py:评估模型
      from GCN_train import model, data
      
      model.eval()
      pred = model(data).argmax(dim=1)
      correct = (pred[data.test_mask] == data.y[data.test_mask]).sum()
      acc = int(correct) / int(data.test_mask.sum())
      print(f'Accuracy: {acc:.4f}')   # Accuracy: 0.8080
      

    以上第一个图神经网络所需的全部内容。


    参考文章

    Introduction by Example — pytorch_geometric documentationhttps://pytorch-geometric.readthedocs.io/en/latest/get_started/introduction.html#data-handling-of-graphshttps://pytorch-geometric.readthedocs.io/en/latest/get_started/introduction.html#data-handling-of-graphs

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值