python中有一个非常有用的语法叫做生成器,所利用到的关键字就是yield。有效利用生成器这个工具可以有效地节约系统资源,避免不必要的内存占用。
数据生成器的作用就是 他不需要把所有的值放在内存中,它是实时地生成数据 ;
(这里所谓的生成数据 就是从ROM 当中加载到 RAM 中,并且释放上一次加载的数据)
你经常使用的 for..in ...这种形式的语句,我们称其为迭代器,
(不太理解迭代器,可以看这里)
它可以处理像 列表,字符串,这类可迭代的对象, 你可以如你所愿的读取其中的元素,这确实很方便。
但是 你把所有的值都存储到了内存中,如果你有大量数据的话这个方式并不是你想要的。
在这里,所有的值都存在内存当中,所以并不适合大量数据
例如你用作深度学习的数据集很大, 有100w 张图片, 你不可能把这一百万张图片都加在到内存里, 然后在分成
训练集, 验证集和测试集 , 用与接下来的训练任务, 你的内存肯定扛不住你这么用的。。
众所周知,神经网络在训练的时候每次只接收一个 batch_size 大小的数据,
你把这么多数据加载进来也是没用,因为每次只用其中的一小部分, 所以我们完全可以每次只加载进来这一个batch_size
数量大小的图片, 训练之后再将他们释放掉,重新加载新的一批。
这就引出了python的生成器,
python 通过 yield 函数来定义一个生成器, 也就是说你见到了一个函数, 它的结尾处不是return 而是 yield,
那么, 就可以断言, 这个函数返回的是一个生成器 。 ----> <class 'generator'>
二者的简单定义如下:
# 迭代器
for i in my_data:
img = np.array(i)
return img
# 生成器
for i in my_data:
img = np.array(i)
yield img
# img 是 <class 'generator'>
使用生成器 来执行, 程序仅仅会返回 yield 关键字后面的那个值, 并且是作为生成器返回,这并不占什么内存。
因为他只是一个生成器, 没有什么实质性的内容,
那么什么时候他才能有实质性的内容呢? 也就是什么时候他能够生成数据呢?
是在你调用它的时候, 但是要注意,与 for ... in ...的这种迭代器不同,生成器每次被调用 返回的都是一批数据,
我不是像迭代器那样 只返回一个数值。
实例如下;
mylist = [0, 1, 4]
for i in mylist :
print(i)
# 输出结果
0
1
4
# 这里虽说输出了三个结果,但是这是因为你调用了三次print函数
def creatGenerator():
mylist = [0, 1, 2]
for i in mylist :
yield i*i
mygenerator = creatGenerator()
print(type(mygenerator))
for j in mygenerator:
print(j)
------- output------
0
1
4
<class 'generator'>
可以看出, 生成器返回的(yield 回来的)是一个可迭代对象,(我们使用for.. in ..可以对其进行处理)
并且,我们只调用了一次 creatGenerator() , 他就给我们 yield 回来了三个值,这三个值组成了我们的可迭代对象。
正如上面所叙述的那样, 你调用一次函数 yield 回来的生成器, 就会一次产生一批数据, 并且这批数据是可以进行迭代的
这就与我们训练神经网络的初衷 完美的相吻合。
-----------------------------
前两天, 我见到了一种这样的写法, 大家可以体会下;
imagePaths = sorted(list(paths.list_images(args["dataset"])))
# 给生成器加了list 之后, 就原形毕露了
# 加了list 后,生成器首先要执行生成数据的操作, 然后再将生成的数据装入list
# 在用 sorted来排序,
random.seed(42)
random.shuffle(imagePaths)