为什么TensorFlow的tf.data.Dataset.shuffle这么慢?

时间:2018-01-13 13:59:12

标签: tensorflow

以下代码中的shuffle步骤对于适度的buffer_size(比如1000)来说效果非常慢:

filenames = tf.constant(filenames)
dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
dataset = dataset.map(_parse_function)
dataset = dataset.batch(batch_size)
dataset = dataset.shuffle(buffer_size)

如果我们使用numpy来重新排列数据,则代码如下所示:

idx = np.arange(len(filenames))
np.random.shuffle(idx)
new_filenames = [filenames[i] for i in idx]
next_batch_filenames = new_filenames[:batch_size]
# get the corresponding files in batch

这要快得多。我想知道TF是否会做一些不仅仅是改组数据的事情。

1 个答案:

答案 0 :(得分:0)

比较是两​​个完全不同的操作。

您的dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))从磁盘读取。像物理长期存储一样,可能是磁旋转硬盘。太慢了如果您能够将所有这些存储在ram或超快速RAID式闪存驱动器中,那么您将解决最大的瓶颈。

您还有一个_parse_function,每次读取数据时都会为每个数据点触发。该解析的计算将需要时间,并且取决于其中的内容可能很重要。

与numpy进行比较并不十分公平,因为您的numpy示例不涉及读取磁盘或解析数据。

那应该是大部分差异。如果您已解决上述问题,那么寻找更多加速的下一个地方就是这些行

3) dataset = dataset.map(_parse_function)
4) dataset = dataset.batch(batch_size)
5) dataset = dataset.shuffle(buffer_size)

这些是您的代码行。第4行制作了一批数据,可能是32(肯定是batch_size)。然后第5行开始,尝试在长度为1000的缓冲区中对32个批次进行混洗。每次训练循环请求新的训练批次时,都会发生这种情况。洗牌步骤将所有这些大笔洗牌进行洗牌,挑选出第一个,然后每隔……一次添加一个新批次。

我们可以像这样颠倒批处理和洗牌的顺序

3) dataset = dataset.map(_parse_function)
4) dataset = dataset.shuffle(buffer_size)
5) dataset = dataset.batch(batch_size)

总之,这是更好的方法,因为在批次的内容始终相同之前,但是订单是混合的。这样,批次的内容也将被随机化。接下来,随机播放仅需要随机播放1000个项目,而不是32x1000个项目。最后,如果确实需要1000个缓冲区,我们可以挑战一下。假设我们的数据集为2000个项目。 320的缓冲区大小和32的批处理大小肯定会很好地使我们的数据随机化,有效地使缓冲区中的任何数据有10%进入下一个批处理,而90%的数据被推回以与其他数据混合。很好缓冲区大小为64且批处理大小为64似乎几乎没有用,除了每次将这些项目一次随机地从批处理中拉出之外,因此实际上有机会不会被提取并与以后的数据混合。只是没有那么多。