理解TensorFlow的Queue
https://www.jianshu.com/p/d063804fb272
这篇文章来说说TensorFlow里与Queue有关的概念和用法。
其实概念只有三个:
Queue
是TF队列和缓存机制的实现QueueRunner
是TF中对操作Queue的线程的封装Coordinator
是TF中用来协调线程运行的工具
虽然它们经常同时出现,但这三样东西在TensorFlow里面是可以单独使用的,不妨先分开来看待。
1. Queue
根据实现的方式不同,分成具体的几种类型,例如:
- tf.FIFOQueue 按入列顺序出列的队列
- tf.RandomShuffleQueue 随机顺序出列的队列
- tf.PaddingFIFOQueue 以固定长度批量出列的队列
- tf.PriorityQueue 带优先级出列的队列
- ... ...
这些类型的Queue除了自身的性质不太一样外,创建、使用的方法基本是相同的。
创建函数的参数:
tf.FIFOQueue(capacity, dtypes, shapes=None, names=None ...)
Queue主要包含入列(enqueue)和出列(dequeue)两个操作。enqueue操作返回计算图中的一个Operation节点,dequeue操作返回一个Tensor值。Tensor在创建时同样只是一个定义(或称为“声明”),需要放在Session中运行才能获得真正的数值。下面是一个单独使用Queue的例子:
import tensorflow as tf
tf.InteractiveSession()
q = tf.FIFOQueue(2, "float")
init = q.enqueue_many(([0,0],))
x = q.dequeue()
y = x+1
q_inc = q.enqueue([y])
init.run()
q_inc.run()
q_inc.run()
q_inc.run()
x.eval() # 返回1
x.eval() # 返回2
x.eval() # 卡住
注意,如果一次性入列超过Queue Size的数据,enqueue操作会卡住,直到有数据(被其他线程)从队列取出。对一个已经取空的队列使用dequeue操作也会卡住,直到有新的数据(从其他线程)写入。
2. QueueRunner
Tensorflow的计算主要在使用CPU/GPU和内存,而数据读取涉及磁盘操作,速度远低于前者操作。因此通常会使用多个线程读取数据,然后使用一个线程消费数据。QueueRunner就是来管理这些读写队列的线程的。
QueueRunner需要与Queue一起使用(这名字已经注定了它和Queue脱不开干系),但并不一定必须使用Coordinator。看下面这个例子:
import tensorflow as tf
import sys
q = tf.FIFOQueue(10, "float")
counter = tf.Variable(0.0) #计数器
# 给计数器加一
increment_op = tf.assign_add(counter, 1.0)
# 将计数器加入队列
enqueue_op = q.enqueue(counter)
# 创建QueueRunner
# 用多个线程向队列添加数据
# 这里实际创建了4个线程,两个增加计数,两个执行入队
qr = tf.train.QueueRunner(q, enqueue_ops=[increment_op, enqueue_op] * 2)
# 主线程
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
# 启动入队线程
qr.create_threads(sess, start=True)
for i in range(20):
print (sess.run(q.dequeue()))
增加计数的进程会不停的后台运行,执行入队的进程会先执行10次(因为队列长度只有10),然后主线程开始消费数据,当一部分数据消费被后,入队的进程又会开始执行。最终主线程消费完20个数据后停止,但其他线程继续运行,程序不会结束。
3. Coordinator
Coordinator是个用来保存线程组运行状态的协调器对象,它和TensorFlow的Queue没有必然关系,是可以单独和Python线程使用的。例如:
import tensorflow as tf
import threading, time
# 子线程函数
def loop(coord, id):
t = 0
while not coord.should_stop():
print(id)
time.sleep(1)
t += 1
# 只有1号线程调用request_stop方法
if (t >= 2 and id == 1):
coord.request_stop()
# 主线程
coord = tf.train.Coordinator()
# 使用Python API创建10个线程
threads = [threading.Thread(target=loop, args=(coord, i)) for i in range(10)]
# 启动所有线程,并等待线程结束
for t in threads: t.start()
coord.join(threads)
将这个程序运行起来,会发现所有的子线程执行完两个周期后都会停止,主线程会等待所有子线程都停止后结束,从而使整个程序结束。由此可见,只要有任何一个线程调用了Coordinator的request_stop
方法,所有的线程都可以通过should_stop
方法感知并停止当前线程。
将QueueRunner和Coordinator一起使用,实际上就是封装了这个判断操作,从而使任何一个现成出现异常时,能够正常结束整个程序,同时主线程也可以直接调用request_stop
方法来停止所有子线程的执行。
4. 在一起
在TensorFlow中用Queue的经典模式有两种,都是配合了QueueRunner和Coordinator一起使用的。
第一种,显式的创建QueueRunner,然后调用它的create_threads
方法启动线程。例如下面这段代码:
import tensorflow as tf
# 1000个4维输入向量,每个数取值为1-10之间的随机数
data = 10 * np.random.randn(1000, 4) + 1
# 1000个随机的目标值,值为0或1
target = np.random.randint(0, 2, size=1000)
# 创建Queue,队列中每一项包含一个输入数据和相应的目标值
queue = tf.FIFOQueue(capacity=50, dtypes=[tf.float32, tf.int32], shapes=[[4], []])
# 批量入列数据(这是一个Operation)
enqueue_op = queue.enqueue_many([data, target])
# 出列数据(这是一个Tensor定义)
data_sample, label_sample = queue.dequeue()
# 创建包含4个线程的QueueRunner
qr = tf.train.QueueRunner(queue, [enqueue_op] * 4)
with tf.Session() as sess:
# 创建Coordinator
coord = tf.train.Coordinator()
# 启动QueueRunner管理的线程
enqueue_threads = qr.create_threads(sess, coord=coord, start=True)
# 主线程,消费100个数据
for step in range(100):
if coord.should_stop():
break
data_batch, label_batch = sess.run([data_sample, label_sample])
# 主线程计算完成,停止所有采集数据的进程
coord.request_stop()
coord.join(enqueue_threads)
第二种,使用全局的start_queue_runners
方法启动线程。
import tensorflow as tf
# 同时打开多个文件,显示创建Queue,同时隐含了QueueRunner的创建
filename_queue = tf.train.string_input_producer(["data1.csv","data2.csv"])
reader = tf.TextLineReader(skip_header_lines=1)
# Tensorflow的Reader对象可以直接接受一个Queue作为输入
key, value = reader.read(filename_queue)
with tf.Session() as sess:
coord = tf.train.Coordinator()
# 启动计算图中所有的队列线程
threads = tf.train.start_queue_runners(coord=coord)
# 主线程,消费100个数据
for _ in range(100):
features, labels = sess.run([data_batch, label_batch])
# 主线程计算完成,停止所有采集数据的进程
coord.request_stop()
coord.join(threads)
在这个例子中,tf.train.string_input_produecer
会将一个隐含的QueueRunner添加到全局图中(类似的操作还有tf.train.shuffle_batch
等)。
由于没有显式地返回QueueRunner来用create_threads启动线程,这里使用了tf.train.start_queue_runners
方法直接启动tf.GraphKeys.QUEUE_RUNNERS
集合中的所有队列线程。
这两种方式在效果上是等效的。
参考文章
作者:巾梵
链接:https://www.jianshu.com/p/d063804fb272
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
理解TensorFlow的Queue的更多相关文章
- python-积卷神经网络全面理解-tensorflow实现手写数字识别
首先,关于神经网络,其实是一个结合很多知识点的一个算法,关于cnn(积卷神经网络)大家需要了解: 下面给出我之前总结的这两个知识点(基于吴恩达的机器学习) 代价函数: 代价函数 代价函数(Cost F ...
- 理解数据结构Priority Queue
我们知道Queue是遵循先进先出(First-In-First-Out)模式的,但有些时候需要在Queue中基于优先级处理对象.举个例子,比方说我们有一个每日交易时段生成股票报告的应用程序,需要处理大 ...
- 4.3CNN卷积神经网络最详细最容易理解--tensorflow源码MLP对比
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1.1 CNN卷积神经网络 ...
- Tensorflow的Queue读取数据机制
参考链接:http://www.sohu.com/a/148245200_115128
- Tensorflow编程基础之Mnist手写识别实验+关于cross_entropy的理解
好久没有静下心来写点东西了,最近好像又回到了高中时候的状态,休息不好,无法全心学习,恶性循环,现在终于调整的好一点了,听着纯音乐突然非常伤感,那些曾经快乐的大学时光啊,突然又慢慢的一下子出现在了眼前, ...
- TensorFlow中的通信机制——Rendezvous(二)gRPC传输
背景 [作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] 本篇是TensorFlow通信机制系列的第二篇文章,主要梳理使用gRPC网络传 ...
- TensorFlow中的通信机制——Rendezvous(一)本地传输
背景 [作者:DeepLearningStack,阿里巴巴算法工程师,开源TensorFlow Contributor] 在TensorFlow源码中我们经常能看到一个奇怪的词——Rendezvous ...
- 第十二节,TensorFlow读取数据的几种方法以及队列的使用
TensorFlow程序读取数据一共有3种方法: 供给数据(Feeding): 在TensorFlow程序运行的每一步, 让Python代码来供给数据. 从文件读取数据: 在TensorFlow图的起 ...
- 21个项目玩转深度学习:基于TensorFlow的实践详解02—CIFAR10图像识别
cifar10数据集 CIFAR-10 是由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集.一共包含 10 个类别的 ...
随机推荐
- JavaScript基础之运算符及全面的运算符优先级总结
算数运算符: 加+,减—,乘*,除/,求余%,加加++,减减——, 加减乘除求余运算与数学上的用法完全一样. 不过,加号+还有连接字符串的作用,其他运算符还可以将字符串数字转换成数值型,参见JavaS ...
- MHDD硬盘坏道检测修复教程(转)
MHDD算是在DOS下比较专业的检测工具,比一些GUI的好用很多,并且现在有人专门做成硬件机器卖到了电脑城,电脑城一般倒卖硬盘的都使用这种机器. 进入MHDD 上面图片中就可以看到硬盘是ST34081 ...
- [转]Twemproxy 介绍与使用
Twemproxy是一种代理分片机制,由Twitter开源.Twemproxy作为代理,可接受来自多个程序的访问,按照路由规则,转发给后台的各个Redis服务器,再原路返回.该方案很好的解决了单个Re ...
- mysql slave 主从 指定表 通配符
slave配置 slave端有可能,只复制部分表,有一些表不需要备份配置如下: 有一些表你可能做水平或则垂直的处理.如果表的前几位一样,就可以用通配符%匹配 replicate-wild-ignore ...
- 一共81个,开源大数据处理工具汇总(下),包括日志收集系统/集群管理/RPC等
作者:大数据女神-诺蓝(微信公号:dashujunvshen).本文是36大数据专稿,转载必须标明来源36大数据. 接上一部分:一共81个,开源大数据处理工具汇总(上),第二部分主要收集整理的内容主要 ...
- python测试开发django-43.session机制(登录/注销)
前言 当我们登录访问一个网站时,服务器需要识别到你已经登录了,才有相应的权限访问登录之后的页面.用户退出登录后,将无权限访问再访问登录后的页面. 从登录到退出的一整个流程,可以看成是与服务器的一次会话 ...
- 大并发下TCP内存消耗优化小记(86万并发业务正常服务)
转自:http://blog.csdn.net/u010954257/article/details/54178160 最近在做一个大并发服务的测试(目前测到86万,当然有大量长连接,每天打的日志高到 ...
- 平台升级至spring 4.3.0 运行稳定
deprecated velocity 部份方法 整理中...
- ios成长之每日一遍(day 7)
今天到UITabBarController 结合 UIPickView, 这里一共有5个实现, 由浅到易. 其实在IB上面使用UITabBarController很简单, 就像平常拖控件一样拖到界面上 ...
- Linux Shell 裡一些很少用到卻很有用的指令
Linux Shell 裡一些很少用到卻很有用的指令 2009年11月30日 13:53:00 yaoyasong 阅读数:414 Linux Shell 裡一些很少用到卻很有用的指令 你是不是已 ...