Keras模型微调后性能变差

3
我正在尝试按照https://www.tensorflow.org/tutorials/images/transfer_learning#create_the_base_model_from_the_pre-trained_convnets中描述的微调步骤,以获取用于二进制分割的训练模型。
我创建了一个编码器-解码器,其中编码器的权重是MobileNetV2的权重,并固定为encoder.trainable = False。然后,我按照教程中所述定义我的解码器,并使用学习率为0.005训练网络300个时期。在最后几个时期中,我获得了以下损失值和Jaccard指数:
Epoch 297/300
55/55 [==============================] - 85s 2s/step - loss: 0.2443 - jaccard_sparse3D: 0.5556 - accuracy: 0.9923 - val_loss: 0.0440 - val_jaccard_sparse3D: 0.3172 - val_accuracy: 0.9768
Epoch 298/300
55/55 [==============================] - 75s 1s/step - loss: 0.2437 - jaccard_sparse3D: 0.5190 - accuracy: 0.9932 - val_loss: 0.0422 - val_jaccard_sparse3D: 0.3281 - val_accuracy: 0.9776
Epoch 299/300
55/55 [==============================] - 78s 1s/step - loss: 0.2465 - jaccard_sparse3D: 0.4557 - accuracy: 0.9936 - val_loss: 0.0431 - val_jaccard_sparse3D: 0.3327 - val_accuracy: 0.9769
Epoch 300/300
55/55 [==============================] - 85s 2s/step - loss: 0.2467 - jaccard_sparse3D: 0.5030 - accuracy: 0.9923 - val_loss: 0.0463 - val_jaccard_sparse3D: 0.3315 - val_accuracy: 0.9740

我会尽力为您翻译。这段内容的意思是:“我存储了这个模型的所有权重,然后按以下步骤进行微调:”。
model.load_weights('my_pretrained_weights.h5')
model.trainable = True
model.compile(optimizer=Adam(learning_rate=0.00001, name='adam'),
                  loss=SparseCategoricalCrossentropy(from_logits=True),
                  metrics=[jaccard, "accuracy"])
model.fit(training_generator, validation_data=(val_x, val_y), epochs=5,
                validation_batch_size=2, callbacks=callbacks)

突然间我的模型表现比解码器训练期间要差得多:
Epoch 1/5
55/55 [==============================] - 89s 2s/step - loss: 0.2417 - jaccard_sparse3D: 0.0843 - accuracy: 0.9946 - val_loss: 0.0079 - val_jaccard_sparse3D: 0.0312 - val_accuracy: 0.9992
Epoch 2/5
55/55 [==============================] - 90s 2s/step - loss: 0.1920 - jaccard_sparse3D: 0.1179 - accuracy: 0.9927 - val_loss: 0.0138 - val_jaccard_sparse3D: 7.1138e-05 - val_accuracy: 0.9998
Epoch 3/5
55/55 [==============================] - 95s 2s/step - loss: 0.2173 - jaccard_sparse3D: 0.1227 - accuracy: 0.9932 - val_loss: 0.0171 - val_jaccard_sparse3D: 0.0000e+00 - val_accuracy: 0.9999
Epoch 4/5
55/55 [==============================] - 94s 2s/step - loss: 0.2428 - jaccard_sparse3D: 0.1319 - accuracy: 0.9927 - val_loss: 0.0190 - val_jaccard_sparse3D: 0.0000e+00 - val_accuracy: 1.0000
Epoch 5/5
55/55 [==============================] - 97s 2s/step - loss: 0.1920 - jaccard_sparse3D: 0.1107 - accuracy: 0.9926 - val_loss: 0.0215 - val_jaccard_sparse3D: 0.0000e+00 - val_accuracy: 1.0000

这种情况是否有已知的原因?这是正常现象吗? 非常感谢您的提前帮助!


在加载权重后,请勿执行model.compile。 - Gerry P
如果我不重新编译模型,那么现在应该是可训练的层中的 model.trainable=True 就不会起作用。我进行了实验验证,并且在 https://www.tensorflow.org/tutorials/images/transfer_learning#un-freeze_the_top_layers_of_the_model 中也有说明:“您应该重新编译模型(必须进行这些更改才能生效)。”编译模型还允许我更改学习率等参数。另一个问题是,在执行 model.trainable=True 之前应该先加载权重,因为它们来自于一些被冻结的层的模型。 - eLearner
不知道,谢谢提供信息。我也会测试一下。 - Gerry P
1个回答

2

好的,我发现了一些不同之处,这使得编译不是必需的。我没有设置encoder.trainable = False。在下面的代码中,我所做的与此相当。

for layer in encoder.layers:
    layer.trainable=False

接下来训练你的模型。然后你可以使用以下代码解除编码器权重的冻结:

for layer in encoder.layers:
    layer.trainable=True


您无需重新编译模型。我已经测试过,它按预期工作。您可以通过在打印模型摘要之前和之后进行验证,并查看可训练参数的数量来验证。至于更改学习率,我发现最好使用keras回调ReduceLROnPlateau根据验证损失自动调整学习率。我还建议使用EarlyStopping回调,它监视验证并在连续'patience'个纪元后如果损失未减少则停止训练。将restore_best_weights设置为True将加载具有最低验证损失的时期的权重,因此您不必保存然后重新加载权重。将epochs设置为一个大数字以确保该回调激活。我使用的代码如下所示。
es=tf.keras.callbacks.EarlyStopping( monitor="val_loss", patience=3,
                                     verbose=1,  restore_best_weights=True)
rlronp=tf.keras.callbacks.ReduceLROnPlateau( monitor="val_loss", factor=0.5, patience=1,
                                             verbose=1)
callbacks=[es, rlronp]

在 model.fit 中设置 callbacks=callbacks。

谢谢!我会试一下看看它是否有效。当我将encoder.trainable=True时,可训练参数的数量增加了,正如你建议的那样,但是在一些epochs之后,属于encoder的权重没有得到更新。然而,在进行model.compile时,它们确实得到了更新。这就是为什么我认为我真的需要编译它。此外,我想在固定编码器为可训练时大幅降低学习率,这与使用ReduceLROnPlateau不同。 - eLearner

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