Source code for zea.backend.tensorflow.losses
"""Container for custom loss functions."""
import keras
from keras import ops
[docs]
class SMSLE(keras.losses.Loss):
"""Loss function for calculating the Signed-Mean-Squared-Logarithmic-Error. This loss function
calculates the the mean squared error on log-scaled data, and then takes the sign of the
difference between the predicted and ground truth values into account.
See https://doi.org/10.1109/TMI.2020.3008537 for more information.
"""
def __init__(self, dynamic_range=60, name="smsle", **kwargs):
super().__init__(name=name, **kwargs)
self.dynamic_range = dynamic_range
[docs]
def call(self, y_true, y_pred):
"""
Args:
y_true (tensor): Ground truth values.
y_pred (tensor): The predicted values.
returns:
loss (tensor): SMSLE loss value.
"""
y_pred_max = ops.maximum(ops.max(ops.abs(y_pred)), keras.config.epsilon())
y_true_max = ops.maximum(ops.max(ops.abs(y_true)), keras.config.epsilon())
first_log_pos = ops.clip(
20
* ops.log(ops.clip(y_pred / y_pred_max, keras.config.epsilon(), 1) + 0.0)
/ ops.log(10),
-self.dynamic_range,
0,
)
secon_log_pos = ops.clip(
20
* ops.log(ops.clip(y_true / y_true_max, keras.config.epsilon(), 1) + 0.0)
/ ops.log(10),
-self.dynamic_range,
0,
)
first_log_neg = ops.clip(
20
* ops.log(ops.clip(-y_pred / y_pred_max, keras.config.epsilon(), 1) + 0.0)
/ ops.log(10),
-self.dynamic_range,
0,
)
secon_log_neg = ops.clip(
20
* ops.log(ops.clip(-y_true / y_true_max, keras.config.epsilon(), 1) + 0.0)
/ ops.log(10),
-self.dynamic_range,
0,
)
loss = 0.5 * ops.mean(ops.square(first_log_pos - secon_log_pos)) + 0.5 * ops.mean(
ops.square(first_log_neg - secon_log_neg)
)
return loss