TensorFlow 数据集导致内核在迭代期间终止进程

Posted

技术标签:

【中文标题】TensorFlow 数据集导致内核在迭代期间终止进程【英文标题】:TensorFlow dataset causes kernel to kill the process during iteration 【发布时间】:2022-01-09 22:52:32 【问题描述】:

我想创建一个用于训练 TensorFlow 模型的数据管道。数据存储在非常大的 HDF5 文件中 (250+ GB)。

我编写了一个适用于较小输入文件的管道,但在消耗过多 RAM+swap 后最终被内核杀死(通过监控验证了这一点)。

import tensorflow as tf
import h5py

class TestGenerator:
    """
    Implements a generator that can be used by tf.data.Dataset.from_generator 
    to produce a dataset for any test data.
    """
    def __init__(self, src, dset):
        self.src = src
        self.dset = dset
        self.output_signature = (
            tf.TensorSpec(shape=(2,), dtype=tf.uint64)
        )

    def __call__(self):
        """This is needed for tf.data.Dataset.from_generator to work."""
        with h5py.File(self.src, 'r', swmr=True) as f:
            for sample in f[self.dset]:
                yield sample[0], sample[1]

gen = TestGenerator('h5file.h5', 'dset_path')

dataset = tf.data.Dataset.from_generator(
    gen, 
    output_signature=gen.output_signature
)

for sample in dataset:
    pass

一开始我以为这可能是h5py模块的问题,所以单独测试了一下:

with h5py.File('h5file.h5', 'r', swmr=True) as f:
    for sample in f['dset_path']:
        pass

这没有问题。由此得出结论,TensorFlow 是造成内存问题的原因。让我恼火的是,我假设 TensorFlow 可以即时获取所需的数据,因此可以避免内存问题。

代码经过测试,适用于较小的文件。我还测试了在迭代之前使用dataset.prefetch 的版本,但结果相同。

TensorFlow 是否会在后台加载整个数据集?

【问题讨论】:

【参考方案1】:

如果你打开任务管理器,在导入 tensorflow 和创建模型时,它会显示 GPU 内存保留的极高值吗?

如果是这样,可能不是模型或数据的大小,而是 tensorflow 为所有模型训练保留尽可能多的内存这一事实。

就我个人而言,我的 3080 有 10 GB 的专用 GPU 内存,而 tensorflow 占用了 9.7 GB。

如果是这种情况,请查看https://www.tensorflow.org/guide/gpu#limiting_gpu_memory_growth 上的 set_memory_growth 方法。

使用它可以将我的专用 GPU 内存使用量从 9.7GB 减少到 3.2GB 和 4GB 之间。

编辑:我不确定它会在什么时候分配该内存,但是如果您尝试训练模型并密切关注 GPU 的任务管理器性能,您应该会发现它是否以这种方式运行!

【讨论】:

我尝试了所有建议,但不幸的是,它没有成功。我认为这是因为 TF 数据不使用 GPU 及其内存。我使用watch -n 1 free -m 监控系统上的 RAM 内存分配,很容易看到可用空间逐渐减少,直到几乎为零。发生这种情况时,进程会被内核杀死并释放内存。 啊,这听起来更像是您试图加载太多信息?我不确定,但你能进一步定义你提到的“RAM+swap”吗?因为你的 GPU 内存需要 1) 足够的内存来运行模型和 2) 足够的内存来获取数据,也就是说,从 RAM 到 GPU 内存的副本? 感谢您的帮助,但似乎我在底层 h5py 库中遇到了一个错误。我从上面的测试代码中省略的是我在数据集上使用了切片运算符,例如f['dataset'][start:stop] 选择数据子集。切片似乎导致将所有选定的数据复制到 RAM 中。不过,我通过在可迭代对象上使用 itertools.islice 找到了一种解决方法。我将保留此主题,因为它可能对其他人有所帮助。

以上是关于TensorFlow 数据集导致内核在迭代期间终止进程的主要内容,如果未能解决你的问题,请参考以下文章

python Tensorflow中的数据集可以在Eager Execution模式下迭代。

迭代 Tensorflow 数据集总是返回一个不同排序的数组

恢复使用迭代器的 TensorFlow 模型

Tensorflow 数据集 API 中的过采样功能

有没有办法堆叠两个 tensorflow 数据集?

如何在 RNN TensorFlow 中使用非常大的数据集?