数据完全存于内存的数据集类

1. InMemoryDataset基类

虽然PyG内置了许多数据集,但用户往往希望使用自行记录的数据集。
PyG提供了两个抽象类:torch_geometric.data.Datasettorch_geometric.data.InMemoryDataset.

  • 在PyG中我们可以通过继承InMemoryDataset类,来将数据全部存储到内存中。
  • PyG可以方便地构造数据完全存于内存的数据集类:InMemory数据集类
1. 1InMemoryDataset基类介绍
class InMemoryDataset(root: Optional[str] = None, transform: Optional[Callable] = None, pre_transform: Optional[Callable] = None, pre_filter: Optional[Callable] = None)
  • root:字符串类型,是存储数据集的文件夹的路径,该文件夹下有两个文件夹:
    • raw_dir:创建用来存储未处理文件的文件夹,存储从网络上下载的数据集原始文件
    • processed_dir: 创建用来存储处理后数据的文件夹,以后从此文件夹下加载文件即可获得Data对象。
    • 均为属性方法,可以覆写以自定义文件夹名字,不覆写时默认为rawprocessed
	# 一个覆写例子
	@property
    def raw_dir(self):
        return osp.join(self.root, 'raw1')
        # 创建了路径为 'self.root/raw1' 的文件夹

    @property
    def processed_dir(self):
        return osp.join(self.root, 'processed1')
        # 创建路径为 'self.root/processed1' 的文件夹
  • transform=None:函数类型
    • 是一个数据转换的函数,该函数接收一个Data对象并返回一个转换后的Data对象
    • 该函数在每次数据获取过程中都被执行,具体流程为:获取数据的函数首先用该transform函数对Data做转换,再返回数据
    • 该参数输入的函数应用于数据增广
      (数据增广是深度学习中常用的技巧之一,主要用于增加训练数据集,让数据集尽可能的多样化,使得训练的模型具有更强的泛化能力;目前数据增广主要包括:水平/垂直翻转,旋转,缩放,裁剪,剪切,平移,对比度,色彩抖动,噪声等)
  • pre_transform=None:函数类型
    • 是一个数据转换的函数,该函数也是接收一个Data对象并返回一个转换后的Data对象
    • 但该函数只在Data`对象被保存到文件前才调用
    • 因此它用于只执行一次的数据预处理
  • pre_filter=None:函数类型
    • 是一个检查数据是否要保留的函数
    • 它接收一个Data对象,返回此Data对象是否应该被包含在最终的数据集中
    • 也在Data对象被保存到文件前调用
    • None时表示不做数据检查,保留所有数据。
1.2 继承过程中的四个基本方法
  • raw_file_names():返回一个数据集原始文件的文件名列表。
	# 以数据集PubMed为例
	@property
	def raw_file_names(self):
		return ['some_file_1', 'some_file_2', ...]
	"""
	一个例子:
	@property
	def raw_file_names(self):
		names = ['x', 'tx', 'allx', 'y', 'ty', 'ally','graph', 'test.index']
		return ['ind.pubmed.{}'.format(name) for name in names]
	"""

  • processed_file_names():返回一个存储处理过的数据的文件名列表。
	@property
	def processed_file_names(self):
		return ['data.pt']

-download():下载原始数据集到raw_dir文件夹中

	def download(self):
		download_url(url, self.raw_dir) # 从url下载该文件到 self.raw_dir (默认是self.root/raw)
	"""
	一个例子
	def download(self):
		for name in self.raw_file_names:
			download_url('{}/{}'.format(self.url,name), self.raw_dir) 
			# 从 self.url/name 下载
	"""

  • process():处理数据,流程如下
    • process方法里,我们实现数据处理的逻辑:
    • 首先,我们从数据集原始文件中读取样本并生成Data对象,所有样本的Data对象保存在列表data_list中。
    • 如果要对数据做过滤的话,我们执行数据过滤的过程。
    • 如果要对数据做处理的话,我们执行数据处理的过程。
    • 我们保存处理好的数据到文件。但由于python保存一个大列表非常慢的,我们需要先将所有Data对象合并成大的Data对象再保存。
    • collate()是一个静态方法,其接收一个列表的Data对象,返回合并后的Data对象以及用于从合并后的Data对象重构各个原始Data对象的切片字典slices
    • 最后通过torch.save(要保存的文件, 路径)将这个巨大的Data对象和切片字典slices保存到文件。
	def process(self):
		data_list = [...] # Read data into huge `Data` list.
		if self.pre_filter is not None:
			data_list = [data for data in data_list if self.pre_filter(data)]
		if self.pre_transform is not None:
			data_list = [self.pre_transform(data) for data in data_list]

		data, slices = self.collate(data_list)
		torch.save((data, slices),self.processed_paths[0])
	"""
	# 一个例子
	def process(self):
		data = read_planetoid_data(self.raw_dir, 'pubmed')
		data = data if self.pre_transform is None else self.pre_transform(data)
		torch.save(self.collate([data]), self.processed_paths[0]) # 这里不加[0]也行
	"""

1.3 继承后生成对象的程序运行流程

当继承了InMemoryDataset类构建某个心累的数据集类之后,生成一个该类的对象,其程序运行的流程如下:

  • 检查数据原始文件是否已下载
    • 检查self.raw_dir目录下是否存在raw_file_names()属性方法返回的每个文
      件,如有文件不存在,则调用download()方法执行原始文件下载。
    • self.raw_dir为osp.join(self.root, ‘raw’)。
  • 检查数据是否经过处理
    • 先检查之前对数据做变换的方法:检查self.processed_dir目录下是否
      存在pre_transform.pt文件:
      • 存在:意味着之前进行过数据变换,接着需要加载该文件,以获取之前所用的数据变换的方法,并检查它与当前pre_transform参数指定的方法是否相同,
      • 如果不相同则会报出一个警告,“The pre_transform argument differs from
        the one used in ……”。
        self.processed_dir为osp.join(self.root, ‘processed’)。
  • 检查之前的样本过滤的方法:检查self.processed_dir目录下是否存
    pre_filter.pt文件:
    • 存在,则加载该文件并获取之前所用的样本过滤的方法,并检查它与当前pre_filter参数指定的方法是否相同,如果不相同则会报出一个警告,“The pre_filter argument differs from theone used in ……”。
  • 检查是否存在处理好的数据:检查self.processed_dir目录下是否存
    self.processed_file_names属性方法返回的所有文件,如有文件不存在,
    则需要执行以下的操作:
    • 调用process()方法,进行数据处理。
    • 如果pre_transform参数不为None,则调用pre_transform()函数进行数据处理。
    • 如果pre_filter参数不为None,则进行样本过滤(此例子中不需要进行样本过滤,pre_filter参数为None)。
    • 保存处理好的数据到文件,文件存储在processed_paths()属性方法返回的文件路径。如果将数据保存到多个文件中,则返回的路径有多个。
    • processed_paths() 属 性 方 法 是 在 基 类 中 定 义 的 , 它 对self.processed_dir文件夹与processed_file_names()属性方法的返回每一个文件名做拼接,然后返回。
  • 最后保存新的pre_transform.pt文件和pre_filter.pt文件,它们分别存当前使用的数据处理方法和样本过滤方法

1.4 一个生成对象的例子

PlanetoidPubMed数据集类的构造

import os.path as osp

import torch
from torch_geometric.data import InMemoryDataset, download_url
from torch_geometric.io import read_planetoid_data

class PlanetoidPubMed(InMemoryDataset):

	url = 'https://gitee.com/rongqinchen/planetoid/raw/master/data'
	""" 节点代表文章,边代表引文关系。
	训练、验证和测试的划分通过二进制掩码给出。
	参数:
	root (string): 存储数据集的文件夹的路径
	transform (callable, optional): 数据转换函数,每一次获取数据时被调用。
	pre_transform (callable, optional): 数据转换函数,数据保存到文件前被调用。
"""
	# url = 'https://gitee.com/rongqinchen/planetoid/raw/master/data'
    # 如果github的链接不可用,请使用gitee的链接

	def __init__(self, root, transform=None, pre_transform=None):
	super(PlanetoidPubMed, self).__init__(root, transform, pre_transform)
	self.data, self.slices = torch.load(self.processed_paths[0])

	@property
	def raw_file_names(self):
		names = ['x', 'tx', 'allx', 'y', 'ty', 'ally', 'graph', 'test.index']
		return ['ind.pubmed.{}'.format(name) for name in names]

	@property
	def processed_file_names(self):
		return 'data.pt'

	def download(self):
		for name in self.raw_file_names:
			download_url('{}/{}'.format(self.url,name), self.raw_dir) # 从 self.url/name 下载该文件到 self.raw_dir (默认是self.root/raw)

	def process(self):
		data = read_planetoid_data(self.raw_dir, 'pubmed')
		data = data if self.pre_transform is None else self.pre_transform(data)
		torch.save(self.collate([data]), self.processed_paths[0])

接下来生成这个类的对象

dataset = PlanetoidPubMed('dataset/PlanetoidPubMed')
print(dataset.num_classes)
print(dataset[0].num_nodes)
print(dataset[0].num_edges)
print(dataset[0].num_features)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值