GNN包torch_geometric使用 2021-09-02

torch_geometric包是一个进行GNN实现的非常方便的包,官网是 https://pytorch-geometric.readthedocs.io/en/latest/notes/introduction.html

安装

需要特别注意【安装顺序,先安装torch-sparse和torch-cluster,再安装torch-geometric】。具体见官网。

确认自己的环境(cuda还是cpu)以及torch版本。进行安装。

pip install torch-scatter torch-sparse torch-cluster torch-spline-conv torch-geometric -f https://data.pyg.org/whl/torch-1.9.0+cpu.html

数据集格式

使用的数据集的格式如下例所示:

>>> 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)
>>> y = torch.tensor([4, 2, 1], dtype=torch.long)
>>> edge_weights = torch.tensor([1, 5, 2, 0.3], dtype=torch.float)
>>> data = Data(edge_index=edge_index, x=x, y=y, edge_attr=edge_weights)
>>> data
Data(edge_attr=[4], edge_index=[2, 4], x=[3, 1], y=[3])

将每条边的源节点和目标节点分别放在edge_index的两行,组成一个 2 × 2\times 2×边数 的矩阵edge_index
节点属性组成一个 节点数 × \times ×feature大小 的矩阵x
label组成一个大小为节点数的数组y
边属性组成一个 边数 × \times ×feature大小 的矩阵edge_attr。边权重也这样处理。

GCN图卷积操作

>>> from torch_geometric.nn import GCNConv
>>> layer = GCNConv(1, 5)
>>> layer(x, edge_index)  # 不加边权重
tensor([[ 0.1100,  0.2275, -0.3096,  0.0185, -0.3546],
        [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000],
        [-0.1100, -0.2275,  0.3096, -0.0185,  0.3546]], grad_fn=<AddBackward0>)
>>> layer(x, edge_index, edge_weights)
tensor([[ 0.0367,  0.0758, -0.1032,  0.0062, -0.1182],
        [ 0.0341,  0.0705, -0.0960,  0.0057, -0.1099],
        [-0.0733, -0.1516,  0.2064, -0.0123,  0.2364]], grad_fn=<AddBackward0>)
>>> layer(data.x, data.edge_index, data.edge_attr)
tensor([[ 0.0367,  0.0758, -0.1032,  0.0062, -0.1182],
        [ 0.0341,  0.0705, -0.0960,  0.0057, -0.1099],
        [-0.0733, -0.1516,  0.2064, -0.0123,  0.2364]], grad_fn=<AddBackward0>)

layer = GCNConv(1, 5)这一句构建了一个输入维度为1,输出维度为5的GCN层,如果需要权重,则将权重传入即可。

省显存的SparseTensor

如果图数据很大,最好使用SparseTensor而非edge_index格式。

如果是自己构建数据集(比如按照 https://pytorch-geometric.readthedocs.io/en/latest/notes/create_dataset.html#creating-in-memory-datasets 的教程来做),则直接import torch_geometric.transforms as T并设置数据集的参数transform=T.ToSparseTensor()即可。

使用之前创建的data,也可以转换。

>>> import torch_geometric.transforms as T
>>> transform=T.ToSparseTensor()
>>> transform(data)
Data(adj_t=[3, 3, nnz=4], x=[3, 1], y=[3])
>>> data
Data(adj_t=[3, 3, nnz=4], x=[3, 1], y=[3])
>>> data.adj_t
SparseTensor(row=tensor([0, 1, 1, 2]),
             col=tensor([1, 0, 2, 1]),
             val=tensor([5.0000, 1.0000, 0.3000, 2.0000]),
             size=(3, 3), nnz=4, density=44.44%)

此时已经将边权重加入邻接矩阵中,因此在进行神经网络forward时,不用额外的边权重。

>>> layer(x, data.adj_t)
tensor([[ 0.0367,  0.0758, -0.1032,  0.0062, -0.1182],
        [ 0.0341,  0.0705, -0.0960,  0.0057, -0.1099],
        [-0.0733, -0.1516,  0.2064, -0.0123,  0.2364]], grad_fn=<AddBackward0>)

batch划分操作

来自 https://e0hyl.github.io/BLOG-OF-E0/PyGeometric_Data/

torch_geometric中,有以下几种划分batch的方法:

  • 对于很多个图:可以用DataLoader,此时会将选出的几个图拼成一个邻接矩阵,形成一个Batch结构;或者用DataListLoader将采样出的几个图分别组成一个列表返回。
  • 对于很多个属性维度相同的图:可以用DenseDataLoader
  • 进行聚类:用ClusterLoaderClusterData
  • 采样:用NeighborSampler,GraphSAGE中的sample方法。

进行采样的方法可以参考 https://towardsdatascience.com/sampling-large-graphs-in-pytorch-geometric-97a6119c41f9

  • 先得到需要划分数据的edge_index(非adj_t),用NeighborSampler处理:data_loader = NeighborSampler(data.edge_index, shuffle=True, sizes=[-1, -1], batch_size=batch_size) (这一句代表:采样两层的全部邻居)
  • 通过for循环读取每个batch的数据,其中data_batch[2][0]data_batch[2][1]分别代表采样出的两层的edge_indexdata_batch[1]是每个节点的原始索引。

两层GCN后进行分类的示例代码为:

data_loader = NeighborSampler(data.edge_index, shuffle=True, sizes=[-1, -1], batch_size=batch_size)
for data_batch in data_loader:
    nodes_index = data_batch[1]
    data_batch_x = data.x[nodes_index]
    preds = classifier(layer2(layer1(data_batch_x, data_batch[2][0])[0], data_batch[2][1])[0]).argmax(dim=1)

你可能感兴趣的:(pytorch,python,图神经网络,pytorch,python,深度学习,gcn)