如何使用 Tensorflow 的数据集将数据移动到多个 GPU 塔 API
How does one move data to multiple GPU towers using Tensorflow's Dataset API
我们正在 Tensorflow 上 运行 宁多 GPU 作业,并评估从基于队列的模型(使用 string_input_producer 接口)到新的 Tensorflow 数据集 API 的迁移。后者似乎提供了一种更简单的方法来同时在训练和验证之间切换。
下面的一段代码展示了我们是如何做到这一点的。
train_dataset, train_iterator = get_dataset(train_files, batch_size, epochs)
val_dataset, val_iterator = get_dataset(val_files, batch_size, epochs)
is_validating = tf.placeholder(dtype=bool, shape=())
next_batch = tf.cond(is_validating,
lambda: val_iterator.get_next(),
lambda: train_iterator.get_next())
validation_tower = self.num_gpus - 1
tower_grads = []
for i in range(self.num_gpus):
with tf.variable_scope(tf.get_variable_scope(),reuse=(i > 0)):
with tf.device('/gpu:%d' % i), tf.name_scope('%s_%d' % ('gpu_', i)) as scope:
if i == validation_tower:
images, labels = next_batch
# Loss funcs snipped out
else:
images, labels = next_batch
# Loss funcs snipped out
get_dataset函数构建数据集,设置地图函数和批量大小。它还构建了一个迭代器,但不对其进行初始化。迭代器的初始化发生在会话开始之前。
在会话 运行ning 时提供 is_validating 布尔值,每隔几步我们通过 feed_dict 将 is_validating 作为 True 传递以使用验证数据集
我的问题是:
假设我有 8 个 GPU,所以我们 运行 在 7 个 GPU 上训练。迭代器是否从这 7 个 GPU 中的每一个的相同点前进,从而为所有 7 个 GPU 提供相同的数据?
目前主要有三个选项,它们具有不同的可用性和性能权衡:
在 Dataset.batch()
transform, create a single large batch containing examples for all of your GPUs. Then use tf.split(..., self.num_gpus)
的输出上 Iterator.get_next()
为每个 GPU 创建子批次。这可能是最简单的方法,但它确实将拆分放在了关键路径上。
在 Dataset.batch()
转换中,创建一个大小适合单个 GPU 的小批量。然后每个 GPU 调用一次 Iterator.get_next()
以获得多个不同的批次。 (相比之下,在您当前的代码中,相同的 next_batch
值被发送到每个 GPU,这可能不是您想要的。)
创建多个迭代器,每个 GPU 一个。在管道的早期使用 Dataset.shard()
对数据进行分片(例如,如果您的数据集已分片,则在文件列表中)。请注意,此方法会消耗主机上的更多资源,因此您可能需要调低任何缓冲区大小and/or 并行度
请注意,当前 tf.data
流水线 运行 仅在 CPU 上,高效流水线的一个重要方面是将训练输入暂存到 GPU,而上一步是还是运行宁。请参阅 TensorFlow CNN benchmarks 示例代码,其中显示了如何高效地将数据暂存到 GPU。我们目前正在努力将此支持直接添加到 tf.data
API。
我们正在 Tensorflow 上 运行 宁多 GPU 作业,并评估从基于队列的模型(使用 string_input_producer 接口)到新的 Tensorflow 数据集 API 的迁移。后者似乎提供了一种更简单的方法来同时在训练和验证之间切换。
下面的一段代码展示了我们是如何做到这一点的。
train_dataset, train_iterator = get_dataset(train_files, batch_size, epochs)
val_dataset, val_iterator = get_dataset(val_files, batch_size, epochs)
is_validating = tf.placeholder(dtype=bool, shape=())
next_batch = tf.cond(is_validating,
lambda: val_iterator.get_next(),
lambda: train_iterator.get_next())
validation_tower = self.num_gpus - 1
tower_grads = []
for i in range(self.num_gpus):
with tf.variable_scope(tf.get_variable_scope(),reuse=(i > 0)):
with tf.device('/gpu:%d' % i), tf.name_scope('%s_%d' % ('gpu_', i)) as scope:
if i == validation_tower:
images, labels = next_batch
# Loss funcs snipped out
else:
images, labels = next_batch
# Loss funcs snipped out
get_dataset函数构建数据集,设置地图函数和批量大小。它还构建了一个迭代器,但不对其进行初始化。迭代器的初始化发生在会话开始之前。
在会话 运行ning 时提供 is_validating 布尔值,每隔几步我们通过 feed_dict 将 is_validating 作为 True 传递以使用验证数据集
我的问题是:
假设我有 8 个 GPU,所以我们 运行 在 7 个 GPU 上训练。迭代器是否从这 7 个 GPU 中的每一个的相同点前进,从而为所有 7 个 GPU 提供相同的数据?
目前主要有三个选项,它们具有不同的可用性和性能权衡:
在
Dataset.batch()
transform, create a single large batch containing examples for all of your GPUs. Then usetf.split(..., self.num_gpus)
的输出上Iterator.get_next()
为每个 GPU 创建子批次。这可能是最简单的方法,但它确实将拆分放在了关键路径上。在
Dataset.batch()
转换中,创建一个大小适合单个 GPU 的小批量。然后每个 GPU 调用一次Iterator.get_next()
以获得多个不同的批次。 (相比之下,在您当前的代码中,相同的next_batch
值被发送到每个 GPU,这可能不是您想要的。)创建多个迭代器,每个 GPU 一个。在管道的早期使用
Dataset.shard()
对数据进行分片(例如,如果您的数据集已分片,则在文件列表中)。请注意,此方法会消耗主机上的更多资源,因此您可能需要调低任何缓冲区大小and/or 并行度
请注意,当前 tf.data
流水线 运行 仅在 CPU 上,高效流水线的一个重要方面是将训练输入暂存到 GPU,而上一步是还是运行宁。请参阅 TensorFlow CNN benchmarks 示例代码,其中显示了如何高效地将数据暂存到 GPU。我们目前正在努力将此支持直接添加到 tf.data
API。