本文主要是介绍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 by example,这里翻译出来意思有点奇怪),并且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)
上述例子的输出类似如下这样:
x1 batch:----------
[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]])]
x2 batch:----------
[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])]
y1 batch:----------
[array([ 1, 9, 17, 9]), array([ 2, 10, 18, 10]), array([ 3, 11, 19, 11]), arra
y([ 4, 12, 20, 12])]
y2 batch:----------
[5 6 7 8]
----------
在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使用)。
这篇关于tf.train.batch 和 tf.train.batch_join的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!