Keras - пользовательская функция потерь - расстояние фаски

Я пытаюсь сегментировать объекты с помощью настраиваемой функции потерь, как определено ниже:

def chamfer_loss_value(y_true, y_pred):           

    # flatten the batch 
    y_true_f = K.batch_flatten(y_true)
    y_pred_f = K.batch_flatten(y_pred)

    # ==========
    # get chamfer distance sum

    // error here
    y_pred_mask_f = K.cast(K.greater_equal(y_pred_f,0.5), dtype='float32')

    finalChamferDistanceSum = K.sum(y_pred_mask_f * y_true_f, axis=1, keepdims=True)  

    return K.mean(finalChamferDistanceSum)

def chamfer_loss(y_true, y_pred):   
    return chamfer_loss_value(y_true, y_pred)

y_pred_f это результат моей U-net. y_true_f является результатом преобразования евклидова расстояния на маске наземной метки истинности x, как показано ниже:

distTrans = ndimage.distance_transform_edt(1 - x)

Чтобы вычислить расстояние фаски, вы умножаете предсказанное изображение (в идеале, маску с 1 и 0) на преобразование наземного истинного расстояния и просто суммируете по всем пикселям. Для этого мне нужно было получить маску y_pred_mask_f, задав порог y_pred_f, затем умножить на y_true_f и просуммировать по всем пикселям.

y_pred_f предоставляет непрерывный диапазон значений в [0,1], и я получаю ошибку None type not supported при оценке y_true_mask_f. Я знаю, что функция потерь должна быть дифференцируемой, а greater_equal и cast - нет. Но есть ли способ обойти это в Керасе? Возможно, использовать какой-нибудь обходной путь в Tensorflow?


person Eagle    schedule 04.02.2018    source источник
comment
Это не дифференцируемо, но вам нужен градиент для оптимизации, если вы используете спуск градиента. У вас есть градиенты, определенные вручную? Если это так, вы можете вручную вычислить градиенты и вставить их. См. Здесь stackoverflow.com/questions/43839431/   -  person THN    schedule 05.02.2018


Ответы (1)


Что ж, это было сложно. Причина вашей ошибки заключается в том, что нет постоянной зависимости между вашими потерями и вашей сетью. Чтобы вычислить градиенты ваших потерь относительно в сеть, ваша потеря должна вычислить градиент индикатора, если ваш результат больше 0.5 (поскольку это единственная связь между вашим окончательным значением потерь и выходом y_pred из вашей сети). Это невозможно, так как этот показатель частично постоянный, а не непрерывный.

Возможное решение - сгладьте индикатор:

def chamfer_loss_value(y_true, y_pred):           

    # flatten the batch 
    y_true_f = K.batch_flatten(y_true)
    y_pred_f = K.batch_flatten(y_pred)

    y_pred_mask_f = K.sigmoid(y_pred_f - 0.5)

    finalChamferDistanceSum = K.sum(y_pred_mask_f * y_true_f, axis=1, keepdims=True)  

    return K.mean(finalChamferDistanceSum)

Поскольку sigmoid - это непрерывная версия пошаговой функции. Если ваш вывод исходит от sigmoid, вы можете просто использовать y_pred_f вместо y_pred_mask_f.

person Marcin Możejko    schedule 04.02.2018