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

Examples or explanations of pytorch dataloaders?

我对 Pytorch 还很陌生(并且从未进行过高级编码)。我正在尝试使用 d2l.ai 教科书学习深度学习的基础知识,但无法理解数据加载器代码背后的逻辑。我阅读了 torch.utils.data docs,但不确定 DataLoader class 的用途,例如我应该将 torch.utils.data.TensorDataset class 与它结合使用。比如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)

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

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

“随机读取是昂贵的或不可能的”以及 batch_size 依赖于获取的数据是什么意思?谁能举个例子?

如果有任何资源可供像我这样的 CompSci 菜鸟学习这些基础知识,我将不胜感激!

非常感谢!

我会给你一个如何使用数据加载器的例子,并解释这些步骤:

数据加载器是数据集上的可迭代对象。所以当你迭代它时,它会 return B 从数据集中随机收集样本(包括数据样本和 target/label),其中 B 是批量大小。

要创建这样的数据加载器,您首先需要一个 class,它继承自数据集 Pytorch class。在 pytorch 中有这个 class 的标准实现,应该是 TensorDataset。但是标准的方法是创建一个自己的。这是图像 classification:

的示例
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)

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

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

好的,现在您已经创建了 class 预处理和 return 一个样本及其标签。现在我们必须创建 datalaoder,它“环绕”这个 class,然后可以 return 来自数据集 class 的整批样本。 让我们创建三个数据加载器,一个遍历训练集,一个用于测试集,一个用于验证集:

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,
)

现在您已经创建了数据加载器并可以开始训练了! 例如像这样:


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)
        
        . . .

通常您会为“YourImageDataset”创建一个自己的文件class,然后导入您要在其中创建数据加载器的文件。 希望能说清楚dataloader和Datasetclass的作用是什么,怎么用!


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

dataset = [1,2,3,4]
dataset  = iter(dataset)

print(next(a))
print(next(a))
print(next(a))
print(next(a))

# output:
# >>> 1
# >>> 2
# >>> 3
# >>> 4

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

您使用数据加载器将数据拆分成批次、打乱数据或动态转换现有数据。

地图式数据集提供随机访问功能。示例:Numpy 数组、Python 字典、磁盘上的文件。

只能按顺序访问可迭代样式数据集。示例:Python 个生成器,来自网络的流式数据。

一般来说,您应该尽可能使用地图样式的数据集。地图风格的数据集提前给你它们的大小,更容易洗牌,并允许简单的并行加载。

我写了一篇简短的 post 关于如何使用 PyTorch 数据集,以及 map-style 和 iterable-style 数据集之间的区别。查看完整的 post here.