0

我想实现一个U型网带Keras与Tensorflow后端的图像分割任务。我将尺寸(128,96)的图像作为输入到网络的图像以及尺寸(12288,6)的蒙版图像,因为它们被平放。我有6个不同的类(0-5),它给出了蒙版图像的形状的第二部分。使用to_categorical()函数将它们编码为单热标签。目前,我只使用一个输入图像,并使用与验证和测试数据相同的图像。如何建立一个多类卷积神经网络Keras

我想在U-Net的执行图像分割,其中0级对应于背景。当我现在只训练我的U-Net几个时代(1-10)时,所得到的预测掩模图像似乎只给每个像素随机分类。当我训练网络的时间更长(50+个时代)时,所有像素都被归类为背景。由于我使用相同的图像进行训练和测试,我发现这很奇怪,因为我正在加速网络过度。我该如何解决这个问题?我将掩模图像和真实图像提供给网络的方式会有什么问题吗?

我试图给权重网络手动放不太重视的背景比其他类,并试图和损失的不同组合,塑造掩模图像的不同的方式很多其他的事情,但没有得到良好的结果。

下面是我的网络的代码。它基于取自this repository的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 

任何人都可以指出我的模型有什么问题吗?

回答

0

根据我的经验,还用U-net进行细分。它往往要做到这一点:

  • 转到全黑或全白
  • 了大量的时间,其中的损失似乎被冻结后,它发现它的方式。

我也使用“训练一个图像”的方法来找到收敛,然后添加其他图像是好的。

但我不得不尝试了很多次,也只有它的工作时间相当快,当我使用:

  • 最终激活=“S形”
  • 损失=“binary_crossentropy”

但是我并没有在任何地方使用“relu”......也许这会影响收敛速度......?考虑到“relu”只有0或者是积极的结果,这个函数中有一个很大的区域没有渐变。也许有很多“relu”激活会创建很多没有渐变的“平坦”区域? (必须好好考虑才能确认)

用不同的权重初始化尝试几次(并耐心等待很多很多的时代)。

有机会的话,你的学习速度过大过。


关于to_categorical():你有没有试图绘制/打印你的口罩?他们真的看起来像你期望的那样吗?

+0

感谢您的回答!我会尝试你的建议!我正在使用sigmoid激活与二进制crossentropy损失。你对隐藏层使用了什么样的激活? 关于'to_categorical()'函数,我绘制了蒙版,当转换为单热标签并返回时,它们看起来很好。但我不确定这是否是Keras网络的正确标签格式。 – Jasmin

+0

这个想法完全是**绘制一个热门编码的**口罩(不是原来的口罩)。正如它所说的,“单热”通​​常**只有一个**值为1,其余的都是0.这永远不会制作一个面具(你需要大量的1来制作面具),但是, m不习惯'to_categorical()'函数来确切地知道它在做什么。但你可能不应该用面具来使用它,你需要每个频道都有很多1。如果你的maks是从0到255之间的值的图像,你所要做的就是将图像除以255. –

+0

我不这么认为,我理解你的意思。我有大小为128x96x6的蒙版,其中128x96是图片的像素大小,我有6个不同的类别。在每个通道中我都有零和一个,总是表示一个像素是否属于相应的通道类别。所以你说我不应该对面具图像进行一次性编码? – Jasmin

0

我不认为这是据我所知必须是一个致密层,而不是一个卷积层的预测层。 也许这就是你的问题。

+0

谢谢,@Flo。你可以通过添加预测层来指定你的意思吗?我正在遵循[U-Net:用于生物医学图像分割的卷积网络]的体系结构(https://lmb.informatik.uni-freiburg.de/people/ronneber/u-net/),我不知道如何为网络添加预测密集层。 – Jasmin

1

谢谢@丹尼尔,你的建议最终帮助我得到了Unet的工作。当我运行500多个纪元时,我设法得到的结果不仅仅将整个图像分类为背景。此外,代替使用kernel_initializer='he_normal'kernel_initializer='zeros'kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.07)为我工作。我用'sigmoid'激活功能和loss='binary_crossentropy'。我为所有隐藏的卷积层保留了“relu”激活。我注意到,我的网络有时会陷入局部最小的地步,而这个地方的损失并没有得到改善,所以我需要重新启动。

相关问题