用十张图详解TensorFlow数据读取机制(附代码)


Posted in Python onFebruary 06, 2018

在学习TensorFlow的过程中,有很多小伙伴反映读取数据这一块很难理解。确实这一块官方的教程比较简略,网上也找不到什么合适的学习材料。今天这篇文章就以图片的形式,用最简单的语言,为大家详细解释一下TensorFlow的数据读取机制,文章的最后还会给出实战代码以供参考。

TensorFlow读取机制图解

首先需要思考的一个问题是,什么是数据读取?以图像数据为例,读取数据的过程可以用下图来表示:

用十张图详解TensorFlow数据读取机制(附代码)

假设我们的硬盘中有一个图片数据集0001.jpg,0002.jpg,0003.jpg……我们只需要把它们读取到内存中,然后提供给GPU或是CPU进行计算就可以了。这听起来很容易,但事实远没有那么简单。事实上,我们必须要把数据先读入后才能进行计算,假设读入用时0.1s,计算用时0.9s,那么就意味着每过1s,GPU都会有0.1s无事可做,这就大大降低了运算的效率。

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

用十张图详解TensorFlow数据读取机制(附代码)

读取线程源源不断地将文件系统中的图片读入到一个内存的队列中,而负责计算的是另一个线程,计算需要数据时,直接从内存队列中取就可以了。这样就可以解决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各放入一次,并在之后标注队列结束。

用十张图详解TensorFlow数据读取机制(附代码)

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

用十张图详解TensorFlow数据读取机制(附代码)

再依次读入B和C:

用十张图详解TensorFlow数据读取机制(附代码)

用十张图详解TensorFlow数据读取机制(附代码)

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

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

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

对于文件名队列,我们使用tf.train.string_input_producer函数。这个函数需要传入一个文件名list,系统会自动将它转为一个文件名队列。

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

用十张图详解TensorFlow数据读取机制(附代码)

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

用十张图详解TensorFlow数据读取机制(附代码)

在TensorFlow中,内存队列不需要我们自己建立,我们只需要使用reader对象从文件名队列中读取数据就可以了,具体实现可以参考下面的实战代码。

除了tf.train.string_input_producer外,我们还要额外介绍一个函数:tf.train.start_queue_runners。初学者会经常在代码中看到这个函数,但往往很难理解它的用处,在这里,有了上面的铺垫后,我们就可以解释这个函数的作用了。

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

用十张图详解TensorFlow数据读取机制(附代码)

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

用十张图详解TensorFlow数据读取机制(附代码)

实战代码

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

用十张图详解TensorFlow数据读取机制(附代码)

对应的代码如下:

# 导入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的文件名队列。并使用reader读取,reader每次读取一张图片并保存。

运行代码后,我们得到就可以看到read文件夹中的图片,正好是按顺序的5个epoch:

用十张图详解TensorFlow数据读取机制(附代码)

如果我们设置filename_queue = tf.train.string_input_producer(filename, shuffle=False, num_epochs=5)中的shuffle=True,那么在每个epoch内图像就会被打乱,如图所示:

用十张图详解TensorFlow数据读取机制(附代码)

我们这里只是用三张图片举例,实际应用中一个数据集肯定不止3张图片,不过涉及到的原理都是共通的。

实例:tensorflow读取图片的方法

下面讲解tensorflow如何读取jpg格式的图片,png格式的图片是一样的。有两种情况:

第一种就是把图片看做是一个图片直接读进来,获取图片的原始数据,再进行解码,主要用到的函数就是tf.gfile.FastGFile,tf.image.decode_jpeg

例如:

import tensorflow as tf;  
image_raw_data = tf.gfile.FastGFile('/home/penglu/Desktop/11.jpg').read() 
image = tf.image.decode_jpeg(image_raw_data) #图片解码 
print image.eval(session=tf.Session())

输出:

[[[ 11  63 110]
  [ 14  66 113]
  [ 17  69 116]
  ...,

第二种方式就是把图片看看成一个文件,用队列的方式读取

例如:

import tensorflow as tf;   
path = '/home/penglu/Desktop/11.jpg' 
file_queue = tf.train.string_input_producer([path]) #创建输入队列 
image_reader = tf.WholeFileReader() 
_, image = image_reader.read(file_queue) 
image = tf.image.decode_jpeg(image) 
 
with tf.Session() as sess: 
  coord = tf.train.Coordinator() #协同启动的线程 
  threads = tf.train.start_queue_runners(sess=sess, coord=coord) #启动线程运行队列 
  print sess.run(image) 
  coord.request_stop() #停止所有的线程 
  coord.join(threads)

输出:

[[[ 11  63 110]
  [ 14  66 113]
  [ 17  69 116]
  ...,

总结

这篇文章主要用图解的方式详细介绍了TensorFlow读取数据的机制,最后还给出了对应的实战代码,希望能够给大家学习TensorFlow带来一些实质性的帮助。也希望大家多多支持三水点靠木。

Python 相关文章推荐
pygame实现弹力球及其变速效果
Jul 03 Python
Python使用当前时间、随机数产生一个唯一数字的方法
Sep 18 Python
pandas string转dataframe的方法
Apr 11 Python
Python图像处理之简单画板实现方法示例
Aug 30 Python
浅谈python下tiff图像的读取和保存方法
Dec 04 Python
神经网络相关之基础概念的讲解
Dec 29 Python
Django REST framework内置路由用法
Jul 26 Python
tensorflow 实现数据类型转换
Feb 17 Python
Python脚本调试工具安装过程
Jan 11 Python
python解包概念及实例
Feb 17 Python
python利用opencv实现颜色检测
Feb 23 Python
pytorch MSELoss计算平均的实现方法
May 12 Python
Python实现matplotlib显示中文的方法详解
Feb 06 #Python
Python实现自动上京东抢手机
Feb 06 #Python
Python获取指定文件夹下的文件名的方法
Feb 06 #Python
TensorFlow如何实现反向传播
Feb 06 #Python
tensorflow TFRecords文件的生成和读取的方法
Feb 06 #Python
TensorFlow实现创建分类器
Feb 06 #Python
Python模拟随机游走图形效果示例
Feb 06 #Python
You might like
php图片裁剪函数
2018/10/31 PHP
JavaScript获取FCK编辑器信息的具体方法
2013/07/12 Javascript
Document:getElementsByName()使用方法及示例
2013/10/28 Javascript
JS实现关闭当前页而不弹出提示框的方法
2016/06/22 Javascript
JS跨域交互(jQuery+php)之jsonp使用心得
2016/07/01 Javascript
AngularJs ng-route路由详解及实例代码
2016/09/14 Javascript
谈谈第三方App接入微信登录 解读
2016/12/27 Javascript
JavaScript中的 attribute 和 jQuery中的 attr 方法浅析
2017/01/04 Javascript
详解vue-Resource(与后端数据交互)
2017/01/16 Javascript
Javascript 链式作用域详细介绍
2017/02/23 Javascript
走进javascript——不起眼的基础,值和分号
2017/02/24 Javascript
angularjs项目的页面跳转如何实现(5种方法)
2017/05/25 Javascript
jQuery导航条固定定位效果实例代码
2017/05/26 jQuery
Angularjs 1.3 中的$parse实例代码
2017/09/14 Javascript
vue中如何动态绑定图片,vue中通过data返回图片路径的方法
2018/02/07 Javascript
JavaScript字符串转数字的5种方法及遇到的坑
2018/07/16 Javascript
jQuery实现的3D版图片轮播示例【滑动轮播】
2019/01/18 jQuery
如何利用ES6进行Promise封装总结
2019/02/11 Javascript
使用easyui从servlet传递json数据到前端页面的两种方法
2019/09/05 Javascript
Vue elementui字体图标显示问题解决方案
2020/08/18 Javascript
[06:45]2018DOTA2亚洲邀请赛 4.5 SOLO赛 Sccc vs Maybe
2018/04/06 DOTA
Python获取apk文件URL地址实例
2013/11/01 Python
Python实现随机生成有效手机号码及身份证功能示例
2017/06/05 Python
在Python中实现替换字符串中的子串的示例
2018/10/31 Python
Python实现的插入排序,冒泡排序,快速排序,选择排序算法示例
2019/05/04 Python
python multiprocessing多进程变量共享与加锁的实现
2019/10/02 Python
使用python和pygame制作挡板弹球游戏
2019/12/03 Python
VSCode基础使用与VSCode调试python程序入门的图文教程
2020/03/30 Python
Python Tkinter实例——模拟掷骰子
2020/10/24 Python
AVON雅芳官网:世界上最大的美容化妆品公司之一
2016/11/02 全球购物
党员评议表自我评价范文
2014/10/20 职场文书
党员民主评议自我评价
2014/10/20 职场文书
个人欠款协议书范本2014
2014/11/02 职场文书
毕业设计指导教师评语
2014/12/30 职场文书
第一书记观后感
2015/06/08 职场文书
Nginx实现负载均衡的项目实践
2022/03/18 Servers