tf.data:“混合”批量大小?

时间:2018-01-30 08:46:08

标签: python tensorflow tensorflow-datasets

我使用Dataset API在TF 1.4.1中工作。我有两组输入数据xy,每个都有相同数量的元素。对于xy,我有大型上下文数组context_xcontext_y,比如说大小为10000×10。

每个输入批次的上下文都不同(尽管批次中的每个样本都是相同的),因此在输入管道中将它们链接在一起是有意义的。我无法为图中的所有批处理存储所有上下文数组,然后从那里读取,因为在所需的内存方面,将所有这些数据静态存储在图中是非常的。我可以做的是为当前批处理输入一个上下文数组,我想将它包含在我的输入管道中。

另请注意,在我的图表中,上下文数组经过一些卷积层,有效地将其缩小到可管理的大小,比原始小得多,因此我tile使用其他特定于样本的特征批处理并继续执行其余任务。因此,即使我需要最终复制到批量大小,我也可以在从尺寸小得多的上下文数组中提取的特征向量上执行此操作。

我使用以下类型的代码来构建一个数据集,该数据集应该将一批xy个样本及其上下文提供给我的图表:

import tensorflow as tf
import numpy as np

# Small data input
x = np.arange(100)
y = np.arange(100)

# Large context array for both x  and y
context_x = np.random.rand(1, 10000, 10)
context_y = np.random.rand(1, 10000, 10)

# Create datasets
dataset_x = tf.data.Dataset.from_tensor_slices(x)
dataset_y = tf.data.Dataset.from_tensor_slices(y)

# same context should be repeated for every data item
dataset_context_x = tf.data.Dataset.from_tensor_slices(context_x)
dataset_context_x = dataset_context_x.repeat()
dataset_context_y = tf.data.Dataset.from_tensor_slices(context_y)
dataset_context_y = dataset_context_y.repeat()

dataset = tf.data.Dataset.zip((dataset_x, dataset_context_x))
dataset = dataset.concatenate( tf.data.Dataset.zip((dataset_y, dataset_context_y)) )
dataset = dataset.batch(32)

iterator = dataset.make_initializable_iterator()
(x_iter, context_iter) = iterator.get_next()
with tf.Session() as sess:
    sess.run(iterator.initializer)
    while True:
        try:
            xi, ci = sess.run([x_iter, context_iter])
            print(xi.shape, ci.shape)
        except tf.errors.OutOfRangeError:
            break

输出表明为每个样本x[i]y[i]复制了大型上下文数组:

((32,), (32, 10000, 10))
((32,), (32, 10000, 10))
((32,), (32, 10000, 10))
((32,), (32, 10000, 10))
((32,), (32, 10000, 10))
((32,), (32, 10000, 10))
((8,), (8, 10000, 10))

这将浪费大量内存,因为所有32 10000 - by - 10切片都是相同的!我应该如何使用数据集API以避免不必要地复制上下文数组,并为每个批次获得((32,), (1, 10000, 10))的输出?您可以将此视为混合批量大小,xy为32,而上下文数组为1。

1 个答案:

答案 0 :(得分:1)

好的,这是我的尝试性解决方案。请注意,我假设您的数据是以某种方式排序的,因此当您构建批次x时,您阅读的下一个context_x始终是与当前批次相关的数据。

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # running on CPU
import tensorflow as tf
import numpy as np

# Small data input
x = np.arange(100)
y = np.arange(100)

# Large context array for both x  and y
context_x = np.random.rand(1, 10000, 10)
context_y = np.random.rand(1, 10000, 10)

# Create datasets
dataset_x = tf.data.Dataset.from_tensor_slices(x).batch(32)
dataset_y = tf.data.Dataset.from_tensor_slices(y).batch(32)

# same context should be repeated for every data item
dataset_context_x = tf.data.Dataset.from_tensor_slices(context_x)
dataset_context_x = dataset_context_x.repeat() # here just for demonstration purposes. Ideally you'll have enough context data to match the batches
dataset_context_y = tf.data.Dataset.from_tensor_slices(context_y)
dataset_context_y = dataset_context_y.repeat() # here just for demonstration purposes. Ideally you'll have enough context data to match the batches

dataset = tf.data.Dataset.zip((dataset_x, dataset_context_x))
dataset = dataset.concatenate( tf.data.Dataset.zip((dataset_y, dataset_context_y)) ) # This stacks all 'x' samples on top of all 'y' samples. Is this really what you wanted?

iterator = dataset.make_initializable_iterator()
(x_iter, context_iter) = iterator.get_next()
with tf.Session() as sess:
    sess.run(iterator.initializer)
    while True:
        try:
            xi, ci = sess.run([x_iter, context_iter])
            print(xi.shape, ci.shape)
        except tf.errors.OutOfRangeError:
            break

在您的实施中,删除dataset_context_* = dataset_context_*.repeat()行。

与您的管道的主要区别在于我在使用上下文压缩它之前批量处理x ,因此上下文不会被复制。但是,这需要您在处理数据加载时要小心(因此我的上述假设)。