TensorFlow数据读取机制

一、TensorFlow读取机制图解

首先需要知道,什么是数据读取?以图像数据为例,读取数据的过程可以用以下图来表示:

假设我们的硬盘中有一个图片数据集合0001.jpg,0002.jpg,0003.jpg……,我们只需要把他们读取到内存中,然后提供给GPU或者是CPU进行计算就可以了。事实上,我们必须先吧数据读取之后才能计算,这就大大降低了运算的效率。 

如何解决这个问题?方法就是将读取数据和计算分别放在两个线程中,将数据读入内存的一个队列,如下图所示:

读取线程源源不断的将文件系统中的图片读取到一个内存序列中,而负责计算的是另一个线程,计算需要数据时,直接从内存队列中取就可以了。这样就可以解决GPU因为IO而空闲的问题。

而在TensorFlow中,为了方便管理,在内存队列前又添加了一层所谓的”文件名队列“。

为什么要添加这一层文件名队列?我们首先了解机器学习中的一个概念,epoch。对于一个数据集来讲,运行一个epoch就是将这个数据集中的图片全部计算一遍。如一个数据集中有三张图片A.jpg、B.jpg、C.jpg,那么跑一个epoch就是指A、B、C三张图片都计算了一遍。两个epoch就是指先对A、B、C各计算一遍,然后再全部计算一遍,也就是说每张图片都计算了两遍。

TensorFlow使用文件名+内存队列的形式读入文件,可以很好的管理epoch。下面我们用图片的形式来说名这个机制的运行方式。如下图,还是以数据集A.jpg、B.jpg、C.jpg为例,假定我们要跑一个epoch,那么我们就在文件名队列中把A、B、C各放入一次,并在之后标注队列结束。

程序运行后,内存队列首先读入A(此时A从文件名队列中出队):

 

再依次读入B和C:

此时,如果再尝试读入,系统由于检测到了“结束”,就会自动抛出一个异常(OutOfRange)。外部捕捉到这个异常后就可以结束程序了。这就是TensorFlow中读取数据的基本机制。如果我们要跑2个epoch而不是1个epoch,那只要在文件名队列中将A、B、C依次放入两次再标记结束就可以了。

二、TensorFlow读取数据机制的对应函数

如何在TensorFlow中创建上述的两个队列呢?

tf.train.string_input_producer(file_list,num_epochs,shuffle)

 

对于文件名队列,我们使用tf.train.string_input_producer函数。这个函数需要传入一个文件名list,系统会自动将它转为一个文件名队列。此外tf.train.string_input_producer还有两个重要的参数,一个是num_epochs,它就是我们上文中提到的epoch数。另外一个就是shuffle,shuffle是指在一个epoch内文件的顺序是否被打乱。若设置shuffle=False,如下图,每个epoch内,数据还是按照A、B、C的顺序进入文件名队列,这个顺序不会改变:

如果设置shuffle=True,那么在一个epoch内,数据的前后顺序就会被打乱,如下图所示:

在TensorFlow中,内存队列不需要我们自己建立,我们只需要使用reader对象从文件名队列中读取数据就可以了。

除了tf.train.string_input_producer外,我们还要额外介绍一个函数:tf.train.start_queue_runners()

在我们使用tf.train.string_input_producer创建文件名队列后,整个系统其实还是处于“停滞状态”的,也就是说,我们文件名并没有真正被加入到队列中(如下图所示)。此时如果我们开始计算,因为内存队列中什么也没有,计算单元就会一直等待,导致整个系统被阻塞。

 

而使用tf.train.start_queue_runners之后,才会启动填充队列的线程,这时系统就不再“停滞”。此后计算单元就可以拿到数据并进行计算,整个程序也就跑起来了,这就是函数tf.train.start_queue_runners的用处。

三、实战代码

我们用一个具体的例子感受TensorFlow中的数据读取。如图,假设我们在当前文件夹中已经有A.jpg、B.jpg、C.jpg三张图片,我们希望读取这三张图片5个epoch并且把读取的结果重新存到read文件夹中。

import tensorflow as tf #导入TensorFlow
with tf.Session() as sess: #新建一个会话
filename=['A.jpg', 'B.jpg', 'C.jpg'] #创建一个文件列表
filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)  # string_input_producer会产生一个文件名队列


#从文件名队列中读取数据。对应的方法是reader.read
reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)


# tf.train.string_input_producer定义了一个epoch变量,要对它进行初始化
tf.local_variables_initializer().run()


# 使用start_queue_runners之后,才会开始填充队列
threads = tf.train.start_queue_runners(sess=sess)

# 获取图片数据并保存
image_data = sess.run(value)
with open('read/test_%d.jpg' % i, 'wb') as f:
f.write(image_data)

我们这里使用filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)建立了一个会跑5个epoch的文件名队列。并使用reader读取,reader每次读取一张图片并保存。

 

 

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值