繁体   English   中英

如何使用Keras构建多类卷积神经网络

[英]How to build a multi-class convolutional neural network with Keras

我正在尝试使用带有Keras和Tensorflow后端的U-Net来实现图像分割任务。 我将大小为(128,96)的图像与大小为(12288,6)的蒙版图像一起输入到网络中,因为它们被展平了。 我有6个不同的类(0-5),它们给出了蒙版图像形状的第二部分。 使用to_categorical()函数将它们编码为一键式标签。 目前,我只使用一张输入图像,也使用同一张图像作为验证和测试数据。

我希望U-Net进行图像分割,其中0类对应于背景。 现在,当我仅在几个时期(1-10)内训练U-Net时,所得的预测蒙版图像似乎只是为每个像素提供了随机类别。 当我训练网络的时间更长(超过50个纪元)时,所有像素都被归类为背景。 由于我使用相同的图像进行训练和测试,因此在加速网络进行过度训练时,我发现这很奇怪。 我该如何解决这个问题? 我将遮罩图像和真实图像提供给网络的方式是否有问题?

我已经尝试过手动给网络赋权,以减少对背景的关注,并且尝试了不同的损失组合,不同的蒙版图像塑造方法以及许多其他事情,但是没有任何结果能带来良好的结果。

下面是我的网络代码。 它基于从此存储库中获取的U-Net。 我设法在两节课的情况下对它进行了培训,并取得了良好的效果,但是我现在不知道如何将其扩展到更多的课。

def get_unet(self):

    inputs = Input((128, 96,1))
    #Input shape=(?,128,96,1)

    conv1 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
      kernel_initializer = 'he_normal', input_shape=(None,128,96,6))(inputs)
    #Conv1 shape=(?,128,96,64)
    conv1 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
          kernel_initializer = 'he_normal')(conv1)
    #Conv1 shape=(?,128,96,64)
    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
    #pool1 shape=(?,64,48,64)


    conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(pool1)
    #Conv2 shape=(?,64,48,128)
    conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(conv2)
    #Conv2 shape=(?,64,48,128)
    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
    #Pool2 shape=(?,32,24,128)

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

    up8 = Conv2D(128, 2, activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv5))
    merge8 = concatenate([conv2,up8], axis = 3)
    conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(merge8)
    conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same',
         kernel_initializer = 'he_normal')(conv8)


    up9 = Conv2D(64, (2,2), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv8))
    merge9 = concatenate([conv1,up9], axis = 3)
    conv9 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(merge9)
    conv9 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(conv9)
    conv9 = Conv2D(6, (3,3), activation = 'relu', padding = 'same',
        kernel_initializer = 'he_normal')(conv9)

    conv10 = Conv2D(6, (1,1), activation = 'sigmoid')(conv9)
    conv10 = Reshape((128*96,6))(conv10)

    model = Model(input = inputs, output = conv10)
    model.compile(optimizer = Adam(lr = 1e-5), loss = 'binary_crossentropy',
          metrics = ['accuracy'])

    return model

谁能指出我的模型出了什么问题?

谢谢@Daniel,您的建议最终帮助我使Unet正常工作。 运行500多个纪元时,我设法获得的结果不只是将整个图像分类为背景。 另外,代替使用kernel_initializer='he_normal'kernel_initializer='zeros'kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.07)为我工作。 我使用了'sigmoid'激活函数和loss='binary_crossentropy' 我为所有隐藏的卷积层保留了“ relu”激活。 我注意到我的网络有时会停留在一个本地最小值范围内,在此范围内损耗不再改善,因此我需要重新启动。

据我所知,我看不到您的预测层必须是密集层而不是卷积层。 也许那是你的问题。

以我的经验,还可以使用U-net进行细分。 它倾向于这样做:

  • 变成全黑或全白
  • 经过很多时间,损失似乎被冻结了,它发现了。

我还使用“仅训练一张图像”的方法来找到收敛,然后添加其他图像即可。

但是我不得不尝试很多次,并且它运行得非常快的唯一一次是我使用时:

  • 最终激活='Sigmoid'
  • 损失='binary_crossentropy'

但是我没有在任何地方使用“ relu”……也许会影响收敛速度……? 考虑只有0或正数结果的“ relu”,此函数中有一个很大的区域没有梯度。 也许有很多“ relu”激活会创建很多没有梯度的“平坦”区域? (必须仔细考虑才能确认)

尝试使用不同的权重初始化几次(并耐心等待许多纪元)。

您的学习率也有可能太大。


关于to_categorical() :您是否尝试绘制/打印蒙版? 他们真的像您期望的那样吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM