我正在尝试使用带有Tensorflow后端的Keras实现U-Net进行图像分割任务。我有大小(128,96)的图像作为网络的输入以及尺寸(12288,6)的掩模图像,因为它们是扁平的。我有6个不同的类(0-5),它给出了掩模图像的第二部分'形状。它们已使用to_categorical()函数编码为单热标签。目前我只使用一个输入图像,并使用相同的一个作为验证和测试数据。
我希望U-Net执行图像分割,其中0级对应于背景。当我现在仅在几个纪元(1-10)中训练我的U-Net时,得到的预测掩模图像似乎只给每个像素提供随机类。当我训练网络更长(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 :(得分:2)
谢谢@Daniel,你的建议最终帮助我让Unet工作。我设法得到的结果不仅仅是在运行500多个时代时将整个图像分类为背景。此外,我没有使用kernel_initializer='he_normal'
,kernel_initializer='zeros'
或kernel_initializer=TruncatedNormal(mean=0.0, stddev=0.07)
。我使用'sigmoid'激活函数和loss='binary_crossentropy'
。我对所有隐藏的卷积层保持“relu”激活。我注意到我的网络有时会陷入局部最小值,而损失不再有所改善,所以我需要重启。
答案 1 :(得分:1)
我不知道你的预测层,据我所知,它必须是一个密集的层,而不是一个卷积层。 也许这就是你的问题。
答案 2 :(得分:1)
根据我的经验,也使用U-net进行细分。它倾向于这样做:
我还使用“训练一个图像”方法来找到收敛,然后添加其他图像就可以了。
但是我不得不尝试很多次,而且它使用的唯一时间就是我使用的时间:
但我并没有在任何地方使用“relu”......也许这会影响收敛速度......?考虑到“relu”,它只有0或正结果,这个函数中有一个没有渐变的大区域。也许有很多“relu”激活创造了很多没有渐变的“平坦”区域? (必须更好地考虑确认)
尝试使用不同的权重初始化几次(并耐心等待许多时期)。
你的学习成绩也有可能太大。
关于to_categorical()
:您是否试图绘制/打印面具?他们真的看起来像你期望的那样吗?