2

我的问题:

我正在尝试在 tf.keras 中训练语义分割模型,事实上,当我使用 channels_last (WHC) 模式时它运行良好(它达到 96%+ val acc)。我想在 channels_first (CHW) 模式下训练它,以便权重与 TensorRT 兼容。当我这样做时,前几个 epoch 中约 80% 的训练准确率下降到 0.020% 左右并永久保持在那里。

知道我的模型的基础是tf.keras.applications.MobileNet()具有预先训练的“imagenet”权重的模型很有用。(底部的模型架构。)

改造过程:

我使用了提供的指南,在这里只更改了几件事:

  1. 设置tf.keras.backend.set_image_data_format()为“channels_first”。
  2. 我将输入张量中的通道顺序从:input_tensor=Input(shape=(376, 672, 3)) 更改为:input_tensor=Input(shape=(3, 376, 672))
  3. 在我的图像预处理(使用tf.data.Dataset)中,我tf.transpose(img, perm=[2, 0, 1])在输入图像和单热编码掩码上都使用了来更改通道顺序。我用相等断言检查了这个,以确保它正确并且看起来很好。

当我更改这些时,训练开始正常,但正如我所说,训练准确度几乎下降到零。当我恢复一切时,一切都很好。

可能的线索:

我做错了什么或者这里有什么问题?我的怀疑是围绕这些问题:

  • 当我设置后端时,预训练的 imageNet 权重是否也更改为“channels_first”顺序?这是我应该考虑的事情吗?
  • 会不会是tf.transpose()函数弄乱了掩码的 one-hot 编码?(我有 3 个类别由 3 种颜色表示:车道、对面车道、背景)

也许我没有看到明显的东西。我可以根据需要提供进一步的代码和答案。

编辑:

08/17:这仍然是一个持续的问题,我尝试了几件事:

  • 我用 numpy 断言转置后检查了图像和掩码是否正确,似乎正确。
  • 我怀疑损失函数在错误的轴上计算,所以我为第一个轴(通道所在的位置)定制了损失函数。这里是:
def ReverseAxisLoss(y_true, y_pred):
    return K.categorical_crossentropy(y_true, y_pred, from_logits=True, axis=1)
  • 我的主要怀疑是“通道优先”后端设置对移动网络部分的预训练“imagenet”权重没有任何作用。TF2.x / Keras 是否有更新的方法将预训练的权重转换为 CHW 格式?

这里是我使用的架构(theskipNet()是head network,mobilenet是base,在create_model()function里面是connected)

def skipNet(encoder_output, feed1, feed2, classes):
    # random initializer and regularizer
    stddev = 0.01
    init = RandomNormal(stddev=stddev)

    weight_decay = 1e-3
    reg = l2(weight_decay)
   

    score_feed2 = Conv2D(kernel_size=(1, 1), filters=classes, padding="SAME",
                kernel_initializer=init, kernel_regularizer=reg)(feed2)
    score_feed2_bn = BatchNormalization()(score_feed2)
    score_feed1 = Conv2D(kernel_size=(1, 1), filters=classes, padding="SAME",
                kernel_initializer=init, kernel_regularizer=reg)(feed1)
    score_feed1_bn = BatchNormalization()(score_feed1)

   

    upscore2 = Conv2DTranspose(kernel_size=(4, 4), filters=classes, strides=(2, 2),
                               padding="SAME", kernel_initializer=init,
                               kernel_regularizer=reg)(encoder_output)
    height_pad1 = ZeroPadding2D(padding=((1,0),(0,0)))(upscore2)
    upscore2_bn = BatchNormalization()(height_pad1)

    fuse_feed1 = add([score_feed1_bn, upscore2_bn])

    upscore4 = Conv2DTranspose(kernel_size=(4, 4), filters=classes, strides=(2, 2),
                               padding="SAME", kernel_initializer=init,
                               kernel_regularizer=reg)(fuse_feed1)
    height_pad2 = ZeroPadding2D(padding=((0,1),(0,0)))(upscore4)
    upscore4_bn = BatchNormalization()(height_pad2)

    fuse_feed2 = add([score_feed2_bn, upscore4_bn])

    upscore8 = Conv2DTranspose(kernel_size=(16, 16), filters=classes, strides=(8, 8),
                               padding="SAME", kernel_initializer=init,
                               kernel_regularizer=reg, activation="softmax")(fuse_feed2)

    return upscore8

def create_model(classes):

    base_model = tf.keras.applications.MobileNet(input_tensor=Input(shape=IMG_SHAPE),
                                                 include_top=False,
                                                 weights='imagenet')
   
    conv4_2_output = base_model.get_layer(index=43).output
    conv3_2_output = base_model.get_layer(index=30).output
    conv_score_output = base_model.output

    head_model = skipNet(conv_score_output, conv4_2_output, conv3_2_output, classes)

    for layer in base_model.layers:
        layer.trainable = False

    model = Model(inputs=base_model.input, outputs=head_model)

    return model
4

0 回答 0