From b11e451b353b474e9cfd31fc12935d019037a157 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 16:24:56 +0000 Subject: [PATCH 1/7] Update with cupy.ndarray Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/transforms/utility/array.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 73fbd6666f..a280eff265 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -330,8 +330,10 @@ def __call__(self, img: NdarrayOrTensor, dtype: Optional[Union[DtypeLike, torch. TypeError: When ``img`` type is not in ``Union[numpy.ndarray, torch.Tensor]``. """ - if not isinstance(img, (torch.Tensor, np.ndarray)): - raise TypeError(f"img must be one of (numpy.ndarray, torch.Tensor) but is {type(img).__name__}.") + if not isinstance(img, (torch.Tensor, np.ndarray, cp.ndarray)): + raise TypeError( + f"img must be one of (numpy.ndarray, torch.Tensor, cupy.ndarray) but is {type(img).__name__}." + ) img_out, *_ = convert_data_type(img, output_type=type(img), dtype=dtype or self.dtype) return img_out From 8d8829fdcf71cc0912efbc575b44a167372260ea Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 16:35:35 +0000 Subject: [PATCH 2/7] Change to use has_cp Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/transforms/utility/array.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index a280eff265..b681deb98a 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -330,10 +330,11 @@ def __call__(self, img: NdarrayOrTensor, dtype: Optional[Union[DtypeLike, torch. TypeError: When ``img`` type is not in ``Union[numpy.ndarray, torch.Tensor]``. """ - if not isinstance(img, (torch.Tensor, np.ndarray, cp.ndarray)): - raise TypeError( - f"img must be one of (numpy.ndarray, torch.Tensor, cupy.ndarray) but is {type(img).__name__}." - ) + if not isinstance(img, (torch.Tensor, np.ndarray)): + if not (has_cp and cp.ndarray): + raise TypeError( + f"img must be one of (numpy.ndarray, torch.Tensor, cupy.ndarray) but is {type(img).__name__}." + ) img_out, *_ = convert_data_type(img, output_type=type(img), dtype=dtype or self.dtype) return img_out From 435281d1d773497537db7ac4be225b656cbbaaf7 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 16:37:29 +0000 Subject: [PATCH 3/7] Change the format Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/transforms/utility/array.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index b681deb98a..b1a441b02b 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -330,11 +330,10 @@ def __call__(self, img: NdarrayOrTensor, dtype: Optional[Union[DtypeLike, torch. TypeError: When ``img`` type is not in ``Union[numpy.ndarray, torch.Tensor]``. """ - if not isinstance(img, (torch.Tensor, np.ndarray)): - if not (has_cp and cp.ndarray): - raise TypeError( - f"img must be one of (numpy.ndarray, torch.Tensor, cupy.ndarray) but is {type(img).__name__}." - ) + if not isinstance(img, (torch.Tensor, np.ndarray)) and not (has_cp and cp.ndarray): + raise TypeError( + f"img must be one of (numpy.ndarray, torch.Tensor, cupy.ndarray) but is {type(img).__name__}." + ) img_out, *_ = convert_data_type(img, output_type=type(img), dtype=dtype or self.dtype) return img_out From 6f9fe874a713cfb2ab38e47514cb8008353cc313 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 16:45:20 +0000 Subject: [PATCH 4/7] Fix a bug Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/transforms/utility/array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index b1a441b02b..70b5db5adb 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -330,7 +330,7 @@ def __call__(self, img: NdarrayOrTensor, dtype: Optional[Union[DtypeLike, torch. TypeError: When ``img`` type is not in ``Union[numpy.ndarray, torch.Tensor]``. """ - if not isinstance(img, (torch.Tensor, np.ndarray)) and not (has_cp and cp.ndarray): + if not isinstance(img, (torch.Tensor, np.ndarray)) and not (has_cp and isinstance(img, cp.ndarray)): raise TypeError( f"img must be one of (numpy.ndarray, torch.Tensor, cupy.ndarray) but is {type(img).__name__}." ) From 36d3a9f086887e5b7a5c40c5b2151e6e5a9b56e4 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:29:13 +0000 Subject: [PATCH 5/7] Add tests Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- tests/test_cast_to_type.py | 22 ++++++++++++++++++++++ tests/test_cast_to_typed.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tests/test_cast_to_type.py b/tests/test_cast_to_type.py index 0ef25cbafa..03c68978bc 100644 --- a/tests/test_cast_to_type.py +++ b/tests/test_cast_to_type.py @@ -16,14 +16,23 @@ from parameterized import parameterized from monai.transforms import CastToType +from monai.utils import optional_import from monai.utils.type_conversion import get_equivalent_dtype from tests.utils import TEST_NDARRAYS +cp, has_cp = optional_import("cupy") + TESTS = [] for p in TEST_NDARRAYS: for out_dtype in (np.float64, torch.float64): TESTS.append([out_dtype, p(np.array([[0, 1], [1, 2]], dtype=np.float32)), out_dtype]) +TESTS_CUPY = [ + [np.float32, np.array([[0, 1], [1, 2]], dtype=np.float32), np.float32], + [np.float32, np.array([[0, 1], [1, 2]], dtype=np.uint8), np.float32], + [np.uint8, np.array([[0, 1], [1, 2]], dtype=np.float32), np.uint8], +] + class TestCastToType(unittest.TestCase): @parameterized.expand(TESTS) @@ -35,6 +44,19 @@ def test_type(self, out_dtype, input_data, expected_type): result = CastToType()(input_data, out_dtype) self.assertEqual(result.dtype, get_equivalent_dtype(expected_type, type(result))) + @unittest.skipUnless(has_cp, "Requires CuPy") + @parameterized.expand(TESTS_CUPY) + def test_type_cupy(self, out_dtype, input_data, expected_type): + input_data = cp.asarray(input_data) + + result = CastToType(dtype=out_dtype)(input_data) + self.assertTrue(isinstance(result, cp.ndarray)) + self.assertEqual(result.dtype, get_equivalent_dtype(expected_type, type(result))) + + result = CastToType()(input_data, out_dtype) + self.assertTrue(isinstance(result, cp.ndarray)) + self.assertEqual(result.dtype, get_equivalent_dtype(expected_type, type(result))) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_cast_to_typed.py b/tests/test_cast_to_typed.py index be495564fb..d5da455b5c 100644 --- a/tests/test_cast_to_typed.py +++ b/tests/test_cast_to_typed.py @@ -16,6 +16,9 @@ from parameterized import parameterized from monai.transforms import CastToTyped +from monai.utils import optional_import + +cp, has_cp = optional_import("cupy") TEST_CASE_1 = [ {"keys": ["img"], "dtype": np.float64}, @@ -33,6 +36,26 @@ ] +TESTS_CUPY = [ + [ + {"keys": "image", "dtype": np.uint8}, + { + "image": np.array([[0, 1], [1, 2]], dtype=np.float32), + "label": np.array([[0, 1], [1, 1]], dtype=np.float32), + }, + {"image": np.uint8, "label": np.float32}, + ], + [ + {"keys": ["image", "label"], "dtype": np.float32}, + { + "image": np.array([[0, 1], [1, 2]], dtype=np.uint8), + "label": np.array([[0, 1], [1, 1]], dtype=np.uint8), + }, + {"image": np.float32, "label": np.float32}, + ], +] + + class TestCastToTyped(unittest.TestCase): @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) def test_type(self, input_param, input_data, expected_type): @@ -40,6 +63,16 @@ def test_type(self, input_param, input_data, expected_type): for k, v in result.items(): self.assertEqual(v.dtype, expected_type[k]) + @unittest.skipUnless(has_cp, "Requires CuPy") + @parameterized.expand(TESTS_CUPY) + def test_type_cupy(self, input_param, input_data, expected_type): + input_data = {k: cp.asarray(v) for k, v in input_data.items()} + + result = CastToTyped(**input_param)(input_data) + for k, v in result.items(): + self.assertTrue(isinstance(v, cp.ndarray)) + self.assertEqual(v.dtype, expected_type[k]) + if __name__ == "__main__": unittest.main() From 7f295bcd690a539e3c0e595e889b13fdb222d881 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:43:02 +0000 Subject: [PATCH 6/7] Remove check Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/transforms/utility/array.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 70b5db5adb..57d43db5d0 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -330,10 +330,6 @@ def __call__(self, img: NdarrayOrTensor, dtype: Optional[Union[DtypeLike, torch. TypeError: When ``img`` type is not in ``Union[numpy.ndarray, torch.Tensor]``. """ - if not isinstance(img, (torch.Tensor, np.ndarray)) and not (has_cp and isinstance(img, cp.ndarray)): - raise TypeError( - f"img must be one of (numpy.ndarray, torch.Tensor, cupy.ndarray) but is {type(img).__name__}." - ) img_out, *_ = convert_data_type(img, output_type=type(img), dtype=dtype or self.dtype) return img_out From e211abdf9e2a68e97df726d3884858e05ca66971 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 20:00:29 +0000 Subject: [PATCH 7/7] Change order of skipUnless Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- tests/test_cast_to_type.py | 2 +- tests/test_cast_to_typed.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_cast_to_type.py b/tests/test_cast_to_type.py index 03c68978bc..d06efb17b5 100644 --- a/tests/test_cast_to_type.py +++ b/tests/test_cast_to_type.py @@ -44,8 +44,8 @@ def test_type(self, out_dtype, input_data, expected_type): result = CastToType()(input_data, out_dtype) self.assertEqual(result.dtype, get_equivalent_dtype(expected_type, type(result))) - @unittest.skipUnless(has_cp, "Requires CuPy") @parameterized.expand(TESTS_CUPY) + @unittest.skipUnless(has_cp, "Requires CuPy") def test_type_cupy(self, out_dtype, input_data, expected_type): input_data = cp.asarray(input_data) diff --git a/tests/test_cast_to_typed.py b/tests/test_cast_to_typed.py index d5da455b5c..342a677ce1 100644 --- a/tests/test_cast_to_typed.py +++ b/tests/test_cast_to_typed.py @@ -63,8 +63,8 @@ def test_type(self, input_param, input_data, expected_type): for k, v in result.items(): self.assertEqual(v.dtype, expected_type[k]) - @unittest.skipUnless(has_cp, "Requires CuPy") @parameterized.expand(TESTS_CUPY) + @unittest.skipUnless(has_cp, "Requires CuPy") def test_type_cupy(self, input_param, input_data, expected_type): input_data = {k: cp.asarray(v) for k, v in input_data.items()}