Как создать гибридную потерю, состоящую из потери кубиков и потери фокуса [Python]

Я пытаюсь реализовать функцию Multiclass Hybrid loss в Python из следующей статьи https://arxiv.org/pdf/1808.05238.pdf для моей проблемы семантической сегментации с использованием несбалансированного набора данных. Мне удалось сделать свою реализацию достаточно правильной, чтобы начать обучение модели, но результаты очень плохие. Архитектура модели - U-net, скорость обучения в оптимизаторе Adam составляет 1e-5. Форма маски (Нет, 512, 512, 3) с 3 классами (в моем случае лес, вырубка леса, другое). Формула, которую я использовал для реализации своей потери: введите здесь описание изображения

Код, который я создал:

def build_hybrid_loss(_lambda_=1, _alpha_=0.5, _beta_=0.5, smooth=1e-6):
    def hybrid_loss(y_true, y_pred):
        C = 3
        tversky = 0
        # Calculate Tversky Loss
        for index in range(C):
            inputs_fl = tf.nest.flatten(y_pred[..., index])
            targets_fl = tf.nest.flatten(y_true[..., index])
        
            #True Positives, False Positives & False Negatives
            TP = tf.reduce_sum(tf.math.multiply(inputs_fl, targets_fl))
            FP = tf.reduce_sum(tf.math.multiply(inputs_fl, 1-targets_fl[0]))
            FN = tf.reduce_sum(tf.math.multiply(1-inputs_fl[0], targets_fl))
           
            tversky_i = (TP + smooth) / (TP + _alpha_ * FP + _beta_ * FN + smooth)  
            tversky += tversky_i
        tversky += C
        
        # Calculate Focal loss
        loss_focal = 0
        for index in range(C):
            f_loss = - (y_true[..., index] * (1 - y_pred[..., index])**2 * tf.math.log(y_pred[..., index]))
            # Average over each data point/image in batch
            axis_to_reduce = range(1, 3)
            f_loss = tf.math.reduce_mean(f_loss, axis=axis_to_reduce)
            loss_focal += f_loss
            
        result = tversky + _lambda_ * loss_focal
        return result
    return hybrid_loss

Прогноз модели после окончания эпохи (у меня проблема с перестановкой цветов, поэтому красный цвет в прогнозе на самом деле зеленый, что означает лес, поэтому прогноз в основном лес, а не обезлесение) ): введите здесь описание изображения

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


person Петр Воротинцев    schedule 03.02.2021    source источник
comment
I have a problem with swapped colors : если вы используете opencv, обратите внимание, что цветовое пространство по умолчанию — BGR, в то время как другие библиотеки обработки изображений обычно работают с RGB.   -  person Lescurel    schedule 03.02.2021
comment
@Lescurel, когда я начал проект, я сделал свой класс 1 = лес (зеленый цвет), а prediction[..., 0] - это предсказанная маска для леса. Но когда я использую plt.imshow(prediction), прогноз имеет три канала, как и изображение RGB, поэтому первая маска (маска леса) красная. Теперь это побочный вопрос.   -  person Петр Воротинцев    schedule 03.02.2021


Ответы (1)


Чтобы немного упростить ситуацию, я разделил гибридный проигрыш на четыре отдельные функции: проигрыш Тверски, коэффициент кости, проигрыш в кости, гибридный проигрыш. Вы можете увидеть код ниже.

def TverskyLoss(targets, inputs, alpha=0.5, beta=0.5, smooth=1e-16, numLabels=3):
    tversky = 0
    for index in range(numLabels):
        inputs_fl = tf.nest.flatten(inputs[..., index])
        targets_fl = tf.nest.flatten(targets[..., index])

        #True Positives, False Positives & False Negatives
        TP = tf.reduce_sum(tf.math.multiply(inputs_fl, targets_fl))
        FP = tf.reduce_sum(tf.math.multiply(inputs_fl, 1-targets_fl[0]))
        FN = tf.reduce_sum(tf.math.multiply(1-inputs_fl[0], targets_fl))
       
        tversky_i = (TP + smooth) / (TP + alpha*FP + beta*FN + smooth)  
        tversky += tversky_i
    return numLabels - tversky

def dice_coef(y_true, y_pred, smooth=1e-16):
    y_true_f = tf.nest.flatten(y_true)
    y_pred_f = tf.nest.flatten(y_pred)
    intersection = tf.math.reduce_sum(tf.math.multiply(y_true_f, y_pred_f))
    return (2. * intersection + smooth) / (tf.math.reduce_sum(y_true_f) + tf.math.reduce_sum(y_pred_f) + smooth)

def dice_coef_multilabel(y_true, y_pred, numLabels=3):
    dice=0
    for index in range(numLabels):
        dice -= dice_coef(y_true[..., index], y_pred[..., index])
    return numLabels + dice

def build_hybrid_loss(_lambda_=0.5, _alpha_=0.5, _beta_=0.5, smooth=1e-16, C=3):
    def hybrid_loss(y_true, y_pred):
        tversky = TverskyLoss(y_true, y_pred, alpha=_alpha_, beta=_beta_)
        dice = dice_coef_multilabel(y_true, y_pred)    
        result = tversky + _lambda_ * dice
        return result
    return hybrid_loss

Добавление loss=build_hybrid_loss() во время компиляции модели добавит гибридные потери в качестве функции потерь модели.

После недолгих исследований я пришел к выводу, что в моем конкретном случае проигрыш Гибрида с _lambda_ = 0.2, _alpha_ = 0.5, _beta_ = 0.5 будет не намного лучше, чем одиночный проигрыш Кубика или одиночный проигрыш Тверски. Ни IoU (пересечение над объединением), ни стандартная метрика точности не намного лучше с гибридными потерями. Но я полагаю, что это не эмпирическое правило, согласно которому такая гибридная потеря будет хуже или на том же уровне производительности, что и одиночная потеря во всех случаях.

ссылка на график точности

ссылка на график IoU

person Петр Воротинцев    schedule 03.02.2021