Exemple #1
0
    def aggregate(  # type: ignore
            self,
            compute_sample: bool = False,
            reduction: Union[MetricReduction, str, None] = None):
        """
        Execute reduction for the confusion matrix values.

        Args:
            compute_sample: when reducing, if ``True``, each sample's metric will be computed based on each confusion matrix first.
                if ``False``, compute reduction on the confusion matrices first, defaults to ``False``.
            reduction: define mode of reduction to the metrics, will only apply reduction on `not-nan` values,
                available reduction modes: {``"none"``, ``"mean"``, ``"sum"``, ``"mean_batch"``, ``"sum_batch"``,
                ``"mean_channel"``, ``"sum_channel"``}, default to `self.reduction`. if "none", will not do reduction.

        """
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("the data to aggregate must be PyTorch Tensor.")

        results = []
        for metric_name in self.metric_name:
            if compute_sample or self.compute_sample:
                sub_confusion_matrix = compute_confusion_matrix_metric(
                    metric_name, data)
                f, not_nans = do_metric_reduction(sub_confusion_matrix,
                                                  reduction or self.reduction)
            else:
                f, not_nans = do_metric_reduction(data, reduction
                                                  or self.reduction)
                f = compute_confusion_matrix_metric(metric_name, f)
            if self.get_not_nans:
                results.append((f, not_nans))
            else:
                results.append(f)
        return results
Exemple #2
0
    def __call__(self, y_pred: torch.Tensor, y: torch.Tensor):
        """
        Args:
            y_pred: input data to compute. It must be one-hot format and first dim is batch.
                The values should be binarized.
            y: ground truth to compute the metric. It must be one-hot format and first dim is batch.
                The values should be binarized.
        Raises:
            ValueError: when `y` is not a binarized tensor.
            ValueError: when `y_pred` has less than two dimensions.
        """
        # check binarized input
        if not torch.all(y_pred.byte() == y_pred):
            warnings.warn("y_pred is not a binarized tensor here!")
        if not torch.all(y.byte() == y):
            raise ValueError("y should be a binarized tensor.")
        # check dimension
        dims = y_pred.ndimension()
        if dims < 2:
            raise ValueError("y_pred should have at least two dimensions.")
        elif dims == 2 or (dims == 3 and y_pred.shape[-1] == 1):
            if self.compute_sample:
                warnings.warn(
                    "As for classification task, compute_sample should be False."
                )
                self.compute_sample = False

        confusion_matrix = get_confusion_matrix(
            y_pred=y_pred,
            y=y,
            include_background=self.include_background,
        )

        if self.compute_sample:
            if isinstance(self.metric_name, str):
                confusion_matrix = compute_confusion_matrix_metric(
                    self.metric_name, confusion_matrix)
                f, not_nans = do_metric_reduction(confusion_matrix,
                                                  self.reduction)
                return f, not_nans
            else:
                if len(self.metric_name) < 1:
                    raise ValueError(
                        "the sequence should at least has on metric name.")
                results = []
                for metric_name in self.metric_name:
                    sub_confusion_matrix = compute_confusion_matrix_metric(
                        metric_name, confusion_matrix)
                    f, not_nans = do_metric_reduction(sub_confusion_matrix,
                                                      self.reduction)
                    results.append(f)
                    results.append(not_nans)
                return results
        else:
            return confusion_matrix
Exemple #3
0
    def __call__(self, y_pred: torch.Tensor, y: torch.Tensor):
        """
        Args:
            y_pred: input data to compute, typical segmentation model output.
                It must be one-hot format and first dim is batch, example shape: [16, 3, 32, 32]. The values
                should be binarized.
            y: ground truth to compute the distance. It must be one-hot format and first dim is batch.
                The values should be binarized.

        Raises:
            ValueError: when `y` is not a binarized tensor.
            ValueError: when `y_pred` has less than three dimensions.
        """
        if not torch.all(y_pred.byte() == y_pred):
            warnings.warn("y_pred is not a binarized tensor here!")
        if not torch.all(y.byte() == y):
            raise ValueError("y should be a binarized tensor.")
        dims = y_pred.ndimension()
        if dims < 3:
            raise ValueError("y_pred should have at least three dimensions.")
        # compute (BxC) for each channel for each batch
        f = compute_hausdorff_distance(
            y_pred=y_pred,
            y=y,
            include_background=self.include_background,
            distance_metric=self.distance_metric,
            percentile=self.percentile,
            directed=self.directed,
        )

        # do metric reduction
        f, not_nans = do_metric_reduction(f, self.reduction)
        return f, not_nans
Exemple #4
0
    def update(self, output: Sequence[torch.Tensor]) -> None:
        """
        Args:
            output: sequence with contents [y_pred, y].

        Raises:
            ValueError: When ``output`` length is not 2. This metric can only support y_pred and y.

        """
        if len(output) != 2:
            raise ValueError(f"output must have length 2, got {len(output)}.")
        y_pred, y = output
        if self.compute_sample is True:
            score, not_nans = self.confusion_matrix(y_pred, y)
            not_nans = int(not_nans.item())

            # add all items in current batch
            self._sum += score.item() * not_nans
            self._num_examples += not_nans
        else:
            confusion_matrix = self.confusion_matrix(y_pred, y)
            confusion_matrix, _ = do_metric_reduction(confusion_matrix,
                                                      MetricReduction.SUM)
            self._total_tp += confusion_matrix[0].item()
            self._total_fp += confusion_matrix[1].item()
            self._total_tn += confusion_matrix[2].item()
            self._total_fn += confusion_matrix[3].item()
Exemple #5
0
    def aggregate(self,
                  reduction: Union[MetricReduction, str,
                                   None] = None):  # type: ignore
        """
        Execute reduction logic for the output of `compute_generalized_dice`.

        Args:
            reduction (Union[MetricReduction, str, None], optional): define mode of reduction to the metrics.
                Available reduction modes: {``"none"``, ``"mean"``, ``"sum"``, ``"mean_batch"``, ``"sum_batch"``}.
                Defaults to ``"mean"``. If "none", will not do reduction.
        """
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("The data to aggregate must be a PyTorch Tensor.")

        # Validate reduction argument if specified
        if reduction is not None:
            reduction_options = [
                "none", "mean", "sum", "mean_batch", "sum_batch"
            ]
            if reduction not in reduction_options:
                raise ValueError(
                    f"reduction must be one of {reduction_options}")

        # Do metric reduction and return
        f, _ = do_metric_reduction(data, reduction or self.reduction)

        return f
Exemple #6
0
    def aggregate(self):
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("the data to aggregate must be PyTorch Tensor.")

        f, not_nans = do_metric_reduction(data, self.reduction)
        return (f, not_nans) if self.get_not_nans else f
Exemple #7
0
    def aggregate(self):  # type: ignore
        """
        Execute reduction logic for the output of `compute_meandice`.

        """
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("the data to aggregate must be PyTorch Tensor.")

        # do metric reduction
        f, not_nans = do_metric_reduction(data, self.reduction)
        return (f, not_nans) if self.get_not_nans else f
Exemple #8
0
    def aggregate(self,
                  reduction: Union[MetricReduction, str,
                                   None] = None):  # type: ignore
        """
        Args:
            reduction: define mode of reduction to the metrics, will only apply reduction on `not-nan` values,
                available reduction modes: {``"none"``, ``"mean"``, ``"sum"``, ``"mean_batch"``, ``"sum_batch"``,
                ``"mean_channel"``, ``"sum_channel"``}, default to `self.reduction`. if "none", will not do reduction.
        """
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("the data to aggregate must be PyTorch Tensor.")

        f, not_nans = do_metric_reduction(data, reduction or self.reduction)
        return (f, not_nans) if self.get_not_nans else f
Exemple #9
0
    def aggregate(self):
        r"""
        Aggregates the output of `_compute_tensor`.

        Returns:
            If `get_not_nans` is set to ``True``, this function returns the aggregated NSD and the `not_nans` count.
            If `get_not_nans` is set to ``False``, this function returns only the aggregated NSD.
        """
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("the data to aggregate must be PyTorch Tensor.")

        # do metric reduction
        f, not_nans = do_metric_reduction(data, self.reduction)
        return (f, not_nans) if self.get_not_nans else f
Exemple #10
0
    def aggregate(self):  # type: ignore
        """
        Execute reduction for the confusion matrix values.

        """
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("the data to aggregate must be PyTorch Tensor.")

        results = []
        for metric_name in self.metric_name:
            if self.compute_sample:
                sub_confusion_matrix = compute_confusion_matrix_metric(
                    metric_name, data)
                f, not_nans = do_metric_reduction(sub_confusion_matrix,
                                                  self.reduction)
            else:
                f, not_nans = do_metric_reduction(data, self.reduction)
                f = compute_confusion_matrix_metric(metric_name, f)
            if self.get_not_nans:
                results.append((f, not_nans))
            else:
                results.append(f)
        return results
Exemple #11
0
    def aggregate(self, reduction: Union[MetricReduction, str, None] = None):  # type: ignore
        r"""
        Aggregates the output of `_compute_tensor`.

        Args:
            reduction: define mode of reduction to the metrics, will only apply reduction on `not-nan` values,
                available reduction modes: {``"none"``, ``"mean"``, ``"sum"``, ``"mean_batch"``, ``"sum_batch"``,
                ``"mean_channel"``, ``"sum_channel"``}, default to `self.reduction`. if "none", will not do reduction.

        Returns:
            If `get_not_nans` is set to ``True``, this function returns the aggregated NSD and the `not_nans` count.
            If `get_not_nans` is set to ``False``, this function returns only the aggregated NSD.
        """
        data = self.get_buffer()
        if not isinstance(data, torch.Tensor):
            raise ValueError("the data to aggregate must be PyTorch Tensor.")

        # do metric reduction
        f, not_nans = do_metric_reduction(data, reduction or self.reduction)
        return (f, not_nans) if self.get_not_nans else f
Exemple #12
0
 def _reduce(self, scores) -> Any:
     confusion_matrix, _ = do_metric_reduction(scores, MetricReduction.MEAN)
     return compute_confusion_matrix_metric(self.metric_name, confusion_matrix)
Exemple #13
0
 def _reduce(self, f: torch.Tensor):
     return do_metric_reduction(f, self.reduction)