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
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
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
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()
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
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
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
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
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
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
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
def _reduce(self, scores) -> Any: confusion_matrix, _ = do_metric_reduction(scores, MetricReduction.MEAN) return compute_confusion_matrix_metric(self.metric_name, confusion_matrix)
def _reduce(self, f: torch.Tensor): return do_metric_reduction(f, self.reduction)