Keras: объединить несколько выходов в окончательный вывод в сегментации изображения - PullRequest
0 голосов
/ 22 апреля 2020

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

Сначала я использовал сеть Unet. И я получаю правильные результаты.

Во время исследования я наткнулся на несколько научных c статей, посвященных этой теме.

В этой статье: https://www.researchgate.net/publication/328649776_DeepCrack_Learning_Hierarchical_Convolutional_Features_for_Crack_Detection

они используют эту архитектуру:

enter image description here

Это архитектура на основе gnet. За исключением того, что между каждым «уровнем» кодера / декодера имеется промежуточное изображение, выводимое с его собственной потерей. В конце сети 5 изображений объединяются, и на выходе будет одно изображение.

Это пример всех промежуточных изображений:

enter image description here

Модель была закодирована в кофе и код недоступен (по крайней мере, я не нашел его)

Я пытался реализовать эту архитектуру в Keras

И это это то, что я получил сейчас (я показываю только конкатенирующую часть, в противном случае она будет слишком длинной):

# CONCATENATE
# S1
concat_1 = concatenate([b5, b6])
conv_1 = Conv2D(filters=1, kernel_size=(1, 1), padding='same', activation='relu')(concat_1)
deconv_1 = Deconv2D(filters=1, kernel_size=(32, 32), strides=(16, 16), padding='same')(conv_1)
scale_1 = Activation(activation='sigmoid', name='scale_1')(deconv_1)

# S2
concat_2 = concatenate([b4, b7])
conv_2 = Conv2D(filters=1, kernel_size=(1, 1), padding='same', activation='relu')(concat_2)
deconv_2 = Deconv2D(filters=1, kernel_size=(16, 16), strides=(8, 8), padding='same')(conv_2)
scale_2 = Activation(activation='sigmoid', name='scale_2')(deconv_2)

# S3
concat_3 = concatenate([b3, b8])
conv_3 = Conv2D(filters=1, kernel_size=(1, 1), padding='same', activation='relu')(concat_3)
deconv_3 = Deconv2D(filters=1, kernel_size=(8, 8), strides=(4, 4), padding='same')(conv_3)
scale_3 = Activation(activation='sigmoid', name='scale_3')(deconv_3)

# S4
concat_4 = concatenate([b2, b9])
conv_4 = Conv2D(filters=1, kernel_size=(1, 1), padding='same', activation='relu')(concat_4)
deconv_4 = Deconv2D(filters=1, kernel_size=(4, 4), strides=(2, 2), padding='same')(conv_4)
scale_4 = Activation(activation='sigmoid', name='scale_4')(deconv_4)

# S5
concat_5 = concatenate([b1, b10])
conv_5 = Conv2D(filters=1, kernel_size=(1, 1), padding='same', activation='relu')(concat_5)
deconv_5 = Deconv2D(filters=1, kernel_size=(1, 1), strides=(1, 1), padding='same')(conv_5)
scale_5 = Activation(activation='sigmoid', name='scale_5')(deconv_5)

# FINAL CONCATENATE
final_concate = concatenate([deconv_1, deconv_2, deconv_3, deconv_4, deconv_5])
final_conv = Conv2D(filters=1, kernel_size=(1, 1), padding='same', activation='sigmoid', name='final_output')(
    final_concate)

model = Model(inputs, outputs=[scale_1, scale_2, scale_3, scale_4, scale_5, final_conv])
model.compile(optimizer=Adam(),
              loss={'scale_1': 'binary_crossentropy',
                    'scale_2': 'binary_crossentropy',
                    'scale_3': 'binary_crossentropy',
                    'scale_4': 'binary_crossentropy',
                    'scale_5': 'binary_crossentropy',
                    'final_output': 'binary_crossentropy'}
              , loss_weights={'scale_1': 0.1,
                              'scale_2': 0.2,
                              'scale_3': 0.4,
                              'scale_4': 0.8,
                              'scale_5': 1.0,
                              'final_output': 1.0}
              , metrics={'final_output': 'accuracy'})
model.summary()

return model

Таким образом, у меня есть 5 промежуточных выходов и конечный выход.

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

Примерно так:

y_train = {
    "scale_1": y_train,
    "scale_2": y_train,
    "scale_3": y_train,
    "scale_4": y_train,
    "scale_5": y_train,
    "final_output": y_train
}

y_test = {
    "scale_1": y_test,
    "scale_2": y_test,
    "scale_3": y_test,
    "scale_4": y_test,
    "scale_5": y_test,
    "final_output": y_test
}
model.fit(X_train, y_train, batch_size=16, epochs=10, validation_data=[X_test, y_test])

Но проблема в том, что я не получаю никаких результатов во время тренировок. Каждая потеря отрицательна. Я использую кросс-энтропию для каждого выхода.

Возможно, я делаю это неправильно. Или что этот тип сети не может быть реализован в Keras

У вас есть предложения?

Я понимаю, что это большой вопрос и что он может не подходить для формата переполнения стека. Я удалю его при необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...