从零开始学习图神经网络 - Data类和Datasets的基本使用

Data类——PyG中图的表示及其使用

  • torch_geometric.data.Data
  • PyG-01 数据预处理-torch_geometric.data.Data

# Data类的构造函数
class Data(object):
    def __init__(self, x=None, edge_index=None, edge_attr=None, y=None, **kwargs):
        pass

从上面代码可以看到 :

  • x (Tensor, optional): 节点属性矩阵,大小为 [num_nodes, num_node_features]
  • edge_index (LongTensor, optional): 边索引矩阵,大小为[2, num_edges],第 0 行可称为头(head)节点、源(source)节点、邻接节点,第 1 行可称为尾(tail)节点、目标(target)节点、中心节点
  • edge_attr (Tensor, optional): 边属性矩阵,大小为 [num_edges, num_edge_features]
  • y (Tensor, optional): 节点或图的标签,任意大小(,其实也可以是 边的标签)

edge_index的每一列定义一条边,其中第一行为边起始节点的索引,第二行为边结 束节点的索引。这种表示方法被称为COO格式(coordinate format),通常用于表示稀疏矩阵。PyG不是用稠密矩阵 来持有邻接矩阵的信息,而是用仅存储邻接矩阵 中非 元素的稀疏矩阵来表示图

通常,一个图至少包含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)

将字典对象转换为图对象

import numpy as np
from numpy.random import randn
from torch_geometric.data import Data

# 定义节点相关数据
num_nodes = 2000
num_node_features = 4000
num_edges = 100

# 定义字典对象
graph_dict = {
    'x': randn(num_nodes, num_node_features),
    'edge_index': randn(2, num_edges),
    'edge_attr': randn(num_edges, num_node_features),
    'y': randn(num_edges),
    'num_nodes': num_nodes
}

graph_data = Data.from_dict(graph_dict)
print(graph_data)
Data(x=[2000, 4000], edge_index=[2, 100], edge_attr=[100, 4000], y=[100], num_nodes=2000)

Data对象转换成其他类型数据

  • 我们可以将Data对象转换为dict对象 : def to_dict(self):
  • 或转换为namedtuple: def to_namedtuple(self):
data_dict = Data.to_dict(graph_data)
print(data_dict)

Data属性相关

# 获取Data的属性
x = graph_data['x']
print(x.shape)
# 获取Data属性包含的关键字
print(graph_data.keys)

图的其他特质

# 导入已有的数据集
from torch_geometric.datasets import KarateClub

datasets = KarateClub()
print("查看图的个数 : {}".format(len(datasets)))
# 获取第一张图
data = datasets[0]
print(data)
# 获取图的相关信息
print("图的节点数量 : {}".format(data.num_nodes))
print("图的节点属性的维度 : {}".format(data.num_node_features))
print("同样是节点属性的维度 : {}".format(data.num_features))
print("图的边的数量 : {}".format(data.num_edges))
print("边属性的维度 : {}".format(data.num_edge_features))
print("平均节点度 : {}".format(data.num_edges / data.num_nodes))
print("用作训练集的节点数 {}".format(data.train_mask.sum()))
print("用作训练集的节点数占比 {}".format(int(data.train_mask.sum()) / data.num_nodes))
print("此图是否包含孤立的节点 {}".format(data.contains_isolated_nodes()))
print("此图是否包含自环的边 {}".format(data.contains_self_loops()))
print("此图是否是无向图 {}".format(data.is_undirected()))
Data(x=[34, 34], edge_index=[2, 156], y=[34], train_mask=[34])
图的节点数量 : 34
图的节点属性的维度 : 34
同样是节点属性的维度 : 34
图的边的数量 : 156
边属性的维度 : 0
平均节点度 : 4.588235294117647
用作训练集的节点数 4
用作训练集的节点数占比 0.11764705882352941
此图是否包含孤立的节点 False
此图是否包含自环的边 False
此图是否是无向图 True

Dataset类——PyG中图数据集的表示及其使用

Planetoid 数据集类的官方文档为torch_geometric.datasets.Planetoid

生成数据集对象并分析

from torch_geometric.datasets import Planetoid
datasets = Planetoid(root="../../datasets/Cora", name="Cora")
print("数据集图的个数 : {}".format(len(datasets)))
print("数据集分类 : {}".format(datasets.num_classes))  # 7
print("数据集特征 : {}".format(datasets.num_features))  # 1433

如上面代码 可以看到该数据集只有一个图,包含7个分类任务,节点的属性为1433维度

分析数据集样本

data = datasets[0]
# 查看图的相关信息
print(data)

print("是否是无向图 : {} ".format(data.is_undirected()))
print("可以用作训练集的节点个数 : {} ".format(data.train_mask.sum().item()))
print("可以用作验证集的节点个数 : {} ".format(data.val_mask.sum().item()))
print("可以用作测试集的节点个数 : {} ".format(data.test_mask.sum().item()))

现在我们看到该数据集包含的唯一的图,有2708个节点,节点特征为1433维,有
10556条边,有140个用作训练集的节点,有500个用作验证集的节点,有1000个用 作测试集的节点

数据集的使用

假设我们定义好了一个图神经网络模型,其名为Net。在下方的代码中,我们展示了节点分类图数据集在训练过程中的使用。

import torch
import torch.nn as nn
import torch.nn as nn

class Net(nn.Module):
    def __init__(self):
        pass

    def forward(self, x):
        pass

    def train(self):
        pass

使用定义好的模型加载数据

device = "cuda" if torch.cuda.is_available() else "cpu"
# 定义模型, 这个模型仅仅是简单定义, 并不能使用
model = Net().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()

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