Tensorflow:如何在 GPU 上从 CPU tf.data.Dataset (from_generator) 预取数据
Tensorflow: How to prefetch data on the GPU from CPU tf.data.Dataset (from_generator)
我正在努力解决以下问题。我正在使用 from_generator 方法创建 tf.data.Dataset。我在 CPU 上执行这些操作,因为我不想让我的 GPU 内存过载。
数据集由元组组成,其中包含固定长度的 tf.bool 一维掩码 (tf.Tensor) 和 tf.float 二维矩阵 (tf.Tensor) 具有可变大小。损失函数是使用以下装饰器装饰的,所以我不认为变量大小是问题所在。
@tf.function(experimental_relax_shapes=True)
理想情况下,数据集保存在 CPU 上,然后预取到 GPU 上。
def gen():
for i, j in zip(mask_list, wmat_list):
yield i, j
dataset = tf.data.Dataset.from_generator(gen, output_types=(tf.bool, tf.float32))
主训练循环目前依赖tf.identity将数据移动到gpu,效率低下。如下面的 Tensorboard 截图所示。大约 70% 的时间用于加载数据并将其移动到 GPU。
for b, (mask, wmat) in enumerate(dataset):
with tf.GradientTape() as tape:
mask = tf.identity(mask)
wmat = tf.identity(wmat)
mean_error, loss = self.model.loss(mask, wmat)
epoch_loss += loss.numpy()
epoch_mean_error += mean_error.numpy()
我试过“prefetch_to_device”功能。但是,它并没有将数据移动到 GPU 上。通过打印验证,例如mask.device 在训练循环中。
gpu_transform = tf.data.experimental.prefetch_to_device('/gpu')
dataset.apply(gpu_transform)
对我来说,它类似于这个错误:https://github.com/tensorflow/tensorflow/issues/30929。然而,它被标记为已解决并且已经超过一年了。
运行 TF 2.3 使用官方 Docker 图片。
我找到了我自己的问题的解决方案。
问题是数据集中的元组 不 包含 tf.Tensors,而是 numpy 数组。因此,管道可能受到 py_func().
功能的限制
下面的屏幕截图显示管道在 CPU 上没有阻塞。但是仍然有相当大的 MemCpy。 prefetch_to_device() 仍然没有做任何事情。这可能是由于已知问题导致的,该问题应在 TF2.4
中修复
https://github.com/tensorflow/tensorflow/issues/35563
(未经证实的)建议的解决方法对我也不起作用。(见编辑)
with tf.device("/gpu:0"):
ds = ds.prefetch(1)
编辑:
我已进一步调查此问题并提交了错误报告。现在看来,建议的解决方法确实有所作为,但不确定它是否及时完全预取。
https://github.com/tensorflow/tensorflow/issues/43905
我正在努力解决以下问题。我正在使用 from_generator 方法创建 tf.data.Dataset。我在 CPU 上执行这些操作,因为我不想让我的 GPU 内存过载。
数据集由元组组成,其中包含固定长度的 tf.bool 一维掩码 (tf.Tensor) 和 tf.float 二维矩阵 (tf.Tensor) 具有可变大小。损失函数是使用以下装饰器装饰的,所以我不认为变量大小是问题所在。
@tf.function(experimental_relax_shapes=True)
理想情况下,数据集保存在 CPU 上,然后预取到 GPU 上。
def gen():
for i, j in zip(mask_list, wmat_list):
yield i, j
dataset = tf.data.Dataset.from_generator(gen, output_types=(tf.bool, tf.float32))
主训练循环目前依赖tf.identity将数据移动到gpu,效率低下。如下面的 Tensorboard 截图所示。大约 70% 的时间用于加载数据并将其移动到 GPU。
for b, (mask, wmat) in enumerate(dataset):
with tf.GradientTape() as tape:
mask = tf.identity(mask)
wmat = tf.identity(wmat)
mean_error, loss = self.model.loss(mask, wmat)
epoch_loss += loss.numpy()
epoch_mean_error += mean_error.numpy()
我试过“prefetch_to_device”功能。但是,它并没有将数据移动到 GPU 上。通过打印验证,例如mask.device 在训练循环中。
gpu_transform = tf.data.experimental.prefetch_to_device('/gpu')
dataset.apply(gpu_transform)
对我来说,它类似于这个错误:https://github.com/tensorflow/tensorflow/issues/30929。然而,它被标记为已解决并且已经超过一年了。
运行 TF 2.3 使用官方 Docker 图片。
我找到了我自己的问题的解决方案。
问题是数据集中的元组 不 包含 tf.Tensors,而是 numpy 数组。因此,管道可能受到 py_func().
功能的限制下面的屏幕截图显示管道在 CPU 上没有阻塞。但是仍然有相当大的 MemCpy。 prefetch_to_device() 仍然没有做任何事情。这可能是由于已知问题导致的,该问题应在 TF2.4
中修复https://github.com/tensorflow/tensorflow/issues/35563
(未经证实的)建议的解决方法对我也不起作用。(见编辑)
with tf.device("/gpu:0"):
ds = ds.prefetch(1)
编辑:
我已进一步调查此问题并提交了错误报告。现在看来,建议的解决方法确实有所作为,但不确定它是否及时完全预取。 https://github.com/tensorflow/tensorflow/issues/43905