Tensorflow 读取机制图解:相关函数及实际代码
1. Tensorflow 读取机制图解
首先要考虑的问题是读取数据是什么?以图像数据为例,读取数据的过程可以用下图来表示: ![]()
假设我们有一组图像数据 0001.jpg, 0002.jpg, 0003.jpg ... 我们只需要读取他们只是将其放入内存中并传递给GPU或CPU进行计算。这听起来很容易,但远非简单。 其实我们需要先读取数据,然后才能进行计算。假设读取需要 0.1 秒,计算需要 0.9 秒,这意味着每 1 秒 GPE 将有 0.1 秒空闲。这大大降低了运行效率。 如何解决这个问题?方法是将读取数据和计算放到两个线程中,将数据读取到内存队列中,如下图所示: ![]()
读取线程不断地将文件系统中的图像读取到内存队列中。 ,另一个线程负责计算。当计算需要数据时,可以直接从内存队列中取出。这样可以解决GPE由于IO而空闲的问题! 在tensorflow中,所谓的“文件名队列”被添加在内存队列之前,以便于管理。
为什么要添加这个文件名队列层?首先,我们需要理解机器学习的概念:时代。对于数据集来说,运行一个纪元意味着计算数据集中的所有图像。例如数据集中有三张图片A.jpg、B.jpg、C.jpg,那么运行一个epoch就意味着计算完所有三张图片A、B、C。运行两个epoch就意味着计算出了A、B、C各一次,然后全部重新计算。这意味着每个图像都会被计算两次。
Tensorflow使用文件名队列+双内存队列来读取文件,可以很好地管理epoch。下面我们用图像来说明这个机制是如何工作的。如下图所示,以数据集A.jpg、B.jpg、C.jpg为例。假设我们要运行一个纪元,那么我们将A、B和C放入文件名队列中一次,然后笔记队列结束。 ![]()
程序启动后,内存队列首先读取A(此时A已从文件名队列中移除): ![]()
然后依次读取B和C: ![]()
![]()
此时,如果你尝试再次读取,系统由于检测到“结束”,会自动抛出异常(OutOfRange)。在外部捕获到该异常后,程序就可以终止。这是张量流中读取数据的基本机制。如果我们想运行 2 个 epoch,而不是 1 个 epoch,那么我们只需要将 A、B 和 C 在一行文件名中排队两次并标记结束即可。
2。 Tensorflow数据读取器对应功能
如何在tensorflow中创建上述两个队列?
我们使用 tf.train.string_input_ Producer 函数对文件名进行排队。该函数必须传递一个文件名列表,系统会自动将其转换为文件名队列。
另外,tf.train.string_input_ Producer还有两个重要的参数。一个是num_epochs,也就是我们上面提到的epoch的数量。第二个是洗牌。 Shuffle是指一个epoch内文件的顺序是否打乱。如果设置了 shuffle=False ,如下所示,在每个 epoch 中,数据仍然按照 A、B、C 的顺序进入文件名队列。这个顺序不会改变: ![]()
如果设置了 shuffle=True ,那么在一个epoch,数据顺序就会乱,如下图: ![]()
在tensorflow中,内存队列不需要自己建立。我们只需要使用读取器对象从文件名队列中读取数据。特殊实现 下面你可以看到实际的代码。
除了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 函数。![]()
3。实用代码
我们用一个特殊的例子来感受一下tensorflow中读取数据的体验。如图所示,假设当前文件夹下已有三张图片A.jpg、B.jpg、C.jpg。我们希望读取这三张图像 5 个 epoch,并将读取结果再次保存到读取文件夹中。中间。 ![]()
对应的代码如下:
# 导入tensorflow
import tensorflow as tf
# 新建一个Session
with tf.Session() as sess:
# 我们要读三幅图片A.jpg, B.jpg, C.jpg
filename = ['A.jpg', 'B.jpg', 'C.jpg']
# string_input_producer会产生一个文件名队列
filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)
# reader从文件名队列中读数据。对应的方法是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)
i = 0
while True:
i += 1
# 获取图片数据并保存
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 的文件名队列。并使用阅读器进行阅读,阅读器一次读取一张图像并保存。
运行代码后,我们可以在 read 文件夹中看到按顺序正好是 5 个 epoch 的图像: ![]()
如果我们设置 filename_queue = tf.train.string_input_ Producer(filename, shuffle=False, num_epochs = shuffle= True 和5) ,那么图像会在每个 epoch 中进行打乱,如图所示: ![]()
例如,我们只使用三张图像。在实际应用中,数据集必须包含3张以上的图像。 ,但所涉及的原则是通用的。
4.总结
本文主要通过图文并茂的方式介绍详细数据读取的张量流机制。最后还提供了相关的实用代码。希望能给大家学习tensorflow带来一些有意义的帮助。 。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网