Keras 模型的验证损失与损失函数输出不匹配

Posted

技术标签:

【中文标题】Keras 模型的验证损失与损失函数输出不匹配【英文标题】:Keras model's validation loss doesn't match the loss function output 【发布时间】:2020-10-07 02:49:47 【问题描述】:

我正在从事一个生物医学图像分割项目。我正在使用 U-net 模型来完成这项工作。问题是,当我训练模型时,验证损失似乎并不实用。

我使用 dice_coef_loss 作为损失函数,以及在 metric 中。训练结果如下图。该图清楚地表明验证损失没有遵循我的损失函数,因为这两个图是可区分的。不过,火车损失确实遵循火车 dice_coef_loss 值。

(左起第一张图片是训练和验证损失,第三张是去皮和验证dice_coef_loss作为指标)

The history graph of training

(对不起,我还没有资格嵌入图片,请查看链接)

这是我的模型

def unet(input_size=(256,256,1)):
    inputs = Input(input_size)

    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs)
    conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)

    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1)
    conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)

    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2)
    conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3)
    pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)

    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool3)
    conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4)
    pool4 = MaxPooling2D(pool_size=(2, 2))(conv4)

    conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool4)
    conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv5)

    up6 = concatenate([Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(conv5), conv4], axis=3)
    conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(up6)
    conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv6)

    up7 = concatenate([Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(conv6), conv3], axis=3)
    conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(up7)
    conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv7)

    up8 = concatenate([Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(conv7), conv2], axis=3)
    conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(up8)
    conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv8)

    up9 = concatenate([Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(conv8), conv1], axis=3)
    conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(up9)
    conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv9)

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

    return Model(inputs=[inputs], outputs=[conv10])

这是损失函数

import keras.backend as K
smooth=100

def dice_coef(y_true, y_pred):
    y_truef=K.flatten(y_true)
    y_predf=K.flatten(y_pred)
    And=K.sum(y_truef* y_predf)
    return((2* And + smooth) / (K.sum(y_truef) + K.sum(y_predf) + smooth))

def dice_coef_loss(y_true, y_pred):
    return -dice_coef(y_true, y_pred)

编译

model.compile(optimizer=Adam(lr=1e-5), loss=dice_coef_loss, metrics=["binary_accuracy", dice_coef_loss, iou])

注意

我试过了:

学习率调整 调整批量大小 数据增强 改变损失函数

如果有人想看这里的代码是link to kaggle kernel

补充说明

澄清一下:

第一个图和第二个图是使用相同数据集(来自训练时间或验证时间)从相同函数生成的,因此我希望第一个图的 train_loss 曲线等于第三个图的 train_dice_coef_loss。第一个图的 val_loss 曲线等于第三个图的 val_dice_coef_loss。

但不幸的是 val_loss 曲线与 val_dice_coef_loss 曲线不匹配。

附:我是新来的。任何改善我的问题的建议表示赞赏。谢谢。

【问题讨论】:

我无法理解您的要求,您显示的图表是训练和验证损失/指标,但这些不必匹配,因为它们是在不同的数据集上评估的,所以我不是确定这里有什么问题。 我使用了一个函数作为损失函数和度量。它们的值在两次都必须相同。两个图的训练时间值应该匹配,以及测试时间值。 我不是要求训练图和测试图相同,我要求两个图(第一个和第三个)的测试图必须匹配,因为它们是在同一个数据集上评估的 从您的代码来看,您似乎在生成器中使用了扩充,并且有许多随机操作。你确定这不是种子问题吗? @ZabirAlNazi 首先,据我所知,图像数据生成器在这里只是对同一种子上的图像和掩码进行随机转换,没有增强。其次,这种随机变换仅用于训练数据而不是验证数据。在验证生成器中,将一个空字典传递给生成器,这样它就不会对验证数据进行任何随机转换。第三,对我来说,这似乎不是种子问题。最后,感谢您的帮助。 @ZabirAlNazi 在 colab 训练中有一个内核在另一个有类似问题的数据集上:colab link 【参考方案1】:

正如,ZabirAlNazi 认为这是使用的库的问题。将导入从 keras 更改为 tensorflow.keras 解决了这个问题。

from tensorflow.keras.models import Model, load_model, save_model
from tensorflow.keras.layers import Input, Activation, BatchNormalization, Dropout, Lambda, Dense, Conv2D

【讨论】:

以上是关于Keras 模型的验证损失与损失函数输出不匹配的主要内容,如果未能解决你的问题,请参考以下文章

可以在 keras 损失函数中直接访问中间层吗?

Keras预测给出的误差与评估不同,损失与指标不同

Keras/Tensorflow:单输出的组合损失函数

标准 Keras 模型输出是啥意思? Keras 的时代和损失是啥?

Keras中验证集的不同损失函数

Keras cifar10 示例验证和测试损失低于训练损失