Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
23 changes: 23 additions & 0 deletions docs/source/transforms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,18 @@ Utility
:members:
:special-members: __call__

`CuCIM`
"""""""
.. autoclass:: CuCIM
:members:
:special-members: __call__

`RandCuCIM`
"""""""""""
.. autoclass:: RandCuCIM
:members:
:special-members: __call__


Dictionary Transforms
---------------------
Expand Down Expand Up @@ -1374,6 +1386,17 @@ Utility (Dict)
:members:
:special-members: __call__

`CuCIMd`
""""""""
.. autoclass:: CuCIMd
:members:
:special-members: __call__

`RandCuCIMd`
""""""""""""
.. autoclass:: RandCuCIMd
:members:
:special-members: __call__

Transform Adaptors
------------------
Expand Down
8 changes: 8 additions & 0 deletions monai/transforms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@
CastToType,
ClassesToIndices,
ConvertToMultiChannelBasedOnBratsClasses,
CuCIM,
DataStats,
EnsureChannelFirst,
EnsureType,
Expand All @@ -368,6 +369,7 @@
LabelToMask,
Lambda,
MapLabelValue,
RandCuCIM,
RandLambda,
RemoveRepeatedChannel,
RepeatChannel,
Expand Down Expand Up @@ -410,6 +412,9 @@
CopyItemsd,
CopyItemsD,
CopyItemsDict,
CuCIMd,
CuCIMD,
CuCIMDict,
DataStatsd,
DataStatsD,
DataStatsDict,
Expand Down Expand Up @@ -440,6 +445,9 @@
MapLabelValued,
MapLabelValueD,
MapLabelValueDict,
RandCuCIMd,
RandCuCIMD,
RandCuCIMDict,
RandLambdad,
RandLambdaD,
RandLambdaDict,
Expand Down
77 changes: 76 additions & 1 deletion monai/transforms/utility/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
PILImageImage, has_pil = optional_import("PIL.Image", name="Image")
pil_image_fromarray, _ = optional_import("PIL.Image", name="fromarray")
cp, has_cp = optional_import("cupy")
cp_ndarray, _ = optional_import("cupy", name="ndarray")


__all__ = [
"Identity",
Expand Down Expand Up @@ -1148,3 +1148,78 @@ def __call__(self, img: torch.Tensor):
raise ValueError("img must be PyTorch Tensor, consider converting img by `EnsureType` transform first.")

return img.to(self.device, **self.kwargs)


class CuCIM(Transform):
"""
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:
super().__init__()
self.transform, _ = optional_import("cucim.core.operations.expose.transform", name=name)
self.args = args
self.kwargs = kwargs

def __call__(self, data):
"""
Args:
data: a CuPy array (`cupy.ndarray`) for the cuCIM transform

Returns:
`cupy.ndarray`

"""
return self.transform(data, *self.args, **self.kwargs)


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.
apply_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 `apply_prob` argument has nothing to do with
the randomness of the underlying cuCIM transform. `apply_prob` defines if the transform (either randomized
or non-randomized) being applied randomly, so it can apply non-randomized tranforms randomly but be careful
with setting `apply_prob` to anything than 1.0 when using along with cuCIM's 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, apply_prob: float = 1.0, *args, **kwargs) -> None:
CuCIM.__init__(self, name, *args, **kwargs)
RandomizableTransform.__init__(self, prob=apply_prob)

def __call__(self, data):
"""
Args:
data: a CuPy array (`cupy.ndarray`) for the cuCIM transform

Returns:
`cupy.ndarray`

"""
self.randomize(data)
if not self._do_transform:
return data
return super().__call__(data)
102 changes: 102 additions & 0 deletions monai/transforms/utility/dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
CastToType,
ClassesToIndices,
ConvertToMultiChannelBasedOnBratsClasses,
CuCIM,
DataStats,
EnsureChannelFirst,
EnsureType,
Expand Down Expand Up @@ -87,6 +88,9 @@
"CopyItemsD",
"CopyItemsDict",
"CopyItemsd",
"CuCIMd",
"CuCIMD",
"CuCIMDict",
"DataStatsD",
"DataStatsDict",
"DataStatsd",
Expand Down Expand Up @@ -117,6 +121,9 @@
"MapLabelValueD",
"MapLabelValueDict",
"MapLabelValued",
"RandCuCIMd",
"RandCuCIMD",
"RandCuCIMDict",
"RandLambdaD",
"RandLambdaDict",
"RandLambdad",
Expand Down Expand Up @@ -1481,6 +1488,99 @@ def __call__(self, data: Mapping[Hashable, torch.Tensor]) -> Dict[Hashable, torc
return d


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.
"""

def __init__(
self,
keys: KeysCollection,
name: str,
allow_missing_keys: bool = False,
*args,
**kwargs,
) -> None:
super().__init__(keys=keys, allow_missing_keys=allow_missing_keys)
self.trans = CuCIM(name, *args, **kwargs)

def __call__(self, data):
"""
Args:
data: Dict[Hashable, `cupy.ndarray`]

Returns:
Dict[Hashable, `cupy.ndarray`]

"""
d = dict(data)
for key in self.key_iterator(d):
d[key] = self.trans(d[key])
return d


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`.

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.
apply_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 `apply_prob` argument has nothing to do with
the randomness of the underlying cuCIM transform. `apply_prob` defines if the transform (either randomized
or non-randomized) being applied randomly, so it can apply non-randomized tranforms randomly but be careful
with setting `apply_prob` to anything than 1.0 when using along with cuCIM's 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,
apply_prob: float = 1.0,
*args,
**kwargs,
) -> None:
CuCIMd.__init__(self, *args, **kwargs)
RandomizableTransform.__init__(self, prob=apply_prob)

def __call__(self, data):
"""
Args:
data: Dict[Hashable, `cupy.ndarray`]

Returns:
Dict[Hashable, `cupy.ndarray`]

"""
self.randomize(data)
if not self._do_transform:
return dict(data)
return super().__call__(data)


IdentityD = IdentityDict = Identityd
AsChannelFirstD = AsChannelFirstDict = AsChannelFirstd
AsChannelLastD = AsChannelLastDict = AsChannelLastd
Expand Down Expand Up @@ -1517,3 +1617,5 @@ def __call__(self, data: Mapping[Hashable, torch.Tensor]) -> Dict[Hashable, torc
MapLabelValueD = MapLabelValueDict = MapLabelValued
IntensityStatsD = IntensityStatsDict = IntensityStatsd
ToDeviceD = ToDeviceDict = ToDeviced
CuCIMD = CuCIMDict = CuCIMd
RandCuCIMD = RandCuCIMDict = RandCuCIMd
Loading