tensorflow学习笔记-队列和线程管理

队列类型

FIFOQueue()          #先入先出队列
RandomShuffleQueue() #随机队列

queue1 = tf.RandomShuffleQueue(...)
queue2 = tf.FIFOQueue(...)

##出入队列
# enqueue()、enqueue_many()
# dequeueu()、dequeue_many()

enqueue_op = queue.enqueue(example)
inputs = queue.dequeue_many(batch_size)

线程管理器Coordinator

  • should_stop():如果线程应该停止则返回True
  • request_stop():请求该线程停止
  • join():等待被指定的子线程终止(才开始继续主线程)
  • 步骤
    • 首先创建一个Coordinator对象,然后建立一些使用Coordinator对象的线程
    • 这些线程通常一直循环运行,一直到should_stop()返回True时停止
    • 任何线程都可以决定计算什么时候应该停止。它只需要调用request_stop(),同时其他线程的should_stop()将会返回True,然后都停下来
# 线程体:循环执行,直到Coordinator收到了停止请求。
 # 如果某些条件为真,请求Coordinator去停止其他线程。
def MyLoop(coord):
    while not coord.should_stop():
        ...do something...
        if ...some condition...:
            coord.request_stop()

# Main code: create a coordinator.
coord = Coordinator()

# Create 10 threads that run 'MyLoop()'
threads = [threading.Thread(target=MyLoop, args=(coord)) for i in xrange(10)]

# Start the threads and wait for all of them to stop. for t in threads: t.start()
    coord.join(threads)

这只是一个简单的例子,具体实现的时候比较灵活。实际中Coordinator会置入queue中,负责在得到线程关闭的请求后,关闭queue启动的多个线程。

队列管理器QueueRunner

创建并启动单个队列管理器的多个线程

qr = tf.train.QueueRunner(queue, [enqueue_op] * 4)
enqueue_threads = qr.create_threads(sess, coord=coord, start=True)
coord.request_stop()
coord.join(enqueue_threads)
  • When you later call the create_threads() method, the QueueRunner will create one thread for each op in enqueue_ops. Each thread will run its enqueue op in parallel with the other threads.
  • If a coordinator is given, this method starts an additional thread to close the queue when the coordinator requests a stop or exception error.

异常处理

  • 通过queue runners启动的线程不仅仅只处理推送样本到队列。他们还捕捉和处理由队列产生的异常,包括OutOfRangeError异常,这个异常是用于报告队列被关闭
  • 使用Coordinator的训练程序在主循环中必须同时捕捉和报告异常
    下面是对上面训练循环的改进版本:
try:
    for step in xrange(1000000):
        if coord.should_stop():
            break
        sess.run(train_op)
except Exception, e:
# Report exceptions to the coordinator.
    coord.request_stop(e)

# Terminate as usual.  It is innocuous to request stop twice.
coord.request_stop()
coord.join(threads)

接下来把队列 多线程利用起来读取数据。
先看一个简单的例子:

import tensorflow as tf
import numpy as np

# 生成一个从1到100的数列
data_en_q = np.linspace(1,100,100)
# 创建一个可容纳50个元素的先进先出的常规队列,其元素类型为tf.uint8
qr = tf.FIFOQueue(capacity=50, dtypes=[tf.uint8,], shapes=[[]])
# en_qr为压数据进队列操作
en_qr = qr.enqueue_many([data_en_q])
# de_qr_1每次拿60个数据
de_qr_1 = qr.dequeue_many(60)
# de_qr_2每次拿50个数据
de_qr_2 = qr.dequeue_many(50)

# 创建一个包含两个线程的队列管理器,用于处理入队操作
qr = tf.train.QueueRunner(qr, enqueue_ops=[en_qr] * 2)
# 创建一个协调器,用于协调不同线程
coord = tf.train.Coordinator()

with tf.Session() as sess:
    # 启动队列管理器管理的线程
    enqueue_threads = qr.create_threads(sess, coord=coord, start=True)
    data_1 = list()
    data_2 = list()
    # 主线程消费100次,每次根据出队要求获取不同的元素个数
    for index in range(100):
        # 判断主线程是否需要停止退出
        if coord.should_stop():
            break
        meta1,meta2 = sess.run([de_qr_1,de_qr_2])
        data_1.append(meta1)
        data_2.append(meta2)
    # 主线程完成拿数据操作,打印出保存的数据
    print(data_1)
    print(data_2)
    # 主线程已完成任务,请求关闭处理入队操作的两个线程
    coord.request_stop()
    # 主线程等待所有线程关闭完毕再进入下一步
    coord.join(enqueue_threads)

注释的很清晰了。
接下来看一个实际使用的demo:

# coding=utf-8
import time
import tensorflow as tf

# We simulate some raw input data 
# (think about it as fetching some data from the file system)
# let's say: batches of 128 samples, each containing 1024 data points
x_input_data = tf.random_normal([128, 1024], mean=0, stddev=1)

# We build our small model: a basic two layers neural net with ReLU
with tf.variable_scope("queue"):
    q = tf.FIFOQueue(capacity=5, dtypes=tf.float32) # enqueue 5 batches
    # We use the "enqueue" operation so 1 element of the queue is the full batch
    enqueue_op = q.enqueue(x_input_data)
    numberOfThreads = 1
    qr = tf.train.QueueRunner(q, [enqueue_op] * numberOfThreads)
    tf.train.add_queue_runner(qr)
    input = q.dequeue() # It replaces our input placeholder
    # We can also compute y_true right into the graph now
    y_true = tf.cast(tf.reduce_sum(input, axis=1, keep_dims=True) > 0, tf.int32)

with tf.variable_scope('FullyConnected'):
    w = tf.get_variable('w', shape=[1024, 1024], initializer=tf.random_normal_initializer(stddev=1e-1))
    b = tf.get_variable('b', shape=[1024], initializer=tf.constant_initializer(0.1))
    z = tf.matmul(input, w) + b
    y = tf.nn.relu(z)

    w2 = tf.get_variable('w2', shape=[1024, 1], initializer=tf.random_normal_initializer(stddev=1e-1))
    b2 = tf.get_variable('b2', shape=[1], initializer=tf.constant_initializer(0.1))
    z = tf.matmul(y, w2) + b2

with tf.variable_scope('Loss'):
    losses = tf.nn.sigmoid_cross_entropy_with_logits(None, tf.cast(y_true, tf.float32), z)
    loss_op = tf.reduce_mean(losses)

with tf.variable_scope('Accuracy'):
    y_pred = tf.cast(z > 0, tf.int32)
    accuracy = tf.reduce_mean(tf.cast(tf.equal(y_pred, y_true), tf.float32))
    accuracy = tf.Print(accuracy, data=[accuracy], message="accuracy:")

# We add the training op ...
adam = tf.train.AdamOptimizer(1e-2)
train_op = adam.minimize(loss_op, name="train_op")

startTime = time.time()
with tf.Session() as sess:
    # ... init our variables, ...
    sess.run(tf.global_variables_initializer())

    # ... add the coordinator, ...
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)

    # ... check the accuracy before training (without feed_dict!), ...
    sess.run(accuracy)

    # ... train ...
    # 此处使用try语句,其实是没有必要的,但是实际中使用tf.train.QueueRunner作为文件队列是设置了最大训练迭代数,
    #在文件队列的出队操作数大于"num_epoches*队列容量"时,从文件队列读取的操作会读到一个"EOF",
    #这样最后一个样本出队的操作会得到一个tf.OutOfRangeError的错误
    try:
        for i in range(5000):
            #  ... without sampling from Python and without a feed_dict !
            _, loss = sess.run([train_op, loss_op])

            # We regularly check the loss
            if i % 500 == 0:
                print('iter:%d - loss:%f' % (i, loss))
    except tf.errors.OutOfRangeError:
        print 'Done training -- epoch limit reached'
    finally:
        # When done, ask the threads to stop.
        coord.request_stop()
 
    coord.join(threads)
    
    # Finally, we check our final accuracy
    sess.run(accuracy)

print("Time taken: %f" % (time.time() - startTime))

你可能感兴趣的:(tensorflow学习笔记-队列和线程管理)