为什么 mse 训练与使用 Encoder-Decoder 的每次训练开始时大不相同

数据挖掘 机器学习 神经网络 深度学习 自动编码器
2022-03-14 06:10:56

我正在使用编码器-解码器模型从灰度图像中预测二进制图像。这是模型

inputs = Input(shape=(height, width, 1))

conv1 = Conv2D(4, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs)

conv1 = Conv2D(4, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv1)

pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)

conv2 = Conv2D(8, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool1)

conv2 = Conv2D(8, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv2)

drop2 = Dropout(0.2)(conv2)

pool2 = MaxPooling2D(pool_size=(2, 2))(drop2)

conv4 = Conv2D(16, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool2)

conv4 = Conv2D(16, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv4)

drop4 = Dropout(0.2)(conv4)

pool4 = MaxPooling2D(pool_size=(2, 2))(drop4)

conv5 = Conv2D(32, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool4)

conv5 = Conv2D(32, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv5)

drop5 = Dropout(0.2)(conv5)

up6 = Conv2D(16, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(drop5))

merge6 = concatenate([drop4,up6], axis = 3)

conv6 = Conv2D(16, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge6)

conv6 = Conv2D(16, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv6)

up7 = Conv2D(8, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv6))

merge7 = concatenate([drop2,up7], axis = 3)

conv7 = Conv2D(8, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge7)

conv7 = Conv2D(8, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv7)


up9 = Conv2D(4, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv7))

merge9 = concatenate([conv1,up9], axis = 3)

conv9 = Conv2D(4, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge9)

conv9 = Conv2D(4, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)

conv9 = Conv2D(2, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)

conv10 = Conv2D(1, 1, activation = 'sigmoid')(conv9)

model = Model(inputs=inputs, outputs=conv10)
nadam = optimizers.Nadam(lr=1e-4, beta_1=0.9, beta_2=0.999, epsilon=None,  schedule_decay=0.0004)
model.compile(loss='mean_squared_error', optimizer=nadam, metrics=['accuracy', norm_mse])

nb_epoch = 30
batch_size = 8
history = unet.fit(training, trainingLabel,
      validation_data=(validation, validationLabel),
      batch_size=batch_size, epochs=nb_epoch, shuffle="batch", callbacks=[checkpointer],  verbose=1)

我也有训练数据集大小为:6912,验证数据集大小为:1728 每次我一开始就开始训练我的编码器-解码器时,我都会得到不同的训练精度和归一化 MSE。它对每次测试都有很大影响。我知道一开始的权重是随机选择的,因此它会影响第一个 epoch 的性能。我担心的是差异太大。这里有些例子:

Epoch 1/30
6912/6912 [==============================] - 27s 4ms/step - loss: 0.0612 -    acc: 0.9252 - normalized_mse: 0.3661 - val_loss: 0.0367 - val_acc: 0.9559 -    val_normalized_mse: 0.2920

另一个例子:

Epoch 1/30
6912/6912 [==============================] - 28s 4ms/step - loss: 0.1251 -     acc: 0.8982 - normalized_mse: 0.5686 - val_loss: 0.1077 - val_acc: 0.9564 -     val_normalized_mse: 0.5302

最后一个:

Epoch 1/30
6912/6912 [==============================] - 26s 4ms/step - loss: 0.1721 -    acc: 0.9400 - normalized_mse: 0.6751 - val_loss: 0.1582 - val_acc: 0.9582 -   val_normalized_mse: 0.6473

如果我运行我的模型超过 30 个 epoch,它就会开始高估。输入图像的大小为 256x256,每个图像都有相当多的特征,并且是灰度的 - 输出是二进制图像。

如果我做错了什么,有人可以帮我理解吗?我怎样才能让我的模型更稳定?

[已解决] 对于那些面临同样问题的人,只需给 kernel_initializer 一些随机种子。示例 kernel_initializer=he_normal(seed=seed_val)。这将解决问题。

1个回答

只是几个想法:

  1. 批次大小:8 是一个相当小的批次,这意味着计算的平均损失可能具有很高的波动性。如果你有足够的内存,你可以增加这个。

  2. 输入的多样性:尝试在编码器部分添加批量归一化层,以尝试平滑卷积层的输入。你说有很多功能,所以也许这会产生嘈杂的输入,这将受益于标准化。

您可以尝试将相同的实验运行 15 个 epoch,然后绘制训练和验证损失(随着它们的发展,可能会与其他人一起使用TensorBoard 回调)。它们是否遵循任何模式或在一段时间后收敛?

您可以尝试使用不同的初始化方法,甚至梯度裁剪,以使训练更加平滑 - 在反向传播期间将更新的大小限制为权重。

最后,对 GAN 模型的研究的另一个(全新的!)结果表明,逐渐增加模型输入的大小可能有助于平滑学习,并提取一组更强大的特征,从而更好地泛化。阅读FastAI 关于他们经验的文章的这一部分。

编辑:有关 ELU 激活的信息

使用此激活有助于学习,因为它比例如 ELU 具有更多的灵活性,因为它也可能采用负值。这是原始论文中的图像:

在此处输入图像描述

这是官方定义(在您的框架的实现中可能略有不同):

在此处输入图像描述

作者提到,这种激活有助于将平均激活推向接近零,就像批量标准化所做的那样。在您的情况下,这可能意味着简单地克服颠簸的初始时期并更快地收敛。

作者强调的最后一个要点是,他们训练的模型也具有更好的泛化能力——因此,使用 ELU 的模型与使用 ReLU 的模型相比,您可能会享受到改进的性能(假设两者的训练时间相似)。