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]

直接输出数据集

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

使用 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])]
  • 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])]
  • 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])]
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长命百岁️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值