Module delta.extensions.losses
Various helpful loss functions.
Functions
def dice_coef(y_true, y_pred, smooth=1)-
Dice = (2|X & Y|)/ (|X|+ |Y|) = 2sum(|A*B|)/(sum(A^2)+sum(B^2)) ref: https://arxiv.org/pdf/1606.04797v1.pdf
def dice_loss(y_true, y_pred)-
Dice coefficient as a loss function.
def ms_ssim(y_true, y_pred)-
tf.image.ssim_multiscaleas a loss function. This loss function requires two dimensional inputs. def ms_ssim_mse(y_true, y_pred)-
Sum of MS-SSIM and Mean Squared Error.
def suggest_filter_size(image1, image2, power_factors, filter_size)-
Figure out if we need to shrink the filter to accomodate a smaller input image
def surface_loss(y_true, y_pred)
Classes
class MappedBinaryCrossentropy (mapping, name=None, reduction='auto')-
MappedLossfor binary_crossentropy.This is a base class for losses when the labels of the input images do not match the labels output by the network. For example, if one class in the labels should be ignored, or two classes in the label should map to the same output, or one label should be treated as a probability between two classes. It applies a transform to the output labels and then applies the loss function.
Note that the transform is applied after preprocessing (labels in the config will be transformed to 0-n in order, and nodata will be n+1).
Parameters
mapping- One of:
* A list with transforms, where the first entry is what to transform the first label, to etc., i.e.,
[1, 0] will swap the order of two labels.
* A dictionary with classes mapped to transformed values. Classes can be referenced by name or by
number (see
ClassesConfig.class_id()for class formats). name:Optional[str]- Optional name for the loss function.
Expand source code
class MappedBinaryCrossentropy(MappedLoss): """ `MappedLoss` for binary_crossentropy. """ def call(self, y_true, y_pred): (y_true, y_pred) = self.preprocess(y_true, y_pred) return tensorflow.keras.losses.binary_crossentropy(y_true, y_pred)Ancestors
- MappedLoss
- keras.src.losses.Loss
Methods
def call(self, y_true, y_pred)-
Invokes the
Lossinstance.Args
y_true- Ground truth values. shape =
[batch_size, d0, .. dN], except sparse loss functions such as sparse categorical crossentropy where shape =[batch_size, d0, .. dN-1] y_pred- The predicted values. shape =
[batch_size, d0, .. dN]
Returns
Loss values with the shape
[batch_size, d0, .. dN-1].
Inherited members
class MappedCategoricalCrossentropy (mapping, name=None, reduction='auto')-
MappedLossfor categorical_crossentropy.This is a base class for losses when the labels of the input images do not match the labels output by the network. For example, if one class in the labels should be ignored, or two classes in the label should map to the same output, or one label should be treated as a probability between two classes. It applies a transform to the output labels and then applies the loss function.
Note that the transform is applied after preprocessing (labels in the config will be transformed to 0-n in order, and nodata will be n+1).
Parameters
mapping- One of:
* A list with transforms, where the first entry is what to transform the first label, to etc., i.e.,
[1, 0] will swap the order of two labels.
* A dictionary with classes mapped to transformed values. Classes can be referenced by name or by
number (see
ClassesConfig.class_id()for class formats). name:Optional[str]- Optional name for the loss function.
Expand source code
class MappedCategoricalCrossentropy(MappedLoss): """ `MappedLoss` for categorical_crossentropy. """ def call(self, y_true, y_pred): y_true = tf.squeeze(y_true) (y_true, y_pred) = self.preprocess(y_true, y_pred) return tensorflow.keras.losses.categorical_crossentropy(y_true, y_pred)Ancestors
- MappedLoss
- keras.src.losses.Loss
Methods
def call(self, y_true, y_pred)-
Invokes the
Lossinstance.Args
y_true- Ground truth values. shape =
[batch_size, d0, .. dN], except sparse loss functions such as sparse categorical crossentropy where shape =[batch_size, d0, .. dN-1] y_pred- The predicted values. shape =
[batch_size, d0, .. dN]
Returns
Loss values with the shape
[batch_size, d0, .. dN-1].
Inherited members
class MappedDiceBceMsssim (mapping, name=None, reduction='auto')-
MappedLossfor sum ofms_ssim(),dice_loss(), andbinary_crossentropy.This is a base class for losses when the labels of the input images do not match the labels output by the network. For example, if one class in the labels should be ignored, or two classes in the label should map to the same output, or one label should be treated as a probability between two classes. It applies a transform to the output labels and then applies the loss function.
Note that the transform is applied after preprocessing (labels in the config will be transformed to 0-n in order, and nodata will be n+1).
Parameters
mapping- One of:
* A list with transforms, where the first entry is what to transform the first label, to etc., i.e.,
[1, 0] will swap the order of two labels.
* A dictionary with classes mapped to transformed values. Classes can be referenced by name or by
number (see
ClassesConfig.class_id()for class formats). name:Optional[str]- Optional name for the loss function.
Expand source code
class MappedDiceBceMsssim(MappedLoss): """ `MappedLoss` for sum of `ms_ssim`, `dice_loss`, and `binary_crossentropy`. """ def call(self, y_true, y_pred): (y_true, y_pred) = self.preprocess(y_true, y_pred) dice = dice_loss(y_true, y_pred) bce = tensorflow.keras.losses.binary_crossentropy(y_true, y_pred) msssim = ms_ssim(y_true, y_pred) # / tf.cast(tf.size(y_true), tf.float32) msssim = tf.expand_dims(tf.expand_dims(msssim, -1), -1) return dice + bce + msssimAncestors
- MappedLoss
- keras.src.losses.Loss
Methods
def call(self, y_true, y_pred)-
Invokes the
Lossinstance.Args
y_true- Ground truth values. shape =
[batch_size, d0, .. dN], except sparse loss functions such as sparse categorical crossentropy where shape =[batch_size, d0, .. dN-1] y_pred- The predicted values. shape =
[batch_size, d0, .. dN]
Returns
Loss values with the shape
[batch_size, d0, .. dN-1].
Inherited members
class MappedDiceLoss (mapping, name=None, reduction='auto')-
MappedLossfordice_loss().This is a base class for losses when the labels of the input images do not match the labels output by the network. For example, if one class in the labels should be ignored, or two classes in the label should map to the same output, or one label should be treated as a probability between two classes. It applies a transform to the output labels and then applies the loss function.
Note that the transform is applied after preprocessing (labels in the config will be transformed to 0-n in order, and nodata will be n+1).
Parameters
mapping- One of:
* A list with transforms, where the first entry is what to transform the first label, to etc., i.e.,
[1, 0] will swap the order of two labels.
* A dictionary with classes mapped to transformed values. Classes can be referenced by name or by
number (see
ClassesConfig.class_id()for class formats). name:Optional[str]- Optional name for the loss function.
Expand source code
class MappedDiceLoss(MappedLoss): """ `MappedLoss` for `dice_loss`. """ def call(self, y_true, y_pred): (y_true, y_pred) = self.preprocess(y_true, y_pred) return dice_loss(y_true, y_pred)Ancestors
- MappedLoss
- keras.src.losses.Loss
Methods
def call(self, y_true, y_pred)-
Invokes the
Lossinstance.Args
y_true- Ground truth values. shape =
[batch_size, d0, .. dN], except sparse loss functions such as sparse categorical crossentropy where shape =[batch_size, d0, .. dN-1] y_pred- The predicted values. shape =
[batch_size, d0, .. dN]
Returns
Loss values with the shape
[batch_size, d0, .. dN-1].
Inherited members
class MappedLoss (mapping, name=None, reduction='auto')-
Loss base class.
To be implemented by subclasses: *
call(): Contains the logic for loss calculation usingy_true,y_pred.Example subclass implementation:
class MeanSquaredError(Loss): def call(self, y_true, y_pred): return tf.reduce_mean(tf.math.square(y_pred - y_true), axis=-1)When using a Loss under a
tf.distribute.Strategy, except passing it toModel.compile()for use byModel.fit(), please use reduction types 'SUM' or 'NONE', and reduce losses explicitly. Using 'AUTO' or 'SUM_OVER_BATCH_SIZE' will raise an error when calling the Loss object from a custom training loop or from user-defined code inLayer.call(). Please see this custom training tutorial for more details on this.This is a base class for losses when the labels of the input images do not match the labels output by the network. For example, if one class in the labels should be ignored, or two classes in the label should map to the same output, or one label should be treated as a probability between two classes. It applies a transform to the output labels and then applies the loss function.
Note that the transform is applied after preprocessing (labels in the config will be transformed to 0-n in order, and nodata will be n+1).
Parameters
mapping- One of:
* A list with transforms, where the first entry is what to transform the first label, to etc., i.e.,
[1, 0] will swap the order of two labels.
* A dictionary with classes mapped to transformed values. Classes can be referenced by name or by
number (see
ClassesConfig.class_id()for class formats). name:Optional[str]- Optional name for the loss function.
Expand source code
class MappedLoss(tf.keras.losses.Loss): #pylint: disable=abstract-method def __init__(self, mapping, name=None, reduction=losses_utils.ReductionV2.AUTO): """ This is a base class for losses when the labels of the input images do not match the labels output by the network. For example, if one class in the labels should be ignored, or two classes in the label should map to the same output, or one label should be treated as a probability between two classes. It applies a transform to the output labels and then applies the loss function. Note that the transform is applied after preprocessing (labels in the config will be transformed to 0-n in order, and nodata will be n+1). Parameters ---------- mapping One of: * A list with transforms, where the first entry is what to transform the first label, to etc., i.e., [1, 0] will swap the order of two labels. * A dictionary with classes mapped to transformed values. Classes can be referenced by name or by number (see `delta.imagery.imagery_config.ClassesConfig.class_id` for class formats). name: Optional[str] Optional name for the loss function. """ super().__init__(name=name, reduction=reduction) self._mapping = mapping self._nodata_classes = [] if isinstance(mapping, list): map_list = mapping # replace nodata for (i, me) in enumerate(map_list): if me == 'nodata': j = 0 while map_list[i] == 'nodata': if j == len(map_list): raise ValueError('All mapping entries are nodata.') if map_list[j] != 'nodata': map_list[i] = map_list[j] break j += 1 self._nodata_classes.append(i) else: # automatically set nodata to 0 (even if there is none it's fine) entry = mapping[next(iter(mapping))] if np.isscalar(entry): map_list = np.zeros((len(config.dataset.classes) + 1,)) else: map_list = np.zeros((len(config.dataset.classes) + 1, len(entry))) assert len(mapping) == len(config.dataset.classes), 'Must specify all classes in loss mapping.' for k in mapping: i = config.dataset.classes.class_id(k) if isinstance(mapping[k], (int, float)): map_list[i] = mapping[k] elif mapping[k] == 'nodata': self._nodata_classes.append(i) else: assert len(mapping[k]) == map_list.shape[1], 'Mapping entry wrong length.' map_list[i, :] = np.asarray(mapping[k]) self._lookup = tf.constant(map_list, dtype=tf.float32) # makes nodata labels 0 in predictions def preprocess(self, y_true, y_pred): y_true = tf.cast(y_true, tf.int32) true_convert = tf.gather(self._lookup, y_true, axis=None) nodata_value = config.dataset.classes.class_id('nodata') nodata = (y_true == nodata_value) # ignore additional nodata classes for c in self._nodata_classes: nodata = tf.logical_or(nodata, y_true == c) while len(nodata.shape) < len(y_pred.shape): nodata = tf.expand_dims(nodata, -1) # zero all nodata entries y_pred = tf.cast(y_pred, tf.float32) * tf.cast(tf.logical_not(nodata), tf.float32) true_convert = tf.cast(tf.logical_not(nodata), tf.float32) * true_convert return (true_convert, y_pred) def get_config(self): base_config = super().get_config() return {**base_config, 'mapping' : self._mapping}Ancestors
- keras.src.losses.Loss
Subclasses
- MappedBinaryCrossentropy
- MappedCategoricalCrossentropy
- MappedDiceBceMsssim
- MappedDiceLoss
- MappedLossSum
- MappedMsssim
Methods
def get_config(self)-
Returns the config dictionary for a
Lossinstance. def preprocess(self, y_true, y_pred)
class MappedLossSum (mapping, name=None, reduction='auto', losses=None, weights=None)-
MappedLossfor sum of any loss functions.Parameters
losses:List[Union[str, dict]]- List of loss functions to add.
weights:Union[List[float], None]- Optional list of weights for the corresponding loss functions.
Expand source code
class MappedLossSum(MappedLoss): """ `MappedLoss` for sum of any loss functions. """ def __init__(self, mapping, name=None, reduction=losses_utils.ReductionV2.AUTO, losses=None, weights=None): """ Parameters ---------- losses: List[Union[str, dict]] List of loss functions to add. weights: Union[List[float], None] Optional list of weights for the corresponding loss functions. """ super().__init__(mapping, name=name) self._losses = list(map(loss_from_dict, losses)) if weights is None: weights = [1] * len(losses) self._weights = weights def _get_loss(self, i, y_true, y_pred): l = self._losses[i](y_true, y_pred) while len(l.shape) < 3: l = tf.expand_dims(l, -1) return self._weights[i] * l def call(self, y_true, y_pred): (y_true, y_pred) = self.preprocess(y_true, y_pred) total = self._get_loss(0, y_true, y_pred) for i in range(1, len(self._losses)): total += self._get_loss(i, y_true, y_pred) return totalAncestors
- MappedLoss
- keras.src.losses.Loss
Methods
def call(self, y_true, y_pred)-
Invokes the
Lossinstance.Args
y_true- Ground truth values. shape =
[batch_size, d0, .. dN], except sparse loss functions such as sparse categorical crossentropy where shape =[batch_size, d0, .. dN-1] y_pred- The predicted values. shape =
[batch_size, d0, .. dN]
Returns
Loss values with the shape
[batch_size, d0, .. dN-1].
Inherited members
class MappedMsssim (mapping, name=None, reduction='auto')-
MappedLossforms_ssim().This is a base class for losses when the labels of the input images do not match the labels output by the network. For example, if one class in the labels should be ignored, or two classes in the label should map to the same output, or one label should be treated as a probability between two classes. It applies a transform to the output labels and then applies the loss function.
Note that the transform is applied after preprocessing (labels in the config will be transformed to 0-n in order, and nodata will be n+1).
Parameters
mapping- One of:
* A list with transforms, where the first entry is what to transform the first label, to etc., i.e.,
[1, 0] will swap the order of two labels.
* A dictionary with classes mapped to transformed values. Classes can be referenced by name or by
number (see
ClassesConfig.class_id()for class formats). name:Optional[str]- Optional name for the loss function.
Expand source code
class MappedMsssim(MappedLoss): """ `MappedLoss` for `ms_ssim`. """ def call(self, y_true, y_pred): (y_true, y_pred) = self.preprocess(y_true, y_pred) return ms_ssim(y_true, y_pred)Ancestors
- MappedLoss
- keras.src.losses.Loss
Methods
def call(self, y_true, y_pred)-
Invokes the
Lossinstance.Args
y_true- Ground truth values. shape =
[batch_size, d0, .. dN], except sparse loss functions such as sparse categorical crossentropy where shape =[batch_size, d0, .. dN-1] y_pred- The predicted values. shape =
[batch_size, d0, .. dN]
Returns
Loss values with the shape
[batch_size, d0, .. dN-1].
Inherited members