#!/usr/bin/python3
from typing import Any, Callable
import tensorflow as tf
from tensorflow.python.keras import backend as K
[docs]def dice_coef(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Count Sorensen-Dice coefficient for output and ground-truth image.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel values
Returns
-------
float
dice coefficient calculated on predicted and input class values.
Example
-------
unagi.utils.metric_utils.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)
dice = (2.0 * intersection + 1.0) / (K.sum(y_true_f) + K.sum(y_pred_f) + 1.0)
return dice
[docs]def dice_coef_loss(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Loss of Sorensen-Dice coefficient for output and ground-truth image.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel values
Returns
-------
float
dice loss calculated from dice coefficient.
See Also
--------
dice_coef()
Example
-------
unagi.utils.metric_utils.dice_coef_loss(y_true, y_pred)
"""
return 1 - dice_coef(y_true, y_pred)
[docs]def jacard_coef(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Count Jaccard coefficient for output and ground-truth image.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel values
Returns
-------
float
Jaccard coefficient calculated on predicted and input class values.
Example
-------
unagi.utils.metric_utils.jacard_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 (intersection + 1.0) / (
K.sum(y_true_f) + K.sum(y_pred_f) - intersection + 1.0
)
[docs]def jacard_coef_loss(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Calculates loss based on Jaccard coefficient for output and ground-truth image.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel values
Returns
-------
float
Jaccard loss calculated from Jaccard coefficient.
See Also
--------
jacard_coef()
Example
-------
unagi.utils.metric_utils.jacard_coef_loss(y_true, y_pred)
"""
return 1 - jacard_coef(y_true, y_pred)
[docs]def weighted_cross_entropy(pos_weight: float = 0.2) -> Callable[[Any, Any], float]:
"""Calculates weighted cross entropy loss on predicted pixels.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel valuesass
Returns
-------
Callable[[Any, Any], float]
loss value calculated based on the weight factor
References
----------
[1] keras implementation :
https://lars76.github.io/neural-networks/object-detection/losses-for-segmentation/
Example
-------
unagi.utils.metric_utils.weighted_cross_entropy(y_true, y_pred)
"""
def convert_to_logits(y_pred: tf.Tensor) -> tf.Tensor:
y_pred = tf.clip_by_value(
y_pred,
tf.keras.backend.epsilon(),
1 - tf.keras.backend.epsilon()
)
return tf.math.log(y_pred / (1 - y_pred))
def loss(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
y_pred = convert_to_logits(y_pred)
loss = tf.nn.weighted_cross_entropy_with_logits(
logits=y_pred,
labels=y_true,
pos_weight=pos_weight
)
# or reduce_sum and/or axis=-1
return tf.reduce_mean(input_tensor=loss * (1 - pos_weight))
return loss
[docs]def focal_loss(alpha: float = 0.25, gamma: float = 2.0) -> Callable[[Any, Any], float]:
"""Calculates focal loss on predicted pixels.
Parameters
----------
alpha: float
tensor of true pixel values
gamma: float
tensor of predicted pixel valuesass
Returns
-------
Callable[[Any, Any], float]
focal loss value calculated predicted pixels.
References
----------
[1] keras implementation :
https://lars76.github.io/neural-networks/object-detection/losses-for-segmentation/
[2] oiginal paper : Focal Loss for Dense Object Detection
https://arxiv.org/abs/1708.02002
Example
-------
unagi.utils.metric_utils.focal_loss()
"""
def focal_loss_with_logits(
logits: tf.Tensor,
targets: tf.Tensor,
alpha: float,
gamma: float,
y_pred: tf.Tensor
) -> tf.Tensor:
"""Calculates focal loss based on aplha and gamma."""
weight_a = alpha * (1 - y_pred) ** gamma * targets
weight_b = (1 - alpha) * y_pred ** gamma * (1 - targets)
return (
tf.math.log1p(tf.exp(-tf.abs(logits))) + tf.nn.relu(-logits)
) * (weight_a + weight_b) + logits * weight_b
def loss(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Calculates final focal loss value."""
y_pred = tf.clip_by_value(
y_pred,
tf.keras.backend.epsilon(),
1 - tf.keras.backend.epsilon()
)
logits = tf.math.log(y_pred / (1 - y_pred))
loss = focal_loss_with_logits(
logits=logits,
targets=y_true,
alpha=alpha,
gamma=gamma,
y_pred=y_pred
)
# or reduce_sum and/or axis=-1
return tf.reduce_mean(input_tensor=loss)
return loss
[docs]def tversky(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Calculates tversky index based on predicted pixels.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel valuesass
Returns
-------
float
tversky index value calculated on predicted pixels.
Example
-------
unagi.utils.metric_utils.tversky(y_true, y_pred)
"""
smooth = 1
y_true_pos = K.flatten(y_true)
y_pred_pos = K.flatten(y_pred)
true_pos = K.sum(y_true_pos * y_pred_pos)
false_neg = K.sum(y_true_pos * (1-y_pred_pos))
false_pos = K.sum((1-y_true_pos)*y_pred_pos)
alpha = 0.7
return (true_pos + smooth)/(
true_pos + alpha*false_neg + (1-alpha)*false_pos + smooth
)
[docs]def tversky_loss(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Calculates tversky loss based on tversky index for predicted pixels.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel valuesass
Returns
-------
float
tversky loss value calculated on tversky index for predicted pixels.
Example
-------
unagi.utils.metric_utils.tversky_loss(y_true, y_pred)
"""
return 1 - tversky(y_true, y_pred)
[docs]def focal_tversky(y_true: tf.Tensor, y_pred: tf.Tensor) -> float:
"""Calculates focal-tversky loss based on tversky index for predicted pixels.
Parameters
----------
y_true: tf.Tensor
tensor of true pixel values
y_pred: tf.Tensor
tensor of predicted pixel valuesass
Returns
-------
float
focal-tversky loss value calculated on tversky index for predicted pixels.
References
----------
[1] keras implementation :
https://github.com/nabsabraham/focal-tversky-unet
[2] oiginal paper : A Novel Focal Tversky loss function with improved Attention
U-Net for lesion segmentation.
https://arxiv.org/abs/1810.07842
Example
-------
unagi.utils.metric_utils.focal_tversky(y_true, y_pred)
"""
pt_1 = tversky(y_true, y_pred)
gamma = 0.75
return K.pow((1-pt_1), gamma)