Tensorflow的使用——队列与线程

队列(queue)本身也是图中的一个节点,是一种有状态的节点,其他节点,如入队节点(enqueue)和出队节点(dequeue),可以修改它的内容。 入队节点可以把元素加到队列的末尾,而出对节点可以把队列中最前面的元素删除。

  • FIFOQueue 创建一个先入先出队列

import tensorflow as tf

# 1.创建一个先入先出的队列,初始化队列插入0.1, 0.2, 0.3 三个数字
queue = tf.FIFOQueue(3, 'float')
init = queue.enqueue_many(([0.1, 0.2, 0.3],))

# 2.定义出队、+1、入队操作
x = queue.dequeue()
y = x + 1
queue_inc = queue.enqueue([y])

# 3.开启一个会话功能,执行上诉操作
with tf.Session() as sess:
    sess.run(init)
    quelen = sess.run(queue.size())
    for i in range(2):
        sess.run(queue_inc)
    quelen = sess.run(queue.size())
    for i in range(quelen):
        print(sess.run(queue.dequeue()))

  • RandomShuffleQueue 创建一个随机队列,在出队列时,是以随机的顺序产生元素

import tensorflow as tf

q = tf.RandomShuffleQueue(capacity=10, min_after_dequeue=2, dtypes='float')
sess = tf.Session()
for i in range(0, 10):
    sess.run(q.enqueue(i))
for i in range(0, 8):
    print(sess.run(q.dequeue()))

  • 队列管理器

当数据量很大的时候,入队操作从磁盘中读取数据,放入内存中,主线程需要等待入队操作完成,才能进行训练操作。会话中可以运行多个线程,使用线程管理器QueueRunner 创建一系列的新线程进行入队操作,让主线程继续使用数据,即训练网络和同步数据时异步的,主线程在训练网络,另一个线程在将数据从磁盘读入内存。

import tensorflow as tf

q = tf.FIFOQueue(1000, 'float')
counter = tf.Variable(0.0)# 计数器
increment_op = tf.assign_add(counter, tf.constant(1.0))# 给计数器+1
enqueue_op = q.enqueue([counter])# 操作:计数器值加入队列

# 创建一个队列管理器 QueueRunner,用这两个操作向队列 q 中添加元素
qr = tf.train.QueueRunner(q, enqueue_ops=[increment_op, enqueue_op] * 1)

# 启动会话,从队列管理器qr中创建线程
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    enqueue_threads = qr.create_threads(sess, start=True)  # 启动入队线程
    # 主线程
    for i in range(10):
        print(sess.run(q.dequeue()))

出现的问题:

ERROR:tensorflow:Exception in QueueRunner: Run call was cancelled
ERROR:tensorflow:Exception in QueueRunner: Enqueue operation was cancelled
	 [[Node: fifo_queue_2_enqueue = QueueEnqueueV2[Tcomponents=[DT_FLOAT], timeout_ms=-1, _device="/job:localhost/replica:0/task:0/device:CPU:0"](fifo_queue_2, Variable/read/_3)]]

原因:因为+1操作和入队操作不同步,可能+1操作执行很多次后,才会进一次入队操作。另外,因为主线程的训练和读取数据时异步的,主线程会一直等待数据输入。入队线程自顾自地进行执行,在需要的出队操作完成后,程序没法结束。

解决办法:使用tf.train.Coordinator来实现线程同步,终止其他的线程。

# 使用协调器来管理线程
import tensorflow as tf

q = tf.FIFOQueue(1000, 'float')
counter = tf.Variable(0.0)# 计数器
increment_op = tf.assign_add(counter, tf.constant(1.0))# 给计数器+1
enqueue_op = q.enqueue([counter])# 操作:计数器值加入队列

# 创建一个队列管理器 QueueRunner,用这两个操作向队列 q 中添加元素
qr = tf.train.QueueRunner(q, enqueue_ops=[increment_op, enqueue_op] * 1)

# 1.主线程
sess = tf.Session()
sess.run(tf.global_variables_initializer())

# 2.Coordinator:协调器,协调线程间的关系可以视为一种信号量,用来同步
coord = tf.train.Coordinator()

# 3.启动入队操作,协调器是线程的参数
enqueue_threads = qr.create_threads(sess, coord=coord, start=True)
coord.request_stop()

# 4.主线程
for i in range(0, 10):
    try:
        print(sess.run(q.dequeue()))
    except tf.errors.OutOfRangeError:  # 使用tf.errors.OutOfRangeError 来捕捉错误,终止循环
        break
coord.join(enqueue_threads)

所有队列管理器被默认加在图的 tf.GraphKeys.QUEUE_RUNNERS 集合中。


参考书目:

Tensorflow技术解析与实战 刘嘉璇

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值