from keras import backend as K from keras.losses import binary_crossentropy def dice_coef(y_true, y_pred): y_true_f = K.flatten(y_true) y_pred_f = K.flatten(y_pred) intersection = K.sum(y_true_f * y_pred_f) return (2. * intersection + 1) / (K.sum(y_true_f) + K.sum(y_pred_f) + 1) def dice_coef_rounded(y_true, y_pred): y_true_f = K.flatten(K.round(y_true)) y_pred_f = K.flatten(K.round(y_pred)) intersection = K.sum(y_true_f * y_pred_f) return (2. * intersection + 1) / (K.sum(y_true_f) + K.sum(y_pred_f) + 1) def dice_coef_loss(y_true, y_pred): return 1 - (dice_coef(y_true, y_pred)) def dice_logloss(y_true, y_pred): return binary_crossentropy(y_true, y_pred) * 0.5 + dice_coef_loss(y_true, y_pred) * 0.5 def dice_logloss2(y_true, y_pred): return binary_crossentropy(y_true, y_pred) * 0.75 + dice_coef_loss(y_true, y_pred) * 0.25 def dice_logloss3(y_true, y_pred): return binary_crossentropy(y_true, y_pred) * 0.15 + dice_coef_loss(y_true, y_pred) * 0.85 #from https://www.kaggle.com/lyakaap/weighing-boundary-pixels-loss-script-by-keras2 # weight: weighted tensor(same shape with mask image) def weighted_bce_loss(y_true, y_pred, weight): # avoiding overflow epsilon = 1e-7 y_pred = K.clip(y_pred, epsilon, 1. - epsilon) logit_y_pred = K.log(y_pred / (1. - y_pred)) # https://www.tensorflow.org/api_docs/python/tf/nn/weighted_cross_entropy_with_logits loss = (1. - y_true) * logit_y_pred + (1. + (weight - 1.) * y_true) * \ (K.log(1. + K.exp(-K.abs(logit_y_pred))) + K.maximum(-logit_y_pred, 0.)) return K.sum(loss) / K.sum(weight) def weighted_dice_loss(y_true, y_pred, weight): smooth = 1. w, m1, m2 = weight * weight, y_true, y_pred intersection = (m1 * m2) score = (2. * K.sum(w * intersection) + smooth) / (K.sum(w * m1) + K.sum(w * m2) + smooth) loss = 1. - K.sum(score) return loss def weighted_bce_dice_loss(y_true, y_pred): y_true = K.cast(y_true, 'float32') y_pred = K.cast(y_pred, 'float32') # if we want to get same size of output, kernel size must be odd number averaged_mask = K.pool2d( y_true, pool_size=(11, 11), strides=(1, 1), padding='same', pool_mode='avg') border = K.cast(K.greater(averaged_mask, 0.005), 'float32') * K.cast(K.less(averaged_mask, 0.995), 'float32') weight = K.ones_like(averaged_mask) w0 = K.sum(weight) weight += border * 2 w1 = K.sum(weight) weight *= (w0 / w1) loss = weighted_bce_loss(y_true, y_pred, weight) + \ weighted_dice_loss(y_true, y_pred, weight) return loss