首页 > 编程知识 正文

calcite解析sql实例,pytorch中文手册

时间:2023-05-03 11:44:42 阅读:175139 作者:3318

首先,我尝试整理pytorch的torch.utils.data模块,但找不到完整的时间。 最近终于可以完全理解了。

这个博客主要参考自觉性和官方文件,结合我自己对例行公事的理解。

(PS)对前半部分模块的理解可能偏向于文档翻译,但其中也有我自己的一些感悟)

importtorchprint (torch._ _ version _ )1.6.0 torch.utils.data最重要的是简单理解这个模块有三个小模块。

datasetsamplerdataloaderdatasetdataset主要有两种类型: Map style和Iterable style,源代码显示如下:

class_datasetkind(object ) : Map=0 Iterable=1 Map style的数据集通常很多。 通俗地说,就是通过键值的对应关系获取想要的数据,也就是通过索引获取对应的数据。

该函数接口的类型通常是classdataset(object ) :def_getitem_(self,index ) : raisenotimplementederrordef _ _ add other] )在pytorch中定义的所有数据集类型都是Map类型的子类,可以向数据集添加数据处理。

Iterable style数据类型是迭代的,简单理解可以理解为顺序读取。 使用这样的数据集的主要原因是随机读取的成本很高。

除了以上两种主要数据类型外,还包括基于这两种类型派生的数据模块。 torch.utils.data.concat dataset #用于连接多个map-styledatasettorch.utils.data.chain dataset #的多个iterable-stystet 用于连接以获取数据集中特定序列的子数据集torch.utils.data.tensor dataset #用于获取封装在每个tensor中的数据集的用户堆基类定义如下。

您可以按torch.utils.data.sequential sampler #的顺序对示例进行采样,并始终按相同的顺序在torch.utils.data.random sampler : #中指定是否存在倒带要进行随机采样的示例元素torch.utils.data.subsetrandomsampler #根据指定的索引列表选择示例元素torch.utils.data.weightedrandomer # 示例元素来自[0,Len(Weights )-1],给定概率(权重) torch.utils.data.BatchSampler #将另一个采样器封装在一个batch中! 此处的sampler与dataloader配合使用,用于将数据加载到torch.utils.data.distributed sampler #中受数据集子集限制的采样器中与torch.nn.parallel.distributeddataparallel结合使用。 在这种情况下,每个进程可以将分布式采样器实例作为DataLoader取样器传递。 #笔者目前没有接触过分布式采样,因此无法将dataloadertorch.utils.data.dataloaderdataloader与sampler结合使用

首先分析一下传递的参数:

dataloader(dataset,batch_size=1,shuffle=False,sampler=None,batch_sampler=None,num_workers=0,c worker_init_fn=None ) # dataset-以上两种类型的数据集# bastch-size-批处理大小# shuffle-每个epoch对数据集# sampler-对进行排序batch_sampler主要是批处理示例,sampler主要是单个数据示例,sampler通常作为输入参数传递

递进batch_sampler中,并且它和batch_size,shuffle,sampler以及drop_last互斥# num_workers-设置进程数,0代表的是主进程# collate_fn-将样本列表组成tesor类型的数据,通常是对Map style类型的数据使用# drop_last-当数据总量没有办法被batch_size整除的时候,会判断是否需要将最后一点元素舍去# timeout-如果是正的就从进程中收集time值,如果超过所设阈值还没有读取数据那么就会报错 (ps:笔者同样没有遇到过使用这个参数的程序)# pin_memory-如果为 True,数据加载器将在返回之前将无情的羊复制到 CUDA 固定内存中。(ps:笔者同样没有遇到过使用这个参数的程序)# work_init_fn-如果不为None的话,它会被每个worker的子进程调用,以worker id([0, num_workers-1]内的整型)为输入,其实就是worker初始化的时候所要执行的函数

简单介绍完这三个小模块之后,接下来介绍一些细节:

批处理

DataLoader 支持通过参数batch_size、drop_last 和batch_sampler 自动将单个获取的数据样本整理成批次。

自动批处理:

这是最常见的一种情况,用于根据batch_size生成批量样本,当从采样器中获得了一系列的样本索引之后,将它们作为参数传递给collate_fn整理成批次。
两种数据集加载的大致流程:
Map

for indices in batch_sampler: yield collate_fn([dataset[i] for i in indices])

Iterable

dataset_iter = iter(dataset)for indices in batch_sampler: yield collate_fn([next(dataset_iter) for _ in indices])

其中,collate_fn可以自定义数据整理的规则,比如将输出的数据填充到batch的最大长度。

非自动批处理

在某些情况下,使用者可能希望手动批处理或者是加载单个样本,这就不太适合使用自动批处理;
当batch_size和batch_sampler都为None(batch_sampler的默认值已经是None)时,自动批处理会被禁用。
从数据集中获得的每个样本都作为 collat​​e_fn 函数传递的参数进行处理。
源码中对应的程序如下:

if collate_fn is None: if self._auto_collation: collate_fn = _utils.collate.default_collate else: collate_fn = _utils.collate.default_convert

其中,_utils.collate.default_convert的作用是将单个numpy转换成tensor。

collate_fn

该函数在自动批处理和非自动批处理中的所实现的功能有所区别。
在非自动批处理中:每个单独的数据样本被调用,输出是从数据加载器迭代器产生的,在这种情况下,默认collate_fn只是将numpy转换成了tensor。
而在自动批处理的操作中,该函数用于数据样本列表。其将输入样本整理为1个batch,举个例子来说:如果每个数据样本是由一个3通道图像和一个完整的类标签组成,即数据集的每个元素返回一个元组(image,index)。那么默认的collate_fn将这些元组的列表整理成单个元组的批处理图片无情的羊和批处理类别标签无情的羊,操作流程如下:

先添加一个新的维度将值转换为无情的羊保留数据结构,如果是字典类型,那么它的输出具有相同的键集,但是值是无情的羊 单进程与多进程的处理

默认情况下,DataLoader 使用单进程数据加载。 在 Python 进程中,全局解释器锁 (GIL) 可防止跨线程完全并行化 Python 代码。为了避免在数据加载时阻塞计算代码,PyTorch 提供了一个简单的开关来执行多进程数据加载,只需将参数 num_workers 设置为正整数即可。

单进程

在单进程模式下,Dataloader初始化的进程和取数据的进程是一样的,因此数据加载可能会阻止计算。当用于在进程之间共享数据的资源有限时(例如共享内存,文件描述符),或者当整个数据集很小并且可以完全加载到内存中时,这种模式就是首选了。并且单进程对调试程序很有用(千万别用多进程调试程序,因为很难调试)。

多进程

当num_workers为正数的时候会进入多进程模式,每一次调用enumerate(dataloader)的时候Dataloader的迭代器就会调用,num_workers个进程就会被创建。这时,dataset,collate_fn和work_init_fn会被传入每一个worker中。

对于Map-style数据集,主进程利用sampler产生索引然后把他们发送到workers中,所以任何的shuffle随机化都是在主进程中完成的它通过分配索引来引导加载。

对于Iterable-style类型的数据集,由于每个工作进程都获得了数据集对象的副本,简单的多进程加载通常会导致重复的数据,所以需要使用torch.utils.data.get_worker_info()或者worker_init_fn是的用户可以独立配置每个副本

其中torch.utils.data.get_worker_info()在工作进程中返回各种有用的信息(包括工作进程ID、数据集副本、初始种子等)在主进程中返回None
在多进程中不推荐返回CUDA无情的羊,因为在多处理过程中使用CUDA和共享CUDA无情的羊有许多微妙之处,很容易出错。

Memory Pining

当计算机的显存充足时可以设置该项为True,其可以更快的将无情的羊传输到固定显存位置中(PS:具体用法笔者目前没有尝试过),因为将数据直接固定到了显存中,不需要借助任何虚拟内存,所以使用该项后传输速度较快。

Dataloader单进程调用流程

当训练程序开始调用:

for data, label in train_loader:

train_loader迭代器开始进行迭代
在可迭代对象中首先判断num_workers的数量再返回对应迭代器:

def __iter__(self): if self.num_workers == 0: return _SingleProcessDataLoaderIter(self) else: return _MultiProcessingDataLoaderIter(self)

本篇文章主要研究的是单进程,所以之后再深入_SingleProcessDataLoaderIter(self):

class _SingleProcessDataLoaderIter(_BaseDataLoaderIter): def __init__(self, loader): ... self._dataset_fetcher = _DatasetKind.create_fetcher( self._dataset_kind, self._dataset, self._auto_collation, self._collate_fn, self._drop_last) def _next_data(self): index = self._next_index() # may raise StopIteration data = self._dataset_fetcher.fetch(index) # may raise StopIteration if self._pin_memory: data = _utils.pin_memory.pin_memory(data) return data

其基类_BaseDataLoaderIter,该类是所有迭代器的基类;派生类在初始化参数中以基类为基础定义了_dataset_fetcher,该方法结合相关参数确定获取数据的方式。
下面给出其基类的源码:

class _BaseDataLoaderIter(object): def __init__(self, loader):... self._index_sampler = loader._index_sampler self._sampler_iter = iter(self._index_sampler) def __iter__(self): return self def _next_index(self): return next(self._sampler_iter) # may raise StopIteration def _next_data(self): raise NotImplementedError def __next__(self): data = self._next_data() self._num_yielded += 1... return data next = __next__ # Python 2 compatibility def __len__(self): return len(self._index_sampler) def __getstate__(self): raise NotImplementedError("{} cannot be pickled", self.__class__.__name__)

将上述两类结合起来看,每次的for循环会调用基类的__next__()函数,在该函数中会调用派生类的_next_data(),而派生类的_next_data调用基类的_next_index,进而返回next(self._sampler_iter),即next(iter(self._index_sampler))。而dataloader中的_index_sampler定义如下(用于产生索引):

def _index_sampler(self): if self._auto_collation: return self.batch_sampler else: return self.sampler

之后产生的索引到self._dataset_fetcher进行取数据的相关操作得到最终的数据
用一张图片表示即为:

结束

这篇博客花费了一些时间去整理,但是最后落笔的时候时间还是有些紧的,如有问题欢迎指正交流!!!!!
再附上参考链接:
[知乎]:(https://zhuanlan.zhihu.com/p/337850513)
[官方文档]:(https://pytorch.org/docs/1.6.0/)

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。