当时Google图神经网络的时候,搜到的一份PDF,这里我将这个PDF中的内容运行一遍,并且记录一下其中的内容。

Dense v. Sparse

例子:存储图的边

  • 以矩阵形式存储(dense)§ 图神经网络简单教程 - 图1#card=math&code=%5CRightarrow%20O%28%7CV%7C%5E2%29)
  • 以索引形式存储(sparse)§ 图神经网络简单教程 - 图2%5Cleqslant%20O(%7CV%7C%5E2)#card=math&code=%5CRightarrow%20O%28%7CE%7C%29%5Cleqslant%20O%28%7CV%7C%5E2%29)
  1. import networkx as nx
  2. import matplotlib.pyplot as plt
  3. G = nx.barabasi_albert_graph(100, 3)
  4. _, axes = plt.subplots(1, 2, figsize=(10, 4), gridspec_kw={'wspace': 0.5})
  5. nx.draw_kamada_kawai(G, ax=axes[0], node_size=120)
  6. axes[1].imshow(nx.to_numpy_matrix(G), aspect='auto', cmap='Blues')
  7. axes[0].set_title('$G$')
  8. axes[1].set_title('$\mathbf{A}$')
  9. plt.show()
  10. # print(G.nodes)
  11. # print(G.edges)

§ 图神经网络简单教程 - 图3

上面的networkx是一个用于研究网络的库,点击链接查看教程。其中重要的部分是barabasi_albert_graph(n,m,seed=None)这个函数。

  • 参数n:图中的节点个数
  • 参数m:一个新的节点和现有的m个节点进行连接

例如,我们现在只让新的节点和现有节点之间只有一条边的连接G = nx.barabasi_albert_graph(100, 3),可以看到效果如下:

§ 图神经网络简单教程 - 图4

Sparse Representations

存储一个大小为§ 图神经网络简单教程 - 图5的图,其中

  • 边:作为矩阵的索引§ 图神经网络简单教程 - 图6
  • 三角:作为矩阵的索引§ 图神经网络简单教程 - 图7
  • 属性:特征矩阵§ 图神经网络简单教程 - 图8或者§ 图神经网络简单教程 - 图9

PyTorch中的索引

  1. import torch
  2. mat = torch.arange(12).view(3, 4) # 将0-11拍成一个3行4列的二维矩阵
  3. print(mat)
  4. print(mat[0]) # 打印出第一行
  5. print(mat[:, -1]) # 打印出最后一列
  6. print(mat[:, 2:]) # 打印出从第3行开始的列
  7. print(mat[:, ::3]) # 打印出第1列和第4列
  8. print(mat[:, :3]) # 打印出第1列和到第4列之前的所有列

输出:

tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]) tensor([0, 1, 2, 3]) tensor([ 3, 7, 11]) tensor([[ 2, 3],
[ 6, 7],
[10, 11]]) tensor([[ 0, 3],
[ 4, 7],
[ 8, 11]]) tensor([[ 0, 1, 2],
[ 4, 5, 6],
[ 8, 9, 10]])

阈值分割

  1. import torch
  2. rnd = torch.rand(1, 3)
  3. print(rnd)
  4. mask = rnd >= 0.5
  5. print(mask)
  6. print(rnd[mask]) # 找到rnd>=0.5的数据

tensor([[0.4009, 0.2571, 0.8022]]) tensor([[False, False, True]]) tensor([0.8022])

索引选择

我们可以把这个部分和上面的部分结合起来,找到§ 图神经网络简单教程 - 图10某个数的坐标索引

  1. import torch
  2. A = torch.randint(2, (5, 5))
  3. print(A)
  4. idx = A.nonzero().T # 找到不为0的数的位置索引
  5. print(idx)
  6. row, col = idx # row, col = idx[0], idx[1] 将不为0的数据列出
  7. print(A[row, col])

tensor([[1, 1, 0, 0, 1],
[0, 1, 1, 0, 1],
[0, 0, 0, 1, 1],
[0, 1, 0, 0, 1],
[1, 0, 1, 1, 0]]) tensor([[0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4],
[0, 1, 4, 1, 2, 4, 3, 4, 1, 4, 0, 2, 3]]) tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])

数据排序

  1. import torch
  2. rnd = torch.randint(10, (2, 4))
  3. print(rnd)
  4. sort, perm = torch.sort(rnd, dim=-1)
  5. rnd = torch.gather(input=rnd, dim=-1, index=perm)
  6. print(rnd)

tensor([[1, 1, 3, 2],
[7, 8, 3, 8]]) tensor([[1, 1, 2, 3],
[3, 7, 8, 8]])

PyTorchGeometric框架介绍

PyTorch-Geometric的子模型:

  • nn:包含了许多的GNN模型,池化层和归一化层
  • data:用于管理稀疏和密集数据的类
  • datasets:基本上每个图形,网格和点云的标准基准数据集都有不同类型的任务
  • transform:数据操作函数
  • utilsand io:接口函数

例子

下面引入TUDataset数据集中的第一幅图,将其画出来

  1. from torch_geometric.datasets import TUDataset, ModelNet, ShapeNet
  2. from torch_geometric import utils
  3. import networkx as nx
  4. import matplotlib.pyplot as plt
  5. ds = TUDataset(root='./data/', name='PROTEINS')
  6. G = utils.to_networkx(ds[0])
  7. nx.draw_kamada_kawai(G)
  8. plt.show()

§ 图神经网络简单教程 - 图11

制作自己的数据集

可以通过InMemoryDataset来制作自己的数据集:

  • raw_file_names()中确定需要的数据
  • processed_file_names()确定需要产生的数据
  • 使用download()process()函数
  • __init__()中加载已经处理的数据

通过一个例子,来看一下如何制作数据集

  1. from torch_geometric.data import InMemoryDataset, download_url
  2. from rdkit import Chem
  3. import pandas as pd
  4. class COVID(InMemoryDataset):
  5. url = 'https://github.com/yangkevin2/coronavirus_data/raw/master/data/mpro_xchem.csv'
  6. def __init__(self, root, transform=None, pre_transform=None,pre_filter=None):
  7. super(COVID, self).__init__(root, transform, pre_transform, pre_filter)
  8. # Load processed data
  9. self.data, self.slices = torch.load(self.processed_paths[0])
  10. @property
  11. def raw_file_names(self):
  12. return ['mpro_xchem.csv']
  13. @property
  14. def processed_file_names(self):
  15. return ['data.pt']
  16. def download(self):
  17. download_url(self.url, self.raw_dir)
  18. def process(self):
  19. df = pd.read_csv(self.raw_paths[0])
  20. data_list = []
  21. for smiles, label in df.itertuples(False, None):
  22. mol = Chem.MolFromSmiles(smiles) # Read the molecule info
  23. adj = Chem.GetAdjacencyMatrix(mol) # Get molecule structure
  24. # You should extract other features here!
  25. data = Data(num_nodes=adj.shape[0],
  26. edge_index=torch.Tensor(adj).nonzero().T, y=label)
  27. data_list.append(data)
  28. self.data, self.slices = self.collate(data_list)
  29. torch.save((self.data, self.slices), self.processed_paths[0])
  30. covid = COVID(root='./data/COVID/')
  31. G = utils.to_networkx(covid[0])
  32. nx.draw_kamada_kawai(G)
  33. plt.show()

原文

Landolfi_tutorial.pdf