如何实现多类语义分割?

16

我可以使用带有二分类标签的带标注图像来训练 U-net。但是,我在配置Keras/Theano的最后一层进行 多类别 分类(4个类别)方面遇到了困难。

我有634张图像和相应的634个掩模,它们是unit8和64 x 64像素。

我的掩模不是黑色(0)和白色(1),而是用颜色标记为3个类别的对象及背景,如下所示:

  • 黑色(0),背景
  • 红色(1),对象类别1
  • 绿色(2),对象类别2
  • 黄色(3),对象类别3

在训练运行之前,包含掩模的数组被独热编码如下:

mask_train = to_categorical(mask_train, 4)

这将使mask_train.shape(634, 1, 64, 64)变成(2596864, 4)

我的模型紧密遵循Unet结构,但最后几层似乎存在问题,因为我无法对其进行扁平化处理,以匹配one-hot编码的数组。

[...]
up3 = concatenate([UpSampling2D(size=(2, 2))(conv7), conv2], axis=1)
conv8 = Conv2D(128, (3, 3), activation='relu', padding='same')(up3)
conv8 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv8)

up4 = concatenate([UpSampling2D(size=(2, 2))(conv8), conv1], axis=1)
conv9 = Conv2D(64, (3, 3), activation='relu', padding='same')(up4)
conv10 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv9)

# here I used number classes = number of filters and softmax although
# not sure if a dense layer should be here instead
conv11 = Conv2D(4, (1, 1), activation='softmax')(conv10)

model = Model(inputs=[inputs], outputs=[conv11])

# here categorical cross entropy is being used but may not be correct
model.compile(optimizer='sgd', loss='categorical_crossentropy',
              metrics=['accuracy'])

return model

你对如何修改模型的最后部分以便成功训练有何建议?我遇到了各种形状不匹配的错误,而且少数几次成功运行模型时,损失在整个时期内都没有变化。

2个回答

11

如果你使用channels_first,那么你的目标应该是(634,4,64,64)。或者如果使用channels_last,则为(634,64,64,4)

你的目标中每个通道都应该代表一个类别。每个通道都是一个由0和1构成的图像,其中1表示该像素属于该类别,0表示该像素不属于该类别。

然后,你的目标包含634组数据,每组数据包含4张图像,每张图像具有64x64个像素,其中像素1表示所需特征的存在。

我不确定结果是否正确排序,但你可以尝试:

mask_train = to_categorical(mask_train, 4)
mask_train = mask_train.reshape((634,64,64,4)) 
#I chose channels last here because to_categorical is outputing your classes last: (2596864,4)

#moving the channel:
mask_train = np.moveaxis(mask_train,-1,1)

如果订购功能无法正常工作,您可以手动完成:

newMask = np.zeros((634,4,64,64))

for samp in range(len(mask_train)):
    im = mask_train[samp,0]
    for x in range(len(im)):
        row = im[x]
        for y in range(len(row)):
            y_val = row[y]
            newMask[samp,y_val,x,y] = 1

我正在使用Theano后端,这意味着通道优先——你认为我的模型中的最终层看起来正确吗? - pepe
决定通道先后顺序的是“keras”,而不是“Theano”。默认情况下,通道是最后一个。 - Daniel Möller
我现在会尝试一下——在模型的末尾使用softmaxcategorical_crossentropy是否是合适的选择? - pepe
如果您使用softmax,必须在正确的轴上使用它,添加一个层Softmax(axis=1)。这是因为您期望有多个“1”结果。但不幸的是,我不知道哪个轴是适当的,我认为它是轴1,即通道轴。(您希望在同一像素的四个通道中只有一个1) - Daniel Möller
那很有帮助,这些类是互斥的(每个像素不应该有超过一个“1”)。 - pepe
显示剩余7条评论

1
有点晚了,但你应该尝试一下。
mask_train = to_categorical(mask_train, num_classes=None)

这将导致mask_train.shape(634, 4, 64, 64),每个类别都有一个二进制掩码(one-hot编码)。最后的卷积层、激活函数和损失函数对于多类分割而言看起来不错。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接