• Datasets与IterableDatasets


    前言

    一直使用 Datasets 类,首次遇到 IterableDatasets 类,遂查找区别

    Dataset Types

    一共有两种数据集:

    • map-style 数据集
    • iterable-style 数据集

    Map-style datasets

    映射样式的数据集是实现了__getitem__()和__len__()协议的数据集,表示从(可能是非整数)索引/键到数据样本的映射

    • 我们使用 dataset[idx] 可以从磁盘上得到第 idx 个数据

    Iterable-style datasets

    可迭代样式的数据集是 IterableDataset 的实例,实现了 iter() 协议,表示数据样本上的可迭代对象,这种类型的数据集特别适用于随机读取非常昂贵甚至不可能的情况,并且批处理大小取决于获取的数据。

    • 例如,当使用 iter(dataset) 时,它可以返回从数据库、远程服务器读取的数据流,甚至是实时生成的日志
    • 注意:当使用多线程数据加载时,每个 worker 都会重复相同的数据集,数据集会重复返回 num_workers

    Python中的可迭代对象(Iterable)

    Python中可迭代对象(Iterable)并不是指某种具体的数据类型,它是指存储了元素的一个容器对象,且容器中的元素可以通过__iter__方法或__getitem__方法访问。

    • iter 方法的作用是让对象可以用 for...in...循环遍历,getitem 方法是让对象可以通过index索引的方式访问实例中的元素。
    • 一个可迭代对象是不能独立进行迭代的,迭代通过 for...in 完成。凡是可迭代对象都可以直接用 for...in循环访问,这个语句做了两件事:
      • 调用__iter__获得一个可迭代器
      • 循环调用__next__
        可迭代对象(Iterable)并不是(Iterator),所有的 Iterable 都可以通过内置函数 __iter__来转变为Iterator。
    • 迭代器的优点是:节约内存。因为 Iterator 对象表示的是一个数据流,可以把这个数据流看作一个有序序列,但是我们却不能提前知道序列的长度。因此,Iterator的计算是惰性的,只有在需要返回下一个数据时才会计算。这就意味着,在循环过程中,不用一次性读入数据,处理文件对象时很有用

    样例验证

    # 构造 iterable-style datasets
    class iter_Dataset(IterableDataset):
        def __init__(self, num_samples):
            self.num_samples = num_samples
    
        def __iter__(self):
            for i in range(self.num_samples):
                label = np.array(i)
                yield label
    
    # 构造 map-style datasets
    class normal_Dataset(Dataset):
        def __init__(self, num_samples):
            self.num_samples = num_samples
            self.data = []
            for i in range(self.num_samples):
                self.data += [i]
    
        def __len__(self):
            return self.num_samples
    
        def __getitem__(self, idx):
            return self.data[idx]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    直接输出数据集

    iter_dataset = iter_Dataset(10)
    dataset = normal_Dataset(10)
    
    print(f"normal dataset type: {type(dataset)}")
    for lbl in dataset:
        print(f"normal Dataset: {lbl}")
    >>normal dataset type: <class '__main__.normal_Dataset'>
    normal Dataset: 0
    normal Dataset: 1
    normal Dataset: 2
    
    print(f"iterable dataset type: {type(iter_dataset)}")
    for lbl in iter_dataset:
        print(f"iter dataset: {lbl}")
    >>iterable dataset type: <class '__main__.iter_Dataset'>
    iter dataset: 0
    iter dataset: 1
    iter dataset: 2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    使用 DataLoader

    • num_workers = 1, batch_size = 1,可以看到,输出的结果是一样的
    iter_dataset = iter_Dataset(10)
    iter_dataloader = DataLoader(
        iter_dataset,
        num_workers=1,
        batch_size=1,
    )
    
    dataset = normal_Dataset(10)
    dataloader = DataLoader(
        dataset,
        num_workers=1,
        batch_size=1,
    )
    
    for lbl in dataloader:
        print(f"normal Dataset: {lbl}")
    >>normal Dataset: Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0])
    normal Dataset: Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [1])
    normal Dataset: Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2])
    
    
    for lbl in iter_dataloader:
        print(f"iter dataset: {lbl}")
    >>iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0])]
    iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [1])]
    iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2])]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • num_workers = 2, batch_size = 1,可以看到,iterable-style 重复输出了两次,这就验证了,这种形式的每个 worker 都会遍历整个数据集,从而导致有几个 workers 就输出几遍
    >>normal Dataset: Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0])
    normal Dataset: Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [1])
    normal Dataset: Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2])
    
    >>iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0])]
    iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0])]
    iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [1])]
    iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [1])]
    iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2])]
    iter dataset: [Tensor(shape=[1], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2])]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • num_workers = 2, batch_size = 2,可以看到,每条数据都变成了两个元素,验证了 batch_size 的效果
    >>normal Dataset: Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0, 1])
    normal Dataset: Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2, 3])
    normal Dataset: Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [4, 5])
    
    
    >>iter dataset: [Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0, 1])]
    iter dataset: [Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [0, 1])]
    iter dataset: [Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2, 3])]
    iter dataset: [Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [2, 3])]
    iter dataset: [Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [4, 5])]
    iter dataset: [Tensor(shape=[2], dtype=int64, place=Place(gpu_pinned), stop_gradient=True,
           [4, 5])]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    【Spring】快速入门Spring Web MVC
    “传统技术”快速搭建AI产品的利器——LLM技术
    小米手机安装面具教程(Xiaomi手机获取root权限)
    基于HTML+CSS+JavaScript制作简单的大学生网页设计——关于我的家乡湖南网页设计主题
    CTF-栈溢出-基本ROP-【ret2shellcode】
    Vue打包好的dist如何在本地运行
    leetcode:650. 只有两个键的键盘【二维dp】
    java基于springboot校园餐厅订餐管理系统
    PostgreSQL逻辑复制(Logical Replication)原理
    软考 第十一章 软件知识产权基础知识
  • 原文地址:https://blog.csdn.net/qq_52852138/article/details/127686327