datawhale 6月学习——图神经网络:图数据表示及应用

图论基础

参考教材:“Chapter 2 - Foundations of Graphs, Deep Learning on Graphs”
包含图的基本概念、图的种类等,此处不展开。

图数据表示——基于PyG库

本部分代码实现基于PyTorch 1.8.1 + cuda 11.1

PyG库

PyG,全称PyTorch Geometric,它包含各种对图和其他不规则结构进行深度学习的方法,也称为几何深度学习,集成了来自各种已发表论文的内容。
PyG是面向几何深度学习的PyTorch的扩展库,几何深度学习指的是应用于图和其他不规则、非结构化数据的深度学习。基于PyG库,我们可以轻松地根据数据生成一个图对象,然后很方便的使用它;我们也可以容易地为一个图数据集构造一个数据集类,然后很方便的将它用于神经网络。
其当前安装要求python <= 3.8,PyTorch >= 1.4.0,cuda。
安装教程可以参考官网 PyG安装

Data类

torch_geometric.data.Data()是PyG的一个基础数据类,用于表示图数据,其官方文档为torch_geometric.data.Data
由于PyG库基于PyTorch,因此,Data类的所有参数对象均torch.tensor()对象,可以参考torch.tensor,常见操作包括torch.tensor.shapetorch.tensor.item()等。
一个Data对象(一个图)一般来说至少包含x, edge_index,edge_attr, y, num_nodes5个属性,当图包含其他属性时,我们可以通过指定额外的参数使Data对象包含其他的属性:

graph = Data(x=x, edge_index=edge_index, edge_attr=edge_attr, y=y, num_nodes=num_nodes, other_attr=other_attr)

在Data里,edge_index的每一列定义一条边,其中第一行为边起始节点的索引,第二行为边结束节点的索引,为稀疏矩阵表示方式。
可以通过一个实例,了解Data的表示方式,对下图
示例图形

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)
#node单一属性

data = Data(x=x, edge_index=edge_index)

Dataset类

PyG内置了大量常用的基准数据集,可以在torch_geometric.datasets上看到。
以PyG内置的Planetoid数据集为例torch_geometric.datasets.Planetoid

from torch_geometric.datasets import Planetoid

dataset = Planetoid(root='/dataset/Cora', name='Cora')

data = dataset[0]

其中只含一个 图对象,可以看到该data对象的结构

{'edge_attr': None,
 'edge_index': tensor([[   0,    0,    0,  ..., 2707, 2707, 2707],
         [ 633, 1862, 2582,  ...,  598, 1473, 2706]]),
 'face': None,
 'normal': None,
 'pos': None,
 'test_mask': tensor([False, False, False,  ...,  True,  True,  True]),
 'train_mask': tensor([ True,  True,  True,  ..., False, False, False]),
 'val_mask': tensor([False, False, False,  ..., False, False, False]),
 'x': tensor([[0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         ...,
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.]]),
 'y': tensor([3, 4, 4,  ..., 3, 3, 3])}

其中test_masktrain_maskval_mask描述了指定哪些点为测试集、训练集及验证集。
并非所有dataset的结构都一致,如TUDataset数据torch_geometric.datasets.TUDataset

from torch_geometric.datasets import TUDataset
dataset = TUDataset(root='/dataset/IMDB-BINARY', name='IMDB-BINARY')

len(dataset)
>>> 1000

其中包含1000个图对象,取第一个data图对象,其结构如下。

{'__num_nodes__': 20,
 'edge_attr': None,
 'edge_index': tensor([[ 0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,
           2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,
           3,  3,  4,  4,  4,  4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  6,
           6,  6,  6,  6,  6,  7,  7,  7,  8,  8,  8,  8,  8,  8,  8,  8,  9,  9,
           9,  9,  9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12,
          12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14,
          15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
          18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
          19, 19],
         [ 2,  4,  5,  9, 10,  2,  6,  8, 12, 14, 17, 18, 19,  0,  1,  3,  4,  5,
           6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  2,  6, 11, 12,
          16, 19,  0,  2,  5,  9, 10,  0,  2,  4,  9, 10,  1,  2,  3,  8, 11, 12,
          14, 16, 17, 18, 19,  2, 13, 15,  1,  2,  6, 12, 14, 17, 18, 19,  0,  2,
           4,  5, 10,  0,  2,  4,  5,  9,  2,  3,  6, 12, 16, 19,  1,  2,  3,  6,
           8, 11, 14, 16, 17, 18, 19,  2,  7, 15,  1,  2,  6,  8, 12, 17, 18, 19,
           2,  7, 13, 19,  2,  3,  6, 11, 12, 19,  1,  2,  6,  8, 12, 14, 18, 19,
           1,  2,  6,  8, 12, 14, 17, 19,  1,  2,  3,  6,  8, 11, 12, 14, 15, 16,
          17, 18]]),
 'face': None,
 'normal': None,
 'pos': None,
 'x': None,
 'y': tensor([0])}

这是一个node没有属性的图。

作业:机构-作者-论文类的实现

具体任务如下

请通过继承Data类实现一个类,专门用于表示“机构-作者-论文”的网络。该网络包含“机构“、”作者“和”论文”三类节点,以及“作者-机构“和“作者-论文“两类边。对要实现的类的要求:
1)用不同的属性存储不同节点的属性;
2)用不同的属性存储不同的边(边没有属性);
3)逐一实现获取不同节点数量的方法。

为方便实现,进行如下假设:
新增属性x_type记录节点的种类,0代表机构(institution),1代表作者(author),2代表文章(paper)。
实现代码如下

class Paper(Data):
  def __init__(self,x=None,x_type=None, edge_index=None, y=None,
         pos=None, normal=None, face=None, **kwargs):
    super().__init__(x,edge_index,None,y,pos,normal,face,**kwargs)
    self.x_institution = x[x_type == 0,:]
    self.x_author = x[x_type == 1,:]
    self.x_paper = x[x_type == 2,:]
    self.x_type = x_type
    self.edge_type()

  def edge_type(self):
    ins_au = [[],[]]
    au_pa = [[],[]]
    for i in range(self.edge_index.shape[1]):
      tail = self.edge_index[0,i]
      head = self.edge_index[1,i]
      if ((self.x_type[tail] == 0 and self.x_type[head] == 1) or 
         (self.x_type[tail] == 1 and self.x_type[head] == 0)):
         ins_au[0].append(tail)
         ins_au[1].append(head)
      elif ((self.x_type[tail] == 1 and self.x_type[head] == 2) or 
          (self.x_type[tail] == 2 and self.x_type[head] == 1)):
         au_pa[0].append(tail)
         au_pa[1].append(head)
    self.edge_au_pa = torch.tensor(au_pa)
    self.edge_ins_au = torch.tensor(ins_au)

  def num_edge_au_pa(self):
    if self.is_undirected():
      return int(self.edge_au_pa.shape[1]/2)
    else:
      return self.edge_au_pa.shape[1]

  def num_edge_ins_au(self):
    if self.is_undirected():
      return int(self.edge_ins_au.shape[1]/2)
    else:
      return self.edge_ins_au.shape[1]

  def num_node_au(self):
    return self.x_author.shape[0]

  def num_node_ins(self):
    return self.x_institution.shape[0]

  def num_node_pa(self):
    return self.x_paper.shape[0]

则对于一个具体的图形
在这里插入图片描述

x = torch.tensor([[1,2,3],[2,3,4],[3,4,5],[1,4,6],[5,8,8],[3,6,7]])
x_type = torch.tensor([2,1,0,1,2,2])
edge_index = torch.tensor([[0,1,2,3,3,5,4,3,2,1],[1,2,3,4,5,3,3,2,1,0]])

#创建对象
a = Paper(x,x_type,edge_index)

其内容如下

{'edge_attr': None, 'edge_au_pa': tensor([[0, 3, 3, 5, 4, 1],
         [1, 4, 5, 3, 3, 0]]), 'edge_index': tensor([[0, 1, 2, 3, 3, 5, 4, 3, 2, 1],
         [1, 2, 3, 4, 5, 3, 3, 2, 1, 0]]), 'edge_ins_au': tensor([[1, 2, 3, 2],
         [2, 3, 2, 1]]), 'face': None, 'normal': None, 'pos': None, 'x': tensor([[1, 2, 3],
         [2, 3, 4],
         [3, 4, 5],
         [1, 4, 6],
         [5, 8, 8],
         [3, 6, 7]]), 'x_author': tensor([[2, 3, 4],
         [1, 4, 6]]), 'x_institution': tensor([[3, 4, 5]]), 'x_paper': tensor([[1, 2, 3],
         [5, 8, 8],
         [3, 6, 7]]), 'x_type': tensor([2, 1, 0, 1, 2, 2]), 'y': None}

调用方法num_edge_au_pa()num_edge_ins_au()num_node_au()num_node_pa()num_node_ins(),可以查看各属性边及节点的数量

a.num_edge_au_pa()
>>> 3
a.num_edge_ins_au()
>>> 2
a.num_node_au()
>>> 2
a.num_node_pa()
>>> 3
a.num_node_ins()
>>> 1

参考阅读:

  1. Datawhale组队学习
  2. PyG文档之二:快速入门
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SheltonXiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值