Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
46c34cd
Implement CuCIM wrapper transfrom
bhashemian Sep 12, 2021
fe09a19
Implement CuCIMd and RandCuCIMd
bhashemian Sep 12, 2021
920ea4e
Update init
bhashemian Sep 12, 2021
751f154
Update docs
bhashemian Sep 12, 2021
4a942e2
Order imports
bhashemian Sep 12, 2021
86767ce
Update RandCuCIM and RandCuCIMd to be randomly applied
bhashemian Sep 13, 2021
f45968c
Merge branch 'dev' into cucim-transform
bhashemian Sep 13, 2021
c9b3198
Add optional_import
bhashemian Sep 13, 2021
97eb1d8
Merge branch 'cucim-transform' of github.com:drbeh/MONAI into cucim-t…
bhashemian Sep 13, 2021
64c11ee
Update docs and docstring
bhashemian Sep 13, 2021
d433a22
Update cucim api for monai
bhashemian Sep 13, 2021
f9b690d
Merge branch 'dev' into cucim-transform
bhashemian Sep 13, 2021
2c260b9
Fix docs
bhashemian Sep 13, 2021
4e7c137
Update imports
bhashemian Sep 13, 2021
2500e09
Remove type checking for cupy.ndarray
bhashemian Sep 14, 2021
6b4505a
Merge branch 'dev' into cucim-transform
bhashemian Sep 14, 2021
da45518
Merge branch 'dev' into cucim-transform
bhashemian Sep 14, 2021
1715212
Update cuCIM exposed API
bhashemian Sep 14, 2021
3ca5d88
Update cucim transfom calls
bhashemian Sep 15, 2021
fca930d
fix typo
bhashemian Sep 15, 2021
299e9b7
Merge branch 'dev' into cucim-transform
bhashemian Sep 15, 2021
22a3ec9
Rename prob to apply_prob
bhashemian Sep 15, 2021
b996567
Add unittests for CuCIM tranform
bhashemian Sep 15, 2021
628b139
Add unittests for CuCIMDict transform
bhashemian Sep 15, 2021
e464c13
Add unittests for RandCuCIM transform
bhashemian Sep 16, 2021
41553ea
Add unittests for RandCuCIMDict transform
bhashemian Sep 16, 2021
71d6311
Merge branch 'dev' into cucim-transform
bhashemian Sep 16, 2021
1f6b6e2
Fix docstrigs
bhashemian Sep 16, 2021
a6c9c48
Merge branch 'dev' into cucim-transform
wyli Sep 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update RandCuCIM and RandCuCIMd to be randomly applied
Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com>
  • Loading branch information
bhashemian committed Sep 13, 2021
commit 86767cead04d6df2429a070acb7688d61f27ef6a
60 changes: 47 additions & 13 deletions monai/transforms/utility/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -1108,30 +1108,64 @@ def __call__(self, img: torch.Tensor):
return img.to(self.device, **self.kwargs)


class CuCIM:
class CuCIM(Transform):
"""
Wrap cuCIM transform, defined based on the transform name and args.
CuCIM transforms only work with CuPy arrays, so this transform expects input data to be `cupy.ndarray`.
Users can call `ToCuPy` transform to convert a numpy array or torch tensor to cupy array.
Wrap a non-randomized cuCIM transform, defined based on the transform name and args.
For randomized transforms (or randomly applying a transform) use :py:class:`monai.transforms.RandCuCIM`.

Args:
name: the transform name in CuCIM package
args: parameters for the CuCIM transform
kwargs: parameters for the CuCIM transform

Note:
CuCIM transform only work with CuPy arrays, so this transform expects input data to be `cupy.ndarray`.
Users can call `ToCuPy` transform to convert a numpy array or torch tensor to cupy array.
"""

def __init__(self, name: str, *args, **kwargs) -> None:
"""
Args:
name: The transform name in CuCIM package.
args: parameters for the CuCIM transform.
kwargs: parameters for the CuCIM transform.

"""
super().__init__()
transform, _ = optional_import("cucim.transforms", name=name)
transform, _ = optional_import("cucim.core.operations", name=name)
self.trans = transform(*args, **kwargs)

def __call__(self, data: cp_ndarray):
"""
Args:
img: CuPy array for the cuCIM transform.
img: CuPy array for the cuCIM transform

"""
return self.trans(data)


class RandCuCIM(CuCIM, RandomizableTransform):
"""
Wrap a randomized cuCIM transform, defined based on the transform name and args,
or randomly apply a non-randomized transform.
For deterministic non-randomized transforms use :py:class:`monai.transforms.CuCIM`.

Args:
name: the transform name in CuCIM package.
prob: the probability to apply the transform (default=1.0)
args: parameters for the CuCIM transform.
kwargs: parameters for the CuCIM transform.

Note:
- CuCIM transform only work with CuPy arrays, so this transform expects input data to be `cupy.ndarray`.
Users can call `ToCuPy` transform to convert a numpy array or torch tensor to cupy array.
- If the cuCIM transform is already randomized, the `prob` argument has nothing to do with
the randomness of the underlying cuCIM transform.
It defines if the transform (either randomized or non-randomized) being applied randomly with `prob=1.0`,
so it can apply non-randomized tranforms randomly but be careful when it is being used along with randomized transforms.
- If the random factor of the underlying cuCIM transform is not derived from `self.R`,
the results may not be deterministic. See Also: :py:class:`monai.transforms.Randomizable`.
"""

def __init__(self, name: str, prob: float = 1.0, *args, **kwargs) -> None:
CuCIM.__init__(self, name, *args, **kwargs)
RandomizableTransform.__init__(self, prob=prob)

def __call__(self, data: cp_ndarray):
self.randomize(data)
if not self._do_transform:
return data
return super().__call__(data)
76 changes: 55 additions & 21 deletions monai/transforms/utility/dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import copy
import logging
from copy import deepcopy
from typing import Any, Callable, Dict, Hashable, List, Mapping, Optional, Sequence, Tuple, Union
from typing import TYPE_CHECKING, Any, Callable, Dict, Hashable, List, Mapping, Optional, Sequence, Tuple, Union

import numpy as np
import torch
Expand Down Expand Up @@ -62,6 +62,11 @@
from monai.utils import convert_to_numpy, ensure_tuple, ensure_tuple_rep
from monai.utils.enums import InverseKeys, TransformBackends

if TYPE_CHECKING:
from cupy import ndarray as cp_ndarray
else:
cp_ndarray, _ = optional_import("cupy", name="ndarray")

__all__ = [
"AddChannelD",
"AddChannelDict",
Expand All @@ -87,6 +92,9 @@
"CopyItemsD",
"CopyItemsDict",
"CopyItemsd",
"CuCIMd",
"CuCIMD",
"CuCIMDict",
"DataStatsD",
"DataStatsDict",
"DataStatsd",
Expand Down Expand Up @@ -117,6 +125,9 @@
"MapLabelValueD",
"MapLabelValueDict",
"MapLabelValued",
"RandCuCIMd",
"RandCuCIMD",
"RandCuCIMDict",
"RandLambdaD",
"RandLambdaDict",
"RandLambdad",
Expand Down Expand Up @@ -1433,6 +1444,14 @@ class CuCIMd(MapTransform):
Dictionary-based wrapper of :py:class:`monai.transforms.CuCIM` for non-randomized transforms.
For randomized transforms of CuCIM use :py:class:`monai.transforms.RandCuCIMd`.

Args:
keys: keys of the corresponding items to be transformed.
See also: :py:class:`monai.transforms.compose.MapTransform`
name: The transform name in CuCIM package.
allow_missing_keys: don't raise exception if key is missing.
args: parameters for the CuCIM transform.
kwargs: parameters for the CuCIM transform.

Note:
CuCIM transforms only work with CuPy arrays, this transform expects input data to be `cupy.ndarray`.
Users can call `ToCuPy` transform to convert a numpy array or torch tensor to cupy array.
Expand All @@ -1446,41 +1465,56 @@ def __init__(
*args,
**kwargs,
) -> None:
"""
Args:
keys: keys of the corresponding items to be transformed.
See also: :py:class:`monai.transforms.compose.MapTransform`
name: The transform name in CuCIM package.
allow_missing_keys: don't raise exception if key is missing.
args: parameters for the CuCIM transform.
kwargs: parameters for the CuCIM transform.

"""
super().__init__(keys, allow_missing_keys)
super().__init__(keys=keys, allow_missing_keys=allow_missing_keys)
self.trans = CuCIM(name, *args, **kwargs)

def __call__(self, data: Mapping[Hashable, torch.Tensor]) -> Dict[Hashable, torch.Tensor]:
def __call__(self, data: Mapping[Hashable, cp_ndarray]) -> Mapping[Hashable, cp_ndarray]:
d = dict(data)
for key in self.key_iterator(d):
d[key] = self.trans(d[key])
return d


class RandCuCIMd(Randomizable, CuCIMd):
class RandCuCIMd(CuCIMd, RandomizableTransform):
"""
Dictionary-based wrapper of :py:class:`monai.transforms.CuCIM` for randomized transforms.
For deterministic non-randomized transforms of CuCIM use :py:class:`monai.transforms.CuCIMd`.

Note:
- CuCIM transforms only work with CuPy arrays, this transform expects input data to be `cupy.ndarray`.
Users can call `ToCuPy` transform to convert a numpy array or torch tensor to cupy array.
- This class inherits the ``Randomizable`` purely to prevent any dataset caching to skip the transform
computation. If the random factor of the underlying cuCIM transform is not derived from `self.R`,
the results may not be deterministic.
See Also: :py:class:`monai.transforms.Randomizable`.
Args:
keys: keys of the corresponding items to be transformed.
See also: :py:class:`monai.transforms.compose.MapTransform`
name: The transform name in CuCIM package.
prob: the probability to apply the transform (default=1.0)
allow_missing_keys: don't raise exception if key is missing.
args: parameters for the CuCIM transform.
kwargs: parameters for the CuCIM transform.

Note:
- CuCIM transform only work with CuPy arrays, so this transform expects input data to be `cupy.ndarray`.
Users can call `ToCuPy` transform to convert a numpy array or torch tensor to cupy array.
- If the cuCIM transform is already randomized, the `prob` argument has nothing to do with
the randomness of the underlying cuCIM transform.
It defines if the transform (either randomized or non-randomized) being applied randomly with `prob=1.0`,
so it can apply non-randomized tranforms randomly but be careful when it is being used along with randomized transforms.
- If the random factor of the underlying cuCIM transform is not derived from `self.R`,
the results may not be deterministic. See Also: :py:class:`monai.transforms.Randomizable`.
"""

def __init__(
self,
prob: float = 1.0,
*args,
**kwargs,
) -> None:
CuCIMd.__init__(self, *args, **kwargs)
RandomizableTransform.__init__(self, prob=prob)

def __call__(self, data: Mapping[Hashable, cp_ndarray]) -> Mapping[Hashable, cp_ndarray]:
self.randomize(data)
if not self._do_transform:
return data
return super().__call__(data)


IdentityD = IdentityDict = Identityd
AsChannelFirstD = AsChannelFirstDict = AsChannelFirstd
Expand Down