Точность обучения "сначала каналы" очень низкая по сравнению с "последними каналами" - PullRequest
1 голос
/ 06 августа 2020

Моя проблема:

Я пытаюсь обучить модель сегментации semanti c в tf.keras, на самом деле она работает очень хорошо, когда я использую режим channels_last (WH C) (он достигает 96% + значение a cc). Я хотел обучить его в режиме channels_first (CHW) , чтобы веса были совместимы с TensorRT. Когда я это делаю, точность обучения ~ 80% в первые несколько эпох опускается примерно до 0,020% и остается там постоянно.

Полезно знать, что основа моей модели представляет собой модель tf.keras.applications.MobileNet() с предварительно обученными весами 'imag enet'. (Архитектура модели внизу.)

Процесс преобразования:

Я использовал предоставленные рекомендации и изменил здесь только несколько вещей:

  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]) как на моем входном изображении, так и на маске с горячим кодированием, чтобы изменить порядок каналов. Я проверил это с помощью утверждения равенства, чтобы убедиться, что оно правильное, и вроде бы все в порядке.

Когда я меняю их, обучение начинается нормально, но, как я уже сказал, точность обучения снижается почти до нуля. Когда я возвращаюсь обратно, все снова в порядке.

Возможные зацепки:

Что я делаю не так или в чем может быть проблема? Мои подозрения связаны с этими вопросами:

  • Изменились ли веса предварительно обученного изображения eNet на порядок «channels_first» также, когда я устанавливаю бэкэнд? Должен ли я вообще об этом подумать?
  • Может быть, функция tf.transpose() испортила горячую кодировку маски? (У меня есть 3 класса, представленные 3 цветами: полоса, противоположная полоса, фон)

Возможно, я не вижу чего-то очевидного. При необходимости я могу предоставить дополнительный код и ответы.

РЕДАКТИРОВАТЬ:

08/17: Это все еще актуальная проблема, я пробовал несколько вещей:

  • Я проверил правильность изображения и маски после транспонирования с утверждением numpy, кажется правильным.
  • Я подозревал, что функция потерь вычисляется не на той оси, поэтому я настроил функцию потерь для первой оси (где каналы). Вот он:
def ReverseAxisLoss(y_true, y_pred):
    return K.categorical_crossentropy(y_true, y_pred, from_logits=True, axis=1)
  • Мое главное подозрение в том, что бэкэнд-настройка «сначала каналы» ничего не делает для транспонирования предварительно обученных весов «imag enet» для mobil enet часть. Есть ли обновленный способ для TF2.x / Keras транспонировать предварительно обученные веса в формат CHW?

Вот архитектура , которую я использую (skipNet() это головная сеть и мобил enet это база, и она подключена в функции create_model())

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
...