在使用TensorFlow进行异步计算时,队列是一种强大的机制。

为了感受一下队列,让我们来看一个简单的例子。我们先创建一个“先入先出”的队列(FIFOQueue),并将其内部所有元素初始化为某些值。然后,我们构建一个TensorFlow图,它从队列前端取走一个元素,加上1之后,放回队列的后端。慢慢地,队列的元素的值就会增加。

TensorFlow提供了两个类来帮助多线程的实现:tf.Coordinator和 tf.QueueRunner。Coordinator类可以用来同时停止多个工作线程并且向那个在等待所有工作线程终止的程序报告异常,QueueRunner类用来协调多个工作线程同时将多个张量推入同一个队列中。

Tensorflow队列

队列,如FIFOQueue(先进先出队列,按顺序出队列)和RandomShuffleQueue(随机出队列),在TensorFlow的张量异步计算时都非常重要。

FIFOQueue(capacity, dtypes, name='fifo_queue'):创建一个以先进先出的顺序对元素进行排队的队列

  • capacity:整数。可能存储在此队列中的元素数量的上限
  • dtypes:DType对象列表。长度dtypes必须等于每个队列元素中的张量数,dtype的类型形状,决定了后面进队列元素形状
  • 方法
    • dequeue(name=None)
    • enqueue(vals, name=None):
    • enqueue_many(vals, name=None):vals列表或者元组,返回一个进队列操作
    • size(name=None)

同步执行队列

完成一个出队列、+1、入队列操作(同步操作):

import tensorflow as tf

# 同步操作,如队列,+1,出队列

# 创建一个队列
Q = tf.FIFOQueue(3, dtypes=tf.float32) # 数据进队列
init_q = Q.enqueue_many([[1.0, 2.0, 3.0], ]) # 定义操作
de_q = Q.dequeue()
data = de_q + 1
en_q = Q.enqueue(data) with tf.Session() as sess: # 初始化队列
sess.run(init_q) # 执行10次 +1 操作
for i in range(10):
sess.run(en_q) # 取出数据
for i in range(Q.size().eval()):
print(Q.dequeue().eval())

输出:

5.0
6.0
5.0

当数据量很大时,入队操作从硬盘中读取数据,放入内存中,主线程需要等待入队操作完成,才能进行训练。会话里可以运行多个线程,实现异步读取。

队列管理器

QueueRunner类会创建一组线程, 这些线程可以重复的执行Enquene操作, 他们使用同一个Coordinator来处理线程同步终止。此外,一个QueueRunner会运行一个closer thread,当Coordinator收到异常报告时,这个closer thread会自动关闭队列。

您可以使用一个queue runner,来实现上述结构。 首先建立一个TensorFlow图表,这个图表使用队列来输入样本。增加处理样本并将样本推入队列中的操作。增加training操作来移除队列中的样本。

tf.train.QueueRunner(queue, enqueue_ops=None):创建一个QueueRunner

  • queue:A Queue
  • enqueue_ops:添加线程的队列操作列表,[]*2,指定两个线程
  • 方法
    • create_threads(sess, coord=None,start=False):创建线程来运行给定会话的入队操作

      • start:布尔值,如果True启动线程;如果为False调用者必须调用start()启动线程
      • coord:线程协调器,后面线程管理需要用到

异步执行队列

通过队列管理器来实现变量加1,入队,主线程出队列的操作(异步操作):

# 异步操作,变量+1,入队,出队列
Q = tf.FIFOQueue(100, dtypes=tf.float32) # 要做的事情
var = tf.Variable(0.0)
data = tf.assign_add(var, 1)
en_q = Q.enqueue(data) # 队列管理器op
qr = tf.train.QueueRunner(Q, enqueue_ops=[en_q] * 5) # 变量初始化op
init_op = tf.global_variables_initializer() with tf.Session() as sess:
# 初始化变量
sess.run(init_op) # 开始子线程
threads = qr.create_threads(sess, start=True) # 主线程读取数据
for i in range(50):
print(sess.run(Q.dequeue()))

分析:这时候有一个问题就是,入队自顾自的去执行,在需要的出队操作完成之后,程序没法结束。需要一个实现线程间的同步,终止其他线程。程序执行完成报如下的错误:

tensorflow.python.framework.errors_impl.CancelledError: Enqueue operation was cancelled
[[{{node fifo_queue_enqueue}}]]

线程协调器

tf.train.Coordinator():线程协调员,实现一个简单的机制来协调一组线程的终止

  • should_stop():如果线程应该停止则返回True。
  • request_stop(): 请求该线程停止。
  • join():等待被指定的线程终止。

首先创建一个Coordinator对象,然后建立一些使用Coordinator对象的线程。这些线程通常一直循环运行,一直到should_stop()返回True时停止。 任何线程都可以决定计算什么时候应该停止。它只需要调用request_stop(),同时其他线程的should_stop()将会返回True,然后都停下来。

加入线程协调器的程序:

# 异步操作,变量+1,入队,出队列
Q = tf.FIFOQueue(100, dtypes=tf.float32) # 要做的事情
var = tf.Variable(0.0)
data = tf.assign_add(var, 1)
en_q = Q.enqueue(data) # 队列管理器op
qr = tf.train.QueueRunner(Q, enqueue_ops=[en_q] * 5) # 变量初始化op
init_op = tf.global_variables_initializer() with tf.Session() as sess:
# 初始化变量
sess.run(init_op) # 开启线程协调器
coord = tf.train.Coordinator() # 开始子线程
threads = qr.create_threads(sess, coord=coord, start=True) # 主线程读取数据
for i in range(50):
print(sess.run(Q.dequeue())) # 请求停止线程
coord.request_stop() coord.join()

【学习笔记】tensorflow队列和线程的更多相关文章

  1. Android(java)学习笔记267:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  2. Android(java)学习笔记211:Android线程池形态

    1. 线程池简介  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.     假设一个服务器完成一项任务所需时间为:T1 创建线程时间, ...

  3. 并发编程学习笔记(14)----ThreadPoolExecutor(线程池)的使用及原理

    1. 概述 1.1 什么是线程池 与jdbc连接池类似,在创建线程池或销毁线程时,会消耗大量的系统资源,因此在java中提出了线程池的概念,预先创建好固定数量的线程,当有任务需要线程去执行时,不用再去 ...

  4. JavaSE学习笔记(12)---线程

    JavaSE学习笔记(12)---线程 多线程 并发与并行 并发:指两个或多个事件在同一个时间段内发生. 并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...

  5. 转:学习笔记: Delphi之线程类TThread

    学习笔记: Delphi之线程类TThread - 5207 - 博客园http://www.cnblogs.com/5207/p/4426074.html 新的公司接手的第一份工作就是一个多线程计算 ...

  6. JavaSE学习笔记(13)---线程池、Lambda表达式

    JavaSE学习笔记(13)---线程池.Lambda表达式 1.等待唤醒机制 线程间通信 概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同. 比如:线程A用来生成包子的,线程B用 ...

  7. 操作系统学习笔记5 | 用户级线程 && 内核级线程

    在上一部分中,我们了解到操作系统实现多进程图像需要组织.切换.考虑进程之间的影响,组织就是用PCB的队列实现,用到了一些简单的数据结构知识.而本部分重点就是进程之间的切换. 参考资料: 课程:哈工大操 ...

  8. Java多线程高并发学习笔记——阻塞队列

    在探讨可重入锁之后,接下来学习阻塞队列,这边篇文章也是断断续续的写了很久,因为最近开始学ssm框架,准备做一个自己的小网站,后续可能更新自己写网站的技术分享. 请尊重作者劳动成果,转载请标明原文链接: ...

  9. Android-Universal-Image-Loader 学习笔记(五)线程池分析

    UniveralImageLoader中的线程池            一般情况网络访问就需要App创建一个线程来执行(不然可能出现很臭的ANR),但是这也导致了当网络访问比较多的情况下,线程的数目可 ...

随机推荐

  1. 文件上传控件bootstrap-fileinput的使用

    1.插件下载地址:https://github.com/kartik-v/bootstrap-fileinput 2.插件的引用 需要引用jquery 需要结合bootstrap使用,即页面需要引入b ...

  2. mysql根据查询结果批量更新多条数据(插入或更新)

    mysql根据查询结果批量更新多条数据(插入或更新) 1.1 前言 mysql根据查询结果执行批量更新或插入时经常会遇到1093的错误问题.基本上批量插入或新增都会涉及到子查询,mysql是建议不要对 ...

  3. request.getRequestDispatcher跳转jsp页面失败

    我在JS里面写了个Ajax,传值给控制器,然后利用request.getRequestDispatcher(),打算跳转至另外一个页面.但是没有跳转成功,运行之后没反应. 在网上搜了资料发现,利用aj ...

  4. emWin酿造机过程演示,含uCOS-III和FreeRTOS两个版本

    第2期:酿造机过程演示 配套例子:V6-902_STemWin提高篇实验_酿造机过程演示(uCOS-III)V6-903_STemWin提高篇实验_酿造机过程演示(FreeRTOS) 例程下载地址:h ...

  5. 最小可用id

    题目:在非负数组(乱序)中找到最小的可分配的id(从1开始编号),数据量10000000. 题目解读:在一个不重复的乱序的自然数组中找到最小的缺失的那个数,比如1,2,3,6,4,5,8,11.那么最 ...

  6. 2018,你与 i 春秋的故事都在这

    年终岁末,深思回顾,过去的一年我们共同创造了很多回忆,有欢乐,有感动,更有收获.回首2018年,伴随着激情与挑战,我们共创了很多佳绩,一起来看看吧. 课程&实验 2018新增原创录制实战视频课 ...

  7. [Swift]LeetCode214. 最短回文串 | Shortest Palindrome

    Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. ...

  8. [Swift]LeetCode840. 矩阵中的幻方 | Magic Squares In Grid

    A 3 x 3 magic square is a 3 x 3 grid filled with distinct numbers from 1 to 9 such that each row, co ...

  9. spring aspect获取抽象基类日志

    在实际的项目开发过程中我们其实封装了很多的类似BaseService.BaseDao等的基类,然后在切日志的时候我们一般是指向继承改抽象基类的实现类的,这时候我们就会出现无法切出调用抽象基类方法的日志 ...

  10. linux清空文件内容的几种方式与区别

    虽然linux清空文件内容的方式有很多种,但是他们之间有着细微的差别.通过实践我将他们分为两类: 将文件清空,文件大小为0k $ : > filename  $ > filename  $ ...