Tensorflow 2.0:在超参数调优循环期间,GPU内存不足 [英] Tensorflow2.0: GPU runs out of memory during hyperparameter tuning loop

查看:84
本文介绍了Tensorflow 2.0:在超参数调优循环期间,GPU内存不足的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试执行一些卷积神经网络的超参数调整,该网络是用带有GPU扩展的TensorFlow 2.0编写的。

我的系统设置为:

  • 64位Windows 10
  • GeForce RTX2070,8 GB
  • TensorFlow 2.0-测试版
  • CUDA 10.0已正确安装(我希望deviceQuery.exe和band widthTest.exe都通过了)

我的神经网络有75.572.574个参数,我正在3777个样本上对其进行训练。在一次跑步中,我在训练CNN方面没有任何问题。

下一步,我想调优CNN的两个超参数。为此,我创建了一个for循环(迭代20个步骤),在该循环中,我每次构建并编译新模型时,在每次循环迭代时更改超参数。 代码(这是而不是一个MWE)的要点如下

import tensorflow as tf
from tensorflow import keras

def build_model(input_shape, output_shape, lr=0.01, dropout=0, summary=True):
    model = keras.models.Sequential(name="CNN")
    model.add(keras.layers.Conv2D(32, (7, 7), activation='relu', input_shape=input_shape, padding="same"))
    model.add(keras.layers.BatchNormalization())
    model.add(keras.layers.MaxPooling2D((2, 2)))
    model.add(keras.layers.Dropout(dropout))
    model.add(keras.layers.Conv2D(128, (3, 3), activation='relu', padding="same"))
    model.add(keras.layers.BatchNormalization())
    model.add(keras.layers.MaxPooling2D((2, 2)))
    model.add(keras.layers.Dropout(dropout))
    model.add(keras.layers.Flatten())
    model.add(keras.layers.Dense(1024, activation='relu'))
    model.add(keras.layers.BatchNormalization())
    model.add(keras.layers.Dense(output_shape, activation='linear'))
    model.build()
    model.compile(optimizer=keras.optimizers.Adam(learning_rate=lr),
                  loss="mse",
                  metrics=[RMSE])
    if summary:
        print(model.summary())
    return model

...

    for run_id in range(25):
        lr = learning_rate.max_value + (learning_rate.min_value - learning_rate.max_value) * np.random.rand(1)
        dropout = dropout.min_value + (dropout.max_value -
                                                 dropout.min_value) * np.random.rand(1)
        print("%=== Run #{0}".format(run_id))
        run_dir = hparamdir + "\run{0}".format(run_id)
        model0 = build_model(IMG_SHAPE, Ytrain.shape[1], lr=lr, dropout=dropout)
        model0_history = model0.fit(Xtrain,
                                    Ytrain,
                                    validation_split=0.3,
                                    epochs=2,
                                    verbose=2)

我遇到的问题是,在几(6)次循环后,程序停止返回错误

tensorflow.python.framework.errors_impl.ResourceExhaustedError: OOM when allocating tensor with shape[73728,1024] and type float on /job:localhost/replica:0/task:0/device:GPU:0 by allocator GPU_0_bfc [Op:Add] name: dense_12/kernel/Initializer/random_uniform/

Process finished with exit code 1.

我认为问题在于,GPU不会在for循环的每次迭代之间释放内存,一段时间后,它会饱和并崩溃。

我仔细研究并尝试了类似帖子(post1post2)中建议的不同解决方案

  1. 尝试在使用
  2. 的for循环的每次迭代结束时使用Kera后端释放内存
from keras import backend as K
K.clear_session()
  1. 尝试使用Numba和CUDA清除GPU
from numba import cuda
cuda.select_device(0)
cuda.close()
  1. 我尝试使用del model0删除图形,但也不起作用。

  2. 我无法尝试使用tf.reset_default_graph(),因为TF2.0的编程风格不再有默认图形(AFAIK),因此我找不到在运行时终止/删除图形的方法。

解决方案1.和3.返回相同的内存不足错误,而解决方案2.在build_model()调用中构建模型时,在for循环的第二次迭代期间返回以下错误:

2019-07-24 19:51:31.909377: F .	ensorflow/core/kernels/random_op_gpu.h:227] Non-OK-status: GpuLaunchKernel(FillPhiloxRandomKernelLaunch<Distribution>, num_blocks, block_size, 0, d.stream(), gen, data, size, dist) status: Internal: invalid resource handle

Process finished with exit code -1073740791 (0xC0000409)

我试着四处看看,但我真的不太明白最后一个错误,我猜是GPU没有正确关闭/被Python占用/无法再看到。

在任何情况下,我都找不到此问题的任何解决方案,除了手动为每个要测试的超参数运行培训。

有人知道如何解决这个问题吗? 或者是超参数调优的变通方法? 我是否应该在TF2.0 Github问题跟踪器中打开问题(它本身似乎不是TensorFlow问题,因为他们声明他们不想释放GPU以避免分段问题)?

推荐答案

这是由于TF处理内存的方式造成的。

如果在迭代训练TF模型的同时监视系统,您将观察到内存消耗呈线性增加。此外,如果watch -n 0.1 nvidia-smi,您将注意到进程的PID在迭代时保持不变。在控制内存的PID终止之前,TF不会完全释放已使用的内存。此外,Numba文档指出,如果您想要重置GPU,cuda.close()是没有用的(尽管当我发现它时,我确实花了一段时间来尝试让它工作!)。

最简单的解决方案是使用Raypython包进行迭代,如下所示:

import ray

@ray.remote(
    num_gpus=1 # or however many you want to use (e.g., 0.5, 1, 2)
)
class RayNetWrapper:

    def __init__(self, net):
        self.net = net

    def train(self):
        return self.net.train()

ray.init()
actors = [RayNetWrapper.remote(model) for _ in range(25)]
results = ray.get([actor.train.remote() for actor in actors]

然后您应该注意到,GPU进程每次都会使用新的PID循环打开/关闭,并且您的系统内存将不再增加。或者,您可以将您的模型训练代码放在一个新的python脚本中,并使用python的subprocess模块迭代地调用。现在,当模型关闭和新模型启动时,您还会注意到一些延迟,但这是意料之中的,因为GPU正在重新启动。Ray还有一个实验性的异步框架,我用它已经取得了一些成功,并且允许部分共享GPU(如果模型大小允许)。

这篇关于Tensorflow 2.0:在超参数调优循环期间,GPU内存不足的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆