使用比 Ram 数据更多的 Tensorflow 数据集和估计器
Using Tensorflow Datasets and Estimators with More Data than Ram
我最近将我的建模框架切换为使用自定义 Tensorflow Estimators and Datasets,并且我对这个工作流总体上非常满意。
但是,我刚刚注意到我的 dataset_input_fn 从 tfrecords 加载数据的方式存在问题。我的输入函数是仿照 example in the Tensorflow documentation. The issue arises when I have more examples than I can fit into RAM. If I have 1e6 examples, and set my shuffle buffer_size to 1e5, a subset of 1e5 examples is selected once, shuffled, and then iterated on. Meaning my model is only trained on 10% of my overall dataset. My code that sets up this behavior is borrowed exactly from the Tensorflow documentation example code:
dataset = dataset.map(parser)
dataset = dataset.shuffle(buffer_size=10000)
dataset = dataset.batch(32)
dataset = dataset.repeat(num_epochs)
iterator = dataset.make_one_shot_iterator()
我的问题: 是否可以在我训练时用初始 1e5 之外的新示例填充洗牌缓冲区? one_shot_iterator 是否支持此类功能?我需要使用可初始化的迭代器吗?
谢谢!
我发现了目前看来可行的解决方法。通过一些实验,我了解到在实例化 TFRecordDataset 时,
filenames = ["file1.tfrecord", ..., "filen.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)
并设置随机播放缓冲区:
dataset = dataset.shuffle(buffer_size=10000)
缓冲区只填充前 10000 个示例,无论需要多少 tf 记录。例如,在我的例子中,我有大约 300 个 tfrecord 文件,每个文件包含 4096 个示例。检查时,我的随机播放缓冲区似乎只包含文件名列表中前 3 个 tf 记录的示例。由于我的文件名列表是静态的,这意味着我的模型只训练了我的前 3 个 tfrecords!
我目前的解决方法非常简单。在我的训练循环中,我已经在 Estimator.train 和 Estimator.evaluate 之间交替,并且我注意到每次调用 Estimator.train 时,洗牌缓冲区都会重新填充。我的解决方案是每次调用我的 input_fn 时随机播放我的文件名。这不是一个非常优雅的解决方案,但确实达到了允许我遍历所有 tfrecords 的预期效果。
#My Crappy Fix: shuffle file names in input_fn
np.random.shuffle(filenames)
dataset = tf.data.TFRecordDataset(filenames)
这个解决方案令人恼火的地方(除了它的笨拙)是我的小批量不是 "globally random"。相反,它们是从 tf 记录的一小部分中选择的,并且每个 training/evaluation 周期仅使用该子集。缓解这种情况的一种方法是增加我的随机播放缓冲区大小或减少我的 tfrecord 大小,我可能会同时执行这两种操作。最后,我认为值得注意的是 if
shuffle_buffer_size < (tf_record_size + minibatch_size)
然后,据我所知,我的 TFRecordDataset 将从单个 tfrecord 文件中提取!
最后,我认为 relevant tensorflow documentation 没有很好地表达这些复杂性。该文档提到了在不适合内存的大型数据集上进行训练的能力,但没有提供太多细节。 tf 作者在写这篇文章时似乎不太可能考虑到我的 hacky 策略,所以我仍然很好奇是否有更好的方法。
我最近将我的建模框架切换为使用自定义 Tensorflow Estimators and Datasets,并且我对这个工作流总体上非常满意。
但是,我刚刚注意到我的 dataset_input_fn 从 tfrecords 加载数据的方式存在问题。我的输入函数是仿照 example in the Tensorflow documentation. The issue arises when I have more examples than I can fit into RAM. If I have 1e6 examples, and set my shuffle buffer_size to 1e5, a subset of 1e5 examples is selected once, shuffled, and then iterated on. Meaning my model is only trained on 10% of my overall dataset. My code that sets up this behavior is borrowed exactly from the Tensorflow documentation example code:
dataset = dataset.map(parser)
dataset = dataset.shuffle(buffer_size=10000)
dataset = dataset.batch(32)
dataset = dataset.repeat(num_epochs)
iterator = dataset.make_one_shot_iterator()
我的问题: 是否可以在我训练时用初始 1e5 之外的新示例填充洗牌缓冲区? one_shot_iterator 是否支持此类功能?我需要使用可初始化的迭代器吗?
谢谢!
我发现了目前看来可行的解决方法。通过一些实验,我了解到在实例化 TFRecordDataset 时,
filenames = ["file1.tfrecord", ..., "filen.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)
并设置随机播放缓冲区:
dataset = dataset.shuffle(buffer_size=10000)
缓冲区只填充前 10000 个示例,无论需要多少 tf 记录。例如,在我的例子中,我有大约 300 个 tfrecord 文件,每个文件包含 4096 个示例。检查时,我的随机播放缓冲区似乎只包含文件名列表中前 3 个 tf 记录的示例。由于我的文件名列表是静态的,这意味着我的模型只训练了我的前 3 个 tfrecords!
我目前的解决方法非常简单。在我的训练循环中,我已经在 Estimator.train 和 Estimator.evaluate 之间交替,并且我注意到每次调用 Estimator.train 时,洗牌缓冲区都会重新填充。我的解决方案是每次调用我的 input_fn 时随机播放我的文件名。这不是一个非常优雅的解决方案,但确实达到了允许我遍历所有 tfrecords 的预期效果。
#My Crappy Fix: shuffle file names in input_fn
np.random.shuffle(filenames)
dataset = tf.data.TFRecordDataset(filenames)
这个解决方案令人恼火的地方(除了它的笨拙)是我的小批量不是 "globally random"。相反,它们是从 tf 记录的一小部分中选择的,并且每个 training/evaluation 周期仅使用该子集。缓解这种情况的一种方法是增加我的随机播放缓冲区大小或减少我的 tfrecord 大小,我可能会同时执行这两种操作。最后,我认为值得注意的是 if
shuffle_buffer_size < (tf_record_size + minibatch_size)
然后,据我所知,我的 TFRecordDataset 将从单个 tfrecord 文件中提取!
最后,我认为 relevant tensorflow documentation 没有很好地表达这些复杂性。该文档提到了在不适合内存的大型数据集上进行训练的能力,但没有提供太多细节。 tf 作者在写这篇文章时似乎不太可能考虑到我的 hacky 策略,所以我仍然很好奇是否有更好的方法。