TensorFlow读取二进制文件数据到队列
2016-11-03 09:30:00      0个评论    来源:diligent_321的博客  
收藏   我要投稿

TensorFlow是一种符号编程框架(与theano类似),先构建数据流图再输入数据进行模型训练。Tensorflow支持很多种样例输入的方式。最容易的是使用placeholder,但这需要手动传递numpy.array类型的数据。第二种方法就是使用二进制文件和输入队列的组合形式。这种方式不仅节省了代码量,避免了进行data augmentation和读文件操作,可以处理不同类型的数据, 而且也不再需要人为地划分开“预处理”和“模型计算”。在使用TensorFlow进行异步计算时,队列是一种强大的机制。

队列使用概述

正如TensorFlow中的其他组件一样,队列就是TensorFlow图中的节点。这是一种有状态的节点,就像变量一样:其他节点可以修改它的内容。具体来说,其他节点可以把新元素插入到队列后端(rear),也可以把队列前端(front)的元素删除。队列,如FIFOQueue和RandomShuffleQueue(A queue implementation that dequeues elements in a random order.)等对象,在TensorFlow的tensor异步计算时都非常重要。例如,一个典型的输入结构是使用一个RandomShuffleQueue来作为模型训练的输入,多个线程准备训练样本,并且把这些样本压入队列,一个训练线程执行一个训练操作,此操作会从队列中移除最小批次的样本(mini-batches),这种结构具有许多优点。

TensorFlow的Session对象是可以支持多线程的,因此多个线程可以很方便地使用同一个会话(Session)并且并行地执行操作。然而,在Python程序实现这样的并行运算却并不容易。所有线程都必须能被同步终止,异常必须能被正确捕获并报告,会话终止的时候, 队列必须能被正确地关闭。所幸TensorFlow提供了两个类来帮助多线程的实现:tf.Coordinator和 tf.QueueRunner。从设计上这两个类必须被一起使用。Coordinator类可以用来同时停止多个工作线程并且向那个在等待所有工作线程终止的程序报告异常。QueueRunner类用来协调多个工作线程同时将多个tensor压入同一个队列中。

(1)读二进制文件数据到队列中

同很多其他的深度学习框架一样,TensorFlow有它自己的二进制格式。它使用了a mixture of its Records 格式和protobuf。Protobuf是一种序列化数据结构的方式,给出了关于数据的一些描述。TFRecords是tensorflow的默认数据格式,一个record就是一个包含了序列化tf.train.Example 协议缓存对象的二进制文件,可以使用python创建这种格式,然后便可以使用tensorflow提供的函数来输入给机器学习模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import tensorflow as tf
 
def read_and_decode_single_example(filename_queue):
# 定义一个空的类对象,类似于c语言里面的结构体定义
    class Image(self):
    pass
    image = Image()
    image.height = 32
    image.width = 32
    image.depth = 3
    label_bytes = 1
     
    Bytes_to_read = label_bytes+image.heigth*image.width*3
    # A Reader that outputs fixed-length records from a file
    reader = tf.FixedLengthRecordReader(record_bytes=Bytes_to_read)
    # Returns the next record (key, value) pair produced by a reader, key 和value都是字符串类型的tensor
    # Will dequeue a work unit from queue if necessary (e.g. when the
    # Reader needs to start reading from a new file since it has
    # finished with the previous file).
    image.key, value_str = reader.read(filename_queue)
    # Reinterpret the bytes of a string as a vector of numbers,每一个数值占用一个字节,在[0, 255]区间内,因此out_type要取uint8类型
    value = tf.decode_raw(bytes=value_str, out_type=tf.uint8)
    # Extracts a slice from a tensor, value中包含了label和feature,故要对向量类型tensor进行'parse'操作
    image.label = tf.slice(input_=value, begin=[0], size=[1])
    value = value.slice(input_=value, begin=[1], size=[-1]).reshape((image.depth, image.height, image.width))
    transposed_value = tf.transpose(value, perm=[2, 0, 1])
    image.mat = transposed_value
    return image

接下来我们便可以调用这个函数了,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
filenames =[os.path.join(data_dir, 'test_batch.bin')]
# Output strings (e.g. filenames) to a queue for an input pipeline
filename_queue = tf.train.string_input_producer(string_tensor=filenames)
# returns symbolic label and image
img_obj = read_and_decode_single_example("filename_queue")
Label = img_obj.label
Image = img_obj.mat
sess = tf.Session()
# 初始化tensorflow图中的所有状态,如待读取的下一个记录tfrecord的位置,variables等
init = tf.initialize_all_variables()
sess.run(init)
tf.train.start_queue_runners(sess=sess)
# grab examples back.
# first example from file
label_val_1, image_val_1 = sess.run([label, image])
# second example from file
label_val_2, image_val_2 = sess.run([label, image])

值得一提的是,TFRecordReader总是作用于文件名队列。它将会从队列中弹出文件名并使用该文件名,直到tfrecord为空时停止,此时它将从文件名队列中弹出下一个filename。然而,文件名队列又是怎么得来的呢?起初这个队列是空的,QueueRunners的概念即源于此。QueueRunners本质上就是一个线程thread,这个线程负责使用会话session并不断地调用enqueue操作。Tensorflow把这个模式封装在tf.train.QueueRunner对象里面。入队列操作99%的时间都可以被忽略掉,因为这个操作是由后台负责运行。(比如在上面的例子中,tf.train.string_input_producer创建了一个这样的线程,添加QueueRunner到数据流图中)。

可想而知,在你运行任何训练步骤之前,我们要告知tensorflow去启动这些线程,否则这些队列会因为等待数据入队而被堵塞,导致数据流图将一直处于挂起状态。我们可以调用tf.train.start_queue_runners(sess=sess)来启动所有的QueueRunners。这个调用并不是符号化的操作,它会启动输入管道的线程,填充样本到队列中,以便出队操作可以从队列中拿到样本。另外,必须要先运行初始化操作再创建这些线程。如果这些队列未被初始化,tensorflow会抛出错误。

(2)从二进制文件中读取mini-batchs

在训练机器学习模型时,使用单个样例更新参数属于“online learning”,然而在线下环境下,我们通常采用基于mini-batchs 随机梯度下降法(SGD),但是在tensorflow中如何利用queuerunners返回训练块数据呢?请参见下面的程序:

1
2
3
4
5
image_batch, label_batch = tf.train.shuffle_batch(tensor_list=[image, label]],
                                                  batch_size=batch_size,
                                                  num_threads=24,
                                                  min_after_dequeue=min_samples_in_queue,
                                                  capacity=min_samples_in_queue+3*batch_size)

读取batch数据需要使用新的队列queues和QueueRunners(大致流程图如下)。Shuffle_batch构建了一个RandomShuffleQueue,并不断地把单个的(image,labels)对送入队列中,这个入队操作是通过QueueRunners启动另外的线程来完成的。这个RandomShuffleQueue会顺序地压样例到队列中,直到队列中的样例个数达到了batch_size+min_after_dequeue个。它然后从队列中选择batch_size个随机的元素进行返回。事实上,shuffle_batch返回的值就是RandomShuffleQueue.dequeue_many()的结果。有了这个batches变量,就可以开始训练机器学习模型了。

函数 tf.train.shuffle_batch(tensor_list, batch_size, capacity, min_after_dequeue, num_threads=1, seed=None, enqueue_many=False, shapes=None, shared_name=None, name=None)的使用说明:

作用:Creates batches by randomly shuffling tensors.(从队列中随机筛选多个样例返回给image_batch和label_batch);

参数说明:

tensor_list: The list of tensors to enqueue.(待入队的tensor list);
batch_size: The new batch size pulled from the queue;
capacity: An integer. The maximum number of elements in the queue(队列长度);
min_after_dequeue: Minimum number elements in the queue after a dequeue, used to ensure a level of mixing of elements.(随机取样的样本总体最小值,用于保证所取mini-batch的随机性);
num_threads: The number of threads enqueuing `tensor_list`.(session会话支持多线程,这里可以设置多线程加速样本的读取)
seed: Seed for the random shuffling within the queue.
enqueue_many: Whether each tensor in `tensor_list` is a single example.(为False时表示tensor_list是一个样例,压入时占用队列中的一个元素;为True时表示tensor_list中的每一个元素都是一个样例,压入时占用队列中的一个元素位置,可以看作为一个batch);
shapes: (Optional) The shapes for each example. Defaults to the inferred shapes for `tensor_list`.
shared_name: (Optional) If set, this queue will be shared under the given name across multiple sessions.

name: (Optional) A name for the operations.

Tensorflow读取文件到队列文件的更多相关文章

  1. 第十二节,TensorFlow读取数据的几种方法以及队列的使用

    TensorFlow程序读取数据一共有3种方法: 供给数据(Feeding): 在TensorFlow程序运行的每一步, 让Python代码来供给数据. 从文件读取数据: 在TensorFlow图的起 ...

  2. 文件 FIFO队列

    <?php /** * Filefifo.php 文件型FIFO队列 */ class Filefifo { /** * $_file_data, 数据文件的路径 */ private $_fi ...

  3. C#内存映射文件消息队列实战演练(MMF—MQ)

    一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的一部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理和 ...

  4. 使用java读取文件夹中文件的行数

    使用java统计某文件夹下所有文件的行数 经理突然交代一个任务:要求统计某个文件夹下所有文件的行数.在网上查了一个多小时没有解决.后来心里不爽就决定自己写一个java类用来统计文件的行数,于是花了两个 ...

  5. Android想服务器传图片,透过流的方式。还有读取服务器图片(文件),也通过流的方式。

    /** * Created by Administrator on 2016/7/19. */ import android.util.Log; import com.gtercn.asPolice. ...

  6. Java读取Level-1行情dbf文件极致优化(3)

    最近架构一个项目,实现行情的接入和分发,需要达到极致的低时延特性,这对于证券系统是非常重要的.接入的行情源是可以配置,既可以是Level-1,也可以是Level-2或其他第三方的源.虽然Level-1 ...

  7. Java读取Level-1行情dbf文件极致优化(2)

    最近架构一个项目,实现行情的接入和分发,需要达到极致的低时延特性,这对于证券系统是非常重要的.接入的行情源是可以配置,既可以是Level-1,也可以是Level-2或其他第三方的源.虽然Level-1 ...

  8. Java读取Level-1行情dbf文件极致优化(1)

    最近架构一个项目,实现行情的接入和分发,需要达到极致的低时延特性,这对于证券系统是非常重要的.接入的行情源是可以配置,既可以是Level-1,也可以是Level-2或其他第三方的源.虽然Level-1 ...

  9. php读取指定结束指针文件内容

    fopen操作时文件读取开始指针位于文件开始部分, fseek 以指定文件大小以及开始指针位置确定结束指针位置 具体案例: <?php//打开文件流,fopen不会把文件整个加载到内存$f = ...

随机推荐

  1. Java设计模式菜鸟系列(十五)建造者模式建模与实现

    转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39863125 建造者模式(Builder):工厂类模式提供的是创建单个类的模式.而建造者模 ...

  2. 项目PMO工作

     算起来.这是第一次以项目PMO人员的身份參与项目,尽管非常可惜没有从头參与,也没有參与到项目结束,仅仅有短短的两个月.但对项目PMO也可略窥一斑.如今就当个流水账写一写吧. 进项目组的时候,是中 ...

  3. Unity3d数据加密

    在unity中能够使用c#自带的对称算法对数据进行加密,以下两种加密算法: using System; using System.Text; using System.Security.Cryptog ...

  4. sql系列(基础篇)-前言 课前补充知识

    前言 课前补充知识 Number(p,s) Number(p,s):数字类型,p 表示数字的有效长度(从数字的左边第 1 位不为 0 的開始算起,直到最右边的长度.取值范围 0~38 位),s 表示数 ...

  5. 《Java程序设计》第16周周五:数据库连接 与 随机数的使用

    第一部分:实验项目 项目二:数据库初步. 目的:了解Java连接数据库的步骤与方法.以及MySQL数据库的安装与使用. 目标: (1)在机房安装上MySQL数据库. 安装成功 MySQL数据库 (2) ...

  6. svn代码回滚命令【转】

    本文转载自:http://www.cnblogs.com/jndream/archive/2012/03/20/2407955.html 取消对代码的修改分为两种情况:   第一种情况:改动没有被提交 ...

  7. Java常见面试题02-方法重写和方法重载的区别?方法重载能改变返回值类型吗?

    方法重写和方法重载的区别?方法重载能改变返回值类型吗?       A:Override方法重写和Overload方法重载的区别? Overload是否可以改变返回值类型?可以 方法重写 •  子类中 ...

  8. zgb老师关于java集合的总结

    数组:存多个数据 操作不便集合(Collection ):存多个数据 管理多个数据 提供更为方便的操作Iterator:专门针对集合 进行迭代List:有序的 允许重复的元素ArrayList:底层数 ...

  9. king枚举帮助类

    可以方便的实现枚举 枚举 public enum DeptType { [Description("科室1")] Professional = , [Description(&qu ...

  10. 使用纯 CSS 实现 Google Photos 照片列表布局

    文章太长,因为介绍了如何一步一步进化到最后接近完美的效果的,不想读的同学可以直接跳到最后一个大标题之后看代码.demo及原理就好,或者也可以直接看下面这个链接的源代码. 不过还是建议顺序读下去,因为后 ...