01_pytorch中的DataSet

news/2024/11/9 0:47:23/

在pytorch 中,
Dataset: 用于数据集的创建;
DataLoader: 用于在训练过程中,传递获取一个batch的数据;

这里先介绍 pytorch 中的 Dataset 这个类,
torch.utils.data. dataset.py 是一个表示数据集的抽象类。任何自定义的数据集都需要继承这个类并覆写相关方法。

数据集,其实就是一个负责处理索引(index)到样本(sample)映射的一个类(class)。

在这里插入图片描述
在torch.utils.data. dataset.py 中可知,
pytorch 提供两种数据集:

  • Map 式数据集, 上图中MapDataPipe()
  • Iterable 式数据集, IterDataPipe()

1. Map 式数据集

即上图中MapDataPipe(),

1.1 需要重写的方法

一个Map式的数据集必须要重写__getitem__(self, index),
len(self) 两个内建方法,用来表示从索引到样本的映射(Map).

这样一个数据集dataset的作用如下,

  • 当使用dataset[idx]命令时,可以在你的硬盘中读取你的数据集中第idx张图片以及其标签(如果有的话);
  • len(dataset)则会返回这个数据集的容量。

1.2 使用方法

例子-1: 自己实验中写的一个例子:这里我们的图片文件储存在“./data/faces/”文件夹下,图片的名字并不是从1开始,而是从final_train_tag_dict.txt这个文件保存的字典中读取,label信息也是用这个文件中读取。大家可以照着注释阅读这段代码。

from torch.utils import data
import numpy as np
from PIL import Imageclass face_dataset(data.Dataset):def __init__(self):self.file_path = './data/faces/'f=open("final_train_tag_dict.txt","r")self.label_dict=eval(f.read())f.close()def __getitem__(self,index):label = list(self.label_dict.values())[index-1]img_id = list(self.label_dict.keys())[index-1]img_path = self.file_path+str(img_id)+".jpg"img = np.array(Image.open(img_path))return img,labeldef __len__(self):return len(self.label_dict)

2. Iterable 式数据集

一个Iterable(迭代)式数据集是抽象类data.IterableDataset的子类,并且覆写了__iter__方法成为一个迭代器。

这种数据集主要用于数据大小未知,或者以流的形式的输入,本地文件不固定的情况,需要以迭代的方式来获取样本索引。

一个 Iterable 式的数据集必须要重写__iter__,

class IterableDataset(Dataset[T_co]):r"""An iterable Dataset.All datasets that represent an iterable of data samples should subclass it.Such form of datasets is particularly useful when data come from a stream.All subclasses should overwrite :meth:`__iter__`, which would return aniterator of samples in this dataset.When a subclass is used with :class:`~torch.utils.data.DataLoader`, eachitem in the dataset will be yielded from the :class:`~torch.utils.data.DataLoader`iterator. When :attr:`num_workers > 0`, each worker process will have adifferent copy of the dataset object, so it is often desired to configureeach copy independently to avoid having duplicate data returned from theworkers. :func:`~torch.utils.data.get_worker_info`, when called in a workerprocess, returns information about the worker. It can be used in either thedataset's :meth:`__iter__` method or the :class:`~torch.utils.data.DataLoader` 's:attr:`worker_init_fn` option to modify each copy's behavior."""def __iter__(self) -> Iterator[T_co]:raise NotImplementedErrordef __add__(self, other: Dataset[T_co]):return ChainDataset([self, other])

所有表示数据样本可迭代的数据集都应该对其进行子类化。
这种形式的数据集在数据来自流的时候特别有用。

所有的子类都应该覆盖 :meth:__iter__,它将返回这个数据集中样本的迭代器。

  • 当子类与 :class:~torch.utils.data.DataLoader一起使用时,数据集中的每个项目将从 :class:~torch.utils.data.DataLoader迭代器中产生。
  • 当 :attr:num_workers > 0时,每个工作进程将有一个不同的数据集对象的副本,所以通常需要独立配置每个副本,以避免从工作进程返回重复的数据。
  • :func:~torch.utils.data.get_worker_info,当在工作进程中调用时,返回关于工作者的信息。它可以被用于数据集的 :meth:__iter__ 方法或 :class:~torch.utils.data.DataLoader 的 j-
  • :attr:worker_init_fn 选项来修改每个副本的行为

2.1  迭代器和生成器之间的关系

在这里插入图片描述

2.2 python 中的迭代器

顾名思义,迭代器就是用于迭代操作(for 循环)的对象,它像列表一样可以迭代获取其中的每一个元素,任何实现了 __next__ 方法 (python2 是 next)的对象都可以称为迭代器。

它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。

比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。
因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素
(按需调用 call by need 的方式,本质上 for 循环就是不断地调用迭代器的__next__方法)。

以斐波那契数列为例来实现一个迭代器:

class Fib:def __init__(self, n):self.prev = 0self.cur = 1self.n = ndef __iter__(self):return selfdef __next__(self):if self.n > 0:value = self.curself.cur = self.cur + self.prevself.prev = valueself.n -= 1return valueelse:raise StopIteration()# 兼容python2def next(self):return self.__next__()f = Fib(10)
print([i for i in f])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 5

2.3  python 中的生成器

知道迭代器之后,就可以正式进入生成器的话题了。

2.3.1 为什么需要生成器

通过列表生成式,我们可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限的,而且创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,在Python中,这种一边循环一边计算的机制,称为生成器:generator

生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。

生成器类似于返回值为数组的一个函数,这个函数可以接受参数,可以被调用,但是,不同于一般的函数会一次性返回包括了所有数值的数组,生成器一次只能产生一个值,这样消耗的内存数量将大大减小,而且允许调用函数可以很快的处理前几个返回值,因此生成器看起来像是一个函数,但是表现得却像是迭代器

  • 生成器函数:也是用def定义的,利用关键字yield一次性返回一个结果,阻塞,重新开始

  • 生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果

普通函数用 return 返回一个值,和 Java 等其他语言是一样的,然而在 Python 中还有一种函数,用关键字 yield 来返回值,这种函数叫生成器函数,函数被调用时会返回一个生成器对象,生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样, 生成器更加简洁。

2.3.2 生成器函数

最简单的生成器函数:

>>> def func(n):
...     yield n*2
...
>>> func
<function func at 0x00000000029F6EB8>
>>> g = func(5)
>>> g
<generator object func at 0x0000000002908630>
>>>

func 就是一个生成器函数,调用该函数时返回对象就是生成器 g ,这个生成器对象的行为和迭代器是非常相似的,可以用在 for 循环等场景中。注意 yield 对应的值在函数被调用时不会立刻返回,而是调用next方法时(本质上 for 循环也是调用 next 方法)才返回。

>>> g = func(5)
>>> next(g)
10>>> g = func(5)
>>> for i in g:
...     print(i)
...
10

那为什么要用生成器呢?用生成器它没有那么多冗长代码了,而且性能上一样的高效。

不足之处,便是需要多理解一下。

来看看用生成器实现斐波那契数列有多简单。

def fib(n):prev, curr = 0, 1while n > 0:n -= 1yield currprev, curr = curr, curr + prevprint([i for i in fib(10)])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

2.3.2 生成器表达式

  • 生成器表达式
    器表达式与列表推导式长的非常像,但是它俩返回的对象不一样,前者返回生成器对象,后者返回列表对象。
>>> g = (x*2 for x in range(10))
>>> type(g)
<type 'generator'>
>>> l = [x*2 for x in range(10)]
>>> type(l)
<type 'list'>

生成器的优势,就是迭代海量数据时,生成器会更加内存。

2.3  生成器在 DataLoader中应用

深度学习框架PyTorch中的DataLoader模块的实现就使用了生成器的机制来生成一次训练用的batch。

DataLoader的详解在博主的另一篇文章Pytorch之Dataloader中,这里只讲其中运用到生成器机制的Sampler类模块。

首先,是 RandomSampler, iter(randomSampler) 会返回一个可迭代对象,这个可迭代对象 每次 next 都会输出当前要采样的 index,SequentialSampler也是一样,只不过产生的 index 是顺序的

class RandomSampler(Sampler):def __init__(self, data_source):self.data_source = data_sourcedef __iter__(self):return iter(torch.randperm(len(self.data_source)).long())def __len__(self):return len(self.data_source)

BatchSampler 是一个普通 Sampler 的 wrapper, 普通Sampler 一次仅产生一个 index, 而 BatchSampler 一次产生一个 batch 的 indices。

class BatchSampler(Sampler):"""Wraps another sampler to yield a mini-batch of indices. Args: sampler (Sampler): Base sampler. batch_size (int): Size of mini-batch. drop_last (bool): If ``True``, the sampler will drop the last batch if its size would be less than ``batch_size`` Example: >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=False)) [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=True)) [[0, 1, 2], [3, 4, 5], [6, 7, 8]] """def __init__(self, sampler, batch_size, drop_last):if not isinstance(sampler, Sampler):raise ValueError("sampler should be an instance of ""torch.utils.data.Sampler, but got sampler={}".format(sampler))if not isinstance(batch_size, _int_classes) or isinstance(batch_size, bool) or \batch_size <= 0:raise ValueError("batch_size should be a positive integeral value, ""but got batch_size={}".format(batch_size))if not isinstance(drop_last, bool):raise ValueError("drop_last should be a boolean value, but got ""drop_last={}".format(drop_last))self.sampler = samplerself.batch_size = batch_sizeself.drop_last = drop_lastdef __iter__(self):batch = []for idx in self.sampler:batch.append(idx)if len(batch) == self.batch_size:yield batchbatch = []if len(batch) > 0 and not self.drop_last:yield batchdef __len__(self):if self.drop_last:return len(self.sampler) // self.batch_sizeelse:return (len(self.sampler) + self.batch_size - 1) // self.batch_size

reference:

https://chenllliang.github.io/2020/02/04/dataloader/
https://chenllliang.github.io/2020/02/06/PyIter/
https://www.zhihu.com/question/20829330/answer/213544776
https://www.cnblogs.com/wj-1314/p/8490822.html


http://www.ppmy.cn/news/172045.html

相关文章

动画制作流程

动画制作的相关流程 动画制作需要大量的流程&#xff0c;这就不仅仅一个人就能完成的&#xff0c;需要部门之间的相互合作&#xff0c;才能达到预期的效果。接下来就为大家带来3D动画制作的工作流程。 第一步&#xff1a;统筹策划 这是做什么事情之前都要做的事情&#xff0…

制作点线动画用它,轻松实现创作 | 万彩动画大师

点线动画具有灵活多变&#xff0c;高端大气的特点。以圆点和线条为主&#xff0c;通过不停地变幻和排列组合给观众带来震撼的视觉冲击力&#xff0c;常常被应用到互联网、金融等行业。虽然只有简单的点和线条&#xff0c;然而用AE制作起来可不简单哦。别担心&#xff0c;有万彩…

Canvas 图片制作动画

Canvas入门文档推荐 菜鸟教程 W3cschool 这个是 做的其中一个动画&#xff0c;只是html案例&#xff0c;后来做了十个添加到项目里面了&#xff0c;另外实现了暂停、继续、背景音乐同步播放/同步暂停、最后还将动画转成了视频并合成了音乐实现上传下载&#xff1b; &#xff…

使用ivx制作进场动画的经验总结

在案例制作中为了让展示效果更加精致&#xff0c;可能用到一些进场的小动效。今天使用时间轴和轨迹做了3个小样例给大家作为一个参考。轨迹在之前的帖子里已经讲过了&#xff0c;时间轴可能还比较陌生&#xff0c;可以把它理解为一个对轨迹进行管理的组件。因为有时案例中会有很…

X3D制作简易三维动画

第一次接触X3D&#xff0c;想留下一些自己的学习想法。 首先&#xff0c;直接百度X3D&#xff0c;会发现除了官网文档&#xff0c;其他的资料很少&#xff0c;官网文档全英文&#xff0c;看完它提供的例子后&#xff0c;知道X3D是一个HTML5框架&#xff0c;可以直接在项目文件…

三维动画设计与制作【2】

1.以下属于Max5中正交视图类型的有&#xff08;&#xff09;。 A.Camera B.Back C.Bottom D.Perspective 2.点的属性有&#xff08;&#xff09;。 A.Smooth B.Corner C.BezierCorner D.Bezier 3.以下属于3dsmax5中常用贴图类型的是&#xff08;&#xff09;。 A.Checker …

PYMOL | 制作动画

1. 方法一&#xff1a;纯命令行 1.命令窗口输入mset 1 x30&#xff0c;定义一个30帧的动画&#xff1b;2.输入frame 1定义第一帧&#xff1b;3.调整分子到一个合适的观察角度&#xff1b;4.输入mview store 存储该观察视角为第一帧;5.输入frame 30 定义第30帧;6.调整观察角度到…

AE制作Json动画教程

本文将从为什么要做动画&#xff0c;到动画实现方式&#xff0c;再到用AEBodymovin制作动画&#xff0c;结合实际案例行分享&#xff0c;希望给新手带来一些启发。 首先我们来聊聊&#xff0c;我们为什么要做动效&#xff1f; 1、突出产品某项功能 在APP中&#xff0c;我们经…