Keras: 在进行超参数网格搜索时出现内存不足的问题

16

我正在运行多个嵌套循环进行超参数网格搜索。每个嵌套循环都遍历一系列超参数值,在最内层循环中,使用生成器构建并评估了一个Keras序贯模型(我没有进行任何训练,只是随机初始化并多次评估模型,然后检索平均损失)。

我的问题是,在此过程中,Keras似乎填充了我的GPU内存,导致最终出现了OOM错误。

有人知道如何解决这个问题,并在每次评估模型后释放GPU内存吗?

在下一次内部循环中构建新模型之前,我不再需要该模型,可以在每次构建新模型之前完全丢弃它。

我正在使用Tensorflow后端。

这是代码,虽然其中大部分与一般问题无关。模型是在第四个循环内构建的,

for fsize in fsizes:

我猜模型构建的细节并不重要,但这是所有内容:

model_losses = []
model_names = []

for activation in activations:
    for i in range(len(layer_structures)):
        for width in layer_widths[i]:
            for fsize in fsizes:

                model_name = "test_{}_struc-{}_width-{}_fsize-{}".format(activation,i,np.array_str(np.array(width)),fsize)
                model_names.append(model_name)
                print("Testing new model: ", model_name)

                #Structure for this network
                structure = layer_structures[i]

                row, col, ch = 80, 160, 3  # Input image format

                model = Sequential()

                model.add(Lambda(lambda x: x/127.5 - 1.,
                          input_shape=(row, col, ch),
                          output_shape=(row, col, ch)))

                for j in range(len(structure)):
                    if structure[j] == 'conv':
                        model.add(Convolution2D(width[j], fsize, fsize))
                        model.add(BatchNormalization(axis=3, momentum=0.99))
                        if activation == 'relu':
                            model.add(Activation('relu'))
                        if activation == 'elu':
                            model.add(ELU())
                            model.add(MaxPooling2D())
                    elif structure[j] == 'dense':
                        if structure[j-1] == 'dense':
                            model.add(Dense(width[j]))
                            model.add(BatchNormalization(axis=1, momentum=0.99))
                            if activation == 'relu':
                                model.add(Activation('relu'))
                            elif activation == 'elu':
                                model.add(ELU())
                        else:
                            model.add(Flatten())
                            model.add(Dense(width[j]))
                            model.add(BatchNormalization(axis=1, momentum=0.99))
                            if activation == 'relu':
                                model.add(Activation('relu'))
                            elif activation == 'elu':
                                model.add(ELU())

                model.add(Dense(1))

                average_loss = 0
                for k in range(5):
                    model.compile(optimizer="adam", loss="mse")
                    val_generator = generate_batch(X_val, y_val, resize=(160,80))
                    loss = model.evaluate_generator(val_generator, len(y_val))
                    average_loss += loss

                average_loss /= 5

                model_losses.append(average_loss)

                print("Average loss after 5 initializations: {:.3f}".format(average_loss))
                print()

2
你使用的是tensorflow还是theano后端? - indraforyou
@indraforyou,我正在使用Tensorflow后端,抱歉没有提到! - Alex
3个回答

20

如所示,正在使用的后端是Tensorflow。在Tensorflow后端中,当前模型没有被销毁,因此您需要清除会话。

在使用模型之后,只需执行以下操作:

if K.backend() == 'tensorflow':
    K.clear_session()

包含后端:

from keras import backend as K

你也可以使用sklearn包装器来进行网格搜索。查看这个例子:这里。对于更高级的超参数搜索,你可以使用hyperas


1
你太棒了!非常感谢,这正是我需要理解的。还要非常感谢您向我指出hyperopt/hyperas! - Alex
我认为 keras.wrappers.scikit_learn.KerasClassifier 已经处理了这个问题。我在运行给定的示例时没有遇到任何问题。如果您遇到问题,请在 Keras 的 Github 上提交一个 issue。 - indraforyou
@indraforyou 在使用GridSearchCV API的同时,如何正确使用K.clear_session()函数,即在grid.fit()中使用它? - undefined

9

根据indraforyou所提供的技巧,我将清除TensorFlow会话的代码添加到了我传递给GridSearchCV的函数中,如下所示:

def create_model():
    # cleanup
    K.clear_session()

    inputs = Input(shape=(4096,))
    x = Dense(2048, activation='relu')(inputs)
    p = Dense(2, activation='sigmoid')(x)
    model = Model(input=inputs, outputs=p)
    model.compile(optimizer='SGD',
              loss='mse',
              metrics=['accuracy'])
    return model

然后我可以调用网格搜索:

model = KerasClassifier(build_fn=create_model)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=1)

它应该可以正常工作。

干杯!


有没有办法让它支持并行处理多个作业? - Fernando Ferreira
难道这不会让我们失去迄今为止的所有进展吗? - Victor Ferreira

0

在我的情况下,添加backend.clear_session()解决了问题:

from keras import backend as backend
def model_builder(hp):
    backend.clear_session()
    model = Sequential()
    hp_drop = hp.Float('drop', min_value=0, max_value=0.2, step=0.025)
    model.add(Dense(128, activation = "relu"))
    model.add(Dropout(hp_drop))
    model.add(Dense(1, activation = "relu"))

    model.compile(
        loss='mean_absolute_error',
        optimizer=tf.keras.optimizers.Adam(0.001),
        metrics=["mean_absolute_percentage_error"]
    )
    return model

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接