Keras 多类语义划分的u-net模型构建

Keras 多类语义划分的u-net模型构建,keras,Keras,我正在尝试在keras中构建用于多类语义分割的u-net。我下面的模型没有学到任何东西。它总是预测背景(第一)类 我使用的最终“softmax”层是否正确?显示了一个轴参数,但我不确定如何设置该参数或它应该是什么 def unet(input_shape=(572, 572, 1), classes=2): input_image = KL.Input(shape=input_shape) contracting_1, pooled_1 = blocks.contractin

我正在尝试在keras中构建用于多类语义分割的u-net。我下面的模型没有学到任何东西。它总是预测背景(第一)类

我使用的最终“softmax”层是否正确?显示了一个
参数,但我不确定如何设置该参数或它应该是什么

def unet(input_shape=(572, 572, 1), classes=2):

    input_image = KL.Input(shape=input_shape)

    contracting_1, pooled_1 = blocks.contracting(input_image,   filters=64, block_name="block1")
    contracting_2, pooled_2 = blocks.contracting(pooled_1,      filters=128, block_name="block2")
    contracting_3, pooled_3 = blocks.contracting(pooled_2,      filters=256, block_name="block3")
    contracting_4, pooled_4 = blocks.contracting(pooled_3,      filters=512, block_name="block4")
    contracting_5, _ = blocks.contracting(pooled_4,             filters=1024, block_name="block5")

    dropout = KL.Dropout(rate=0.5)(contracting_5)

    expanding_1 = blocks.expanding(dropout,     merge_layer=contracting_4, filters=512, block_name="block6")
    expanding_2 = blocks.expanding(expanding_1, merge_layer=contracting_3, filters=256, block_name="block7")
    expanding_3 = blocks.expanding(expanding_2, merge_layer=contracting_2, filters=128, block_name="block8")
    expanding_4 = blocks.expanding(expanding_3, merge_layer=contracting_1, filters=64, block_name="block9")

    class_output = KL.Conv2D(classes, kernel_size=(1, 1), activation='softmax', name='class_output')(expanding_4)

    model = KM.Model(inputs=[input_image], outputs=[class_output])

    return model
区块:

def contracting(input_layer, filters, kernel_size=(3, 3), padding='same',
                block_name=""):

    conv_a = KL.Conv2D(filters, kernel_size, activation='relu', padding=padding,
                       name='{}_contracting_conv_a'.format(block_name))(input_layer)
    conv_b = KL.Conv2D(filters, kernel_size, activation='relu', padding=padding,
                       name='{}_contracting_conv_b'.format(block_name))(conv_a)
    pool = KL.MaxPooling2D(pool_size=(2, 2), padding=padding,
                           name='{}_contracting_pool'.format(block_name))(conv_b)

    batch_normalization = KL.BatchNormalization()(pool)

    return conv_b, batch_normalization


def expanding(input_layer, merge_layer, filters, kernel_size=(3, 3), padding='same',
              block_name=""):

    input_layer = KL.UpSampling2D(size=(2, 2))(input_layer)

    conv_up = KL.Conv2D(filters, kernel_size=(2, 2), activation='relu',
                        padding='same', name='{}_expanding_conv_up'.format(block_name))(input_layer)

    conv_up_height, conv_up_width = int(conv_up.shape[1]), int(conv_up.shape[2])
    merge_height, merge_width = int(merge_layer.shape[1]), int(merge_layer.shape[2])

    crop_top = (merge_height - conv_up_height) // 2
    crop_bottom = (merge_height - conv_up_height) - crop_top
    crop_left = (merge_width - conv_up_width) // 2
    crop_right = (merge_width - conv_up_width) - crop_left

    cropping = ((crop_top, crop_bottom), (crop_left, crop_right))
    merge_layer = KL.Cropping2D(cropping)(merge_layer)
    merged = KL.concatenate([merge_layer, conv_up])

    conv_a = KL.Conv2D(filters, kernel_size, activation='relu', padding=padding,
                       name='{}_expanding_conv_a'.format(block_name))(merged)
    conv_b = KL.Conv2D(filters, kernel_size, activation='relu', padding=padding,
                       name='{}_expanding_conv_b'.format(block_name))(conv_a)

    batch_normalization = KL.BatchNormalization()(conv_b)

    return batch_normalization
汇编:

optimizer = keras.optimizers.SGD(lr=0.0001, momentum=0.9)
loss = keras.losses.categorical_crossentropy
metrics = [keras.metrics.categorical_accuracy]

model.compile(optimizer, loss, metrics)
模型摘要:


数据集中的类百分比:

{0: 0.6245757457188198,
 1: 0.16082110268729075,
 2: 0.1188858904157366,
 3: 0.09571726117815291}
  • class
    0
    是背景
  • 来自生成器(rgb)的图像形状:
    (1,96,96,3)
  • 生成器的标签形状:
    (1,96,96,4)

    • 您的模型中似乎没有任何错误

      Softmax是正常的,因为它默认为最后一个轴,并且您显然使用了
      'channels\u last'
      作为配置。所以没关系

      建议如下:

      • 添加一些
        BatchNormalization()
        层,降低您的学习速度(这可以防止relu过快地变成“全零”)
      • 检查您的输出数据范围是否正确,
        np.unique(y\u train)
        仅包含0和1
      • 检查每个像素是否仅按一个类别分类:
        (np.sum(y\u列,轴=-1)==1)。all()==True
      • 检查您的图像是否过于偏向第一类
        np.sum(y_列[,:,:,0])
        不应大于
        np.sum(y_列[,:,:,1:])
          如果是,请考虑使用<代码>类质量权重>代码>参数,通过权重来平衡每个类的丢失(检查代码>文件> <代码>如何使用它)

      这个模型对我来说非常适合大多数分割项目,我使用交叉熵进行多类分割,使用平滑骰子进行二进制类分割

      def conv_block(tensor, nfilters, size=3, padding='same', initializer="he_normal"):
          x = Conv2D(filters=nfilters, kernel_size=(size, size), padding=padding, kernel_initializer=initializer)(tensor)
          x = BatchNormalization()(x)
          x = Activation("relu")(x)
          x = Conv2D(filters=nfilters, kernel_size=(size, size), padding=padding, kernel_initializer=initializer)(x)
          x = BatchNormalization()(x)
          x = Activation("relu")(x)
          return x
      
      
      def deconv_block(tensor, residual, nfilters, size=3, padding='same', strides=(2, 2)):
          y = Conv2DTranspose(nfilters, kernel_size=(size, size), strides=strides, padding=padding)(tensor)
          y = concatenate([y, residual], axis=3)
          y = conv_block(y, nfilters)
          return y
      
      
      def Unet(img_height, img_width, nclasses=3, filters=64):
      # down
          input_layer = Input(shape=(img_height, img_width, 3), name='image_input')
          conv1 = conv_block(input_layer, nfilters=filters)
          conv1_out = MaxPooling2D(pool_size=(2, 2))(conv1)
          conv2 = conv_block(conv1_out, nfilters=filters*2)
          conv2_out = MaxPooling2D(pool_size=(2, 2))(conv2)
          conv3 = conv_block(conv2_out, nfilters=filters*4)
          conv3_out = MaxPooling2D(pool_size=(2, 2))(conv3)
          conv4 = conv_block(conv3_out, nfilters=filters*8)
          conv4_out = MaxPooling2D(pool_size=(2, 2))(conv4)
          conv4_out = Dropout(0.5)(conv4_out)
          conv5 = conv_block(conv4_out, nfilters=filters*16)
          conv5 = Dropout(0.5)(conv5)
      # up
          deconv6 = deconv_block(conv5, residual=conv4, nfilters=filters*8)
          deconv6 = Dropout(0.5)(deconv6)
          deconv7 = deconv_block(deconv6, residual=conv3, nfilters=filters*4)
          deconv7 = Dropout(0.5)(deconv7) 
          deconv8 = deconv_block(deconv7, residual=conv2, nfilters=filters*2)
          deconv9 = deconv_block(deconv8, residual=conv1, nfilters=filters)
      # output
          output_layer = Conv2D(filters=nclasses, kernel_size=(1, 1))(deconv9)
          output_layer = BatchNormalization()(output_layer)
          output_layer = Activation('softmax')(output_layer)
      
          model = Model(inputs=input_layer, outputs=output_layer, name='Unet')
          return model
      

      有时,问题与模型体系结构有关。在处理复杂的数据集进行分割时,需要增强模型体系结构。我在一个新的数据集上遇到了同样的问题,而该模型可以在另一个数据集上很好地工作。因此,我使用Res-Unet而不是Unet作为模型架构并解决了问题。
      希望这会有帮助

      什么是好的学习率?我试过1e-5。班级比例分别为62%、16%、12%、10%。我试着用它作为我的损失。它应该解决阶级平衡问题吗
      np.unique(标签)
      array([0,1],dtype=int8)
      <代码>np。唯一(数据)是1004个不同的值,从4到254,作为浮点32。我还试着减去平均值(
      (123.68116.779103.939)
      ),以及其他标准化,但没有一个是有效的。我在使用
      (np.sum(labels,axis=-1)==1)时遇到问题。all()==True
      返回True如果使用类权重,请使用
      {0:100/62,1:100/16,2:100/12,3:100/10.}
      和一些标准keras损失(您的jaccard可能正在折叠keras将用于应用权重的某些维度)。分类交叉熵似乎是个不错的选择。试试
      BatchNormalization()
      层,每个块一层应该是个好主意。好的,我试试BatchNormalization。当我尝试使用类权重时,我得到:
      “类权重”不支持3+维目标。
      我使用的是
      fit\u生成器。
      。Argh…:(-好吧……只要确保你的训练准确率高于62%。既然
      class\u weights
      似乎对keras不起作用,你是如何克服班级不平衡的?@Jonathan,我最后用了感谢你给我发的那篇帖子。只是为了确认一下,你使用了加权交叉熵,对吗?你是如何传递班级权重的它们是如何计算的?你是否也使用了论坛中建议的class_weights函数?如果你提供了解决方法,这对本文将非常有帮助。例如,你的损失函数和将其传递到compile中所需的修改。
      def conv_block(tensor, nfilters, size=3, padding='same', initializer="he_normal"):
          x = Conv2D(filters=nfilters, kernel_size=(size, size), padding=padding, kernel_initializer=initializer)(tensor)
          x = BatchNormalization()(x)
          x = Activation("relu")(x)
          x = Conv2D(filters=nfilters, kernel_size=(size, size), padding=padding, kernel_initializer=initializer)(x)
          x = BatchNormalization()(x)
          x = Activation("relu")(x)
          return x
      
      
      def deconv_block(tensor, residual, nfilters, size=3, padding='same', strides=(2, 2)):
          y = Conv2DTranspose(nfilters, kernel_size=(size, size), strides=strides, padding=padding)(tensor)
          y = concatenate([y, residual], axis=3)
          y = conv_block(y, nfilters)
          return y
      
      
      def Unet(img_height, img_width, nclasses=3, filters=64):
      # down
          input_layer = Input(shape=(img_height, img_width, 3), name='image_input')
          conv1 = conv_block(input_layer, nfilters=filters)
          conv1_out = MaxPooling2D(pool_size=(2, 2))(conv1)
          conv2 = conv_block(conv1_out, nfilters=filters*2)
          conv2_out = MaxPooling2D(pool_size=(2, 2))(conv2)
          conv3 = conv_block(conv2_out, nfilters=filters*4)
          conv3_out = MaxPooling2D(pool_size=(2, 2))(conv3)
          conv4 = conv_block(conv3_out, nfilters=filters*8)
          conv4_out = MaxPooling2D(pool_size=(2, 2))(conv4)
          conv4_out = Dropout(0.5)(conv4_out)
          conv5 = conv_block(conv4_out, nfilters=filters*16)
          conv5 = Dropout(0.5)(conv5)
      # up
          deconv6 = deconv_block(conv5, residual=conv4, nfilters=filters*8)
          deconv6 = Dropout(0.5)(deconv6)
          deconv7 = deconv_block(deconv6, residual=conv3, nfilters=filters*4)
          deconv7 = Dropout(0.5)(deconv7) 
          deconv8 = deconv_block(deconv7, residual=conv2, nfilters=filters*2)
          deconv9 = deconv_block(deconv8, residual=conv1, nfilters=filters)
      # output
          output_layer = Conv2D(filters=nclasses, kernel_size=(1, 1))(deconv9)
          output_layer = BatchNormalization()(output_layer)
          output_layer = Activation('softmax')(output_layer)
      
          model = Model(inputs=input_layer, outputs=output_layer, name='Unet')
          return model