【问题标题】:Python Keras code out of memory for no apparent reasonPython Keras 代码无故内存不足
【发布时间】:2020-07-15 14:33:03
【问题描述】:

考虑以下代码,该代码适用于 CIFAR-10 数据集上的 Keras Sequential 模型。背景在文末给出:

import tensorflow as tf
from sklearn.datasets import fetch_openml
from sklearn.utils import shuffle

data, targets = shuffle(*fetch_openml('CIFAR_10', version=1, return_X_y=True))
train_sz = 50000
X_train, X_test, y_train, y_test = data[:train_sz, :], data[train_sz:, :], np.asarray(targets[:train_sz], dtype=np.int), np.asarray(targets[train_sz:], dtype=np.int)

model = tf.keras.Sequential()
model.add(tf.keras.Input(shape=(X_train.shape[1],)))
model.add(tf.keras.layers.Dense(64, activation='relu'))
model.add(tf.keras.layers.Dense(10))
model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), optimizer='adam')

s = 0
for _ in range(500):
    for i in range(100):
        layers = []
        for layer in model.get_weights():
            layers.append(np.random.normal(0, 1, layer.shape))
        model.set_weights(layers)
        eval = model.evaluate(X_train, y_train)
        s += eval
        print(f'Done {i}')
print(s)

在外部 for 循环大约 1 次(有时在此之前,有时在之后)迭代之后,Python 崩溃并出现退出代码 137,这通常意味着内存不足 AFAIK。我的系统上有 16 GB 的内存,其中大约 20% 在运行之前使用。运行后,它会稳步增长到 大约 80%-90% 的内存使用率,然后下降到 60%-70%(GC 启动?),然后再次增加,以此类推,持续 2-3 次,直到最终崩溃。

我在无头 Ubuntu 18.04 服务器机器上,在 Anaconda 中使用 Python 3.7,在 Tensorflow 2.2 上使用 Titan X GTX GPU,该 GPU 没有用于其他任何事情(因此那里大约有 11GB 的可用内存)。

我的计算(当然,非常悲观):

  1. 运行此程序时,我有大约 12 GB 可用空间。
  2. 存储数据使用60000*32*32*3 浮点数,这对于float64s 大约是1500 MB。由于我正在制作的所有副本,让我们在此处放下 6 GB。不管怎样,这似乎是占用内存最多的地方。
  3. 此时层大小可以忽略不计:X_train.shape[1] 为 3072 (32*32*3),64 个隐藏单元算不了什么。
  4. model.evaluate 的默认批量大小为 32,因此在其中,它应该使用大约 32*32*32*3*64 float64s 作为中间层的输出。那是 50 MB,让我们在此处输入 1 GB 以再次确定。
  5. model.evaluate 可能还需要存储预测,所以这是 50000*10 float64s,又是 4 MB。让我们在此处再添加一个 1 GB

总计:6 + 1 + 1 = 8 GB。我的内存使用绝对不应该超过 80%,而且我高估了很多。

为什么要使用这么多内存,我可以优化管理数据的方式吗?

我尝试使用np.asarray 将X 强制为np.int,float64s 没有意义,但这只会让它崩溃得更快——就像它将float64s 和ints 都保留在内存中一样。

背景

我正在研究一种训练人工神经网络的遗传算法。我已经将崩溃追溯到适应度的计算,这涉及将存储在每个个体中的训练权重应用于神经网络并评估网络(内部 i 循环,我的人口中有 100 个人)。这对每一代重复(最外层的 for 循环)。那里使用了更多的内存,但仍然很少。

这就是为什么这里没有进行拟合,权重由我的遗传算法确定并应用于网络。

这个简化的代码重现了这个问题。

【问题讨论】:

  • Related: github.com/keras-team/keras/issues/13118 or github.com/tensorflow/tensorflow/issues/33030 只是在模型上重复调用evaluatepredict 会导致OOM,使用的数据或操纵权重似乎无关紧要。
  • @IVIAd 我知道了,你看到我最后的三个厘米了吗
  • 不使用GPU是否存在问题?我没有任何特别的期望,但是如果 CPU 出现这种情况,那将排除这是 GPU 问题的可能性。禁用 GPU 的前导代码:import os; os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"; os.environ["CUDA_VISIBLE_DEVICES"] = ""
  • @dannyadam 是的,确实如此。请注意,超出了系统内存,而不是 GPU 内存。
  • 解决方法和讨论在这里:github.com/tensorflow/tensorflow/issues/41428 - 如果有人建议其他解决方法或可以提供解释,我会暂时保留它,然后决定如何处理赏金。

标签: python python-3.x numpy tensorflow keras


【解决方案1】:

我能够在具有 12GB 内存的 google colab GPU 实例上的笔记本中复制您的问题。在 6 次迭代后,我的内存飙升至 ~2.5GB,然后在 50 次迭代时达到 ~6GB,然后内核死亡。

只需在每个内部循环内存中调用垃圾收集器,内存稳定在 ~1gb,我就能够继续通过 2 次外部迭代。 (然后我取消了它)

我怀疑为什么会发生这种情况是tensorflow 在迭代中创建引用的速度比垃圾收集器默认收集它们的速度要快。

import gc
import tensorflow as tf
from sklearn.datasets import fetch_openml
from sklearn.utils import shuffle
import numpy as np

data, targets = shuffle(*fetch_openml('CIFAR_10', version=1, return_X_y=True))

train_sz = 50000
X_train, X_test, y_train, y_test = data[:train_sz, :], data[train_sz:, :], np.asarray(targets[:train_sz], dtype=np.int), np.asarray(targets[train_sz:], dtype=np.int)

model = tf.keras.Sequential()
model.add(tf.keras.Input(shape=(X_train.shape[1],)))
model.add(tf.keras.layers.Dense(64, activation='relu'))
model.add(tf.keras.layers.Dense(10))
model.compile(loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), optimizer='adam')

s = 0
for _ in range(500):
    for i in range(100):
        gc.collect()
        layers = []
        for layer in model.get_weights():
            layers.append(np.random.normal(0, 1, layer.shape))
        model.set_weights(layers)
        eval = model.evaluate(X_train, y_train)
        s += eval
        print(f'Done {i} eval {eval}')
s

PS:正式手动调用垃圾收集器是您想要避免的事情,但有时它可以完成工作。

【讨论】:

    【解决方案2】:

    首先,在我的带有python-3.6tensorflow-1.14 的 Ubuntu 18.04 无头服务器(16GB RAM)中,此代码可以正常运行,并且无需退出代码即可运行。我有一个具有 11GB 内存的 RTX 2080 Ti GPU。我不使用蟒蛇。这是提供的可重现代码的训练日志。

    我注意到 GPU 使用率很高(从下面的快照中观察到 10GB),但是,这是很正常的,具有这种内存级别的处理单元应该能够轻松地拖动这样的负载。

    但话又说回来,您的 GPU Titan X GTX 与 RTX 2080 Ti 一样强大,还有额外的 1GB 内存,除非其他一些进程限制了 GPU/ CPU 使用率。

    可以尝试的几件事

    1. keras model.evaluate() 接受 batch_size 作为参数。所以尝试减少它
    2. 您的代码需要在循环内更改权重,这可能会占用大量 CPU,因此我怀疑此问题主要归因于 CPU 内存溢出。使用top 命令检查cpu 使用情况并提出问题“在循环中处理权重是否绝对必要?”
    3. 我不确定这是否相关,但我看到 here 建议为 docker 分配更多内存解决了此类问题
    4. 如果没有任何效果,并且您准备好冒险安装tensorflow-1.14 并在终端而不是笔记本上运行代码,那么这也是一种选择。你永远不知道!

    祝你好运。

    【讨论】:

    • 我使用的是 Tensorflow 2.2,所以版本完全不同。不在笔记本中运行,从 PyCharm 远程运行。
    【解决方案3】:

    退出代码 137 表示您的进程已被 (signal 9) SIGKILL 杀死。如果您手动停止脚本并仍然收到此错误代码,则该脚本已被您的操作系统杀死。在大多数情况下,它是由内存使用过多引起的。

    清理缓存数据,为每个不再使用的变量添加以下代码:

    VariableName = None

    检查 docker,因为您的内存限制设置可能太低。

    正如您所说,您的 20% 即 3.2 GB 已在使用中, 额外的 8 GB 意味着大约 70% 的内存在使用中,这是一个巨大的数量。

    【讨论】:

    • +1 来自我,但它并没有完全回答我的问题。是的,数量巨大,问题是我不明白它是从哪里来的。将变量设置为 None 不起作用,我没有使用 docker(是否有我不知道的全局 Python 或 OS 内存设置?)并且购买更多 RAM / 云计算时间并不是一个真正的选择。跨度>
    • 你不认为你的输出层根据你的记忆太大了
    • 对于深度学习应用程序,建议至少有 16GB 内存(Jeremy Howard 建议获得 32GB)。关于时钟,越高越好。理想情况下,它表示速度 - 访问时间,但建议至少 2400 MHz。
    • 你的电脑/笔记本电脑是否满足条件
    猜你喜欢
    • 2019-04-15
    • 2019-05-29
    • 1970-01-01
    • 2011-02-28
    • 2011-09-01
    • 2015-03-11
    • 2015-11-11
    • 1970-01-01
    • 2018-12-15
    相关资源
    最近更新 更多