我想实现一个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
任何人都可以指出我的模型有什么问题吗?
感谢您的回答!我会尝试你的建议!我正在使用sigmoid激活与二进制crossentropy损失。你对隐藏层使用了什么样的激活? 关于'to_categorical()'函数,我绘制了蒙版,当转换为单热标签并返回时,它们看起来很好。但我不确定这是否是Keras网络的正确标签格式。 – Jasmin
这个想法完全是**绘制一个热门编码的**口罩(不是原来的口罩)。正如它所说的,“单热”通常**只有一个**值为1,其余的都是0.这永远不会制作一个面具(你需要大量的1来制作面具),但是, m不习惯'to_categorical()'函数来确切地知道它在做什么。但你可能不应该用面具来使用它,你需要每个频道都有很多1。如果你的maks是从0到255之间的值的图像,你所要做的就是将图像除以255. –
我不这么认为,我理解你的意思。我有大小为128x96x6的蒙版,其中128x96是图片的像素大小,我有6个不同的类别。在每个通道中我都有零和一个,总是表示一个像素是否属于相应的通道类别。所以你说我不应该对面具图像进行一次性编码? – Jasmin