PyG学习笔记1-INTRODUCTION BY EXAMPLE(一)
官方示例
torch_geometric.data.Data
节点和节点之间的边构成了图。所以在 PyG 中,如果要构建图,那么需要两个要素:节点和边。PyG 提供了torch_geometric.data.Data 用于构建图,包括 5 个属性,每一个属性都不是必须的,可以为空。
x: 用于存储每个节点的特征,形状是[num_nodes, num_node_features]。
edge_index: 用于存储节点之间的边,形状是 [2, num_edges]。
pos: 存储节点的坐标,形状是[num_nodes, num_dimensions]。
y: 存储样本标签。如果是每个节点都有标签,那么形状是[num_nodes, *];如果是整张图只有一个标签,那么形状是[1, *]。
edge_attr: 存储边的特征。形状是[num_edges, num_edge_features]。
实际上,Data对象不仅仅限制于这些属性,我们可以通过data.face来扩展Data,以张量保存三维网格中三角形的连接性。
需要注意的的是,在Data里包含了样本的 label,这意味和 PyTorch 稍有不同。在PyTorch中,我们重写Dataset的__getitem__(),根据 index 返回对应的样本和 label。在 PyG 中,我们使用的不是这种写法,而是在get()函数中根据 index 返回torch_geometric.data.Data类型的数据,在Data里包含了数据和 label。
下面一个例子是未加权无向图 ( 未加权指边上没有权值 ),包括 3 个节点和 4 条边。
import torch from torch_geometric.data import Data # 由于是无向图,因此有 4 条边:(0 -> 1), (1 -> 0), (1 -> 2), (2 -> 1) 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)
Dataset 与 DataLoader
PyG 的 Dataset继承自torch.utils.data.Dataset,自带了很多图数据集,我们以TUDataset为例,通过以下代码就可以加载数据集,root参数设置数据下载的位置。通过索引可以访问每一个数据。
from torch_geometric.datasets import TUDataset dataset = TUDataset(root='/tmp/ENZYMES', name='ENZYMES') data = dataset[0]
在一个图中,由edge_index和edge_attr可以决定所有节点的邻接矩阵。PyG 通过创建稀疏的对角邻接矩阵,并在节点维度中连接特征矩阵和 label 矩阵,实现了在 mini-batch 的并行化。PyG 允许在一个 mini-batch 中的每个Data (图) 使用不同数量的节点和边。
让我们再试一个!让我们下载 Cora,半监督图节点分类的标准基准数据集:(需要开VPN下载数据)
from torch_geometric.datasets import Planetoid dataset = Planetoid(root='/tmp/Cora', name='Cora') >>> Cora() len(dataset) >>> 1 dataset.num_classes >>> 7 dataset.num_node_features >>> 1433
这一次,Data对象包含每个节点的标签,以及其他节点级属性:、和 ,其中train_mask``val_mask``test_mask
train_mask表示针对哪些节点进行训练(140 个节点),
val_mask表示要用于验证的节点,例如,执行早期停止(500 个节点),
test_mask表示要针对哪些节点进行测试(1000 个节点)。
Mini-Batches
神经网络通常以批处理的方式进行训练。PyG 通过创建稀疏块对角邻接矩阵(由 定义)并在节点维度中连接特征矩阵和目标矩阵,在小型批处理上实现并行化。这种组合允许在一个批次中与示例相比,节点和边缘的数量不同:edge_index
from torch_geometric.datasets import TUDataset from torch_geometric.loader import DataLoader dataset = TUDataset(root='/tmp/ENZYMES', name='ENZYMES', use_node_attr=True) loader = DataLoader(dataset, batch_size=32, shuffle=True) for batch in loader: batch >>> DataBatch(batch=[1082], edge_index=[2, 4066], x=[1082, 21], y=[32]) batch.num_graphs >>> 32
torch_geometric.data.Batch 继承自 torch_geometric.data.Data 并包含一个名为 batch 的附加属性。batch是一个列向量,它将每个节点映射到批处理中的相应图中。
Data Transforms
变换是变换图像和执行增强的常用方法。PyG 附带了自己的转换,这些转换期望Data对象作为输入,并返回新的转换数据对象。转换可以使用torch_geometric.transforms.Compose链接在一起,并在将已处理的数据集保存到磁盘 () 上之前或在访问数据集 () 中的图形之前应用。torchvision``pre_transform``transform
我们可以通过转换从点云生成最近邻图,从而将点云数据集转换为图形数据集:
import torch_geometric.transforms as T from torch_geometric.datasets import ShapeNet dataset = ShapeNet(root='/tmp/ShapeNet', categories=['Airplane'], pre_transform=T.KNNGraph(k=6)) dataset[0]
Learning Methods on Graphs
我们将使用一个简单的GCN图层,并在Cora引文数据集上复制实验。
我们首先需要加载Cora数据集:
from torch_geometric.datasets import Planetoid dataset = Planetoid(root='/tmp/Cora', name='Cora')
现在,让我们实现一个双层 GCN:
import torch import torch.nn.functional as F from torch_geometric.nn import GCNConv 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)
构造函数定义了两个GCNConv层.
请注意,非线性没有集成到调用中,因此需要在之后应用(这在PyG中的所有运算符中是一致的)。在这里,我们选择使用ReLU作为我们的中间非线性,并最终输出类数的softmax分布。让我们在训练节点上训练此模型 200 个 epoch:
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()
最后,我们可以在测试节点上评估我们的模型:
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}')
相关文章
- 微软出品自动化神器【Playwright+Java】系列(九)多线程、重定向、弹出新窗口、截图、新页面、录制、页面对象模式操作
- 2022社交平台设备风险安卓占三成,iOS 仅占一成
- 美国出台终极封杀令!外购芯片路径被阻断,华为到了最危险的时候!
- 如期而至,HarmonyOS 2.0 手机开发者Beta来了!
- 创始人服药自杀!遗书曝光:做网约车是我这辈子最傻的决定
- 全球首个云渗透测试认证专家课程发布!腾讯安全领衔编制
- EasyCVR设置宣传位出现报错“Error1292:Incorrect datetime”是什么原因?
- PS 2023最新版本 Photoshop 各版本分享-Adobe怎么安装
- R语言CART决策树、随机森林、chaid树预测母婴电商平台用户寿命、流失可视化
- 297个机器学习彩图知识点(12)
- 基于深度学习的表格检测与识别技术优势
- 【文末彩蛋】Adobe国际认证证书查询
- Eclipse开发环境与VS开发环境的调试对比
- 池建强:如何学习一门编程语言
- 如何成为一个C++高级程序员
- 从汇编到太空——保罗·艾伦
- 微软将Bing变开放平台 同谷歌争夺开发者
- 看完这些计算机论文,我自闭了
- 达摩院首次将Pure Transformer引入目标重识别,论文入选ICCV 2021
- 奔四的听障码农,被开除15次面试被拒200+次,还要继续干下去吗?