我有一个CNN模型,正在对存储在tfrecord
中的图像集进行训练。相关代码如下:
def parse_function(proto): .... train_path = "...." seed = random.randint(0, int(2**32 - 1)) buffer_size = 300 tf.set_random_seed(seed) train_set = tf.data.TFRecordDataset(train_path) train_set = train_set.map(parse_function) train_set = train_set.shuffle(buffer_size=buffer_size, seed=seed) train_set = train_set.batch(batch_size) train_set = train_set.repeat() iterator = train_set.make_one_shot_iterator() next_element = iterator.get_next() model = build_mode(next_element) with tf.Session() as sess: for i in range(iters): sess.run(model.train_op)
在使用不同随机种子的多次运行中,损失函数表现出许多宏观相似性(如下面图片中的箭头所示)
这里有4次独立的运行。请注意,为了突出相似性,这张图稍微放大了,这是前1000次迭代的情况。这些相似性大约每1000次迭代就会出现一次。如果我改变批次大小,相同的情况似乎只是发生了位移。
对我来说,这表明数据集根本没有被打乱。你知道这是为什么吗?
回答:
我怀疑这个问题与使用的批次大小和缓冲区大小有关。在shuffle
中的buffer_size
参数代表在任何给定时间由后续的batch
函数从数据集中抽取的元素数量。因此,如果buffer_size
不够大(特别是与batch_size
相比时),在抽取数据集时可能不会有足够的随机化。
我喜欢把buffer_size
想象成一个在数据集上移动的窗口,随机化发生在窗口内(这比实际情况更细致,但这是我喜欢的可视化图像)。所以,如果你的窗口大小相对于数据集大小来说非常小,通常在任何给定时间都不会对数据集的大部分进行随机化,导致批次之间在迭代中的周期性相关性。
尝试将buffer_size
从300
增加到你可以舒适地在内存中容纳的数据点数量。例如,如果你处理的是n
维浮点数据,并且你有500MB
的内存用于数据预处理,那么你可以在内存中为shuffle容纳大约500MB/(n*64B)
的数据(对于n=100
大约是80000
)。这应该能增强创建批次时的随机化程度。