子进程是否可以直接将数据交给Tensorflow而不经过主Python进程(避免GIL锁)?

子进程是否可以直接将数据交给Tensorflow而不经过主Python进程(避免GIL锁)?,python,tensorflow,subprocess,Python,Tensorflow,Subprocess,我使用的是高IO模式(单个GPU可以处理每秒600 MB的不可压缩数据)。它需要大约4个CPU核来单独处理IO,因此主训练循环进程无法完成这一任务 目前,我有多个子进程从分布式文件系统中采样数据并写入本地tfrecords文件(数据集大小超过本地存储)。我的主要培训过程使用TFRecordsDataset&tf.data.Dataset.from_generator在文件写入磁盘时对其进行迭代 它可以工作,但仅仅为了再次读取而写入磁盘显然是次优的。我想知道是否有更好的方法可以使用子流程将样本直接

我使用的是高IO模式(单个GPU可以处理每秒600 MB的不可压缩数据)。它需要大约4个CPU核来单独处理IO,因此主训练循环进程无法完成这一任务

目前,我有多个子进程从分布式文件系统中采样数据并写入本地tfrecords文件(数据集大小超过本地存储)。我的主要培训过程使用
TFRecordsDataset
&
tf.data.Dataset.from_generator
在文件写入磁盘时对其进行迭代

它可以工作,但仅仅为了再次读取而写入磁盘显然是次优的。我想知道是否有更好的方法可以使用子流程将样本直接传递给Tensorflow。我不能通过Python将数据传递到主培训过程,因为它需要超过1个CPU核心来移动那么多数据,而且Python的GIL瓶颈


我试图将数据写入命名管道,但TFRecordsDataset执行查找操作,因此无法从管道中读取数据,只能读取文件。还有其他想法吗?

我想到了几件事

如果尚未这样做,请将本地数据放在SSD上(如果可能,请放在NVMe上)。这在不需要任何代码更改的情况下提供了显著的加速

您可以尝试使用
mmap
读取/写入本地文件。操作系统将把最近访问的页面保存在内存中;磁盘缓存中可以容纳的数量。如果一个程序写入数据,其他程序读取数据,这就像共享内存,但有一个类似文件的接口

您可以使用套接字在进程之间传输数据

例如,见本节


如果您使用的是类UNIX系统,则可以通过
ctypes
使用POSIX共享内存。当然,如果您可以从
多处理
使用3.8的共享内存,那可能会容易得多。

您可以将共享内存与来自张量
(或来自张量切片
)的
或来自自定义生成器的
结合使用吗?
TFRecordDataset
是由一个文件显式支持的。Python 3.8共享内存似乎是最好的解决方案,TF2.2几乎支持3.8。我很期待这一点。我已经将其降低到套接字级别,以便将数据传输到主进程中,但要如此快速地移动数据,仍然需要花费太多的CPU,GIL成为一个瓶颈,即使是基于套接字的数据传输,也需要多个内核。本地磁盘是NVMe,但它是500 GB,数据集是3TB,因此不能选择整个数据集的本地存储。确实有必要绕过Python,GIL是Python的一个主要限制。NVMe能够处理先写后读的IO,这就是我现在所做的,只是不理想。目前,我在本地保留了一个100GB的旋转样本子集。我肯定遗漏了一些东西,因为在进程之间移动数据时,GIL不应该是一个因素,除非您使用的是
多处理
线程
。您的帖子明确提到了
子进程
,但没有提到
多处理
线程化
。我做了一个非常低级的测试,以了解使用套接字在python进程之间移动数据的速度。我得到了每秒4GB的移动速度,在读取端使用了一个完整的内核。那就是阅读和抛弃。当我在读取端加入字节数组时,速度减半到2GB/秒,读取端使用了一个完整的内核。当我使用更高级别的工具(如python Pipe)尝试此操作并尝试为tensorflow提供数据时,我总是将CPU锁定在主培训过程中。在反序列化过程中,问题变成CPU受限。当我写入tfrecords文件并让tensorflow使用
TFReacordDataset
读取时,CPU在训练过程中占400%,但这是在tensorflow中,在Python的GIL之外。因此,在实际数据速率上的基本序列化操作需要大约4个内核。tensorflow可以很好地并行化,但是单个Python进程不能(由于GIL限制为大约1个内核)值得注意的是,Python 3.8共享内存在理论上应该可以解决这个问题,因为在进程之间传输数据时不再需要序列化,只需传递一个微不足道的字符串指针。但由于tensorflow还不支持3.8,所以我想验证一下,我没有错过其他选项。