【发布时间】:2020-01-10 18:33:44
【问题描述】:
为了在训练期间充分利用 GPU,我需要能够向 GPU 提供大约 250 MB/s 的原始数据(数据不可压缩)。我正在通过快速网络访问数据,该网络可以毫无问题地提供超过 2GB/秒的数据。 Python 的 GIL 使得在不对训练循环产生负面影响的情况下,将这些速度融入到运行 TensorFlow 的同一进程中变得相当困难。 Python 3.8 的共享内存可能会缓解这种情况,但 Tensorflow 尚不支持。
所以我使用tf.io.gfile.GFile 通过网络读取数据(数据存储在高带宽 S3 兼容接口上)。 GFile 的价值在于它不参与 GIL,因此可以很好地与训练循环配合使用。为了实现高吞吐量,需要对网络 IO 进行显着的并行化。
不过,我似乎只能通过这种方法获得大约 75-100 MB/秒的速度。
我已经为两种方法计时:
- 创建一个
tf.data.Dataset并使用tf.data.Dataset.map(mymapfunc, num_parallel_calls=50)(我尝试了许多num_parallel_calls 的值,包括AUTOTUNE)。 - 创建一个使用
tf.io.gfile.GFile读取数据的函数,并在concurrent.futures.ThreadPoolExecutor中使用多个线程简单地运行它,尝试线程数达到大约100 个(大约20 个以上没有任何改进,最终更多的线程会减慢它的速度)。
在这两种情况下,我的最高速度都是 75-100 MB/秒。
问题:
我想知道
GFile是否有理由达到可能更高的上限 对其他人来说是显而易见的。我也在做一个我应该验证的假设:
tf.io.gfile.GFile在 numpy 土地上运行,在上述两种情况下,我都在运行GFile操作 来自 python 土地(在tf.data.Dataset的情况下,我正在使用tf.py_function)。如果 GFile 旨在作为图形的一部分运行 更有效地运营我不知道这一点,需要 已更正。
【问题讨论】:
-
是的,在 S3 方面,管理员监控显示当我运行多个作业时,在我这边,我使用多个运行 asyncio 的 Python 进程将 1+GB/sec 基准测试到单个 pod以及针对 S3 接口的 500-1000 次并行操作。这是一个运行 Ceph 分布式文件系统的大型 kubernetes 集群。我非常确信瓶颈不在 S3 上,但如果其他人从 gfile 中看到高于 100MB/秒的速度,我很想听听。
-
但是,如果不将 GIL 完全锁定在主要 python 进程中,您就无法将 1GB/秒的数据从一个 python 进程移动到另一个进程,这会阻止 tensorflow 训练循环快速迭代,从而阻碍GPU ,所以在我可以尝试 python 3.8 和 SystemV 共享内存之前,多处理和多线程都不能很好地与 GPU 上的训练循环配合使用。这就是 gfile 的吸引力所在,它不会锁定 GIL。
-
当您说您尝试过
Dataset.map时,是不是就像DatasetReader(filename).map(...)?这试图通过一个来压缩所有数据。你看过Dataset.interleave吗,它更像FileNamesDataset().interleave(lambda f:DatasetReader(f))通过多个连接流式传输......曾经有一个“sloppy_interleave”选项可以提高性能,因为它可以跳过停滞的连接......但这似乎已经消失了tf2 可能隐藏在tf.data.Options.experimental_deterministic中。 -
map接收到一组要下载的文件段(文件名、偏移量、长度),大小为 5-30 MB,map 函数为每个段打开一个 gfile 并执行seek和read。针对 S3 接口打开 gfile 似乎没有任何明显的开销,因此我没有缓存该操作。我期待num_parallel_calls是并行化的。由于我在线程池中看到了相同的行为,因此我并没有过多地质疑 map 操作。 -
“地图接收到一组要下载的文件段”听起来不错。 “大小为 5-30 MB”我听说每个文件 100 MB 的建议以获得最佳性能,但谁知道这是否会有所帮助。
标签: python-3.x tensorflow tensorflow-datasets