tf.data:"mixing" 批量大小?

tf.data: "mixing" batch sizes?

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

每个输入批次的上下文都不同(尽管批次中的每个样本都相同),因此 link 在输入管道中将它们放在一起是有意义的。我无法将所有批次的所有上下文数组存储在图中,然后从那里读取,因为就所需的内存而言,将所有这些静态地存储在图中是令人望而却步的。我可以做的是为当前批次输入单个上下文数组,我想将其包含在我的输入管道中。

另请注意,在我的图表中,上下文数组经过一些卷积层,这有效地将其减小到可管理的大小,比原来的小得多,因此我 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。

好的,这是我的初步解决方案。请注意,我假设您的数据以某种方式排序,因此当您构建 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 之前 将其与上下文一起压缩,这样上下文就不会被复制。然而,这要求您在处理数据加载时要小心(因此我上面的假设)。