pytorch 数据加载器的示例或解释?

Mer*_*rry 3 python pytorch dataloader

我对 Pytorch 相当陌生(并且从未做过高级编码)。我正在尝试使用 d2l.ai 教科书学习深度学习的基础知识,但在理解数据加载器代码背后的逻辑时遇到困难。我阅读了torch.utils.data 文档,但不确定 DataLoader 类的用途,以及例如我应该将 torch.utils.data.TensorDataset 类与其结合使用时。例如,d2l定义了一个函数:

def load_array(data_arrays, batch_size, is_train=True):
    """Construct a PyTorch data iterator."""
    dataset = data.TensorDataset(*data_arrays)
    return data.DataLoader(dataset, batch_size, shuffle=is_train)
Run Code Online (Sandbox Code Playgroud)

我认为这应该返回一个迭代不同批次的迭代。但是,我不明白 data.TensorDataset 部分的作用(似乎文档页面上列出了很多选项)。此外,文档还说有两种类型的数据集:可迭代数据集和地图样式数据集。在描述前一种类型时,它说

“这种类型的数据集特别适合随机读取成本昂贵甚至不可能的情况,并且批量大小取决于获取的数据。”

“随机读取成本昂贵或不可能”以及批量大小取决于获取的数据意味着什么?谁能举个例子吗?

如果有任何资源可以让像我这样的 CompSci 新手学习这些基础知识,我真的很感激!

非常感谢!

The*_*fer 6

我将给您一个如何使用数据加载器的示例,并解释步骤:

数据加载器是数据集上的可迭代对象。因此,当您对其进行迭代时,它将从数据集中收集的样本(包括数据样本和目标/标签)中随机返回 B,其中 B 是批量大小。

要创建这样的数据加载器,您首先需要一个继承自 Dataset Pytorch 类的类。pytorch 中有该类的标准实现,应该是TensorDataset. 但标准方法是创建一个自己的方法。这是图像分类的示例:

import torch
from PIL import Image


class YourImageDataset(torch.utils.data.Dataset):
    def __init__(self, image_folder):
        self.image_folder = image_folder
        self.images = os.listdir(image_folder)

    # get sample
    def __getitem__(self, idx):
        image_file = self.images[idx]

        image = Image.open((self.image_folder + image_file))
        image = np.array(image)
        
        # normalize image
        image = image / 255

        # convert to tensor
        image = torch.Tensor(image).reshape(3, 512, 512)
        
        # get the label, in this case the label was noted in the name of the image file, ie: 1_image_28457.png where 1 is the label and the number at the end is just the id or something
        target = int(image_file.split("_")[0])
        target = torch.Tensor(target)

        return image, target

    def __len__(self):
        return len(self.images)

Run Code Online (Sandbox Code Playgroud)

要获取示例图像,您可以调用该类并将一些随机索引传递到getitem函数中。然后它将返回图像矩阵的张量和该索引处标签的张量。例如:

dataset = YourImageDataset("/path/to/image/folder")
data, sample = dataset.__getitem__(0) # get data at index 0
Run Code Online (Sandbox Code Playgroud)

好的,现在您已经创建了一个类来预处理并返回一个样本及其标签。现在我们必须创建 datalaoder,它“包装”此类,然后可以从数据集类返回整批样本。让我们创建三个数据加载器,一个用于迭代训练集,一个用于测试集,一个用于验证集:

dataset = YourImageDataset("/path/to/image/folder")

# lets split the dataset into three parts (train 70%, test 15%, validation 15%)
test_size = 0.15
val_size = 0.15

test_amount, val_amount = int(dataset.__len__() * test_size), int(dataset.__len__() * val_size)

# this function will automatically randomly split your dataset but you could also implement the split yourself
train_set, val_set, test_set = torch.utils.data.random_split(dataset, [
            (dataset.__len__() - (test_amount + val_amount)), 
            test_amount, 
            val_amount
])


# B is your batch-size, ie. 128

train_dataloader = torch.utils.data.DataLoader(
            train_set,
            batch_size=B,
            shuffle=True,
)
val_dataloader = torch.utils.data.DataLoader(
            val_set,
            batch_size=B,
            shuffle=True,
)
test_dataloader = torch.utils.data.DataLoader(
            test_set,
            batch_size=B,
            shuffle=True,
)
Run Code Online (Sandbox Code Playgroud)

现在您已经创建了数据加载器并准备好进行训练!例如这样:

dataset = YourImageDataset("/path/to/image/folder")

# lets split the dataset into three parts (train 70%, test 15%, validation 15%)
test_size = 0.15
val_size = 0.15

test_amount, val_amount = int(dataset.__len__() * test_size), int(dataset.__len__() * val_size)

# this function will automatically randomly split your dataset but you could also implement the split yourself
train_set, val_set, test_set = torch.utils.data.random_split(dataset, [
            (dataset.__len__() - (test_amount + val_amount)), 
            test_amount, 
            val_amount
])


# B is your batch-size, ie. 128

train_dataloader = torch.utils.data.DataLoader(
            train_set,
            batch_size=B,
            shuffle=True,
)
val_dataloader = torch.utils.data.DataLoader(
            val_set,
            batch_size=B,
            shuffle=True,
)
test_dataloader = torch.utils.data.DataLoader(
            test_set,
            batch_size=B,
            shuffle=True,
)
Run Code Online (Sandbox Code Playgroud)

通常,您将为“YourImageDataset”类创建一个自己的文件,然后导入到要在其中创建数据加载器的文件中。我希望我能弄清楚dataloader和Dataset类的作用以及如何使用它们!


我对 iter 风格的数据集了解不多,但据我了解:我上面向您展示的方法是地图风格。如果您的数据集存储在 .csv、.json 或任何类型的文件中,则可以使用它。因此,您可以迭代数据集的所有行或条目。Iter-style 将获取数据集或数据集的一部分,并将其转换为可迭代对象。例如,如果您的数据集是一个列表,则该列表的可迭代对象如下所示:


for epoch in range(epochs):

    for images, targets in train_dataloder:
        # now 'images' is a batch containing B samples
        # and 'targets' is a batch containing B targets (of the images in 'images' with the same index

        optimizer.zero_grad()
        images, targets = images.cuda(), targets.cuda()
        predictions = model.train()(images)
        
        . . .
Run Code Online (Sandbox Code Playgroud)

因此,它将next为您提供列表中的下一项。与 Pytorch Dataloader 一起使用可能会更高效、更快。通常,地图数据加载器足够快且常用,但文档认为,当您从数据库加载数据批次(可能会更慢)时,iter 样式的数据集会更有效。这种对 iter-style 的解释有点含糊,但我希望它能让你明白我的理解。我建议您首先使用地图样式,正如我在原始答案中所解释的那样。