在 keras 中使用批量标准化进行微调

Posted

技术标签:

【中文标题】在 keras 中使用批量标准化进行微调【英文标题】:fine-tune with batch normalization in keras 【发布时间】:2019-05-23 12:21:28 【问题描述】:

我已经成功训练了超过 100000 个样本的模型,该模型在训练集和测试集上都表现良好。然后,我尝试在一个特定样本(100000 个样本之一)上对其进行微调,并使用训练后的权重作为初始化。

但是结果有点奇怪,我相信是批量归一化层造成的。具体来说,我的代码可以列举如下:

model = mymodel()
model.load_weights('./pre_trained.h5') #start from history
rate = model.evaluate(x, y)
print(rate)
checkpoint = tf.keras.callbacks.ModelCheckpoint('./trained.h5', monitor='loss',
        verbose=0, save_best_only=True, mode='min',save_weights_only=True)
model.fit(x, y,validation_data=[x, y], epochs=5, verbose=2, callbacks=[checkpoint])

model.load_weights('./trained.h5') 率 = model.evaluate(x, y) 打印(速率)

mymodel 是一个自定义函数来生成我的模型,由 Dense 和 Batch 标准化组成。 x,y 是一个特定样本的输入和标签。我想进一步优化样本的损失。但是,结果很奇怪:

 1/1 [==============================] - 0s 209ms/step
-6.087581634521484
Train on 1 samples, validate on 1 samples
Epoch 1/200
 - 1s - loss: -2.7749e-01 - val_loss: -6.0876e+00
Epoch 2/200
 - 0s - loss: -2.8791e-01 - val_loss: -6.0876e+00
Epoch 3/200
 - 0s - loss: -3.0012e-01 - val_loss: -6.0876e+00
Epoch 4/200
 - 0s - loss: -3.1325e-01 - val_loss: -6.0876e+00

如图所示,首先model.evaluate 运行良好,因为损失结果 (-6.087581634521484) 接近加载的训练模型的性能。但是训练集的损失(实际上与model.fit() 中的验证集相同)很奇怪。 val_loss是正常的,和第一行model.evaluate的结果类似。所以我真的很困惑,为什么train loss和inference loss之间仍然有很大的差异(train loss更差),因为train sample和validation sample是一样的,我想结果也应该是一样的,或者至少非常接近。我怀疑问题是由 BN 层引起的,因为训练和推理之间的差异很大。但是,我已经在加载预训练的权重之后和model.fit之前设置了BN层的trainable = False,但是问题并没有解决。

out = tf.keras.layers.BatchNormalization(trainable=False)(out)

我还是怀疑BN层,不知道设置trainable=False是否足以保持BN的参数不变。

谁能给我一些建议?非常感谢您提前提供的帮助。 对不起我的英语,但我已尽力解释我的问题。

【问题讨论】:

简而言之,为什么loss和val_loss在model.fit()中有如此大的差异,而训练集和推理集共享同一个样本?我认为结果必须相同或至少接近,原因是什么? 【参考方案1】:

我想分享在 pytorch 中的类似发现。 首先,你的keras版本是什么?因为在 2.1.3 之后,设置 BN 层 trainable=False 会使 BN 在推理模式下表现完全一样,这意味着它不会将输入归一化为 0 均值 1 方差(如在训练模式中),而是归一化为运行均值和方差。如果您将学习阶段设置为 1,则 BN 本质上成为实例范数,它忽略了运行均值和方差,只需归一化为 0 均值和 1 方差,这可能是您想要的行为。

keras 发行说明参考链接:https://github.com/keras-team/keras/releases/tag/2.1.3

API 更改 BatchNormalization 中的可训练属性现在禁用 批量统计的更新(即如果 trainable == False 该层 现在将在推理模式下 100% 运行)。

【讨论】:

鼓励链接到外部资源,但请在链接周围添加上下文,以便您的其他用户了解它是什么以及为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线。【参考方案2】:

我在这里找到了一个可能的解释: https://github.com/keras-team/keras/pull/9965 和这里: https://github.com/keras-team/keras/issues/9214

【讨论】:

【参考方案3】:

有点别扭,我在另一个问题Keras: Accuracy Drops While Finetuning Inception找到了一个奇怪的解决方法

其实我觉得还不够回答,但是当我加了

 tf.keras.backend.set_learning_phase(1)

model.compile() 之前。结果变得很正常了,虽然还是有一些问题:

1/1 [==============================] - 0s 246ms/step
-6.087581634521484
Train on 1 samples, validate on 1 samples
Epoch 1/10
 - 1s - loss: -6.0876e+00 - val_loss: -6.0893e+00
Epoch 2/10
 - 0s - loss: -6.0893e+00 - val_loss: -6.0948e+00
Epoch 3/10
 - 0s - loss: -6.0948e+00 - val_loss: -6.0903e+00
Epoch 4/10
 - 0s - loss: -6.0903e+00 - val_loss: -6.0927e+00

这很神奇,也是我想要的,但我仍然对这个问题感到困惑。 首先,它为什么起作用,tf.keras.backend.set_learning_phase(1) 是做什么的?另外我设置了layers.trainbale=True,为什么在这种情况下BN层工作正常? 那么,为什么 loss 和 val_loss 还是有很小的差别呢?由于样品相同,是什么原因造成的? 最后我发现不管是用tf.keras.backend.set_learning_phase(0)还是tf.keras.backend.set_learning_phase(1),结果都差不多,正常。以下是tf.keras.backend.set_learning_phase(0)的结果:

1/1 [==============================] - 0s 242ms/step
-6.087581634521484
Train on 1 samples, validate on 1 samples
Epoch 1/10
 - 1s - loss: -6.0876e+00 - val_loss: -6.0775e+00
Epoch 2/10
 - 0s - loss: -6.0775e+00 - val_loss: -6.0925e+00
Epoch 3/10
 - 0s - loss: -6.0925e+00 - val_loss: -6.0908e+00
Epoch 4/10
 - 0s - loss: -6.0908e+00 - val_loss: -6.0883e+00

tf.keras.backend.set_learning_phase(1)有点不同,也有待解释。

我是深度学习和 Keras 的新手,我从 Stack Overflow 中受益良多。为了我的知识和我的英语。

提前感谢您的帮助。

【讨论】:

以上是关于在 keras 中使用批量标准化进行微调的主要内容,如果未能解决你的问题,请参考以下文章

如何在 keras 中正确使用 U-net 批量标准化?

Keras 中具有批量标准化的双向 LSTM

Keras:使用批量标准化在同一数据集上的不同训练和验证结果

Keras:批量标准化(axis = 1)的等级为0

如果您使用批量标准化,您是不是需要标准化输入?

Keras 中的损失函数和批量大小