【问题标题】:Keras with Tensorflow: Use memory as it's needed [ResourceExhaustedError]带有 Tensorflow 的 Keras:根据需要使用内存 [ResourceExhaustedError]
【发布时间】:2018-06-26 03:11:51
【问题描述】:

所以我试图用多个数据集来维护我的 CNN,当我添加足够的数据时(例如,当我将多个集合作为一个集合添加时,或者当我尝试添加具有超过一百万个样本的集合时)它会接缝抛出ResourceExhaustedError

至于here的说明,我尝试添加

from keras.backend.tensorflow_backend import set_session
import tensorflow as tf
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.3
set_session(tf.Session(config=config))

我的代码,但这并没有什么不同。 我在打印出config.gpu_options.per_process_gpu_memory_fraction 后看到 0.3,所以部分接缝没问题。

我什至投了一个config.gpu_options.allow_growth = True 以获得良好的测量结果,但它并不想做任何事情,只是尝试一次使用所有内存,却发现这还不够。

我试图用来训练这个 CNN 的计算机有 4 个 GTX1080 Ti,每个都有 12gb 的专用内存。

编辑:我很抱歉没有说明我是如何加载数据的,老实说,我没有意识到有不止一种方法。在我学习的时候,他们总是有加载已经内置的数据集的示例,我花了一段时间才意识到如何加载自提供的数据集。

我这样做的方式是创建两个 numpy 数组。一个具有路径或每个图像,另一个具有相应的标签。这是最基本的例子:

data_dir = "folder_name"

# There is a folder for every form and in that folder is every line of that form
for filename in glob.glob(os.path.join(data_dir, '*', '*')):

    # the format for file names are: "{author id}-{form id}-{line number}.png"
    # filename is a path to the file so .split('\\')[-1] get's the raw file name without the path and .split('-')[0] get's the author id
    authors.append(filename.split('\\')[-1].split('-')[0])
    files.append(filename)

#keras requires numpy arrays 
img_files  = np.asarray(files)
img_targets = np.asarray(authors)

【问题讨论】:

  • 这通常发生在 GPU 上没有足够的 RAM 来加载整个数据集(或其中的一批)时。您也可以发布您的代码吗?此外,如果您的图像文件在硬盘上,您是否尝试过使用ImageDataGenerator 类及其flow_from_directory 方法?另外,您应该 properly set up your model 能够在多个 GPU 上训练它。
  • 我不会发布我的整个代码,因为其中很多是不相关的,而且因为它很长而且需要更多的时间来完成它,而不是对这里的大多数人来说是值得的,但我会如果您愿意,很乐意发布代码的特定部分。我会尝试使用 ImageDataGenerator。让我们看看发生了什么。感谢您的回复
  • 在查看了 ImageDataGenerator 之后,我意识到我实际上是在代码中自己手动完成的。我对其进行了测试,它可以正常工作,而且使用 Keras 的那个对我来说不起作用,因为我需要拆分每个图像而不是简单地调整它的大小
  • 请发布您的生成器和适合的方法。
  • @The-IT 然后发布相关部分,例如网络架构(即使用的层)、fit_generator 方法和生成器本身。

标签: python tensorflow keras deep-learning


【解决方案1】:

你确定你用的不是巨型batch_size

“添加数据”:老实说,我不知道这是什么意思,如果你能用代码准确描述你在这里做什么,那会有所帮助。

样本数量根本不会对 GPU 内存造成任何问题。导致问题的是batch_size

加载庞大的数据集可能会导致 CPU RAM 问题,与 keras/tensorflow 无关。 numpy 数组太大的问题。 (您可以通过“不创建任何模型”简单地加载数据来测试它)

如果这是您的问题,您应该使用generator 逐步加载批次。同样,由于您的问题中绝对没有代码,我们无能为力。

但这是简单地为图像创建生成器的两种形式:

  • 使用现有的ImageDataGeneratorflow_from_directory() 方法,explained here
  • 创建您自己的编码生成器,它可以是:

循环生成器的简单示例:

def imageBatchGenerator(imageFiles, imageLabels, batch_size):
    while True:
        batches = len(imageFiles) // batch_size
        if len(imageFiles) % batch_size > 0:
            batches += 1

        for b in range(batches):
            start = b * batch_size
            end = (b+1) * batch_size

            images = loadTheseImagesIntoNumpy(imageFiles[start:end])
            labels = imageLabels[start:end]

            yield images,labels

警告:即使使用生成器,您也必须确保批量大小不要太大!

使用它:

model.fit_generator(imageBatchGenerator(files,labels,batchSize), steps_per_epoch = theNumberOfBatches, epochs= ....)

在 GPU 之间划分模型

您应该能够决定哪个层由哪个 GPU 处理,这“可以”优化您的 RAM 使用率。

例如,创建模型时:

with tf.device('/gpu:0'):
    createLayersThatGoIntoGPU0

with tf.device('/gpu:1'):
    createLayersThatGoIntoGPU1

#you will probably need to go back to a previous GPU, as you must define your layers in a proper sequence
with tf.device('/cpu:0'):
    createMoreLayersForGPU0

#and so on

我不确定这是否会更好,但也值得尝试。

在此处查看更多详细信息:https://keras.io/getting-started/faq/#how-can-i-run-a-keras-model-on-multiple-gpus

【讨论】:

  • 1:是的。我曾多次尝试调整批次大小,即使大小为 2 也会引发相同的错误。 2:我的意思是最直接的方式。我有很多数据,我开始对大约 600 个样本进行训练,除了它过度拟合之外,我认为我可以通过从数据集中加载更多样本来改变它。当我达到 1000 个样本时,就会发生此错误。 3:加载数据接缝对我来说不是问题,尽管我想这取决于你的意思。我通过创建两个带有标签和类的 numpy 数组来“加载数据”...继续
  • 即使在创建这些包含超过一百万个样本(一个标签和一个相应的类)的数组时,接缝也没有问题。输入模型的是来自生成器函数的图像,该生成器函数对图像进行一些预处理,包括将它们拆分并单独传递每个部分。将尝试使用 ImageDataGenerator。感谢您的回复
  • 在查看了 ImageDataGenerator 之后,我意识到我实际上是在代码中自己手动完成的。我对其进行了测试,它可以正常工作,而且使用 Keras 的那个对我来说不起作用,因为我需要拆分每个图像而不是简单地调整它的大小
【解决方案2】:

ResourceExhaustedError 被引发是因为您尝试分配的内存比 GPU 或主内存中的可用内存多。内存分配大约等于您的网络占用空间(要估计这一点,请保存检查点并查看文件大小)加上您的批量大小乘以数据集单个元素的大小。

如果没有有关您的设置的更多信息,很难直接回答您的问题,但这个问题的一个元素引起了我的注意:您说当您“添加足够的数据”或“使用大足够的数据集。”这很奇怪。请注意,数据集的大小不包括在内存分配占用的计算中。因此,数据集的大小应该无关紧要。既然如此,这似乎意味着您正试图以某种方式将整个数据集加载到 GPU 内存或主内存中。如果你这样做,那就是你问题的根源。要修复它,请使用 TensorFlow Dataset API。使用Dataset 通过将数据隐藏在Iterator 后面来回避这种有限的内存资源,该Iterator 仅在调用时产生批次。或者,您可以使用较旧的 feed_dictQueueRunner 数据馈送结构,但我不推荐它。你可以找到这个here 的一些例子。

如果您已经在使用 Dataset API,您需要发布更多代码作为对您问题的修改,以便我们为您提供帮助。

【讨论】:

    【解决方案3】:

    没有任何设置可以神奇地让您拥有比 GPU 更多的内存。在我看来,您的输入太大以适合 GPU RAM(以及所有必需的状态和梯度)。 您应该使用config.gpu_options.allow_growth = True,但不是为了获得更多内存,只是为了了解每个输入长度需要多少内存。从较小的长度开始,查看nvidia-smi 您的 GPU 占用多少 RAM,然后增加长度。一遍又一遍地这样做,直到您了解 GPU 可以容纳的最大输入长度(批量大小)是多少。

    【讨论】:

    • 我不是想获得更多内存,我是想让 Tensorflow 不尝试一次使用所有内存,而只使用处理当前样本所需的内存量。我从你这里得到的是,我的批量大小对于我的数据集来说太大了,对吧?
    • Tensorflow 默认情况下会占用 GPU 中的所有内存,以确保其安全以供以后使用。大多数情况下,这是所需的行为,因为它保证您在整个会话期间拥有最大的可用内存。如果您希望 tensorflow 仅分配实际运行所需的内容,只需如前所述设置“allow_growth = True”。现在,如果您将其设置为 True 并且仍然看到所有 RAM 已被占用 - 这意味着需要所有 RAM,如果不是更多的话!
    猜你喜欢
    • 1970-01-01
    • 2018-02-11
    • 1970-01-01
    • 2016-08-01
    • 2019-06-06
    • 2012-12-15
    • 2018-02-15
    • 1970-01-01
    • 2020-06-12
    相关资源
    最近更新 更多