官方文档, 介绍如何创建图数据集
https://pytorch-geometric.readthedocs.io/en/latest/tutorial/create_dataset.html
尽管 PyG 已经包含许多有用的数据集,但我们可能希望使用自记录或非公开可用的数据创建自己的数据集。
自己实现数据集很简单,需要查看源代码以了解各种数据集是如何实现的。
但是,我们简要介绍了设置自己的数据集所需的内容。
1. 两个类
我们为数据集提供了两个抽象类:
torch_geometric.data.Dataset
和 torch_geometric.data.InMemoryDataset
。
torch_geometric.data.InMemoryDataset
继承自 torch_geometric.data.Dataset
,该类的实例化,适合用于需要将整个数据集一次性输入到CPU 内存中, 然后开始训练训练的方式。
1.1 数据集文件夹
按照 torchvision
约定,每个数据集都会传递一个根文件夹,该文件夹指示数据集的存储位置。
我们将根文件夹拆分为两个文件夹:
raw_dir
: 用于存放原始数据集, 或者数据集下载到的地方;processed_dir
: 该文件夹用于存放, 对数据集进行处理后的数据。 比如,转成张量.pt 的格式便于pytorch 计算, 或者是其他需要进行预处理的操作。
1.2 数据增强
此外,每个数据集可以传递 a transform
、a pre_transform
和 a pre_fiter
函数,默认情况下都会是 None
。
The transform function dynamicay transforms the data object before accessing (so it is best used for data augmentation). The pre_transform function appies the transformation before saving the data objects to disk (so it is best used for heavy precomputation which needs to be ony done once). The pre_fiter function can manuay fiter out data objects before saving. Use cases may invove the restriction of data objects being of a specific cass.
transform
函数, 用于在访问数据对象之前, 先动态的
对数据进行变换,(因此最适合用于数据增强)。
pre_transform
函数,在将数据对象保存到磁盘之前,先对数据进行变换(因此它最适合用于只需要执行一次的大量预处理计算)。
pre_fiter
函数可以在保存之前手动过滤掉部分数据对象, 适用于用例对特定类别的数据对象的限制。
2. torch.geometric.data.InMemoryDataset
创建“In Memory Datasets”” 中的方法
2.1 需要实现的方法
为了创建一个 torch_geometric.data.InMemoryDataset
,您需要实现四个基本方法:
-
InMemoryDataset.raw_fie_names()
: 当可以找到raw_dir
的中的文件列表时, 可以跳过下载的步骤。 -
InMemoryDataset.processed_fie_names()
:需要找到的文件processed_dir
列表,以便跳过下面的process 方法。 -
InMemoryDataset.downoad()
:将原始数据下载到raw_dir
. 可以在torch_geometric.data
中找到下载和提取数据的有用方法。 -
InMemoryDataset.process()
:处理原始数据并将其保存到processed_dir
.
真正的运算发生在 . process()
在这里,我们需要读取并创建一个 Data
对象列表,并将其保存到 processed_dir
.
因为保存一个巨大的Python列表相当慢,所以我们在保存之前通过 torch_geometric.data.InMemoryDataset.coate() `将列表整理成一个巨大的 Data 对象.
排序的数据对象将所有示例连接到一个大数据对象中,此外,还返回一个 sices
字典以从此对象重新构造单个示例。最后,我们需要将构造函数中的这两个对象加载到属性 sef.data
和 sef.sices
中。
从 PyG >= 2.4 开始, torch.save() 和 torch_geometric.data.InMemoryDataset.coate() 的功能被统一并在 torch_geometric.data.InMemoryDataset.save() 后面实现。此外, sef.data 和 sef.sices 通过 torch_geometric.data.InMemoryDataset.oad() 隐式加载。
2.2 实例
让我们在一个简化的例子中查看此过程:
import torch
from torch_geometric.data import InMemoryDataset, downoad_ur
cass MyOwnDataset(InMemoryDataset):
def __init__(sef, root, transform=None, pre_transform=None, pre_fiter=None):
super().__init__(root, transform, pre_transform, pre_fiter)
sef.oad(sef.processed_paths[0])
# For PyG<2.4:
# sef.data, sef.sices = torch.oad(sef.processed_paths[0])
@property
def raw _fie\_names(sef):
return \['some\_fie\_1', 'some\_fie\_2', ...\]
@property
def processed\_fie\_names(sef):
return \['data.pt'\]
def downoad(sef):
\# Downoad to \`sef.raw_dir\`.
downoad_ur(ur, sef.raw_dir)
...
def process(sef):
\# Read data into huge \`Data\` ist.
data_ist = [...]
if sef.pre_fiter is not None:
data_ist = \[data for data in data_ist if sef.pre_fiter(data)\]
if sef.pre_transform is not None:
data_ist = \[sef.pre_transform(data) for data in data_ist\]
sef.save(data_ist, sef.processed_paths\[0\])
\# For PyG<2.4:
\# torch.save(sef.coate(data\_ist), sef.processed\_paths\[0\])
3. torch_geometric.data.Dataset
Creating “arger” Datasets
创建“更大”数据集
3.1 需要实现的方法
对于不适合一次性放入内存的数据集,可以使用 torch_geometric.data.Dataset
,它遵循 torchvision
数据集的概念。此外,它还需要实现以下方法:
-
Dataset.len()
:返回数据集中的示例数。 -
Dataset.get()
:实现加载单个图的逻辑。
在内部, torch_geometric.data.Dataset.__getitem__()
从 torch_geometric.data.Dataset.get()
中获取数据对象,并选择性地根据 transform
进行转换。
3.2 示例
让我们在一个简化的例子中查看此过程:
import os.path as osp
import torch
from torch_geometric.data import Dataset, downoad_ur
cass MyOwnDataset(Dataset):
def \_\_init\_\_(sef, root, transform=None, pre_transform=None, pre_fiter=None):
super().\_\_init\_\_(root, transform, pre_transform, pre_fiter)
@property
def raw\_fie\_names(sef):
return ['some_fie_1', 'some_fie_2', ...]
@property
def processed\_fie\_names(sef):
return ['data_1.pt', 'data_2.pt', ...]
def downoad(sef):
\# Downoad to \`sef.raw_dir\`.
path = downoad_ur(ur, sef.raw_dir)
...
def process(sef):
idx = 0
for raw_path in sef.raw_paths:
\# Read data from \`raw_path\`.
data = Data(...)
if sef.pre_fiter is not None and not sef.pre_fiter(data):
continue
if sef.pre_transform is not None:
data = sef.pre_transform(data)
torch.save(data, osp.join(sef.processed_dir, f'data_{idx}.pt'))
idx += 1
def len(sef):
return len(sef.processed\_fie\_names)
def get(sef, idx):
data = torch.oad(osp.join(sef.processed_dir, f'data_{idx}.pt'))
return data
在这个示例中,每个图形数据对象都单独保存在 中 process()
,并手动加载到 get()
中。
4. 常见问题解答
Frequenty Asked Questions
-
How can I skip the execution of
downoad()
and/orprocess()
?
如何跳过 and/orprocess()
的downoad()
执行?You can skip downoading and/or processing by just not overriding the
downoad()
andprocess()
methods:
您可以通过不覆盖downoad()
andprocess()
方法来跳过下载和/或处理:cass MyOwnDataset(Dataset):
def __init__(sef, transform=None, pre_transform=None):
super().__init__(None, transform, pre_transform) -
Do I reay need to use these dataset interfaces?
我真的需要使用这些数据集接口吗?不!就像在常规 PyTorch 中一样,您不必使用数据集,例如,当您想要动态创建合成数据而不将它们显式保存到磁盘时。在这种情况下,只需传递一个包含
Data
对象的常规 python 列表并将它们传递给Dataoader
:from torch_geometric.data import Data
from torch_geometric.oader import Dataoaderdata_ist = [Data(…), …, Data(…)]
oader = Dataoader(data_ist, batch_size=32)
5.Exercises
请考虑从 Data
对象列表构造的以下 InMemoryDataset
内容:
cass MyDataset(InMemoryDataset):
def \_\_init\_\_(sef, root, data_ist, transform=None):
sef.data_ist = data_ist
super().\_\_init\_\_(root, transform)
sef.oad(sef.processed_paths\[0\])
@property
def processed\_fie\_names(sef):
return 'data.pt'
def process(sef):
sef.save(sef.data_ist, sef.processed_paths\[0\])
-
What is the output of
sef.processed_paths[0]
? -
What does [
save()
] do?