使用自定义pytorch数据集为高效小批量循环编码模式

使用自定义pytorch数据集为高效小批量循环编码模式,pytorch,Pytorch,对于如何在自定义数据集中高效地处理数据,以使其与minibatch eval/train循环配合良好,是否有任何一般性建议?为了更具体地说明我的意思,假设我定义了这个将x映射到x+1的合成玩具数据集: 导入torch.utils.data作为数据 类数据集(data.Dataset): 定义初始化(自): 超级(数据集,自我)。\uuuu初始化 #[x,y] self.dataset=[ [1, 2], [2, 3], [3, 4], [4, 5] ] 定义uu获取项目uu(自身,索引): it

对于如何在自定义数据集中高效地处理数据,以使其与minibatch eval/train循环配合良好,是否有任何一般性建议?为了更具体地说明我的意思,假设我定义了这个将x映射到x+1的合成玩具数据集:

导入torch.utils.data作为数据
类数据集(data.Dataset):
定义初始化(自):
超级(数据集,自我)。\uuuu初始化
#[x,y]
self.dataset=[
[1, 2],
[2, 3],
[3, 4],
[4, 5]
]
定义uu获取项目uu(自身,索引):
item=self.dataset[索引]
退货项目[0],项目[1]
定义(自我):
返回len(self.dataset)
在实践中,这将被包装在数据加载器中,并在eval/train循环中访问,如下所示:

dataset=dataset()
数据加载器=数据。数据加载器(数据集=数据集,批量大小=2,随机播放=真)
纪元=100
对于范围内的i_历元(历元):
对于i_minibatch,枚举中的minibatch(数据加载器):
x、 y=小批量
#预测与训练
dataset对象可能返回原始Python对象,如数字或列表,如我的示例实现中所示,但在最后一个代码段的“预测和训练”部分,我们需要一些特定的数据类型来计算数据,如torch.FloatTensor(似乎数据加载器可以隐式地完成这项工作),甚至可能包装为torch.autograd.Variable,可能还需要调用.cuda()。我的问题是关于何时进行这些数据转换和函数调用的一般建议


例如,一个选项是将所有内容都保存为数据集中的torch.FloatTensor,在data_loader循环中,我们可以添加变量wrapper并调用.cuda()。通过在Dataset构造函数或getitem方法中调用.cuda(),我们还可以在GPU上拥有全部或部分数据。我认为所有这些方法都有利弊。如果我正在为几个历元训练一个模型,我不想在每个历元或小批量迭代中引入不必要的开销,这些本来可以通过在数据集中预计算来避免。可能对pytorch的内部结构有更多了解的人(可能与某些缓存或jit编译有关)能够指出选择一种方法而不是另一种方法的更具体的原因。

您是否阅读过一些官方示例,例如?在这些示例中,它们首先获取数据。正如您所说,数据已隐式转换为torch张量。如果你有GPU,把cpu张量转换成GPU张量。最后,将GPU上的普通张量转换为torch
变量
,以便autograd工作

我认为这是做这件事的标准方法。至少,到目前为止我看到的所有pytorch代码都是这样做的。如果你想提高速度,你可以考虑

  • 使用dataloader中的多个工作进程获取数据
  • 使用多个GPU进行培训
  • 如果您有多台安装了多个GPU的服务器,甚至可以进行分布式培训

您是否阅读过一些官方示例,例如:?在这些示例中,它们首先获取数据。正如您所说,数据已隐式转换为torch张量。如果你有GPU,把cpu张量转换成GPU张量。最后,将GPU上的普通张量转换为torch
变量
,以便autograd工作

我认为这是做这件事的标准方法。至少,到目前为止我看到的所有pytorch代码都是这样做的。如果你想提高速度,你可以考虑

  • 使用dataloader中的多个工作进程获取数据
  • 使用多个GPU进行培训
  • 如果您有多台安装了多个GPU的服务器,甚至可以进行分布式培训

通常,数据集以一种对磁盘存储更友好的格式存储在文件中。加载数据集时,您希望数据类型对PyTorch更加友好。这是由torchvision库的管理员完成的。例如,对于MNIST,下面是标准转换:

datasets.MNIST('../data', train=True, download=True,
               transform=transforms.Compose([
                   transforms.ToTensor(),
                   transforms.Normalize((0.1307,), (0.3081,))
               ])
此处
ToTensor
将所有张量值除以255,这样,如果数据是RGB图像,则张量值将为0.0到1.0

这里的关键是,理想情况下,磁盘中的数据应该不知道您可能想用它做什么(培训、可视化、计算统计数据等),也不知道正在使用的框架。在加载与您正在做的事情相关的数据后应用转换

我想提到的另一件事是处理像ImageNet这样的大型数据集。有几件重要的事情:

  • 您应该避免使用单独的图像文件作为数据集,因为这在集群中不起作用。相反,您可以将所有文件打包为LMDB或解压缩zip(使用Python ZipFile模块)格式,然后只按顺序访问这些文件。对大文件的随机访问将大大降低您的速度
  • 对于大型数据集,应该避免在DataLoader类中使用shuffle选项。如果您这样做了,那么再次访问大文件时会使用随机访问,性能会下降。相反,您可以做的是顺序读取
    K=C*总纪元数*批量大小
    记录,其中
    C
    是您选择的某个常量>=1。然后在内存中洗牌K个记录,然后将它们分批分割。不幸的是,您现在必须手动执行此操作

  • 通常,数据集存储在文件中的格式对磁盘存储更友好。加载数据集时,您希望数据类型对PyTorch更加友好。这是由torchvision库的管理员完成的。例如,对于MNIST,下面是标准转换:

    datasets.MNIST('../data', train=True, download=True,
                   transform=transforms.Compose([
                       transforms.ToTensor(),
                       transforms.Normalize((0.1307,), (0.3081,))
                   ])
    
    此处
    ToTensor
    将张量中的所有值除以255,以便如果数据为RGB imag