tensorflow中协调器 tf.train.Coordinator 和入队线程启动器 tf.train.start_queue_runners

TensorFlow的Session对象是支持多线程的,可以在同一个会话(Session)中创建多个线程,并行执行。在Session中的所有线程都必须能被同步终止,异常必须能被正确捕获并报告,会话终止的时候, 队列必须能被正确地关闭。

TensorFlow提供了两个类来实现对Session中多线程的管理:tf.Coordinator和 tf.QueueRunner,这两个类往往一起使用。

Coordinator类用来管理在Session中的多个线程,可以用来同时停止多个工作线程并且向那个在等待所有工作线程终止的程序报告异常,该线程捕获到这个异常之后就会终止所有线程。使用 tf.train.Coordinator()来创建一个线程管理器(协调器)对象。

QueueRunner类用来启动tensor的入队线程,可以用来启动多个工作线程同时将多个tensor(训练数据)推送入文件名称队列中,具体执行函数是 tf.train.start_queue_runners , 只有调用 tf.train.start_queue_runners 之后,才会真正把tensor推入内存序列中,供计算单元调用,否则会由于内存序列为空,数据流图会处于一直等待状态。

tf中的数据读取机制如下图:

  1. 调用 tf.train.slice_input_producer,从 本地文件里抽取tensor,准备放入Filename Queue(文件名队列)中;
  2. 调用 tf.train.batch,从文件名队列中提取tensor,使用单个或多个线程,准备放入文件队列;
  3. 调用 tf.train.Coordinator() 来创建一个线程协调器,用来管理之后在Session中启动的所有线程;
  4. 调用tf.train.start_queue_runners, 启动入队线程,由多个或单个线程,按照设定规则,把文件读入Filename Queue中。函数返回线程ID的列表,一般情况下,系统有多少个核,就会启动多少个入队线程(入队具体使用多少个线程在tf.train.batch中定义);
  5. 文件从 Filename Queue中读入内存队列的操作不用手动执行,由tf自动完成;
  6. 调用sess.run 来启动数据出列和执行计算;
  7. 使用 coord.should_stop()来查询是否应该终止所有线程,当文件队列(queue)中的所有文件都已经读取出列的时候,会抛出一个 OutofRangeError 的异常,这时候就应该停止Sesson中的所有线程了;
  8. 使用coord.request_stop()来发出终止所有线程的命令,使用coord.join(threads)把线程加入主线程,等待threads结束。

以上对列(Queue)和 协调器(Coordinator)操作示例:

1# -*- coding:utf-8 -*- 2import tensorflow as tf 3import numpy as np 4 5# 样本个数 6sample_num=5 7# 设置迭代次数 8epoch_num = 2 9# 设置一个批次中包含样本个数 10batch_size = 3 11# 计算每一轮epoch中含有的batch个数 12batch_total = int(sample_num/batch_size)+1 13 14# 生成4个数据和标签 15def generate_data(sample_num=sample_num): 16 labels = np.asarray(range(0, sample_num)) 17 images = np.random.random([sample_num, 224, 224, 3]) 18 print('image size {},label size :{}'.format(images.shape, labels.shape)) 19 return images,labels 20 21def get_batch_data(batch_size=batch_size): 22 images, label = generate_data() 23 # 数据类型转换为tf.float32 24 images = tf.cast(images, tf.float32) 25 label = tf.cast(label, tf.int32) 26 27 #从tensor列表中按顺序或随机抽取一个tensor准备放入文件名称队列 28 input_queue = tf.train.slice_input_producer([images, label], num_epochs=epoch_num, shuffle=False) 29 30 #从文件名称队列中读取文件准备放入文件队列 31 image_batch, label_batch = tf.train.batch(input_queue, batch_size=batch_size, num_threads=2, capacity=64, allow_smaller_final_batch=False) 32 return image_batch, label_batch 33 34image_batch, label_batch = get_batch_data(batch_size=batch_size) 35 36 37with tf.Session() as sess: 38 39 # 先执行初始化工作 40 sess.run(tf.global_variables_initializer()) 41 sess.run(tf.local_variables_initializer()) 42 43 # 开启一个协调器 44 coord = tf.train.Coordinator() 45 # 使用start_queue_runners 启动队列填充 46 threads = tf.train.start_queue_runners(sess, coord) 47 48 try: 49 while not coord.should_stop(): 50 print '************' 51 # 获取每一个batch中batch_size个样本和标签 52 image_batch_v, label_batch_v = sess.run([image_batch, label_batch]) 53 print(image_batch_v.shape, label_batch_v) 54 except tf.errors.OutOfRangeError: #如果读取到文件队列末尾会抛出此异常 55 print("done! now lets kill all the threads……") 56 finally: 57 # 协调器coord发出所有线程终止信号 58 coord.request_stop() 59 print('all threads are asked to stop!') 60 coord.join(threads) #把开启的线程加入主线程,等待threads结束 61 print('all threads are stopped!')

输出:

1************ 2((3, 224, 224, 3), array([0, 1, 2], dtype=int32)) 3************ 4((3, 224, 224, 3), array([3, 4, 0], dtype=int32)) 5************ 6((3, 224, 224, 3), array([1, 2, 3], dtype=int32)) 7************ 8done! now lets kill all the threads…… 9all threads are asked to stop! 10all threads are stopped!

以上程序在 tf.train.slice_input_producer 函数中设置了 num_epochs 的数量, 所以在文件队列末尾有结束标志,读到这个结束标志的时候抛出 OutofRangeError 异常,就可以结束各个线程了。

如果不设置 num_epochs 的数量,则文件队列是无限循环的,没有结束标志,程序会一直执行下去。

点赞
收藏

评论区

加载中...

相关推荐

C++多线程编程和同步机制:详解和实例演示

C中的多线程编程和同步机制使得程序员可以利用计算机的多核心来提高程序的运行效率和性能。本文将介绍多线程编程和同步机制的基本概念和使用方法。多线程编程基础在C中,使用库来创建和管理线程。线程可以通过函数、成员函数或者Lambda表达式来实现。以下是一

【Flutter实战】Dart线程模型及异常捕获

2.6Flutter异常捕获在介绍Flutter异常捕获之前必须先了解一下Dart单线程模型,只有了解了Dart的代码执行流程,我们才能知道该在什么地方去捕获异常。2.6.1Dart单线程模型在Java和ObjectiveC(以下简称“OC”)中,如果程序发生异常且没有被捕获,那么程序将会终止,但是这在Dart或JavaScript中则不会!

cookie和session的详解与区别

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。本章将系统地讲述Cookie与Session机制,并比较说明什么时候不能用Cookie,什么时候不能用Session。1.1 C

Java Web学习总结(11)——Session使用示例教程

一、Session简单介绍  在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中

PHP如何配置session存储在redis

当网站用户量增多的时候,正常的session存取就会出现有点慢的问题,如果提高速度呢。我们可以使用redis去保存session的会话信息。PHP的会话默认是以文件的形式存在的,可以配置到NoSQL中,即提高了访问速度,又能很好地实现会话共享。 配置方式如下: 方法一:修改php.ini的设置session.save\_handler

Java线程知识深入解析(2)

多线程程序对于多线程的好处这就不多说了。但是,它同样也带来了某些新的麻烦。只要在设计程序时特别小心留意,克服这些麻烦并不算太困难。(1)同步线程许多线程在执行中必须考虑与其他线程之间共享数据或协调执行状态。这就需要同步机制。在Java中每个对象都有一把锁与之对应。但Java不提供单独的lock和unlock操作。它由高层的结构隐