U-сеть с попиксельной взвешенной кросс-энтропией: ошибки входного измерения - PullRequest
1 голос
/ 18 марта 2019

Я использовал реализацию U-Net от Zhixuhao , чтобы попытаться выполнить семантическую двоичную сегментацию, и я слегка изменил ее, используя предложения из этого ответа Stackoverflow: Keras, двоичная сегментация, добавляет вес к потерефункция
, чтобы иметь возможность выполнять попиксельно взвешенную двоичную кросс-энтропию, как они делают в оригинальной бумаге U-Net ( см. стр. 5 ), чтобы заставить мою U-Netузнать границы пикселей.По сути, идея состоит в том, чтобы добавить лямбда-слой, который вычисляет взвешенную по пикселям перекрестную энтропию внутри самой модели, а затем использовать «потерю идентичности», которая просто копирует выходные данные сети.

Вот что мойВходные данные выглядят так:
Входное изображение Groundtruth Вес

А вот как выглядит мой код:

def unet(pretrained_weights = None,input_size = (256,256,1)):

    inputs = Input(input_size)
    # [... Unet architecture from Zhixuhao's model.py file...]
    conv10 = Conv2D(1, 1, activation = 'sigmoid', name='true_output')(conv9)

    mask_weights = Input(input_size)
    true_masks = Input(input_size)
    loss1 = Lambda(weighted_binary_loss, output_shape=input_size, name='loss_output')([conv10, mask_weights, true_masks])

    model = Model(inputs = [inputs, mask_weights, true_masks], outputs = loss1)
    model.compile(optimizer = Adam(lr = 1e-4), loss =identity_loss)

И добавил эти две функции:

def weighted_binary_loss(X):
    y_pred, weights, y_true = X
    loss = keras.losses.binary_crossentropy(y_pred, y_true)
    loss = multiply([loss, weights])
    return loss

def identity_loss(y_true, y_pred):
    return y_pred

И наконец вот соответствующая часть моего main.py:

input_size = (256,256,1)
target_size = (256,256)
myGene = trainGenerator(5,'data/moma/train','img','seg','wei',data_gen_args,save_to_dir=None,target_size=target_size)
model = unet(input_size=input_size)
model_checkpoint = ModelCheckpoint('unet_moma_weights.hdf5',monitor='loss',verbose=1, save_best_only=True)
model.fit_generator(myGene,steps_per_epoch=300,epochs=5,callbacks=[model_checkpoint])

Теперь этот код работает нормально, я могу тренироватьсямой U-Net, и он распознает граничные пиксели, но только , если я изменю размер входных изображений до 256 * 256.Если я вместо этого использую input_size = (256,32,1) и target_size = (256,32) в main.py, который является релевантными измерениями для моих данных и который позволяет мне использовать большие размеры пакетов, я получаю следующую ошибку:

ValueError: Операнды не могут передаваться вместе с фигурами (256, 32, 1) (256, 32)

Для строки loss = multiply([loss, weights]).И действительно, веса имеют одно дополнительное одноэлементное измерение.Я не понимаю, почему ошибка не возникает, когда я использую 256 * 256 входов, но я попытался сделать оба входа одинаковыми с помощью k.expand_dims () или Reshape (), но пока код не выдает ошибкуи потери сходятся, когда я тестирую свою сеть на дополнительных входах, я получаю пустые выходы (то есть полностью серые, белые или черные изображения или вещи, которые не имеют ничего общего с моими входами).

Так что это многотекста следующего вопроса: почему multiply () выдает ошибку в случае 256 * 32, а не 256 * 256, и почему создание / удаление измерений на входах не помогает?

Спасибо!

ps: чтобы заставить сеть выводить фактический прогноз вместо потери по пикселям после тренировки, я удаляю слой потерь и два дополнительных входных слоя со следующим кодом:

new_model = Model(inputs=model.inputs,outputs=model.get_layer("true_output").output)
new_model.compile(optimizer = Adam(lr = 1e-4), loss = 'binary_crossentropy')
new_model.set_weights(model.get_weights())

Это отлично работает (опять же в случае 256 * 256 по крайней мере)

...