Repository: Project-MONAI/MONAI
File: monai/metrics/generalized_dice.py (Python)

Code before:
    """
    Compute the Generalized Dice Score metric between tensors.

    This metric is the complement of the Generalized Dice Loss defined in:
    Sudre, C. et. al. (2017) Generalised Dice overlap as a deep learning
    loss function for highly unbalanced segmentations. DLMIA 2017.

    The inputs `y_pred` and `y` are expected to be one-hot, binarized batch-first tensors, i.e., NCHW[D].

    Example of the typical execution steps of this metric class follows :py:class:`monai.metrics.metric.Cumulative`.

    Args:
        include_background: Whether to include the background class (assumed to be in channel 0) in the
            score computation. Defaults to True.
        reduction: Define mode of reduction to the metrics. Available reduction modes:
            {``"none"``, ``"mean_batch"``, ``"sum_batch"``, ``"mean"`, ``"sum"`}. Defaults to ``"mean"``.
            If "none", will not do reduction.
        weight_type: {``"square"``, ``"simple"``, ``"uniform"``}. Type of function to transform
            ground truth volume into a weight factor. Defaults to ``"square"``.

    Raises:
        ValueError: When the `reduction` is not one of MetricReduction enum.
    """

    def __init__(
        self, include_background: bool = True, reduction: str = "mean", weight_type: Weight | str = Weight.SQUARE
    ) -> None:
        super().__init__()
        self.include_background = include_background
        self.reduction = look_up_option(reduction, MetricReduction)
        self.weight_type = look_up_option(weight_type, Weight)
        self.sum_over_labels = self.reduction == MetricReduction.SUM or self.reduction == MetricReduction.MEAN

    def _compute_tensor(self, y_pred: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
        """
        Computes the Generalized Dice Score and returns a tensor with its per image values.

        Args:
            y_pred: Binarized segmentation model output. It must be in one-hot format and in the NCHW[D] format,
                where N is the batch dimension, C is the channel dimension, and the remaining are the spatial dimensions.
            y: Binarized ground-truth. It must be in one-hot format and have the same shape as `y_pred`.

        Returns:
            torch.Tensor: Per batch and per class Generalized Dice Score.

        Raises:
            ValueError: If `y_pred` and `y` have less than 3 dimensions, or `y_pred` and `y` don't have the same shape.
        """
        return compute_generalized_dice(
            y_pred=y_pred,
            y=y,

Review comment (performance):
The `reduction` default value should not be a string literal (this is like a magic number essentially) and should use the value from the `MetricReduction` enum. The original default was also mean_batch and not mean, this shouldn't be changed or if it must there should be a deprecated warning using `deprecated_arg_default`.

Code after:
    """
    Compute the Generalized Dice Score metric between tensors.

    This metric is the complement of the Generalized Dice Loss defined in:
    Sudre, C. et. al. (2017) Generalised Dice overlap as a deep learning
    loss function for highly unbalanced segmentations. DLMIA 2017.

    The inputs `y_pred` and `y` are expected to be one-hot, binarized batch-first tensors, i.e., NCHW[D].

    Example of the typical execution steps of this metric class follows :py:class:`monai.metrics.metric.Cumulative`.

    Args:
        include_background: Whether to include the background class (assumed to be in channel 0) in the
            score computation. Defaults to True.
        reduction: Define mode of reduction to the metrics. Available reduction modes:
            {``"none"``, ``"mean"``, ``"sum"``, ``"mean_batch"``, ``"sum_batch"``,
            ``"mean_channel"``, ``"sum_channel"``}, default to ``"mean"``. if "none", will not do reduction.
        weight_type: {``"square"``, ``"simple"``, ``"uniform"``}. Type of function to transform
            ground truth volume into a weight factor. Defaults to ``"square"``.

    Raises:
        ValueError: When the `reduction` is not one of MetricReduction enum.
    """

    @deprecated_arg_default(
        "reduction",
        old_default=MetricReduction.MEAN_BATCH,
        new_default=MetricReduction.MEAN,
        since="1.4.0",
        replaced="1.5.0",
        msg_suffix=(
            "Old versions computed `mean` when `mean_batch` was provided due to bug in reduction， "
            "If you want to retain the old behavior (calculating the mean), please explicitly set the parameter to 'mean'."
        ),
    )
    def __init__(
        self,
        include_background: bool = True,
        reduction: MetricReduction | str = MetricReduction.MEAN_BATCH,
        weight_type: Weight | str = Weight.SQUARE,
    ) -> None:
        super().__init__()
        self.include_background = include_background
        self.reduction = look_up_option(reduction, MetricReduction)
        self.weight_type = look_up_option(weight_type, Weight)
        self.sum_over_classes = self.reduction in {
            MetricReduction.SUM,
            MetricReduction.MEAN,
            MetricReduction.MEAN_CHANNEL,
            MetricReduction.SUM_CHANNEL,
        }