tf.train.batch和tf.train.batch_join区别

tf.train.batch和tf.train.batch_join区别

(2017-07-23 21:26:00)
转载
标签:

tensorflow

tf.train.batch

tf.train.batch_join

分类: 深度学习

先看两个函数的官方文档说明

tf.train.batch官方文档地址:

https://www.tensorflow.org/api_docs/python/tf/train/batch

tf.train.batch_join官方文档地址:

https://www.tensorflow.org/api_docs/python/tf/train/batch_join

tf.train.batch

batch(
    tensors,
    batch_size,
   num_threads=1,
    capacity=32,
   enqueue_many=False,
    shapes=None,
   dynamic_pad=False,
   allow_smaller_final_batch=False,
   shared_name=None,
    name=None
)

创建在参数tensors里的张量的batch。

参数tensors可以是一个张量的列表或者字典。函数的返回值将会和参数tensors的类型一致。

这个函数使用队列来实现。一个用于队列的QueueRunner对象被添加当前图的QUEUE_RUNNER的集合中。

如果enqueue_many设置为False,tensors被认为代表单个样本。那么输入维度(shape)为[x,y,z]的张量,将会输出一个维度为[batch_size,x,y,z]的张量。

 

如果enqueue_many设置为True,参数tensors被认为是一批次的样本,其中第一维是按样本编索引的(where the first dimension is indexed byexample,这里翻译出来意思有点奇怪),并且tensors中所有成员都应该在第一维上有相同的大小。如果输入的张量的维度是[*,x,y,z],那么输出的张量的维度将会是[batch_size,x,y,z]。参数capacity控制着增长队列时,预先分配的队列长度。

 

返回的操作是一个出队操作,如果输入的队列被耗尽,那么这个操作会抛出tf.errors.OutOfRangeError的异常。如果这个操作供给了另一个输入队列,那么它的队列运行器(queue runner)会捕捉这个异常,但是如果这个操作在你的主线程中使用,你需要自己捕捉这个异常。

 

注意:如果dynamic_pad参数为False,你应该确保(1)shapes参数被传递进来,(2)所有在tensors参数中的张量必须有完整定义的形状。如果上述任意一个条件没有满足,那么会抛出ValueError的异常。

 

如果dynamic_pad参数设置为True,那么知道tensors的秩就足够了,但是tensors的个别维度的形状可能为空(None)。这种情况下,每个有维度值为空的队列可能有一个可变的长度;在出队的时候,输出的张量将在左边填充当前最小批次中的张量的最大形状。对于数字,填充的是数值0.对于字符串,填充的是空字符串。参见PaddingFIFOQueue获得更多信息。

 

如果allow_smaller_final_batch参数为True,当队列被关闭并且没有足够的元素来填满一批次的数据的情况下,操作将会返回一个数量小于batch_size个数的批次数据,否则待处理的数据将被丢弃。除此之外,通过get_shape方法访问的所有输出的张量的静态形状的第一维将为空,依赖于固定为batch_size大小的操作将会失败。

 

参数:

  • tensors: 入队张量的列表或字典。
  • batch_size: 整数。一个从队列中出队新的批次的大小。
  • num_threads:入队tensors的线程的个数。如果num_threads大于1,那么批次的数据是不确定的。
  • capacity: 整数。在队列中的最大元素个数。
  • enqueue_many: 在tensor_list_list中的每个张量是否是单个样本。
  • shapes:(可选)每个样本的形状。默认的为tensors推断的形状。
  • dynamic_pad: 布尔变量。允许输入形状的可变维度。出队时被填充到指定维度,使得一批次的张量具有相同的形状。
  • allow_smaller_final_batch: (可选)布尔型变量。如果为True,允许在没有足够的元素留在队列中时,最后一批次的元素的个数比batch_size小。
  • shared_name:(可选)如果被设置的话,这个队列将在多个会话中以给定的名字被共享。
  • name:(可选)操作的名字。

 

返回:

有着与tensors参数相同类型的张量的列表或字典(除了如果输入的是一个元素的列表,那么返回的是一个张量,而不是列表)

 

抛出:

  • ValueError: 如果形状没有被指定,并且不能从tensors的元素中推断出来。

 

tf.train.batch_join

batch_join(
    tensors_list,
    batch_size,
    capacity=32,
    enqueue_many=False,
    shapes=None,
    dynamic_pad=False,
    allow_smaller_final_batch=False,
    shared_name=None,
    name=None
)

运行张量列表来填充队列,以创建样本的批次。

 

tensors_list参数是一个张量元组的列表,或者张量字典的列表。在列表中的每个元素被类似于tf.train.batch()函数中的tensors一样对待。

 

警告:这个函数是非确定性的,因为它为每个张量启动了独立的线程。

 

在不同的线程中入队不同的张量列表。用队列实现——队列的QueueRunner被添加到当前图的QUEUE_RUNNER集合中。

 

len(tensors_list)个线程被启动,第i个线程入队来自tensors_list[i]中的张量。tensors_list[i1][j]比如在类型和形状上与tensors_list[i2][j]相匹配,除了当enqueue_many参数为True的时候的第一维。

 

如果enqueue_many设置为False,那么每个tensors_list[i]被认为是单个样本。一个输入的张量x将被输出为形状为[batch_size] + x.shape的张量。

 

如果dequeue_many设置为True,那么tensors_list[i]被认为代表一个批次的样本,其中第一维是按样本编索引的,并且tensors_list[i]的所有成员都应该在第一维上有相同的大小。任何输入的张量x的切片都被当做样本,并且输出的张量的形状将是[batch_size]+x.shape[1:]。

 

capacity参数控制着当增长队列的时候,预分配队列的长度。

 

函数返回的操作是一个出队操作,并且会再输入的队列耗尽的情况下,抛出tf.errors.OutOfRangeError的异常。如果这个操作供给给其他输入队列,那么那个队列的队列运行器会捕捉这个异常,但是如果这个操作在你的主线程中操作,你需要自己负责捕捉这个异常。

 

注意:如果dynamic_pad参数为False,你应该确保(1)shapes参数被传递进来,(2)所有在tensors参数中的张量必须有完整定义的形状。如果上述任意一个条件没有满足,那么会抛出ValueError的异常。

 

如果dynamic_pad参数设置为True,那么知道tensors的秩就足够了,但是tensors的个别维度的形状可能为空(None)。这种情况下,每个有维度值为空的队列可能有一个可变的长度;在出队的时候,输出的张量将在左边填充当前最小批次中的张量的最大形状。对于数字,填充的是数值0.对于字符串,填充的是空字符串。参见PaddingFIFOQueue获得更多信息。

 

如果allow_smaller_final_batch参数为True,当队列被关闭并且没有足够的元素来填满一批次的数据的情况下,操作将会返回一个数量小于batch_size个数的批次数据,否则待处理的数据将被丢弃。除此之外,通过get_shape方法访问的所有输出的张量的静态形状的第一维将为空,依赖于固定为batch_size大小的操作将会失败。

 

参数:

  • tensors_list: 入队的张量的元组或字典的列表。
  • batch_size: 整数。一个从队列中出队新的批次的大小。
  • capacity: 整数。在队列中的最大元素个数。
  • enqueue_many: 在tensor_list_list中的每个张量是否是单个样本。
  • shapes:(可选)每个样本的形状。默认的为tensor_list_list[i]推断的形状。
  • dynamic_pad: 布尔变量。允许输入形状的可变维度。出队时被填充到指定维度,使得一批次的张量具有相同的形状。
  • allow_smaller_final_batch: (可选)布尔型变量。如果为True,允许在没有足够的元素留在队列中时,最后一批次的元素的个数比batch_size小。
  • shared_name:(可选)如果被设置的话,这个队列将在多个会话中以给定的名字被共享。
  • name:(可选)操作的名字。

 

返回:

与tensors_list[i]有着相同数量和类型的张量的列表或者字典。

 

抛出:

  • ValueError: 如果形状没有被指定,并且不能从tensor_list_list中的元素推断出来。

 

看完上述官方文档的说明,其实还是挺蒙的,下面给一段例子,就很容易理解这两个函数了,例子的代码如下:

# -*- coding: utf-8 -*-

import tensorflow as tf

 

tensor_list = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16],[17,18,19,20]]

tensor_list2 = [[[1,2,3,4]],[[5,6,7,8]],[[9,10,11,12]],[[13,14,15,16]],[[17,18,19,20]]]

with tf.Session() as sess:

    x1 =tf.train.batch(tensor_list, batch_size=4,enqueue_many=False)

    x2 =tf.train.batch(tensor_list, batch_size=4,enqueue_many=True)

 

    y1 =tf.train.batch_join(tensor_list, batch_size=4,enqueue_many=False)

    y2 =tf.train.batch_join(tensor_list2, batch_size=4,enqueue_many=True)

 

   coord = tf.train.Coordinator()

   threads = tf.train.start_queue_runners(sess=sess,coord=coord)

   print("x1 batch:"+"-"*10)

   print(sess.run(x1))

   print("x2 batch:"+"-"*10)

   print(sess.run(x2))

   print("y1 batch:"+"-"*10)

   print(sess.run(y1))

   print("y2 batch:"+"-"*10)

   print(sess.run(y2))

   print("-"*10)

   coord.request_stop()

   coord.join(threads)

上述例子的输出类似如下这样:

x1batch:----------

[array([[1, 2, 3, 4],

      [1, 2, 3, 4],

      [1, 2, 3, 4],

      [1, 2, 3, 4]]), array([[5, 6, 7, 8],

      [5, 6, 7, 8],

      [5, 6, 7, 8],

      [5, 6, 7, 8]]), array([[ 9, 10, 11, 12],

      [ 9, 10, 11, 12],

      [ 9, 10, 11, 12],

      [ 9, 10, 11, 12]]), array([[13, 14, 15, 16],

      [13, 14, 15, 16],

      [13, 14, 15, 16],

      [13, 14, 15, 16]]), array([[17, 18, 19, 20],

      [17, 18, 19, 20],

      [17, 18, 19, 20],

      [17, 18, 19, 20]])]

x2batch:----------

[array([1,2, 3, 4]), array([5, 6, 7, 8]), array([ 9, 10, 11, 12]), array([13,1

4, 15,16]), array([17, 18, 19, 20])]

y1batch:----------

[array([1,  9, 17,  9]), array([ 2, 10,18, 10]), array([ 3, 11, 19, 11]), arra

y([ 4, 12,20, 12])]

y2batch:----------

[5 6 78]

----------

在enqueue_many参数设置为False(默认值)的时候,tf.train.batch的输出,是batch_size*tensor.shape,其含义就是将tensors参数看做一个样本,那么batch_size个样本,只是单一样本的复制。在其实际应用中,tensors参数一般对应的是一个文件,那么这样操作意味着从文件中读取batch_size次, 以获得一个batch的样本。

而在enqueu_many参数设置为True的时候,tf.train.batch将tensors参数看做一个batch的样本,那么batch_size只是调整一个batch中样本的维度的,因为输出的维度是batch_size*tensor.shape[1:](可以尝试将代码例子中batch_size改成3,再看结果)。

最后需要注意的tf.train.batch的num_threads参数,指定的是进行入队操作的线程数量,可以进行多线程对于同一个文件进行操作,这样会比单一线程读取文件快。

tf.train.batch_join一般就对应于多个文件的多线程读取,可以看到当enqueue_many参数设置为False(默认值)的时候,tensor_list中每个tensor被看做单个样本,这个时候组成batch_size的一个batch的样本,是从各个单一样本中凑成一个batch_size的样本。可以看到由于是多线程,每次取值不同,也就是类似,每个tensor对应一个文件,也对应一个线程,那么组成batch的时候,该线程读取到文件(例子中是tensor的哪个值)是不确定,这样就形成了打乱的形成样本的时候。

而在enqueue_many参数设置为True的时候,取一个batch的数据,是在tensor_list中随机取一个,因为每一个就是一个batch的数据,batch_size只是觉得截断或填充这个batch的大小。

这样就很容易明白了tf.train.batch和tf.train.batch_join的区别,一般来说,单一文件多线程,那么选用tf.train.batch(需要打乱样本,有对应的tf.train.shuffle_batch);而对于多线程多文件的情况,一般选用tf.train.batch_join来获取样本(打乱样本同样也有对应的tf.train.shuffle_batch_join使用)。

你可能感兴趣的:(tensorflow)