在使用pytorch训练模型,经常需要加载大量图片数据,因此pytorch提供了好用的数据加载工具Dataloader。

为了实现小批量循环读取大型数据集,在Dataloader类具体实现中,使用了迭代器和生成器。

这一应用场景正是python中迭代器模式的意义所在,因此本文对Dataloader中代码进行解读,可以更好的理解python中迭代器和生成器的概念。

本文的内容主要有:

解释python中的迭代器和生成器概念

解读pytorch中Dataloader代码,如何使用迭代器和生成器实现数据加载

python迭代基础

python中围绕着迭代有以下概念:

可迭代对象 iterables

迭代器 iterator

生成器 generator

这三个概念互相关联,并不是孤立的。在可迭代对象的基础上发展了迭代器,在迭代器的基础上又发展了生成器。

学习这些概念的名词解释没有多大意义。编程中很多的抽象概念都是为了更好的实现某些功能,才去人为创造的协议和模式。

因此,要理解它们,需要探究概念背后的逻辑,为什么这样设计?要解决的真正问题是什么?在哪些场景下应用是最好的?

迭代模式首先要解决的基础问题是,需要按一定顺序获取集合内部数据,比如循环某个list。

当数据很小时,不会有问题。但当读取大量数据时,一次性读取会超出内存限制,因此想出以下方法:

把大的数据分成几个小块,分批处理

惰性的取值方式,按需取值

循环读数据可分为下面三种应用场景,对应着容器(可迭代对象),迭代器和生成器:

for x in container: 为了遍历python内部序列容器(如list), 这些类型内部实现了__getitem__() 方法,可以从0开始按顺序遍历序列容器中的元素。

for x in iterator: 为了循环用户自定义的迭代器,需要实现__iter__和__next__方法,__iter__是迭代协议,具体每次迭代的执行逻辑在 __next__或next方法里

for x in generator: 为了节省循环的内存和加速,使用生成器来实现惰性加载,在迭代器的基础上加入了yield语句,最简单的例子是 range(5)

代码示例:

# 普通循环 for x in list

numbers = [1, 2, 3,]

for n in numbers:

print(n) # 1,2,3

# for循环实际干的事情

# iter输入一个可迭代对象list,返回迭代器

# next方法取数据

my_iterator = iter(numbers)

next(my_iterator) # 1

next(my_iterator) # 2

next(my_iterator) # 3

next(my_iterator) # StopIteration exception

# 迭代器循环 for x in iterator

for i,n in enumerate(numbers):

print(i,n) # 0,1 / 1,3 / 2,3

# 生成器循环 for x in generator

for i in range(3):

print(i) # 0,1,2

for x in container方法:

list, deque, …

set, frozensets, …

dict, defaultdict, OrderedDict, Counter, …

tuple, namedtuple, …

str

for x in iterator方法:

enumerate() # 加上list的index

sorted() # 排序list

reversed() # 倒序list

zip() # 合并list

for x in generator方法:

range()

map()

filter()

reduce()

[x for x in list(...)]

上面示例代码中python内置函数iter和next的用法:

iter函数,调用__iter__,返回一个迭代器

next函数,输入迭代器,调用__next__,取出数据

比较容易混淆的是__iter__和__next__两个方法。它们的区别是:

__iter__是为了可以迭代,真正执行取数据的逻辑是__next__方法实现的,实际调用是通过next(iterator)完成

__iter__可以返回自身(return self),实际读取数据的实现放在__next__方法

__iter__可以和yield搭配,返回生成器对象

__iter__返回自身的做法有点类似 python中的类型系统。为了保持一致性,python中一切皆对象。

每个对象创建后,都有类型指针,而类型对象的指针指向元对象,元对象的指针指向自身。

生成器,是在__iter__方法中加入yield语句,好处有:

减少循环判断逻辑的复杂度

惰性取值,节省内存和时间

yield作用:

代替函数中的return语句

记住上一次循环迭代器内部元素的位置

Dataloder源码分析

pytorch采用for x in iterator模式,从Dataloader类中读取数据。

为了实现该迭代模式,在Dataloader内部实现__iter__方法,实际返回的是_DataLoaderIter类。

_DataLoaderIter类里面,实现了 __iter__方法,返回自身,具体执行读数据的逻辑,在__next__方法中。

以下代码只截取了单线程下的数据读取。

class DataLoader(object):

r"""

Data loader. Combines a dataset and a sampler, and provides

single- or multi-process iterators over the dataset.

"""

def __init__(self, dataset, batch_size=1, shuffle=False, ...):

self.dataset = dataset

self.batch_sampler = batch_sampler

...

def __iter__(self):

return _DataLoaderIter(self)

def __len__(self):

return len(self.batch_sampler)

class _DataLoaderIter(object):

r"""Iterates once over the DataLoader's dataset, as specified by the sampler"""

def __init__(self, loader):

self.sample_iter = iter(self.batch_sampler)

...

def __next__(self):

if self.num_workers == 0: # same-process loading

indices = next(self.sample_iter) # may raise StopIteration

batch = self.collate_fn([self.dataset[i] for i in indices])

if self.pin_memory:

batch = pin_memory_batch(batch)

return batch

...

def __iter__(self):

return self

Dataloader类中读取数据Index的方法,采用了 for x in generator方式,但是调用采用iter和next函数

构建随机采样类RandomSampler,内部实现了 __iter__方法

__iter__方法内部使用了 yield,循环遍历数据集,当数量达到batch_size大小时,就返回

实例化随机采样类,传入iter函数,返回一个迭代器

next会调用随机采样类中生成器,返回相应的index数据

class RandomSampler(object):

"""random sampler to yield a mini-batch of indices."""

def __init__(self, batch_size, dataset, drop_last=False):

self.dataset = dataset

self.batch_size = batch_size

self.num_imgs = len(dataset)

self.drop_last = drop_last

def __iter__(self):

indices = np.random.permutation(self.num_imgs)

batch = []

for i in indices:

batch.append(i)

if len(batch) == self.batch_size:

yield batch

batch = []

## if images not to yield a batch

if len(batch)>0 and not self.drop_last:

yield batch

def __len__(self):

if self.drop_last:

return self.num_imgs // self.batch_size

else:

return (self.num_imgs + self.batch_size - 1) // self.batch_size

batch_sampler = RandomSampler(batch_size. dataset)

sample_iter = iter(batch_sampler)

indices = next(sample_iter)

总结

本文总结了python中循环的三种模式:

for x in container 可迭代对象

for x in iterator 迭代器

for x in generator 生成器

pytorch中的数据加载模块 Dataloader,使用生成器来返回数据的索引,使用迭代器来返回需要的张量数据,可以在大量数据情况下,实现小批量循环迭代式的读取,避免了内存不足问题。

参考文章

python is、==区别;with;gil;python中tuple和list的区别;Python 中的迭代器、生成器、装饰器

1. is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同 == 比较的是两个对象的内容是否相等 2. with语句时用于对try except finally 的优 ...

Python中的迭代器和生成器

本文以实例详解了python的迭代器与生成器,具体如下所示: 1. 迭代器概述: 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后 ...

终于理解Python中的迭代器和生成器了!

迭代器和生成器 目录 迭代器和生成器 可迭代对象和迭代器 基础概念 判断 for循环本质 不想用for循环迭代了,如何使用迭代器? 列表推导式 生成器Generator 概念 如何实现和使用? 生成器 ...

Python中的迭代器、生成器

from collections import Iterable, Iterator 1. 可迭代(iterable)对象 参考官网链接 class I: def __init__(self, v): ...

python中的迭代器和生成器学习笔记总结

生成器就是一个在行为上和迭代器非常类似的对象.   是个对象! 迭代,顾名思意就是不停的代换的意思,迭代是重复反馈过程的活动,其目的通常是为了逼近所需目标或结果.每一次对过程的重复称为一次“迭代”,而 ...

python中的迭代器与生成器

迭代器 迭代器的引入 假如我现在有一个列表l=['a','b','c','d','e'],我想取列表中的内容,那么有几种方式? 1.通过索引取值 ,如了l[0],l[1] 2.通过for循环取值 fo ...

JS中的迭代器和生成器

利用迭代器生成一个遍历方法: let arr1 = [1, 2, 3, 11, 22, 13, 24]; function forOf(arr, callback) { // 找到迭代器函数 let ...

python中迭代器和生成器

l=[1,2,3,4] for n in l: print n 在看上面这段代码的时候,我们没有显式的控制列表的偏移量,就可以自动的遍历了整个列表对象.那么for 语句是怎么来遍历列表l的呢?要回答这 ...

ES6中的迭代器(Iterator)和生成器(Generator)

前面的话 用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素 迭代器的使用可以极大地简 ...

随机推荐

使用RMAN创建复制数据库

我的实验环境: - 源数据库A机: RHEL6.4 + Oracle 11.2.0.4 IP地址:192.168.99.159 db_name=oradb 数据库已正常运行 - 复制数据库B机: RH ...

NETMON& Message Analyzer

NMCap /network * /capture  /file c:\folder\t.chn:1MB NMCap /network * /capture (IPv4.SourceAddress = ...

xcode中的第三方库配置问题总结

xcode中的第三方库配置总结 在导入第三方库的时候,总是会遇到许多的问题.在这里,我记录一下学到的一些知识点.写得比较乱.只要是想要记录下来,在第三方库导入的时候,遇到的一些问题. 参考网址: ht ...

QLockFile,QRunInfo

http://doc.qt.io/qt-5/qlockfile.html http://www.dushibaiyu.com/2014/10/qruninfo-api-smple.html

Android7.0 PowerManagerService 之亮灭屏(一)

本篇从按下power按键后,按键事件从InputManagerService 传到PhoneWindowManager.java开始分析power 按键做屏幕亮灭过程的分析,关于power 按键的其他 ...

Android初级教程进程间的通信AIDL

在介绍跨程序进程间通信AIDL前,先看一下本程序activity与某个服务是怎么绑定在一起进行交互的. 需求:服务有两个方法.分别是播放音乐与停止播放音乐.该程序的活动要访问这两个方法,在activi ...

ioremap_nocache() 函数的使用【转】

本篇文章主要是在ioremap_nocache函数说明的基础上进行整理,加入该函数的用法简介. 函数原型 void __iomem * ioremap_nocache (unsigned long o ...

单纯linux系统下hadoop2.7.3 eclipse,记一次成功的运行wordcount的注意事项

hadoop要正确安装好 hadoop eclipse plugin要对应相应的eclipse版本 define hadoop location mr master:9000 另一个9001  下面的 ...

冲刺NOIP复习,算法知识点总结

前言        离NOIP还有一个星期,匆忙的把整理的算法补充完善,看着当时的整理觉得那时还年少.第二页贴了几张从贴吧里找来的图片,看着就很热血的.当年来学这个竞赛就是为了兴趣,感受计算机之美的. ...

users-and-groups-in-linux

https://www.tecmint.com/compress-files-and-finding-files-in-linux/ https://www.tecmint.com/manage-us ...

dataloader 源码_pytorch :: Dataloader中的迭代器和生成器应用相关推荐

  1. dataloader 源码_带你从零掌握迭代器及构建最简DataLoader

    点蓝色字关注"机器学习算法工程师" 设为星标,干货直达! AI编辑:深度眸 0 摘要 本文本意是写 pytorch 中 DataLoader 源码学习心得,但是发现自己对迭代器和生 ...

  2. 5单个编译总会编译全部_玩转Android10(五)源码编译开发中常用命令

    源码开发编译中,熟练掌握常用命令,可以提高开发工作效率.Android源码中,将相关的命令分为如下几类: 1.初始化源码编译环境 初始化编译环境,为后续提供如lunch.make.xxgrep.god ...

  3. JDK源码解析 Comparator 中的策略模式

    JDK源码解析 Comparator 中的策略模式.在Arrays类中有一个 sort() 方法,如下: public class Arrays{public static <T> voi ...

  4. 阅读react-redux源码(五) - connectAdvanced中store改变的事件转发、ref的处理和pure模式的处理

    阅读react-redux源码 - 零 阅读react-redux源码 - 一 阅读react-redux源码(二) - createConnect.match函数的实现 阅读react-redux源 ...

  5. 深入分析ConcurrentHashMap的源码设计(中)-hash冲突

    深入分析ConcurrentHashMap的源码设计(上) 深入分析ConcurrentHashMap的源码设计(中) 深入分析ConcurrentHashMap的源码设计(下) 一.前言: 本章节, ...

  6. Spring源码 - 从缓存中获取单例Bean

    # Spring源码 - 从缓存中获取单例Bean Spring版本:Spring 5.3.13-release # 1.从缓存中获取单例Bean 单实例Bean在Spring的同一个容器中只会创建一 ...

  7. 一对一视频直播源码实现网络中一对一视频聊天

    一对一视频直播源码实现网络中一对一视频聊天 代码实现步骤 概述 首先要通信那就得满足通信的基础,我选择和目标放通信,前提就是我通过一定的条件将自己和目标建立链接,然后再将自己的通信信息交给目标,目标也 ...

  8. 基于 GoogleMap 离线 API 源码在内网中加载卫星地图的方法

    1. 概述 我们之前为大家分享过在三维地球开源平台离线加载卫星影像的方法,主要包括基于桌面端的OsgEarth开源三维地球和基于Web端的Cesium开源三维地球等平台的局域网离线加载. 另外,也为大 ...

  9. Python3 中打的迭代器与生成器

    迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...

最新文章

  1. SSL证书可以给多个域名使用吗?
  2. GAN(Generative Adversarial Network,GAN)模型之:EBGAN、PGGAN、CGAN、ACGAN模型
  3. 用MacBook对交换机进行初始化配置
  4. Protobuf 安装及 Python、C# 示例
  5. 求职中最吃香的编程语言:JavaScript、Java 和 Python
  6. [转载] 使用backbone.js、zepto.js和trigger.io开发HTML5 App
  7. java正则题_牛客网java编程题整理(不定期更新)
  8. Win7安装VC++6.0已知的兼容性问题的解决方法
  9. Linux系统中添加硬盘,并挂载到已有的目录,比如/home/user
  10. 使用 BenchmarkDotnet 测试代码性能
  11. P1133 教主的花园 (动态规划)
  12. twitter.common.concurrent deadline and defer
  13. Android - get email attachment name in my application
  14. IntelliJ 中类似于Eclipse ctrl+o的是ctrl+F12
  15. C#反编译软件查看dll文件源码
  16. 台式计算机如何上无线网络,台式电脑如何实现无线上网
  17. Python爬取文章和小说内容
  18. RouterOS 重置密码
  19. 转:接班人都是“剩出来”的,选接班人9条必用原则
  20. 2021苹果CMSV10完美对接萝卜影视(原生)蓝色版

热门文章

  1. IBM服务器系统盘更换后检查,IBM服务器更换rootvg故障磁盘操作指南
  2. [云炬创业基础笔记]第五章创业机会评估测试8
  3. 雨中赶班车 2019-12-19
  4. Delphi中拖动无边框窗口的5种方法
  5. 阿拉伯数字转为罗马数字
  6. Java平台无关性——跨平台
  7. struts2采用convention-plugin实现零配置
  8. 【⚡小丑竟然是我自己⚡】安防三年,今天才知道什么是ONVIF
  9. UNIX再学习 -- 网络IPC:套接字
  10. hdu1589(枚举+并查集)