From 966f719a96a42f00e7643fc4a60c68b4cab68c46 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sat, 9 Jul 2022 23:30:45 +0530 Subject: [PATCH 01/14] Create meaniou.py Signed-off-by: Yashika Jain --- monai/metrics/meaniou.py | 149 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 monai/metrics/meaniou.py diff --git a/monai/metrics/meaniou.py b/monai/metrics/meaniou.py new file mode 100644 index 0000000000..0020a91736 --- /dev/null +++ b/monai/metrics/meaniou.py @@ -0,0 +1,149 @@ +# Copyright (c) MONAI Consortium +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Union + +import torch + +from monai.metrics.utils import do_metric_reduction, ignore_background, is_binary_tensor +from monai.utils import MetricReduction + +from .metric import CumulativeIterationMetric + + +class IoUMetric(CumulativeIterationMetric): + """ + Compute average IoU score between two tensors. It can support both multi-classes and multi-labels tasks. + Input `y_pred` is compared with ground truth `y`. + `y_pred` is expected to have binarized predictions and `y` should be in one-hot format. You can use suitable transforms + in ``monai.transforms.post`` first to achieve binarized values. + The `include_background` parameter can be set to ``False`` to exclude + the first category (channel index 0) which is by convention assumed to be background. If the non-background + segmentations are small compared to the total image size they can get overwhelmed by the signal from the + background. + `y_pred` and `y` can be a list of channel-first Tensor (CHW[D]) or a batch-first Tensor (BCHW[D]). + + Args: + include_background: whether to skip IoU computation on the first channel of + the predicted output. Defaults to ``True``. + 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 ``"mean"``. if "none", will not do reduction. + get_not_nans: whether to return the `not_nans` count, if True, aggregate() returns (metric, not_nans). + Here `not_nans` count the number of not nans for the metric, thus its shape equals to the shape of the metric. + ignore_empty: whether to ignore empty ground truth cases during calculation. + If `True`, NaN value will be set for empty ground truth cases. + If `False`, 1 will be set if the predictions of empty ground truth cases are also empty. + + """ + + def __init__( + self, + include_background: bool = True, + reduction: Union[MetricReduction, str] = MetricReduction.MEAN, + get_not_nans: bool = False, + ignore_empty: bool = True, + ) -> None: + super().__init__() + self.include_background = include_background + self.reduction = reduction + self.get_not_nans = get_not_nans + self.ignore_empty = ignore_empty + + def _compute_tensor(self, y_pred: torch.Tensor, y: torch.Tensor): # type: ignore + """ + 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 mean IoU 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 three dimensions. + """ + is_binary_tensor(y_pred, "y_pred") + is_binary_tensor(y, "y") + + dims = y_pred.ndimension() + if dims < 3: + raise ValueError(f"y_pred should have at least 3 dimensions (batch, channel, spatial), got {dims}.") + # compute IoU (BxC) for each channel for each batch + return compute_meaniou( + y_pred=y_pred, y=y, include_background=self.include_background, ignore_empty=self.ignore_empty + ) + + def aggregate(self, reduction: Union[MetricReduction, str, None] = None): # type: ignore + """ + Execute reduction logic for the output of `compute_meaniou`. + + 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.") + + # 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 compute_meaniou( + y_pred: torch.Tensor, y: torch.Tensor, include_background: bool = True, ignore_empty: bool = True +) -> torch.Tensor: + """Computes IoU score metric from full size Tensor and collects average. + + 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 mean IoU metric. It must be one-hot format and first dim is batch. + The values should be binarized. + include_background: whether to skip IoU computation on the first channel of + the predicted output. Defaults to True. + ignore_empty: whether to ignore empty ground truth cases during calculation. + If `True`, NaN value will be set for empty ground truth cases. + If `False`, 1 will be set if the predictions of empty ground truth cases are also empty. + + Returns: + IoU scores per batch and per class, (shape [batch_size, num_classes]). + + Raises: + ValueError: when `y_pred` and `y` have different shapes. + + """ + + if not include_background: + y_pred, y = ignore_background(y_pred=y_pred, y=y) + + y = y.float() + y_pred = y_pred.float() + + if y.shape != y_pred.shape: + raise ValueError(f"y_pred and y should have same shapes, got {y_pred.shape} and {y.shape}.") + + # reducing only spatial dimensions (not batch nor channels) + n_len = len(y_pred.shape) + reduce_axis = list(range(2, n_len)) + intersection = torch.sum(y * y_pred, dim=reduce_axis) + + y_o = torch.sum(y, reduce_axis) + y_pred_o = torch.sum(y_pred, dim=reduce_axis) + union = y_o + y_pred_o - intersection + + if ignore_empty is True: + return torch.where(y_o > 0, (intersection) / union, torch.tensor(float("nan"), device=y_o.device)) + return torch.where(denominator > 0, (intersection) / union, torch.tensor(1.0, device=y_o.device)) From 6b028632ecf27e566b0b32efc0ed292c9e02f5e1 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sat, 9 Jul 2022 23:34:13 +0530 Subject: [PATCH 02/14] Create test_compute_meaniou.py Signed-off-by: Yashika Jain --- tests/test_compute_meaniou.py | 220 ++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 tests/test_compute_meaniou.py diff --git a/tests/test_compute_meaniou.py b/tests/test_compute_meaniou.py new file mode 100644 index 0000000000..2ad15addc9 --- /dev/null +++ b/tests/test_compute_meaniou.py @@ -0,0 +1,220 @@ +# Copyright (c) MONAI Consortium +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest + +import numpy as np +import torch +from parameterized import parameterized + +from monai.metrics import IoUMetric, compute_meaniou + +# keep background +TEST_CASE_1 = [ # y (1, 1, 2, 2), y_pred (1, 1, 2, 2), expected out (1, 1) + { + "y_pred": torch.tensor([[[[1.0, 0.0], [0.0, 1.0]]]]), + "y": torch.tensor([[[[1.0, 0.0], [1.0, 1.0]]]]), + "include_background": True, + }, + [[0.6667]], +] + +# remove background and not One-Hot target +TEST_CASE_2 = [ # y (2, 3, 2, 2), y_pred (2, 3, 2, 2), expected out (2, 2) (no background) + { + "y_pred": torch.tensor( + [ + [[[0.0, 1.0], [0.0, 0.0]], [[0.0, 0.0], [1.0, 1.0]], [[1.0, 0.0], [0.0, 0.0]]], + [[[0.0, 0.0], [0.0, 1.0]], [[1.0, 0.0], [0.0, 0.0]], [[0.0, 1.0], [1.0, 0.0]]], + ] + ), + "y": torch.tensor( + [ + [[[0.0, 0.0], [0.0, 1.0]], [[1.0, 0.0], [1.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]]], + [[[0.0, 0.0], [0.0, 1.0]], [[1.0, 1.0], [0.0, 0.0]], [[0.0, 0.0], [1.0, 0.0]]], + ] + ), + "include_background": False, + }, + [[0.4000, 0.0000],[0.4000, 0.5000]], +] + +# should return Nan for all labels=0 case and skip for MeanIoU +TEST_CASE_3 = [ + { + "y_pred": torch.tensor( + [ + [[[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]], [[1.0, 1.0], [1.0, 1.0]]], + [[[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]], [[1.0, 1.0], [1.0, 1.0]]], + ] + ), + "y": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + [[[0.0, 1.0], [1.0, 0.0]], [[1.0, 0.0], [0.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]]], + ] + ), + "include_background": True, + }, + [[False, True, True], [False, False, True]], +] + +TEST_CASE_4 = [ + {"include_background": True, "reduction": "mean_batch", "get_not_nans": True}, + { + "y_pred": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]], [[0.0, 1.0], [1.0, 1.0]]], + [[[1.0, 0.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 0.0]]], + ] + ), + "y": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + [[[0.0, 0.0], [0.0, 1.0]], [[1.0, 1.0], [0.0, 0.0]], [[0.0, 0.0], [1.0, 0.0]]], + ] + ), + }, + [0.5416, 0.2500, 0.5000], +] + +TEST_CASE_5 = [ + {"include_background": True, "reduction": "mean", "get_not_nans": True}, + { + "y_pred": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]], [[0.0, 1.0], [1.0, 1.0]]], + [[[1.0, 0.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 0.0]]], + ] + ), + "y": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + [[[0.0, 0.0], [0.0, 1.0]], [[1.0, 1.0], [0.0, 0.0]], [[0.0, 0.0], [1.0, 0.0]]], + ] + ), + }, + 0.5555, +] + +TEST_CASE_6 = [ + {"include_background": True, "reduction": "sum_batch", "get_not_nans": True}, + { + "y_pred": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]], [[0.0, 1.0], [1.0, 1.0]]], + [[[1.0, 0.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 0.0]]], + ] + ), + "y": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + ] + ), + }, + [1.5000, 0.0000, 0.0000], +] + +TEST_CASE_7 = [ + {"include_background": True, "reduction": "mean", "get_not_nans": True}, + { + "y_pred": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]], [[0.0, 1.0], [1.0, 1.0]]], + [[[1.0, 0.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 0.0]]], + ] + ), + "y": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + ] + ), + }, + 0.7500, +] + +TEST_CASE_8 = [ + {"include_background": False, "reduction": "sum_batch", "get_not_nans": True}, + { + "y_pred": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 0.0]], [[0.0, 1.0], [0.0, 0.0]], [[0.0, 1.0], [1.0, 1.0]]], + [[[1.0, 0.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 1.0]], [[0.0, 1.0], [1.0, 0.0]]], + ] + ), + "y": torch.tensor( + [ + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + [[[1.0, 1.0], [1.0, 1.0]], [[0.0, 0.0], [0.0, 0.0]], [[0.0, 0.0], [0.0, 0.0]]], + ] + ), + }, + [0.0000, 0.0000], +] + +TEST_CASE_9 = [ + {"y": torch.ones((2, 2, 3, 3)), "y_pred": torch.ones((2, 2, 3, 3))}, + [[1.0000, 1.0000], [1.0000, 1.0000]], +] + +TEST_CASE_10 = [ + {"y": [torch.ones((2, 3, 3)), torch.ones((2, 3, 3))], "y_pred": [torch.ones((2, 3, 3)), torch.ones((2, 3, 3))]}, + [[1.0000, 1.0000], [1.0000, 1.0000]], +] + +TEST_CASE_11 = [ + {"y": torch.zeros((2, 2, 3, 3)), "y_pred": torch.zeros((2, 2, 3, 3)), "ignore_empty": False}, + [[1.0000, 1.0000], [1.0000, 1.0000]], +] + +TEST_CASE_12 = [ + {"y": torch.zeros((2, 2, 3, 3)), "y_pred": torch.ones((2, 2, 3, 3)), "ignore_empty": False}, + [[0.0000, 0.0000], [0.0000, 0.0000]], +] + + +class TestComputeMeanIoU(unittest.TestCase): + @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_9, TEST_CASE_11, TEST_CASE_12]) + def test_value(self, input_data, expected_value): + result = compute_meaniou(**input_data) + np.testing.assert_allclose(result.cpu().numpy(), expected_value, atol=1e-4) + + @parameterized.expand([TEST_CASE_3]) + def test_nans(self, input_data, expected_value): + result = compute_meaniou(**input_data) + self.assertTrue(np.allclose(np.isnan(result.cpu().numpy()), expected_value)) + + # IoUMetric class tests + @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_10]) + def test_value_class(self, input_data, expected_value): + + # same test as for compute_iou + vals = {} + vals["y_pred"] = input_data.pop("y_pred") + vals["y"] = input_data.pop("y") + iou_metric = IoUMetric(**input_data) + iou_metric(**vals) + result = iou_metric.aggregate(reduction="none") + np.testing.assert_allclose(result.cpu().numpy(), expected_value, atol=1e-4) + + @parameterized.expand([TEST_CASE_4, TEST_CASE_5, TEST_CASE_6, TEST_CASE_7, TEST_CASE_8]) + def test_nans_class(self, params, input_data, expected_value): + + iou_metric = IoUMetric(**params) + iou_metric(**input_data) + result, _ = iou_metric.aggregate() + np.testing.assert_allclose(result.cpu().numpy(), expected_value, atol=1e-4) + + +if __name__ == "__main__": + unittest.main() From dabc0b39baa812fb0446beaf288db4883ea0fbf2 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sat, 9 Jul 2022 23:35:17 +0530 Subject: [PATCH 03/14] Update __init__.py Signed-off-by: Yashika Jain --- monai/metrics/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monai/metrics/__init__.py b/monai/metrics/__init__.py index 0cefe056e8..850a29d422 100644 --- a/monai/metrics/__init__.py +++ b/monai/metrics/__init__.py @@ -15,6 +15,7 @@ from .generalized_dice import GeneralizedDiceScore, compute_generalized_dice from .hausdorff_distance import HausdorffDistanceMetric, compute_hausdorff_distance, compute_percent_hausdorff_distance from .meandice import DiceMetric, compute_meandice +from .meaniou import IoUMetric, compute_meaniou from .metric import Cumulative, CumulativeIterationMetric, IterationMetric, Metric from .regression import MAEMetric, MSEMetric, PSNRMetric, RMSEMetric, SSIMMetric from .rocauc import ROCAUCMetric, compute_roc_auc From 2b9a633d97d2a69336800811733563329356efa1 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sat, 9 Jul 2022 23:37:04 +0530 Subject: [PATCH 04/14] Update metrics.rst Signed-off-by: Yashika Jain --- docs/source/metrics.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/source/metrics.rst b/docs/source/metrics.rst index bac06b3067..9ecca90cf5 100644 --- a/docs/source/metrics.rst +++ b/docs/source/metrics.rst @@ -38,6 +38,13 @@ Metrics .. autoclass:: DiceMetric :members: + +`Mean IoU` +----------- +.. autofunction:: compute_meaniou + +.. autoclass:: IoUMetric + :members: `Generalized Dice Score` ------------------------ From f89bf56fd7eb9c50396db3ccf8990d4956b0dcfb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 9 Jul 2022 18:23:34 +0000 Subject: [PATCH 05/14] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Signed-off-by: Yashika Jain --- docs/source/metrics.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/metrics.rst b/docs/source/metrics.rst index 9ecca90cf5..379e6cd950 100644 --- a/docs/source/metrics.rst +++ b/docs/source/metrics.rst @@ -38,13 +38,13 @@ Metrics .. autoclass:: DiceMetric :members: - + `Mean IoU` ----------- .. autofunction:: compute_meaniou .. autoclass:: IoUMetric - :members: + :members: `Generalized Dice Score` ------------------------ From f0e8df3810d7a8cbc969fa10ee4a690d69669e1f Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 00:14:43 +0530 Subject: [PATCH 06/14] Update test_compute_meaniou.py Signed-off-by: Yashika Jain --- tests/test_compute_meaniou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_compute_meaniou.py b/tests/test_compute_meaniou.py index 2ad15addc9..03debb98f2 100644 --- a/tests/test_compute_meaniou.py +++ b/tests/test_compute_meaniou.py @@ -44,7 +44,7 @@ ), "include_background": False, }, - [[0.4000, 0.0000],[0.4000, 0.5000]], + [[0.3333, 0.0000],[0.5000, 0.5000]], ] # should return Nan for all labels=0 case and skip for MeanIoU From 764fcea923204f9e832db6c9d4e1023e5600ef02 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 00:23:03 +0530 Subject: [PATCH 07/14] Update meaniou.py Signed-off-by: Yashika Jain --- monai/metrics/meaniou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monai/metrics/meaniou.py b/monai/metrics/meaniou.py index 0020a91736..05d60e09af 100644 --- a/monai/metrics/meaniou.py +++ b/monai/metrics/meaniou.py @@ -146,4 +146,4 @@ def compute_meaniou( if ignore_empty is True: return torch.where(y_o > 0, (intersection) / union, torch.tensor(float("nan"), device=y_o.device)) - return torch.where(denominator > 0, (intersection) / union, torch.tensor(1.0, device=y_o.device)) + return torch.where(union > 0, (intersection) / union, torch.tensor(1.0, device=y_o.device)) From dfd9a077076fbc9e826b9f14673439c326a8cab0 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 10:47:31 +0530 Subject: [PATCH 08/14] Update metrics.rst Signed-off-by: Yashika Jain --- docs/source/metrics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/metrics.rst b/docs/source/metrics.rst index 379e6cd950..fda54ab40d 100644 --- a/docs/source/metrics.rst +++ b/docs/source/metrics.rst @@ -40,7 +40,7 @@ Metrics :members: `Mean IoU` ------------ +---------- .. autofunction:: compute_meaniou .. autoclass:: IoUMetric From 58b2fcafd956767809b8303c51d1a8ca2e44e3aa Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 10:59:52 +0530 Subject: [PATCH 09/14] Update __init__.py Signed-off-by: Yashika Jain --- monai/metrics/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monai/metrics/__init__.py b/monai/metrics/__init__.py index 850a29d422..4d472a148f 100644 --- a/monai/metrics/__init__.py +++ b/monai/metrics/__init__.py @@ -15,7 +15,7 @@ from .generalized_dice import GeneralizedDiceScore, compute_generalized_dice from .hausdorff_distance import HausdorffDistanceMetric, compute_hausdorff_distance, compute_percent_hausdorff_distance from .meandice import DiceMetric, compute_meandice -from .meaniou import IoUMetric, compute_meaniou +from .meaniou import MeanIoU, compute_meaniou from .metric import Cumulative, CumulativeIterationMetric, IterationMetric, Metric from .regression import MAEMetric, MSEMetric, PSNRMetric, RMSEMetric, SSIMMetric from .rocauc import ROCAUCMetric, compute_roc_auc From b033d1121e42b52f1e8ffd8a7b2ab41c17cc2d2e Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:00:00 +0530 Subject: [PATCH 10/14] Update meaniou.py Signed-off-by: Yashika Jain --- monai/metrics/meaniou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monai/metrics/meaniou.py b/monai/metrics/meaniou.py index 05d60e09af..2206a3dfd6 100644 --- a/monai/metrics/meaniou.py +++ b/monai/metrics/meaniou.py @@ -19,7 +19,7 @@ from .metric import CumulativeIterationMetric -class IoUMetric(CumulativeIterationMetric): +class MeanIoU(CumulativeIterationMetric): """ Compute average IoU score between two tensors. It can support both multi-classes and multi-labels tasks. Input `y_pred` is compared with ground truth `y`. From 78d0218c44782fc3542d78e6f808c85b91548467 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:00:07 +0530 Subject: [PATCH 11/14] Update test_compute_meaniou.py Signed-off-by: Yashika Jain --- tests/test_compute_meaniou.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_compute_meaniou.py b/tests/test_compute_meaniou.py index 03debb98f2..fd1342a821 100644 --- a/tests/test_compute_meaniou.py +++ b/tests/test_compute_meaniou.py @@ -15,7 +15,7 @@ import torch from parameterized import parameterized -from monai.metrics import IoUMetric, compute_meaniou +from monai.metrics import MeanIoU, compute_meaniou # keep background TEST_CASE_1 = [ # y (1, 1, 2, 2), y_pred (1, 1, 2, 2), expected out (1, 1) @@ -194,7 +194,7 @@ def test_nans(self, input_data, expected_value): result = compute_meaniou(**input_data) self.assertTrue(np.allclose(np.isnan(result.cpu().numpy()), expected_value)) - # IoUMetric class tests + # MeanIoU class tests @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_10]) def test_value_class(self, input_data, expected_value): @@ -202,7 +202,7 @@ def test_value_class(self, input_data, expected_value): vals = {} vals["y_pred"] = input_data.pop("y_pred") vals["y"] = input_data.pop("y") - iou_metric = IoUMetric(**input_data) + iou_metric = MeanIoU(**input_data) iou_metric(**vals) result = iou_metric.aggregate(reduction="none") np.testing.assert_allclose(result.cpu().numpy(), expected_value, atol=1e-4) @@ -210,7 +210,7 @@ def test_value_class(self, input_data, expected_value): @parameterized.expand([TEST_CASE_4, TEST_CASE_5, TEST_CASE_6, TEST_CASE_7, TEST_CASE_8]) def test_nans_class(self, params, input_data, expected_value): - iou_metric = IoUMetric(**params) + iou_metric = MeanIoU(**params) iou_metric(**input_data) result, _ = iou_metric.aggregate() np.testing.assert_allclose(result.cpu().numpy(), expected_value, atol=1e-4) From 6ad87279698e4db55a87603e28f5b30fcd90eb85 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:00:17 +0530 Subject: [PATCH 12/14] Update metrics.rst Signed-off-by: Yashika Jain --- docs/source/metrics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/metrics.rst b/docs/source/metrics.rst index fda54ab40d..aea3f1789a 100644 --- a/docs/source/metrics.rst +++ b/docs/source/metrics.rst @@ -43,7 +43,7 @@ Metrics ---------- .. autofunction:: compute_meaniou -.. autoclass:: IoUMetric +.. autoclass:: MeanIoU :members: `Generalized Dice Score` From a0959942c6e67a9b09823a6d215bcf3dd7fd4353 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:26:40 +0530 Subject: [PATCH 13/14] Update test_compute_meaniou.py Signed-off-by: Yashika Jain --- tests/test_compute_meaniou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_compute_meaniou.py b/tests/test_compute_meaniou.py index fd1342a821..d454afe514 100644 --- a/tests/test_compute_meaniou.py +++ b/tests/test_compute_meaniou.py @@ -44,7 +44,7 @@ ), "include_background": False, }, - [[0.3333, 0.0000],[0.5000, 0.5000]], + [[0.3333, 0.0000], [0.5000, 0.5000]], ] # should return Nan for all labels=0 case and skip for MeanIoU From 90fc460887323731d59e88497a8c5837f8605e41 Mon Sep 17 00:00:00 2001 From: Yashika Jain <40869641+yashika-git@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:42:29 +0530 Subject: [PATCH 14/14] Update test_compute_meaniou.py Signed-off-by: Yashika Jain --- tests/test_compute_meaniou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_compute_meaniou.py b/tests/test_compute_meaniou.py index d454afe514..d6ff95dc74 100644 --- a/tests/test_compute_meaniou.py +++ b/tests/test_compute_meaniou.py @@ -198,7 +198,7 @@ def test_nans(self, input_data, expected_value): @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_10]) def test_value_class(self, input_data, expected_value): - # same test as for compute_iou + # same test as for compute_meaniou vals = {} vals["y_pred"] = input_data.pop("y_pred") vals["y"] = input_data.pop("y")