              loss += (func(n_true, n_pred) * weight)
          return loss
  
      @classmethod
      def _apply_mask(cls, y_true, y_pred, mask_channel, mask_prop=1.0):
          """ Apply the mask to the input y_true and y_pred. If a mask is not required then
          return the unmasked inputs.
  
          Parameters
          ----------
 
</s> remove         Weights are returned as the weighted sum of the chosen losses.
 </s> add         Loss is returned as the weighted sum of the chosen losses. </s> remove     def call(self, y_true, y_pred):
 </s> add     def __call__(self, y_true: tf.Tensor, y_pred: tf.Tensor) -> tf.Tensor: </s> remove         If a mask is being applied to the loss, then the appropriate mask is extracted from y_true
        and added as the 4th channel being passed to the penalized loss function.
 </s> add         If masks are being applied to the loss function inputs, then they should be included as
        additional channels at the end of :param:`y_true`, so that they can be split off and
        applied to the actual inputs to the selected loss function(s). </s> remove class LossWrapper(tf.keras.losses.Loss):
    """ A wrapper class for multiple keras losses to enable multiple weighted loss functions on a
    single output.
 </s> add class LossWrapper():
    """ A wrapper class for multiple keras losses to enable multiple masked weighted loss
    functions on a single output.

    Notes
    -----
    Whilst Keras does allow for applying multiple weighted loss functions, it does not allow
    for an easy mechanism to add additional data (in our case masks) that are batch specific
    but are not fed in to the model.

    This wrapper receives this additional mask data for the batch stacked onto the end of the
    color channels of the received :param:`y_true` batch of images. These masks are then split
    off the batch of images and applied to both the :param:`y_true` and :param:`y_pred` tensors
    prior to feeding into the loss functions.

    For example, for an image of shape (4, 128, 128, 3) 3 additional masks may be stacked onto
    the end of y_true, meaning we receive an input of shape (4, 128, 128, 6). This wrapper then
    splits off (4, 128, 128, 3:6) from the end of the tensor, leaving the original y_true of
    shape (4, 128, 128, 3) ready for masking and feeding through the loss functions. </s> remove         function: :class:`keras.losses.Loss`
 </s> add         function: :class:`tf.keras.losses.Loss`
    def _apply_mask(cls,
                    y_true: tf.Tensor,
                    y_pred: tf.Tensor,
                    mask_channel: int,
                    mask_prop: float = 1.0) -> Tuple[tf.Tensor, tf.Tensor]:
              loss += (func(n_true, n_pred) * weight)
          return loss
  
      @classmethod
    def _apply_mask(cls,
                    y_true: tf.Tensor,
                    y_pred: tf.Tensor,
                    mask_channel: int,
                    mask_prop: float = 1.0) -> Tuple[tf.Tensor, tf.Tensor]:
          """ Apply the mask to the input y_true and y_pred. If a mask is not required then
          return the unmasked inputs.
  
          Parameters
          ----------
keep keep keep keep replace keep keep keep keep keep
 bugfix: distibuted training with dssim 
lib/model/losses_tf.py