From 7cfc8ea3c73ab63cfdca2e0cba9302f9286478a7 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Wed, 8 Sep 2021 12:38:05 +0100 Subject: [PATCH 01/89] 2901 ndim -> spatial_dims (#2903) * ndim -> spatial_dims Signed-off-by: Wenqi Li * dimensions -> spatial_dims Signed-off-by: Wenqi Li * deprecated arg with auto replacement Signed-off-by: Wenqi Li --- monai/apps/deepgrow/transforms.py | 14 ++- monai/losses/image_dissimilarity.py | 17 ++-- monai/networks/blocks/activation.py | 6 +- monai/networks/blocks/aspp.py | 2 +- monai/networks/blocks/convolutions.py | 39 ++++++--- monai/networks/blocks/fcn.py | 4 +- monai/networks/blocks/localnet_block.py | 11 ++- monai/networks/blocks/regunet_block.py | 10 ++- monai/networks/blocks/segresnet_block.py | 2 +- .../networks/blocks/squeeze_and_excitation.py | 6 +- monai/networks/blocks/upsample.py | 42 ++++++--- monai/networks/nets/autoencoder.py | 31 ++++--- monai/networks/nets/basic_unet.py | 87 ++++++++++++------- monai/networks/nets/generator.py | 4 +- monai/networks/nets/highresnet.py | 8 +- monai/networks/nets/regressor.py | 4 +- monai/networks/nets/senet.py | 2 +- monai/networks/nets/unet.py | 31 +++++-- monai/networks/nets/varautoencoder.py | 18 +++- monai/networks/nets/vnet.py | 6 +- monai/networks/utils.py | 23 +++-- monai/optimizers/utils.py | 2 +- monai/transforms/intensity/array.py | 4 +- monai/transforms/utils.py | 31 +++++-- monai/utils/deprecated.py | 20 +++-- tests/test_autoencoder.py | 2 +- tests/test_basic_unet.py | 2 +- tests/test_deprecated.py | 28 ++++++ tests/test_integration_determinism.py | 2 +- tests/test_integration_segmentation_3d.py | 4 +- tests/test_integration_sliding_window.py | 2 +- tests/test_integration_unet_2d.py | 4 +- tests/test_integration_workflows.py | 4 +- tests/test_inverse.py | 2 +- tests/test_unet.py | 8 +- 35 files changed, 331 insertions(+), 151 deletions(-) diff --git a/monai/apps/deepgrow/transforms.py b/monai/apps/deepgrow/transforms.py index db450792b0..7ededcd94c 100644 --- a/monai/apps/deepgrow/transforms.py +++ b/monai/apps/deepgrow/transforms.py @@ -19,7 +19,7 @@ from monai.transforms import Resize, SpatialCrop from monai.transforms.transform import MapTransform, Randomizable, Transform from monai.transforms.utils import generate_spatial_bounding_box -from monai.utils import InterpolateMode, ensure_tuple, ensure_tuple_rep, min_version, optional_import +from monai.utils import InterpolateMode, deprecated_arg, ensure_tuple, ensure_tuple_rep, min_version, optional_import measure, _ = optional_import("skimage.measure", "0.14.2", min_version) distance_transform_cdt, _ = optional_import("scipy.ndimage.morphology", name="distance_transform_cdt") @@ -476,7 +476,7 @@ class AddGuidanceFromPointsd(Transform): background: key that represents user background (-ve) clicks. axis: axis that represents slices in 3D volume. (axis to Depth) depth_first: if depth (slices) is positioned at first dimension. - dimensions: dimensions based on model used for deepgrow (2D vs 3D). + spatial_dims: dimensions based on model used for deepgrow (2D vs 3D). slice_key: key that represents applicable slice to add guidance. meta_keys: explicitly indicate the key of the meta data dictionary of `ref_image`. for example, for data with key `image`, the metadata by default is in `image_meta_dict`. @@ -486,8 +486,13 @@ class AddGuidanceFromPointsd(Transform): to the key data, default is `meta_dict`, the meta data is a dictionary object. For example, to handle key `image`, read/write affine matrices from the metadata `image_meta_dict` dictionary's `affine` field. + + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + """ + @deprecated_arg(name="dimensions", since="0.6", msg_suffix="Please use `spatial_dims` instead.") def __init__( self, ref_image, @@ -496,10 +501,11 @@ def __init__( background: str = "background", axis: int = 0, depth_first: bool = True, - dimensions: int = 2, + spatial_dims: int = 2, slice_key: str = "slice", meta_keys: Optional[str] = None, meta_key_postfix: str = "meta_dict", + dimensions: Optional[int] = None, ): self.ref_image = ref_image self.guidance = guidance @@ -507,7 +513,7 @@ def __init__( self.background = background self.axis = axis self.depth_first = depth_first - self.dimensions = dimensions + self.dimensions = spatial_dims if dimensions is None else dimensions self.slice = slice_key self.meta_keys = meta_keys self.meta_key_postfix = meta_key_postfix diff --git a/monai/losses/image_dissimilarity.py b/monai/losses/image_dissimilarity.py index eed5808aa3..33a532c387 100644 --- a/monai/losses/image_dissimilarity.py +++ b/monai/losses/image_dissimilarity.py @@ -8,14 +8,14 @@ # 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 Tuple, Union +from typing import Optional, Tuple, Union import torch from torch.nn import functional as F from torch.nn.modules.loss import _Loss from monai.networks.layers import gaussian_1d, separable_filtering -from monai.utils import LossReduction +from monai.utils import LossReduction, deprecated_arg def make_rectangular_kernel(kernel_size: int) -> torch.Tensor: @@ -59,18 +59,20 @@ class LocalNormalizedCrossCorrelationLoss(_Loss): DeepReg (https://github.com/DeepRegNet/DeepReg) """ + @deprecated_arg(name="ndim", since="0.6", msg_suffix="Please use `spatial_dims` instead.") def __init__( self, - ndim: int = 3, + spatial_dims: int = 3, kernel_size: int = 3, kernel_type: str = "rectangular", reduction: Union[LossReduction, str] = LossReduction.MEAN, smooth_nr: float = 1e-5, smooth_dr: float = 1e-5, + ndim: Optional[int] = None, ) -> None: """ Args: - ndim: number of spatial ndimensions, {``1``, ``2``, ``3``}. Defaults to 3. + spatial_dims: number of spatial ndimensions, {``1``, ``2``, ``3``}. Defaults to 3. kernel_size: kernel spatial size, must be odd. kernel_type: {``"rectangular"``, ``"triangular"``, ``"gaussian"``}. Defaults to ``"rectangular"``. reduction: {``"none"``, ``"mean"``, ``"sum"``} @@ -81,10 +83,15 @@ def __init__( - ``"sum"``: the output will be summed. smooth_nr: a small constant added to the numerator to avoid nan. smooth_dr: a small constant added to the denominator to avoid nan. + + .. deprecated:: 0.6.0 + ``ndim`` is deprecated, use ``spatial_dims``. """ super(LocalNormalizedCrossCorrelationLoss, self).__init__(reduction=LossReduction(reduction).value) - self.ndim = ndim + if ndim is not None: + spatial_dims = ndim + self.ndim = spatial_dims if self.ndim not in [1, 2, 3]: raise ValueError(f"Unsupported ndim: {self.ndim}-d, only 1-d, 2-d, and 3-d inputs are supported") diff --git a/monai/networks/blocks/activation.py b/monai/networks/blocks/activation.py index a380f8e757..9841dbd060 100644 --- a/monai/networks/blocks/activation.py +++ b/monai/networks/blocks/activation.py @@ -48,8 +48,7 @@ class Swish(nn.Module): Shape: - - Input: :math:`(N, *)` where `*` means, any number of additional - dimensions + - Input: :math:`(N, *)` where `*` means, any number of additional dimensions - Output: :math:`(N, *)`, same shape as the input @@ -143,8 +142,7 @@ class Mish(nn.Module): this class will utilize `torch.nn.functional.mish` to do the calculation if meets the version. Shape: - - Input: :math:`(N, *)` where `*` means, any number of additional - dimensions + - Input: :math:`(N, *)` where `*` means, any number of additional dimensions - Output: :math:`(N, *)`, same shape as the input diff --git a/monai/networks/blocks/aspp.py b/monai/networks/blocks/aspp.py index f8bf8a5ba6..9796ea8148 100644 --- a/monai/networks/blocks/aspp.py +++ b/monai/networks/blocks/aspp.py @@ -86,7 +86,7 @@ def __init__( out_channels = conv_out_channels * len(pads) # final conv. output channels self.conv_k1 = Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=out_channels, out_channels=out_channels, kernel_size=1, diff --git a/monai/networks/blocks/convolutions.py b/monai/networks/blocks/convolutions.py index 39ce60e3f8..d9ef0fd4a1 100644 --- a/monai/networks/blocks/convolutions.py +++ b/monai/networks/blocks/convolutions.py @@ -18,6 +18,7 @@ from monai.networks.blocks import ADN from monai.networks.layers.convutils import same_padding, stride_minus_kernel_padding from monai.networks.layers.factories import Conv +from monai.utils.deprecated import deprecated_arg class Convolution(nn.Sequential): @@ -59,7 +60,7 @@ class Convolution(nn.Sequential): ) Args: - dimensions: number of spatial dimensions. + spatial_dims: number of spatial dimensions. in_channels: number of input channels. out_channels: number of output channels. strides: convolution stride. Defaults to 1. @@ -69,13 +70,13 @@ class Convolution(nn.Sequential): act: activation type and arguments. Defaults to PReLU. norm: feature normalization type and arguments. Defaults to instance norm. dropout: dropout ratio. Defaults to no dropout. - dropout_dim: determine the dimensions of dropout. Defaults to 1. + dropout_dim: determine the spatial dimensions of dropout. Defaults to 1. - When dropout_dim = 1, randomly zeroes some of the elements for each channel. - When dropout_dim = 2, Randomly zeroes out entire channels (a channel is a 2D feature map). - When dropout_dim = 3, Randomly zeroes out entire channels (a channel is a 3D feature map). - The value of dropout_dim should be no no larger than the value of `dimensions`. + The value of dropout_dim should be no no larger than the value of `spatial_dims`. dilation: dilation rate. Defaults to 1. groups: controls the connections between inputs and outputs. Defaults to 1. bias: whether to have a bias term. Defaults to True. @@ -86,6 +87,9 @@ class Convolution(nn.Sequential): output_padding: controls the additional size added to one side of the output shape. Defaults to None. + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + See also: :py:class:`monai.networks.layers.Conv` @@ -93,9 +97,12 @@ class Convolution(nn.Sequential): """ + @deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) def __init__( self, - dimensions: int, + spatial_dims: int, in_channels: int, out_channels: int, strides: Union[Sequence[int], int] = 1, @@ -112,15 +119,16 @@ def __init__( is_transposed: bool = False, padding: Optional[Union[Sequence[int], int]] = None, output_padding: Optional[Union[Sequence[int], int]] = None, + dimensions: Optional[int] = None, ) -> None: super().__init__() - self.dimensions = dimensions + self.dimensions = spatial_dims if dimensions is None else dimensions self.in_channels = in_channels self.out_channels = out_channels self.is_transposed = is_transposed if padding is None: padding = same_padding(kernel_size, dilation) - conv_type = Conv[Conv.CONVTRANS if is_transposed else Conv.CONV, dimensions] + conv_type = Conv[Conv.CONVTRANS if is_transposed else Conv.CONV, self.dimensions] conv: nn.Module if is_transposed: @@ -159,7 +167,7 @@ def __init__( in_channels=out_channels, act=act, norm=norm, - norm_dim=dimensions, + norm_dim=self.dimensions, dropout=dropout, dropout_dim=dropout_dim, ), @@ -177,7 +185,7 @@ class ResidualUnit(nn.Module): from monai.networks.blocks import ResidualUnit convs = ResidualUnit( - dimensions=3, + spatial_dims=3, in_channels=1, out_channels=1, adn_ordering="AN", @@ -209,7 +217,7 @@ class ResidualUnit(nn.Module): ) Args: - dimensions: number of spatial dimensions. + spatial_dims: number of spatial dimensions. in_channels: number of input channels. out_channels: number of output channels. strides: convolution stride. Defaults to 1. @@ -234,15 +242,19 @@ class ResidualUnit(nn.Module): padding: controls the amount of implicit zero-paddings on both sides for padding number of points for each dimension. Defaults to None. + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + See also: :py:class:`monai.networks.blocks.Convolution` """ + @deprecated_arg(name="dimensions", since="0.6", msg_suffix="Please use `spatial_dims` instead.") def __init__( self, - dimensions: int, + spatial_dims: int, in_channels: int, out_channels: int, strides: Union[Sequence[int], int] = 1, @@ -257,9 +269,10 @@ def __init__( bias: bool = True, last_conv_only: bool = False, padding: Optional[Union[Sequence[int], int]] = None, + dimensions: Optional[int] = None, ) -> None: super().__init__() - self.dimensions = dimensions + self.dimensions = spatial_dims if dimensions is None else dimensions self.in_channels = in_channels self.out_channels = out_channels self.conv = nn.Sequential() @@ -273,7 +286,7 @@ def __init__( for su in range(subunits): conv_only = last_conv_only and su == (subunits - 1) unit = Convolution( - dimensions, + self.dimensions, schannels, out_channels, strides=sstrides, @@ -304,7 +317,7 @@ def __init__( rkernel_size = 1 rpadding = 0 - conv_type = Conv[Conv.CONV, dimensions] + conv_type = Conv[Conv.CONV, self.dimensions] self.residual = conv_type(in_channels, out_channels, rkernel_size, strides, rpadding, bias=bias) def forward(self, x: torch.Tensor) -> torch.Tensor: diff --git a/monai/networks/blocks/fcn.py b/monai/networks/blocks/fcn.py index d84e506774..0c4fa3e320 100644 --- a/monai/networks/blocks/fcn.py +++ b/monai/networks/blocks/fcn.py @@ -155,7 +155,7 @@ def __init__( if self.upsample_mode == "transpose": self.up_conv = UpSample( - dimensions=2, + spatial_dims=2, in_channels=self.out_channels, scale_factor=2, mode="deconv", @@ -236,7 +236,7 @@ def __init__( ) self.init_proj = Convolution( - dimensions=2, + spatial_dims=2, in_channels=in_channels, out_channels=3, kernel_size=1, diff --git a/monai/networks/blocks/localnet_block.py b/monai/networks/blocks/localnet_block.py index 3997d42436..4e008b128a 100644 --- a/monai/networks/blocks/localnet_block.py +++ b/monai/networks/blocks/localnet_block.py @@ -29,7 +29,7 @@ def get_conv_block( norm: Optional[Union[Tuple, str]] = "BATCH", ) -> nn.Module: padding = same_padding(kernel_size) - return Convolution( + mod: nn.Module = Convolution( spatial_dims, in_channels, out_channels, @@ -40,6 +40,7 @@ def get_conv_block( conv_only=False, padding=padding, ) + return mod def get_conv_layer( @@ -49,7 +50,7 @@ def get_conv_layer( kernel_size: Union[Sequence[int], int] = 3, ) -> nn.Module: padding = same_padding(kernel_size) - return Convolution( + mod: nn.Module = Convolution( spatial_dims, in_channels, out_channels, @@ -58,6 +59,7 @@ def get_conv_layer( conv_only=True, padding=padding, ) + return mod def get_deconv_block( @@ -65,8 +67,8 @@ def get_deconv_block( in_channels: int, out_channels: int, ) -> nn.Module: - return Convolution( - dimensions=spatial_dims, + mod: nn.Module = Convolution( + spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels, strides=2, @@ -77,6 +79,7 @@ def get_deconv_block( padding=1, output_padding=1, ) + return mod class ResidualBlock(nn.Module): diff --git a/monai/networks/blocks/regunet_block.py b/monai/networks/blocks/regunet_block.py index d2cd3518b9..29fa3d5d85 100644 --- a/monai/networks/blocks/regunet_block.py +++ b/monai/networks/blocks/regunet_block.py @@ -32,7 +32,7 @@ def get_conv_block( ) -> nn.Module: if padding is None: padding = same_padding(kernel_size) - conv_block = Convolution( + conv_block: nn.Module = Convolution( spatial_dims, in_channels, out_channels, @@ -65,7 +65,7 @@ def get_conv_layer( kernel_size: Union[Sequence[int], int] = 3, ) -> nn.Module: padding = same_padding(kernel_size) - return Convolution( + mod: nn.Module = Convolution( spatial_dims, in_channels, out_channels, @@ -74,6 +74,7 @@ def get_conv_layer( conv_only=True, padding=padding, ) + return mod class RegistrationResidualConvBlock(nn.Module): @@ -193,8 +194,8 @@ def get_deconv_block( in_channels: int, out_channels: int, ) -> nn.Module: - return Convolution( - dimensions=spatial_dims, + mod: nn.Module = Convolution( + spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels, strides=2, @@ -205,6 +206,7 @@ def get_deconv_block( padding=1, output_padding=1, ) + return mod class RegistrationExtractionBlock(nn.Module): diff --git a/monai/networks/blocks/segresnet_block.py b/monai/networks/blocks/segresnet_block.py index d8f6d7b268..4d2a5b0623 100644 --- a/monai/networks/blocks/segresnet_block.py +++ b/monai/networks/blocks/segresnet_block.py @@ -39,7 +39,7 @@ def get_upsample_layer( spatial_dims: int, in_channels: int, upsample_mode: Union[UpsampleMode, str] = "nontrainable", scale_factor: int = 2 ): return UpSample( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=in_channels, out_channels=in_channels, scale_factor=scale_factor, diff --git a/monai/networks/blocks/squeeze_and_excitation.py b/monai/networks/blocks/squeeze_and_excitation.py index 4db6dc30f7..76cbbb5037 100644 --- a/monai/networks/blocks/squeeze_and_excitation.py +++ b/monai/networks/blocks/squeeze_and_excitation.py @@ -186,16 +186,16 @@ def __init__( if not conv_param_1: conv_param_1 = {"kernel_size": 1, "norm": Norm.BATCH, "act": ("relu", {"inplace": True})} self.conv1 = Convolution( - dimensions=spatial_dims, in_channels=in_channels, out_channels=n_chns_1, **conv_param_1 + spatial_dims=spatial_dims, in_channels=in_channels, out_channels=n_chns_1, **conv_param_1 ) if not conv_param_2: conv_param_2 = {"kernel_size": 3, "norm": Norm.BATCH, "act": ("relu", {"inplace": True})} - self.conv2 = Convolution(dimensions=spatial_dims, in_channels=n_chns_1, out_channels=n_chns_2, **conv_param_2) + self.conv2 = Convolution(spatial_dims=spatial_dims, in_channels=n_chns_1, out_channels=n_chns_2, **conv_param_2) if not conv_param_3: conv_param_3 = {"kernel_size": 1, "norm": Norm.BATCH, "act": None} - self.conv3 = Convolution(dimensions=spatial_dims, in_channels=n_chns_2, out_channels=n_chns_3, **conv_param_3) + self.conv3 = Convolution(spatial_dims=spatial_dims, in_channels=n_chns_2, out_channels=n_chns_3, **conv_param_3) self.se_layer = ChannelSELayer( spatial_dims=spatial_dims, in_channels=n_chns_3, r=r, acti_type_1=acti_type_1, acti_type_2=acti_type_2 diff --git a/monai/networks/blocks/upsample.py b/monai/networks/blocks/upsample.py index 5320611ce6..a6aa13dde4 100644 --- a/monai/networks/blocks/upsample.py +++ b/monai/networks/blocks/upsample.py @@ -16,7 +16,7 @@ from monai.networks.layers.factories import Conv, Pad, Pool from monai.networks.utils import icnr_init, pixelshuffle -from monai.utils import InterpolateMode, UpsampleMode, ensure_tuple_rep, look_up_option +from monai.utils import InterpolateMode, UpsampleMode, deprecated_arg, ensure_tuple_rep, look_up_option __all__ = ["Upsample", "UpSample", "SubpixelUpsample", "Subpixelupsample", "SubpixelUpSample"] @@ -34,9 +34,12 @@ class UpSample(nn.Sequential): (often used to map the number of features from `in_channels` to `out_channels`). """ + @deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) def __init__( self, - dimensions: int, + spatial_dims: int, in_channels: Optional[int] = None, out_channels: Optional[int] = None, scale_factor: Union[Sequence[float], float] = 2, @@ -47,10 +50,11 @@ def __init__( align_corners: Optional[bool] = True, bias: bool = True, apply_pad_pool: bool = True, + dimensions: Optional[int] = None, ) -> None: """ Args: - dimensions: number of spatial dimensions of the input image. + spatial_dims: number of spatial dimensions of the input image. in_channels: number of channels of the input image. out_channels: number of channels of the output image. Defaults to `in_channels`. scale_factor: multiplier for spatial size. Has to match input size if it is a tuple. Defaults to 2. @@ -75,16 +79,21 @@ def __init__( apply_pad_pool: if True the upsampled tensor is padded then average pooling is applied with a kernel the size of `scale_factor` with a stride of 1. See also: :py:class:`monai.networks.blocks.SubpixelUpsample`. Only used in the "pixelshuffle" mode. + + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. """ super().__init__() - scale_factor_ = ensure_tuple_rep(scale_factor, dimensions) + if dimensions is not None: + spatial_dims = dimensions + scale_factor_ = ensure_tuple_rep(scale_factor, spatial_dims) up_mode = look_up_option(mode, UpsampleMode) if up_mode == UpsampleMode.DECONV: if not in_channels: raise ValueError(f"in_channels needs to be specified in the '{mode}' mode.") self.add_module( "deconv", - Conv[Conv.CONVTRANS, dimensions]( + Conv[Conv.CONVTRANS, spatial_dims]( in_channels=in_channels, out_channels=out_channels or in_channels, kernel_size=scale_factor_, @@ -98,7 +107,7 @@ def __init__( raise ValueError(f"in_channels needs to be specified in the '{mode}' mode.") self.add_module( "preconv", - Conv[Conv.CONV, dimensions]( + Conv[Conv.CONV, spatial_dims]( in_channels=in_channels, out_channels=out_channels or in_channels, kernel_size=1, bias=bias ), ) @@ -112,7 +121,7 @@ def __init__( interp_mode = InterpolateMode(interp_mode) linear_mode = [InterpolateMode.LINEAR, InterpolateMode.BILINEAR, InterpolateMode.TRILINEAR] if interp_mode in linear_mode: # choose mode based on dimensions - interp_mode = linear_mode[dimensions - 1] + interp_mode = linear_mode[spatial_dims - 1] self.add_module( "upsample_non_trainable", nn.Upsample( @@ -126,7 +135,7 @@ def __init__( self.add_module( "pixelshuffle", SubpixelUpsample( - dimensions=dimensions, + spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels, scale_factor=scale_factor_[0], # isotropic @@ -164,19 +173,23 @@ class SubpixelUpsample(nn.Module): """ + @deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) def __init__( self, - dimensions: int, + spatial_dims: int, in_channels: Optional[int], out_channels: Optional[int] = None, scale_factor: int = 2, conv_block: Optional[Union[nn.Module, str]] = "default", apply_pad_pool: bool = True, bias: bool = True, + dimensions: Optional[int] = None, ) -> None: """ Args: - dimensions: number of spatial dimensions of the input image. + spatial_dims: number of spatial dimensions of the input image. in_channels: number of channels of the input image. out_channels: optional number of channels of the output image. scale_factor: multiplier for spatial size. Defaults to 2. @@ -190,21 +203,24 @@ def __init__( size of `scale_factor` with a stride of 1. This implements the nearest neighbour resize convolution component of subpixel convolutions described in Aitken et al. bias: whether to have a bias term in the default conv_block. Defaults to True. + + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. """ super().__init__() if scale_factor <= 0: raise ValueError(f"The `scale_factor` multiplier must be an integer greater than 0, got {scale_factor}.") - self.dimensions = dimensions + self.dimensions = spatial_dims if dimensions is None else dimensions self.scale_factor = scale_factor if conv_block == "default": out_channels = out_channels or in_channels if not out_channels: raise ValueError("in_channels need to be specified.") - conv_out_channels = out_channels * (scale_factor ** dimensions) - self.conv_block = Conv[Conv.CONV, dimensions]( + conv_out_channels = out_channels * (scale_factor ** self.dimensions) + self.conv_block = Conv[Conv.CONV, self.dimensions]( in_channels=in_channels, out_channels=conv_out_channels, kernel_size=3, stride=1, padding=1, bias=bias ) diff --git a/monai/networks/nets/autoencoder.py b/monai/networks/nets/autoencoder.py index d0a54b8148..08b84d0566 100644 --- a/monai/networks/nets/autoencoder.py +++ b/monai/networks/nets/autoencoder.py @@ -16,14 +16,18 @@ from monai.networks.blocks import Convolution, ResidualUnit from monai.networks.layers.factories import Act, Norm +from monai.utils import deprecated_arg __all__ = ["AutoEncoder"] class AutoEncoder(nn.Module): + @deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) def __init__( self, - dimensions: int, + spatial_dims: int, in_channels: int, out_channels: int, channels: Sequence[int], @@ -38,10 +42,15 @@ def __init__( norm: Union[Tuple, str] = Norm.INSTANCE, dropout: Optional[Union[Tuple, str, float]] = None, bias: bool = True, + dimensions: Optional[int] = None, ) -> None: + """ + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + """ super().__init__() - self.dimensions = dimensions + self.dimensions = spatial_dims if dimensions is None else dimensions self.in_channels = in_channels self.out_channels = out_channels self.channels = list(channels) @@ -95,7 +104,7 @@ def _get_intermediate_module(self, in_channels: int, num_inter_units: int) -> Tu for i, (dc, di) in enumerate(zip(self.inter_channels, self.inter_dilations)): if self.num_inter_units > 0: unit = ResidualUnit( - dimensions=self.dimensions, + spatial_dims=self.dimensions, in_channels=layer_channels, out_channels=dc, strides=1, @@ -109,7 +118,7 @@ def _get_intermediate_module(self, in_channels: int, num_inter_units: int) -> Tu ) else: unit = Convolution( - dimensions=self.dimensions, + spatial_dims=self.dimensions, in_channels=layer_channels, out_channels=dc, strides=1, @@ -141,9 +150,10 @@ def _get_decode_module( def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Module: + mod: nn.Module if self.num_res_units > 0: - return ResidualUnit( - dimensions=self.dimensions, + mod = ResidualUnit( + spatial_dims=self.dimensions, in_channels=in_channels, out_channels=out_channels, strides=strides, @@ -155,8 +165,8 @@ def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, i bias=self.bias, last_conv_only=is_last, ) - return Convolution( - dimensions=self.dimensions, + mod = Convolution( + spatial_dims=self.dimensions, in_channels=in_channels, out_channels=out_channels, strides=strides, @@ -167,13 +177,14 @@ def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, i bias=self.bias, conv_only=is_last, ) + return mod def _get_decode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Sequential: decode = nn.Sequential() conv = Convolution( - dimensions=self.dimensions, + spatial_dims=self.dimensions, in_channels=in_channels, out_channels=out_channels, strides=strides, @@ -190,7 +201,7 @@ def _get_decode_layer(self, in_channels: int, out_channels: int, strides: int, i if self.num_res_units > 0: ru = ResidualUnit( - dimensions=self.dimensions, + spatial_dims=self.dimensions, in_channels=out_channels, out_channels=out_channels, strides=1, diff --git a/monai/networks/nets/basic_unet.py b/monai/networks/nets/basic_unet.py index 63205f45ee..f96b299d2b 100644 --- a/monai/networks/nets/basic_unet.py +++ b/monai/networks/nets/basic_unet.py @@ -16,7 +16,7 @@ from monai.networks.blocks import Convolution, UpSample from monai.networks.layers.factories import Conv, Pool -from monai.utils import ensure_tuple_rep +from monai.utils import deprecated_arg, ensure_tuple_rep __all__ = ["BasicUNet", "BasicUnet", "Basicunet"] @@ -24,19 +24,21 @@ class TwoConv(nn.Sequential): """two convolutions.""" + @deprecated_arg(name="dim", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead.") def __init__( self, - dim: int, + spatial_dims: int, in_chns: int, out_chns: int, act: Union[str, tuple], norm: Union[str, tuple], bias: bool, dropout: Union[float, tuple] = 0.0, + dim: Optional[int] = None, ): """ Args: - dim: number of spatial dimensions. + spatial_dims: number of spatial dimensions. in_chns: number of input channels. out_chns: number of output channels. act: activation type and arguments. @@ -44,11 +46,17 @@ def __init__( bias: whether to have a bias term in convolution blocks. dropout: dropout ratio. Defaults to no dropout. + .. deprecated:: 0.6.0 + ``dim`` is deprecated, use ``spatial_dims`` instead. """ super().__init__() - conv_0 = Convolution(dim, in_chns, out_chns, act=act, norm=norm, dropout=dropout, bias=bias, padding=1) - conv_1 = Convolution(dim, out_chns, out_chns, act=act, norm=norm, dropout=dropout, bias=bias, padding=1) + if dim is not None: + spatial_dims = dim + conv_0 = Convolution(spatial_dims, in_chns, out_chns, act=act, norm=norm, dropout=dropout, bias=bias, padding=1) + conv_1 = Convolution( + spatial_dims, out_chns, out_chns, act=act, norm=norm, dropout=dropout, bias=bias, padding=1 + ) self.add_module("conv_0", conv_0) self.add_module("conv_1", conv_1) @@ -56,19 +64,21 @@ def __init__( class Down(nn.Sequential): """maxpooling downsampling and two convolutions.""" + @deprecated_arg(name="dim", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead.") def __init__( self, - dim: int, + spatial_dims: int, in_chns: int, out_chns: int, act: Union[str, tuple], norm: Union[str, tuple], bias: bool, dropout: Union[float, tuple] = 0.0, + dim: Optional[int] = None, ): """ Args: - dim: number of spatial dimensions. + spatial_dims: number of spatial dimensions. in_chns: number of input channels. out_chns: number of output channels. act: activation type and arguments. @@ -76,11 +86,14 @@ def __init__( bias: whether to have a bias term in convolution blocks. dropout: dropout ratio. Defaults to no dropout. + .. deprecated:: 0.6.0 + ``dim`` is deprecated, use ``spatial_dims`` instead. """ super().__init__() - - max_pooling = Pool["MAX", dim](kernel_size=2) - convs = TwoConv(dim, in_chns, out_chns, act, norm, bias, dropout) + if dim is not None: + spatial_dims = dim + max_pooling = Pool["MAX", spatial_dims](kernel_size=2) + convs = TwoConv(spatial_dims, in_chns, out_chns, act, norm, bias, dropout) self.add_module("max_pooling", max_pooling) self.add_module("convs", convs) @@ -88,9 +101,10 @@ def __init__( class UpCat(nn.Module): """upsampling, concatenation with the encoder feature map, two convolutions""" + @deprecated_arg(name="dim", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead.") def __init__( self, - dim: int, + spatial_dims: int, in_chns: int, cat_chns: int, out_chns: int, @@ -103,10 +117,11 @@ def __init__( interp_mode: str = "linear", align_corners: Optional[bool] = True, halves: bool = True, + dim: Optional[int] = None, ): """ Args: - dim: number of spatial dimensions. + spatial_dims: number of spatial dimensions. in_chns: number of input channels to be upsampled. cat_chns: number of channels from the decoder. out_chns: number of output channels. @@ -124,14 +139,19 @@ def __init__( Only used in the "nontrainable" mode. halves: whether to halve the number of channels during upsampling. This parameter does not work on ``nontrainable`` mode if ``pre_conv`` is `None`. + + .. deprecated:: 0.6.0 + ``dim`` is deprecated, use ``spatial_dims`` instead. """ super().__init__() + if dim is not None: + spatial_dims = dim if upsample == "nontrainable" and pre_conv is None: up_chns = in_chns else: up_chns = in_chns // 2 if halves else in_chns self.upsample = UpSample( - dim, + spatial_dims, in_chns, up_chns, 2, @@ -140,7 +160,7 @@ def __init__( interp_mode=interp_mode, align_corners=align_corners, ) - self.convs = TwoConv(dim, cat_chns + up_chns, out_chns, act, norm, bias, dropout) + self.convs = TwoConv(spatial_dims, cat_chns + up_chns, out_chns, act, norm, bias, dropout) def forward(self, x: torch.Tensor, x_e: Optional[torch.Tensor]): """ @@ -167,9 +187,12 @@ def forward(self, x: torch.Tensor, x_e: Optional[torch.Tensor]): class BasicUNet(nn.Module): + @deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) def __init__( self, - dimensions: int = 3, + spatial_dims: int = 3, in_channels: int = 1, out_channels: int = 2, features: Sequence[int] = (32, 32, 64, 128, 256, 32), @@ -178,6 +201,7 @@ def __init__( bias: bool = True, dropout: Union[float, tuple] = 0.0, upsample: str = "deconv", + dimensions: Optional[int] = None, ): """ A UNet implementation with 1D/2D/3D supports. @@ -189,7 +213,7 @@ def __init__( http://dx.doi.org/10.1038/s41592-018-0261-2 Args: - dimensions: number of spatial dimensions. Defaults to 3 for spatial 3D inputs. + spatial_dims: number of spatial dimensions. Defaults to 3 for spatial 3D inputs. in_channels: number of input channels. Defaults to 1. out_channels: number of output channels. Defaults to 2. features: six integers as numbers of features. @@ -207,16 +231,19 @@ def __init__( upsample: upsampling mode, available options are ``"deconv"``, ``"pixelshuffle"``, ``"nontrainable"``. + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + Examples:: # for spatial 2D - >>> net = BasicUNet(dimensions=2, features=(64, 128, 256, 512, 1024, 128)) + >>> net = BasicUNet(spatial_dims=2, features=(64, 128, 256, 512, 1024, 128)) # for spatial 2D, with group norm - >>> net = BasicUNet(dimensions=2, features=(64, 128, 256, 512, 1024, 128), norm=("group", {"num_groups": 4})) + >>> net = BasicUNet(spatial_dims=2, features=(64, 128, 256, 512, 1024, 128), norm=("group", {"num_groups": 4})) # for spatial 3D - >>> net = BasicUNet(dimensions=3, features=(32, 32, 64, 128, 256, 32)) + >>> net = BasicUNet(spatial_dims=3, features=(32, 32, 64, 128, 256, 32)) See Also @@ -225,22 +252,24 @@ def __init__( """ super().__init__() + if dimensions is not None: + spatial_dims = dimensions fea = ensure_tuple_rep(features, 6) print(f"BasicUNet features: {fea}.") - self.conv_0 = TwoConv(dimensions, in_channels, features[0], act, norm, bias, dropout) - self.down_1 = Down(dimensions, fea[0], fea[1], act, norm, bias, dropout) - self.down_2 = Down(dimensions, fea[1], fea[2], act, norm, bias, dropout) - self.down_3 = Down(dimensions, fea[2], fea[3], act, norm, bias, dropout) - self.down_4 = Down(dimensions, fea[3], fea[4], act, norm, bias, dropout) + self.conv_0 = TwoConv(spatial_dims, in_channels, features[0], act, norm, bias, dropout) + self.down_1 = Down(spatial_dims, fea[0], fea[1], act, norm, bias, dropout) + self.down_2 = Down(spatial_dims, fea[1], fea[2], act, norm, bias, dropout) + self.down_3 = Down(spatial_dims, fea[2], fea[3], act, norm, bias, dropout) + self.down_4 = Down(spatial_dims, fea[3], fea[4], act, norm, bias, dropout) - self.upcat_4 = UpCat(dimensions, fea[4], fea[3], fea[3], act, norm, bias, dropout, upsample) - self.upcat_3 = UpCat(dimensions, fea[3], fea[2], fea[2], act, norm, bias, dropout, upsample) - self.upcat_2 = UpCat(dimensions, fea[2], fea[1], fea[1], act, norm, bias, dropout, upsample) - self.upcat_1 = UpCat(dimensions, fea[1], fea[0], fea[5], act, norm, bias, dropout, upsample, halves=False) + self.upcat_4 = UpCat(spatial_dims, fea[4], fea[3], fea[3], act, norm, bias, dropout, upsample) + self.upcat_3 = UpCat(spatial_dims, fea[3], fea[2], fea[2], act, norm, bias, dropout, upsample) + self.upcat_2 = UpCat(spatial_dims, fea[2], fea[1], fea[1], act, norm, bias, dropout, upsample) + self.upcat_1 = UpCat(spatial_dims, fea[1], fea[0], fea[5], act, norm, bias, dropout, upsample, halves=False) - self.final_conv = Conv["conv", dimensions](fea[5], out_channels, kernel_size=1) + self.final_conv = Conv["conv", spatial_dims](fea[5], out_channels, kernel_size=1) def forward(self, x: torch.Tensor): """ diff --git a/monai/networks/nets/generator.py b/monai/networks/nets/generator.py index 1f24944a63..ea05787173 100644 --- a/monai/networks/nets/generator.py +++ b/monai/networks/nets/generator.py @@ -112,7 +112,7 @@ def _get_layer( strides=strides, is_transposed=True, conv_only=is_last or self.num_res_units > 0, - dimensions=self.dimensions, + spatial_dims=self.dimensions, out_channels=out_channels, kernel_size=self.kernel_size, act=self.act, @@ -126,7 +126,7 @@ def _get_layer( in_channels=out_channels, subunits=self.num_res_units, last_conv_only=is_last, - dimensions=self.dimensions, + spatial_dims=self.dimensions, out_channels=out_channels, kernel_size=self.kernel_size, act=self.act, diff --git a/monai/networks/nets/highresnet.py b/monai/networks/nets/highresnet.py index f644a7835a..cd0950804d 100644 --- a/monai/networks/nets/highresnet.py +++ b/monai/networks/nets/highresnet.py @@ -84,7 +84,7 @@ def __init__( ) layers.append( Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=_in_chns, out_channels=_out_chns, kernel_size=kernel_size, @@ -154,7 +154,7 @@ def __init__( _in_chns, _out_chns = in_channels, params["n_features"] blocks.append( Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=_in_chns, out_channels=_out_chns, kernel_size=params["kernel_size"], @@ -190,7 +190,7 @@ def __init__( _in_chns, _out_chns = _out_chns, params["n_features"] blocks.append( Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=_in_chns, out_channels=_out_chns, kernel_size=params["kernel_size"], @@ -206,7 +206,7 @@ def __init__( _in_chns = _out_chns blocks.append( Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=_in_chns, out_channels=out_channels, kernel_size=params["kernel_size"], diff --git a/monai/networks/nets/regressor.py b/monai/networks/nets/regressor.py index 25acb9bfa5..0153014902 100644 --- a/monai/networks/nets/regressor.py +++ b/monai/networks/nets/regressor.py @@ -107,7 +107,7 @@ def _get_layer( layer = ResidualUnit( subunits=self.num_res_units, last_conv_only=is_last, - dimensions=self.dimensions, + spatial_dims=self.dimensions, in_channels=in_channels, out_channels=out_channels, strides=strides, @@ -120,7 +120,7 @@ def _get_layer( else: layer = Convolution( conv_only=is_last, - dimensions=self.dimensions, + spatial_dims=self.dimensions, in_channels=in_channels, out_channels=out_channels, strides=strides, diff --git a/monai/networks/nets/senet.py b/monai/networks/nets/senet.py index 9b7035c259..65089afc2c 100644 --- a/monai/networks/nets/senet.py +++ b/monai/networks/nets/senet.py @@ -192,7 +192,7 @@ def _make_layer( downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = Convolution( - dimensions=self.spatial_dims, + spatial_dims=self.spatial_dims, in_channels=self.inplanes, out_channels=planes * block.expansion, strides=stride, diff --git a/monai/networks/nets/unet.py b/monai/networks/nets/unet.py index 70cc816fe9..1dd52455d9 100644 --- a/monai/networks/nets/unet.py +++ b/monai/networks/nets/unet.py @@ -10,7 +10,7 @@ # limitations under the License. import warnings -from typing import Sequence, Tuple, Union +from typing import Optional, Sequence, Tuple, Union import torch import torch.nn as nn @@ -18,7 +18,7 @@ from monai.networks.blocks.convolutions import Convolution, ResidualUnit from monai.networks.layers.factories import Act, Norm from monai.networks.layers.simplelayers import SkipConnection -from monai.utils import alias, export +from monai.utils import alias, deprecated_arg, export __all__ = ["UNet", "Unet", "unet"] @@ -26,9 +26,12 @@ @export("monai.networks.nets") @alias("Unet") class UNet(nn.Module): + @deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) def __init__( self, - dimensions: int, + spatial_dims: int, in_channels: int, out_channels: int, channels: Sequence[int], @@ -40,6 +43,7 @@ def __init__( norm: Union[Tuple, str] = Norm.INSTANCE, dropout: float = 0.0, bias: bool = True, + dimensions: Optional[int] = None, ) -> None: """ Enhanced version of UNet which has residual units implemented with the ResidualUnit class. @@ -48,7 +52,7 @@ def __init__( Refer to: https://link.springer.com/chapter/10.1007/978-3-030-12029-0_40. Args: - dimensions: number of spatial dimensions. + spatial_dims: number of spatial dimensions. in_channels: number of input channels. out_channels: number of output channels. channels: sequence of channels. Top block first. The length of `channels` should be no less than 2. @@ -65,6 +69,9 @@ def __init__( According to `Performance Tuning Guide `_, if a conv layer is directly followed by a batch norm layer, bias should be False. + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + Note: The acceptable spatial size of input data depends on the parameters of the network, to set appropriate spatial size, please check the tutorial for more details: https://github.com/Project-MONAI/tutorials/blob/master/modules/UNet_input_size_constrains.ipynb. @@ -83,14 +90,16 @@ def __init__( raise ValueError("the length of `strides` should equal to `len(channels) - 1`.") if delta > 0: warnings.warn(f"`len(strides) > len(channels) - 1`, the last {delta} values of strides will not be used.") + if dimensions is not None: + spatial_dims = dimensions if isinstance(kernel_size, Sequence): - if len(kernel_size) != dimensions: + if len(kernel_size) != spatial_dims: raise ValueError("the length of `kernel_size` should equal to `dimensions`.") if isinstance(up_kernel_size, Sequence): - if len(up_kernel_size) != dimensions: + if len(up_kernel_size) != spatial_dims: raise ValueError("the length of `up_kernel_size` should equal to `dimensions`.") - self.dimensions = dimensions + self.dimensions = spatial_dims self.in_channels = in_channels self.out_channels = out_channels self.channels = channels @@ -145,8 +154,10 @@ def _get_down_layer(self, in_channels: int, out_channels: int, strides: int, is_ strides: convolution stride. is_top: True if this is the top block. """ + mod: nn.Module if self.num_res_units > 0: - return ResidualUnit( + + mod = ResidualUnit( self.dimensions, in_channels, out_channels, @@ -158,7 +169,8 @@ def _get_down_layer(self, in_channels: int, out_channels: int, strides: int, is_ dropout=self.dropout, bias=self.bias, ) - return Convolution( + return mod + mod = Convolution( self.dimensions, in_channels, out_channels, @@ -169,6 +181,7 @@ def _get_down_layer(self, in_channels: int, out_channels: int, strides: int, is_ dropout=self.dropout, bias=self.bias, ) + return mod def _get_bottom_layer(self, in_channels: int, out_channels: int) -> nn.Module: """ diff --git a/monai/networks/nets/varautoencoder.py b/monai/networks/nets/varautoencoder.py index 7f54890992..31e187106f 100644 --- a/monai/networks/nets/varautoencoder.py +++ b/monai/networks/nets/varautoencoder.py @@ -19,16 +19,25 @@ from monai.networks.layers.convutils import calculate_out_shape, same_padding from monai.networks.layers.factories import Act, Norm from monai.networks.nets import AutoEncoder +from monai.utils import deprecated_arg __all__ = ["VarAutoEncoder"] class VarAutoEncoder(AutoEncoder): - """Variational Autoencoder based on the paper - https://arxiv.org/abs/1312.6114""" + """ + Variational Autoencoder based on the paper - https://arxiv.org/abs/1312.6114 + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + """ + + @deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) def __init__( self, - dimensions: int, + spatial_dims: int, in_shape: Sequence[int], out_channels: int, latent_size: int, @@ -44,15 +53,18 @@ def __init__( norm: Union[Tuple, str] = Norm.INSTANCE, dropout: Optional[Union[Tuple, str, float]] = None, bias: bool = True, + dimensions: Optional[int] = None, ) -> None: self.in_channels, *self.in_shape = in_shape self.latent_size = latent_size self.final_size = np.asarray(self.in_shape, dtype=int) + if dimensions is not None: + spatial_dims = dimensions super().__init__( - dimensions, + spatial_dims, self.in_channels, out_channels, channels, diff --git a/monai/networks/nets/vnet.py b/monai/networks/nets/vnet.py index 72f3290a89..c7eea67e62 100644 --- a/monai/networks/nets/vnet.py +++ b/monai/networks/nets/vnet.py @@ -34,7 +34,7 @@ def __init__(self, spatial_dims: int, nchan: int, act: Union[Tuple[str, Dict], s self.act_function = get_acti_layer(act, nchan) self.conv_block = Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=nchan, out_channels=nchan, kernel_size=5, @@ -74,7 +74,7 @@ def __init__( self.in_channels = in_channels self.act_function = get_acti_layer(act, 16) self.conv_block = Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=in_channels, out_channels=16, kernel_size=5, @@ -180,7 +180,7 @@ def __init__( self.act_function1 = get_acti_layer(act, out_channels) self.conv_block = Convolution( - dimensions=spatial_dims, + spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels, kernel_size=5, diff --git a/monai/networks/utils.py b/monai/networks/utils.py index 9d20d2a83b..8ba32f1871 100644 --- a/monai/networks/utils.py +++ b/monai/networks/utils.py @@ -20,6 +20,8 @@ import torch import torch.nn as nn +from monai.utils.deprecated import deprecated_arg + __all__ = [ "one_hot", "slice_channels", @@ -225,9 +227,14 @@ def icnr_init(conv, upsample_factor, init=nn.init.kaiming_normal_): conv.weight.data.copy_(kernel) -def pixelshuffle(x: torch.Tensor, dimensions: int, scale_factor: int) -> torch.Tensor: +@deprecated_arg( + name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." +) +def pixelshuffle( + x: torch.Tensor, spatial_dims: int, scale_factor: int, dimensions: Optional[int] = None +) -> torch.Tensor: """ - Apply pixel shuffle to the tensor `x` with spatial dimensions `dimensions` and scaling factor `scale_factor`. + Apply pixel shuffle to the tensor `x` with spatial dimensions `spatial_dims` and scaling factor `scale_factor`. See: Shi et al., 2016, "Real-Time Single Image and Video Super-Resolution Using a nEfficient Sub-Pixel Convolutional Neural Network." @@ -236,17 +243,21 @@ def pixelshuffle(x: torch.Tensor, dimensions: int, scale_factor: int) -> torch.T Args: x: Input tensor - dimensions: number of spatial dimensions, typically 2 or 3 for 2D or 3D + spatial_dims: number of spatial dimensions, typically 2 or 3 for 2D or 3D scale_factor: factor to rescale the spatial dimensions by, must be >=1 + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + Returns: Reshuffled version of `x`. Raises: - ValueError: When input channels of `x` are not divisible by (scale_factor ** dimensions) + ValueError: When input channels of `x` are not divisible by (scale_factor ** spatial_dims) """ - - dim, factor = dimensions, scale_factor + if dimensions is not None: + spatial_dims = dimensions + dim, factor = spatial_dims, scale_factor input_size = list(x.size()) batch_size, channels = input_size[:2] scale_divisor = factor ** dim diff --git a/monai/optimizers/utils.py b/monai/optimizers/utils.py index c52ab07a04..08949912d7 100644 --- a/monai/optimizers/utils.py +++ b/monai/optimizers/utils.py @@ -47,7 +47,7 @@ def generate_param_groups( .. code-block:: python - net = Unet(dimensions=3, in_channels=1, out_channels=3, channels=[2, 2, 2], strides=[1, 1, 1]) + net = Unet(spatial_dims=3, in_channels=1, out_channels=3, channels=[2, 2, 2], strides=[1, 1, 1]) print(net) # print out network components to select expected items print(net.named_parameters()) # print out all the named parameters to filter out expected items params = generate_param_groups( diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 20d306be04..de0c89e7b0 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1318,7 +1318,7 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, # map back img = self.inv_shift_fourier(k, n_dims) - return img if self.as_tensor_output else img.cpu().detach().numpy() + return img if self.as_tensor_output else img.cpu().detach().numpy() # type: ignore def _apply_mask(self, k: torch.Tensor) -> torch.Tensor: """Builds and applies a mask on the spatial dimensions. @@ -1448,7 +1448,7 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, k = torch.exp(log_abs) * torch.exp(1j * phase) img = self.inv_shift_fourier(k, n_dims) - return img if self.as_tensor_output else img.cpu().detach().numpy() + return img if self.as_tensor_output else img.cpu().detach().numpy() # type: ignore def _check_indices(self, img) -> None: """Helper method to check consistency of self.loc and input image. diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 30aa5e7b99..9618723430 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -30,6 +30,7 @@ GridSampleMode, InterpolateMode, InverseKeys, + deprecated_arg, ensure_tuple, ensure_tuple_rep, ensure_tuple_size, @@ -1088,36 +1089,54 @@ class Fourier: """ @staticmethod - def shift_fourier(x: torch.Tensor, n_dims: int) -> torch.Tensor: + @deprecated_arg( + name="n_dims", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) + def shift_fourier(x: torch.Tensor, spatial_dims: int, n_dims: Optional[int] = None) -> torch.Tensor: """ Applies fourier transform and shifts the zero-frequency component to the center of the spectrum. Only the spatial dimensions get transformed. Args: x: Image to transform. - n_dims: Number of spatial dimensions. + spatial_dims: Number of spatial dimensions. + + .. deprecated:: 0.6.0 + ``n_dims`` is deprecated, use ``spatial_dims`` instead. + Returns k: K-space data. """ + if n_dims is not None: + spatial_dims = n_dims k: torch.Tensor = torch.fft.fftshift( - torch.fft.fftn(x, dim=tuple(range(-n_dims, 0))), dim=tuple(range(-n_dims, 0)) + torch.fft.fftn(x, dim=tuple(range(-spatial_dims, 0))), dim=tuple(range(-spatial_dims, 0)) ) return k @staticmethod - def inv_shift_fourier(k: torch.Tensor, n_dims: int) -> torch.Tensor: + @deprecated_arg( + name="n_dims", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." + ) + def inv_shift_fourier(k: torch.Tensor, spatial_dims: int, n_dims: Optional[int] = None) -> torch.Tensor: """ Applies inverse shift and fourier transform. Only the spatial dimensions are transformed. Args: k: K-space data. - n_dims: Number of spatial dimensions. + spatial_dims: Number of spatial dimensions. + + .. deprecated:: 0.6.0 + ``n_dims`` is deprecated, use ``spatial_dims`` instead. + Returns: x: Tensor in image space. """ + if n_dims is not None: + spatial_dims = n_dims x: torch.Tensor = torch.fft.ifftn( - torch.fft.ifftshift(k, dim=tuple(range(-n_dims, 0))), dim=tuple(range(-n_dims, 0)) + torch.fft.ifftshift(k, dim=tuple(range(-spatial_dims, 0))), dim=tuple(range(-spatial_dims, 0)) ).real return x diff --git a/monai/utils/deprecated.py b/monai/utils/deprecated.py index 3a4568b06c..c66b60996b 100644 --- a/monai/utils/deprecated.py +++ b/monai/utils/deprecated.py @@ -60,6 +60,9 @@ def deprecated( Decorated definition which warns or raises exception when used """ + # if version_val.startswith("0+"): + # # version unknown, set version_val to a large value (assuming the latest version) + # version_val = "100" if since is not None and removed is not None and not version_leq(since, removed): raise ValueError(f"since must be less or equal to removed, got since={since}, removed={removed}.") is_not_yet_deprecated = since is not None and version_val != since and version_leq(version_val, since) @@ -116,6 +119,7 @@ def deprecated_arg( removed: Optional[str] = None, msg_suffix: str = "", version_val: str = __version__, + new_name: Optional[str] = None, ): """ Marks a particular named argument of a callable as deprecated. The same conditions for `since` and `removed` as @@ -130,6 +134,8 @@ def deprecated_arg( using the Sphinx directives such as `.. versionchanged:: version` and `.. deprecated:: version`. https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-versionadded + In the current implementation type annotations are not preserved. + Args: name: name of position or keyword argument to mark as deprecated. @@ -137,17 +143,21 @@ def deprecated_arg( removed: version at which the argument was removed and no longer usable. msg_suffix: message appended to warning/exception detailing reasons for deprecation and what to use instead. version_val: (used for testing) version to compare since and removed against, default is MONAI version. + new_name: name of position or keyword argument to replace the deprecated argument. Returns: - Decorated callable which warns or raises exception when deprecated argument used + Decorated callable which warns or raises exception when deprecated argument used. """ + + if version_val.startswith("0+") or not f"{version_val}".strip()[0].isdigit(): + # version unknown, set version_val to a large value (assuming the latest version) + version_val = "100" if since is not None and removed is not None and not version_leq(since, removed): raise ValueError(f"since must be less or equal to removed, got since={since}, removed={removed}.") is_not_yet_deprecated = since is not None and version_val != since and version_leq(version_val, since) if is_not_yet_deprecated: # smaller than `since`, do nothing return lambda obj: obj - if since is None and removed is None: # raise a DeprecatedError directly is_removed = True @@ -157,9 +167,6 @@ def deprecated_arg( is_deprecated = since is not None and version_leq(since, version_val) is_removed = removed is not None and version_leq(removed, version_val) - if is_not_yet_deprecated: - return lambda obj: obj - def _decorator(func): argname = f"{func.__name__}_{name}" @@ -180,6 +187,9 @@ def _decorator(func): @wraps(func) def _wrapper(*args, **kwargs): + if new_name is not None and name in kwargs: + # replace the deprecated arg "name" with "new_name" + kwargs[new_name] = kwargs[name] binding = sig.bind(*args, **kwargs).arguments positional_found = name in binding diff --git a/tests/test_autoencoder.py b/tests/test_autoencoder.py index 54d6832c8d..d67964f034 100644 --- a/tests/test_autoencoder.py +++ b/tests/test_autoencoder.py @@ -92,7 +92,7 @@ def test_shape(self, input_param, input_shape, expected_shape): self.assertEqual(result.shape, expected_shape) def test_script(self): - net = AutoEncoder(dimensions=2, in_channels=1, out_channels=1, channels=(4, 8), strides=(2, 2)) + net = AutoEncoder(spatial_dims=2, in_channels=1, out_channels=1, channels=(4, 8), strides=(2, 2)) test_data = torch.randn(2, 1, 32, 32) test_script_save(net, test_data) diff --git a/tests/test_basic_unet.py b/tests/test_basic_unet.py index 09d7f72d0e..1e553b363b 100644 --- a/tests/test_basic_unet.py +++ b/tests/test_basic_unet.py @@ -101,7 +101,7 @@ def test_shape(self, input_param, input_shape, expected_shape): self.assertEqual(result.shape, expected_shape) def test_script(self): - net = BasicUNet(dimensions=2, in_channels=1, out_channels=3) + net = BasicUNet(spatial_dims=2, in_channels=1, out_channels=3) test_data = torch.randn(16, 1, 32, 32) test_script_save(net, test_data) diff --git a/tests/test_deprecated.py b/tests/test_deprecated.py index 429d5ee767..04f8173282 100644 --- a/tests/test_deprecated.py +++ b/tests/test_deprecated.py @@ -222,3 +222,31 @@ def future1(): warnings.warn("fake warning", DeprecationWarning) self.assertEqual(aw.warning.args[0], "fake warning") + + def test_arg_except2_unknown(self): + """ + Test deprecated_arg decorator raises exception with `removed` set in the past. + with unknown version + """ + + @deprecated_arg("b", removed=self.prev_version, version_val="0+untagged.1.g3131155") + def afoo4(a, b=None): + pass + + self.assertRaises(DeprecatedError, lambda: afoo4(1, b=2)) + + def test_replacement_arg(self): + """ + Test deprecated arg being replaced. + """ + + @deprecated_arg("b", new_name="a", since=self.prev_version, version_val=self.test_version) + def afoo4(a, b=None): + return a + + self.assertEqual(afoo4(b=2), 2) + # self.assertRaises(DeprecatedError, lambda: afoo4(1, b=2)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_integration_determinism.py b/tests/test_integration_determinism.py index e077420420..7725990763 100644 --- a/tests/test_integration_determinism.py +++ b/tests/test_integration_determinism.py @@ -41,7 +41,7 @@ def __len__(self): return train_steps net = UNet( - dimensions=2, in_channels=1, out_channels=1, channels=(4, 8, 16, 32), strides=(2, 2, 2), num_res_units=2 + spatial_dims=2, in_channels=1, out_channels=1, channels=(4, 8, 16, 32), strides=(2, 2, 2), num_res_units=2 ).to(device) loss = DiceLoss(sigmoid=True) diff --git a/tests/test_integration_segmentation_3d.py b/tests/test_integration_segmentation_3d.py index d5eb69f7af..215a5b3f9a 100644 --- a/tests/test_integration_segmentation_3d.py +++ b/tests/test_integration_segmentation_3d.py @@ -100,7 +100,7 @@ def run_training_test(root_dir, device="cuda:0", cachedataset=0, readers=(None, # create UNet, DiceLoss and Adam optimizer model = monai.networks.nets.UNet( - dimensions=3, + spatial_dims=3, in_channels=1, out_channels=1, channels=(16, 32, 64, 128, 256), @@ -199,7 +199,7 @@ def run_inference_test(root_dir, device="cuda:0"): dice_metric = DiceMetric(include_background=True, reduction="mean", get_not_nans=False) model = UNet( - dimensions=3, + spatial_dims=3, in_channels=1, out_channels=1, channels=(16, 32, 64, 128, 256), diff --git a/tests/test_integration_sliding_window.py b/tests/test_integration_sliding_window.py index b63f331ba6..0522bf080e 100644 --- a/tests/test_integration_sliding_window.py +++ b/tests/test_integration_sliding_window.py @@ -34,7 +34,7 @@ def run_test(batch_size, img_name, seg_name, output_dir, device="cuda:0"): loader = DataLoader(ds, batch_size=1, pin_memory=torch.cuda.is_available()) net = UNet( - dimensions=3, in_channels=1, out_channels=1, channels=(4, 8, 16, 32), strides=(2, 2, 2), num_res_units=2 + spatial_dims=3, in_channels=1, out_channels=1, channels=(4, 8, 16, 32), strides=(2, 2, 2), num_res_units=2 ).to(device) roi_size = (16, 32, 48) sw_batch_size = batch_size diff --git a/tests/test_integration_unet_2d.py b/tests/test_integration_unet_2d.py index a46a174dc9..88e6d7e795 100644 --- a/tests/test_integration_unet_2d.py +++ b/tests/test_integration_unet_2d.py @@ -32,10 +32,10 @@ def __len__(self): return train_steps if net_name == "basicunet": - net = BasicUNet(dimensions=2, in_channels=1, out_channels=1, features=(4, 8, 8, 16, 16, 32)) + net = BasicUNet(spatial_dims=2, in_channels=1, out_channels=1, features=(4, 8, 8, 16, 16, 32)) elif net_name == "unet": net = UNet( - dimensions=2, in_channels=1, out_channels=1, channels=(4, 8, 16, 32), strides=(2, 2, 2), num_res_units=2 + spatial_dims=2, in_channels=1, out_channels=1, channels=(4, 8, 16, 32), strides=(2, 2, 2), num_res_units=2 ) net.to(device) diff --git a/tests/test_integration_workflows.py b/tests/test_integration_workflows.py index 7fcc0b4064..4a3e027993 100644 --- a/tests/test_integration_workflows.py +++ b/tests/test_integration_workflows.py @@ -98,7 +98,7 @@ def run_training_test(root_dir, device="cuda:0", amp=False, num_workers=4): # create UNet, DiceLoss and Adam optimizer net = monai.networks.nets.UNet( - dimensions=3, + spatial_dims=3, in_channels=1, out_channels=1, channels=(16, 32, 64, 128, 256), @@ -230,7 +230,7 @@ def run_inference_test(root_dir, model_file, device="cuda:0", amp=False, num_wor # create UNet, DiceLoss and Adam optimizer net = monai.networks.nets.UNet( - dimensions=3, + spatial_dims=3, in_channels=1, out_channels=1, channels=(16, 32, 64, 128, 256), diff --git a/tests/test_inverse.py b/tests/test_inverse.py index f2470d47fd..9535a40c05 100644 --- a/tests/test_inverse.py +++ b/tests/test_inverse.py @@ -666,7 +666,7 @@ def test_inverse_inferred_seg(self, extra_transform): device = "cuda" if torch.cuda.is_available() else "cpu" model = UNet( - dimensions=2, + spatial_dims=2, in_channels=1, out_channels=1, channels=(2, 4), diff --git a/tests/test_unet.py b/tests/test_unet.py index 4091c4e9d7..94077dad14 100644 --- a/tests/test_unet.py +++ b/tests/test_unet.py @@ -170,13 +170,15 @@ def test_shape(self, input_param, input_shape, expected_shape): self.assertEqual(result.shape, expected_shape) def test_script(self): - net = UNet(dimensions=2, in_channels=1, out_channels=3, channels=(16, 32, 64), strides=(2, 2), num_res_units=0) + net = UNet( + spatial_dims=2, in_channels=1, out_channels=3, channels=(16, 32, 64), strides=(2, 2), num_res_units=0 + ) test_data = torch.randn(16, 1, 32, 32) test_script_save(net, test_data) def test_script_without_running_stats(self): net = UNet( - dimensions=2, + spatial_dims=2, in_channels=1, out_channels=3, channels=(16, 32, 64), @@ -189,7 +191,7 @@ def test_script_without_running_stats(self): def test_ill_input_shape(self): net = UNet( - dimensions=2, + spatial_dims=2, in_channels=1, out_channels=3, channels=(16, 32, 64), From 7f3050a8199634bd097c04afcd04be9fdd39426b Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Thu, 9 Sep 2021 00:16:01 +0800 Subject: [PATCH 02/89] 2898 Merge LocalPatchShuffle with RandCoarseDropout (#2907) * [DLMED] merge LocalPatchShuffle Signed-off-by: Nic Ma * [DLMED] enhance doc-string Signed-off-by: Nic Ma --- docs/source/transforms.rst | 18 +- monai/transforms/__init__.py | 3 +- monai/transforms/intensity/array.py | 246 +++++++++--------- ...shuffle.py => test_rand_coarse_shuffle.py} | 29 ++- 4 files changed, 151 insertions(+), 145 deletions(-) rename tests/{test_rand_local_patch_shuffle.py => test_rand_coarse_shuffle.py} (59%) diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index b8f57e0dbe..d1083a641b 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -308,24 +308,30 @@ Intensity :members: :special-members: __call__ +`RandCoarseTransform` +""""""""""""""""""""" + .. autoclass:: RandCoarseTransform + :members: + :special-members: __call__ + `RandCoarseDropout` """"""""""""""""""" .. autoclass:: RandCoarseDropout :members: :special-members: __call__ +`RandCoarseShuffle` +""""""""""""""""""" + .. autoclass:: RandCoarseShuffle + :members: + :special-members: __call__ + `HistogramNormalize` """""""""""""""""""" .. autoclass:: HistogramNormalize :members: :special-members: __call__ -`LocalPatchShuffling` -""""""""""""""""""""" -.. autoclass:: LocalPatchShuffling - :members: - :special-members: __call__ - IO ^^ diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index 2ea7e3aa63..b9ba303ed7 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -85,12 +85,13 @@ GibbsNoise, HistogramNormalize, KSpaceSpikeNoise, - LocalPatchShuffling, MaskIntensity, NormalizeIntensity, RandAdjustContrast, RandBiasField, RandCoarseDropout, + RandCoarseShuffle, + RandCoarseTransform, RandGaussianNoise, RandGaussianSharpen, RandGaussianSmooth, diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index de0c89e7b0..d10c3017a3 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -13,7 +13,7 @@ https://github.com/Project-MONAI/MONAI/wiki/MONAI_Design """ -import copy +from abc import abstractmethod from collections.abc import Iterable from functools import partial from typing import Any, Callable, List, Optional, Sequence, Tuple, Union @@ -69,9 +69,10 @@ "RandGibbsNoise", "KSpaceSpikeNoise", "RandKSpaceSpikeNoise", + "RandCoarseTransform", "RandCoarseDropout", + "RandCoarseShuffle", "HistogramNormalize", - "LocalPatchShuffling", ] @@ -1630,13 +1631,11 @@ def _set_default_range(self, img: torch.Tensor) -> Sequence[Sequence[float]]: return tuple((i * 0.95, i * 1.1) for i in shifted_means) -class RandCoarseDropout(RandomizableTransform): +class RandCoarseTransform(RandomizableTransform): """ - Randomly coarse dropout regions in the image, then fill in the rectangular regions with specified value. - Or keep the rectangular regions and fill in the other areas with specified value. - Refer to papers: https://arxiv.org/abs/1708.04552, https://arxiv.org/pdf/1604.07379 - And other implementation: https://albumentations.ai/docs/api_reference/augmentations/transforms/ - #albumentations.augmentations.transforms.CoarseDropout. + Randomly select coarse regions in the image, then execute transform operations for the regions. + It's the base class of all kinds of region transforms. + Refer to papers: https://arxiv.org/abs/1708.04552 Args: holes: number of regions to dropout, if `max_holes` is not None, use this arg as the minimum number to @@ -1646,12 +1645,6 @@ class RandCoarseDropout(RandomizableTransform): if some components of the `spatial_size` are non-positive values, the transform will use the corresponding components of input img size. For example, `spatial_size=(32, -1)` will be adapted to `(32, 64)` if the second spatial dimension size of img is `64`. - dropout_holes: if `True`, dropout the regions of holes and fill value, if `False`, keep the holes and - dropout the outside and fill value. default to `True`. - fill_value: target value to fill the dropout regions, if providing a number, will use it as constant - value to fill all the regions. if providing a tuple for the `min` and `max`, will randomly select - value for every pixel / voxel from the range `[min, max)`. if None, will compute the `min` and `max` - value of input image then randomly select value to fill, default to None. max_holes: if not None, define the maximum number to randomly select the expected number of regions. max_spatial_size: if not None, define the maximum spatial size to randomly select size for every region. if some components of the `max_spatial_size` are non-positive values, the transform will use the @@ -1665,8 +1658,6 @@ def __init__( self, holes: int, spatial_size: Union[Sequence[int], int], - dropout_holes: bool = True, - fill_value: Optional[Union[Tuple[float, float], float]] = None, max_holes: Optional[int] = None, max_spatial_size: Optional[Union[Sequence[int], int]] = None, prob: float = 0.1, @@ -1676,11 +1667,6 @@ def __init__( raise ValueError("number of holes must be greater than 0.") self.holes = holes self.spatial_size = spatial_size - self.dropout_holes = dropout_holes - if isinstance(fill_value, (tuple, list)): - if len(fill_value) != 2: - raise ValueError("fill value should contain 2 numbers if providing the `min` and `max`.") - self.fill_value = fill_value self.max_holes = max_holes self.max_spatial_size = max_spatial_size self.hole_coords: List = [] @@ -1697,28 +1683,126 @@ def randomize(self, img_size: Sequence[int]) -> None: valid_size = get_valid_patch_size(img_size, size) self.hole_coords.append((slice(None),) + get_random_patch(img_size, valid_size, self.R)) + @abstractmethod + def _transform_holes(self, img: np.ndarray) -> np.ndarray: + """ + Transform the randomly selected `self.hole_coords` in input images. + + """ + raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.") + def __call__(self, img: np.ndarray): self.randomize(img.shape[1:]) - ret = img if self._do_transform: - fill_value = (img.min(), img.max()) if self.fill_value is None else self.fill_value - - if self.dropout_holes: - for h in self.hole_coords: - if isinstance(fill_value, (tuple, list)): - ret[h] = self.R.uniform(fill_value[0], fill_value[1], size=img[h].shape) - else: - ret[h] = fill_value - else: + img = self._transform_holes(img=img) + + return img + + +class RandCoarseDropout(RandCoarseTransform): + """ + Randomly coarse dropout regions in the image, then fill in the rectangular regions with specified value. + Or keep the rectangular regions and fill in the other areas with specified value. + Refer to papers: https://arxiv.org/abs/1708.04552, https://arxiv.org/pdf/1604.07379 + And other implementation: https://albumentations.ai/docs/api_reference/augmentations/transforms/ + #albumentations.augmentations.transforms.CoarseDropout. + + Args: + holes: number of regions to dropout, if `max_holes` is not None, use this arg as the minimum number to + randomly select the expected number of regions. + spatial_size: spatial size of the regions to dropout, if `max_spatial_size` is not None, use this arg + as the minimum spatial size to randomly select size for every region. + if some components of the `spatial_size` are non-positive values, the transform will use the + corresponding components of input img size. For example, `spatial_size=(32, -1)` will be adapted + to `(32, 64)` if the second spatial dimension size of img is `64`. + dropout_holes: if `True`, dropout the regions of holes and fill value, if `False`, keep the holes and + dropout the outside and fill value. default to `True`. + fill_value: target value to fill the dropout regions, if providing a number, will use it as constant + value to fill all the regions. if providing a tuple for the `min` and `max`, will randomly select + value for every pixel / voxel from the range `[min, max)`. if None, will compute the `min` and `max` + value of input image then randomly select value to fill, default to None. + max_holes: if not None, define the maximum number to randomly select the expected number of regions. + max_spatial_size: if not None, define the maximum spatial size to randomly select size for every region. + if some components of the `max_spatial_size` are non-positive values, the transform will use the + corresponding components of input img size. For example, `max_spatial_size=(32, -1)` will be adapted + to `(32, 64)` if the second spatial dimension size of img is `64`. + prob: probability of applying the transform. + + """ + + def __init__( + self, + holes: int, + spatial_size: Union[Sequence[int], int], + dropout_holes: bool = True, + fill_value: Optional[Union[Tuple[float, float], float]] = None, + max_holes: Optional[int] = None, + max_spatial_size: Optional[Union[Sequence[int], int]] = None, + prob: float = 0.1, + ) -> None: + super().__init__( + holes=holes, + spatial_size=spatial_size, + max_holes=max_holes, + max_spatial_size=max_spatial_size, + prob=prob, + ) + self.dropout_holes = dropout_holes + if isinstance(fill_value, (tuple, list)): + if len(fill_value) != 2: + raise ValueError("fill value should contain 2 numbers if providing the `min` and `max`.") + self.fill_value = fill_value + + def _transform_holes(self, img: np.ndarray): + """ + Fill the randomly selected `self.hole_coords` in input images. + Please note that we usually only use `self.R` in `randomize()` method, here is a special case. + + """ + fill_value = (img.min(), img.max()) if self.fill_value is None else self.fill_value + + if self.dropout_holes: + for h in self.hole_coords: if isinstance(fill_value, (tuple, list)): - ret = self.R.uniform(fill_value[0], fill_value[1], size=img.shape).astype(img.dtype) + img[h] = self.R.uniform(fill_value[0], fill_value[1], size=img[h].shape) else: - ret = np.full_like(img, fill_value) - for h in self.hole_coords: - ret[h] = img[h] + img[h] = fill_value + ret = img + else: + if isinstance(fill_value, (tuple, list)): + ret = self.R.uniform(fill_value[0], fill_value[1], size=img.shape).astype(img.dtype) + else: + ret = np.full_like(img, fill_value) + for h in self.hole_coords: + ret[h] = img[h] return ret +class RandCoarseShuffle(RandCoarseTransform): + """ + Randomly select regions in the image, then shuffle the pixels within every region. + It shuffles every channel separately. + Refer to paper: + Kang, Guoliang, et al. "Patchshuffle regularization." arXiv preprint arXiv:1707.07103 (2017). + https://arxiv.org/abs/1707.07103 + + """ + + def _transform_holes(self, img: np.ndarray): + """ + Shuffle the content of randomly selected `self.hole_coords` in input images. + Please note that we usually only use `self.R` in `randomize()` method, here is a special case. + + """ + for h in self.hole_coords: + # shuffle every channel separately + for i, c in enumerate(img[h]): + patch_channel = c.flatten() + self.R.shuffle(patch_channel) + img[h][i] = patch_channel.reshape(c.shape) + return img + + class HistogramNormalize(Transform): """ Apply the histogram normalization to input image. @@ -1759,95 +1843,3 @@ def __call__(self, img: np.ndarray, mask: Optional[np.ndarray] = None) -> np.nda max=self.max, dtype=self.dtype, ) - - -class LocalPatchShuffling(RandomizableTransform): - """ - Takes a 3D image and based on input of the local patch size, shuffles the pixels of the local patch within it. - This process is repeated a for N number of times where every time a different random block is selected for local - pixel shuffling. - - Kang, Guoliang, et al. "Patchshuffle regularization." arXiv preprint arXiv:1707.07103 (2017). - """ - - def __init__( - self, - prob: float = 1.0, - number_blocks: int = 1000, - blocksize_ratio: int = 10, - channel_wise: bool = True, - device: Optional[torch.device] = None, - image_only: bool = False, - ) -> None: - """ - Args: - prob: The chance of this transform occuring on the given volume. - number_blocks: Total number of time a random 3D block will be selected for local shuffling of pixels/voxels - contained in the block. - blocksize_ratio: This ratio can be used to estimate the local 3D block sizes that will be selected. - channel_wise: If True, treats each channel of the image separately. - device: device on which the tensor will be allocated. - image_only: if True return only the image volume, otherwise return (image, affine). - """ - RandomizableTransform.__init__(self, prob) - self.prob = prob - self.number_blocks = number_blocks - self.blocksize_ratio = blocksize_ratio - self.channel_wise = channel_wise - - def _local_patch_shuffle(self, img: Union[torch.Tensor, np.ndarray], number_blocks: int, blocksize_ratio: int): - im_shape = img.shape - img_copy = copy.deepcopy(img) - for _each_block in range(number_blocks): - - block_size_x = self.R.randint(1, im_shape[0] // blocksize_ratio) - block_size_y = self.R.randint(1, im_shape[1] // blocksize_ratio) - block_size_z = self.R.randint(1, im_shape[2] // blocksize_ratio) - - noise_x = self.R.randint(0, im_shape[0] - block_size_x) - noise_y = self.R.randint(0, im_shape[1] - block_size_y) - noise_z = self.R.randint(0, im_shape[2] - block_size_z) - - local_patch = img[ - noise_x : noise_x + block_size_x, - noise_y : noise_y + block_size_y, - noise_z : noise_z + block_size_z, - ] - - local_patch = local_patch.flatten() - self.R.shuffle(local_patch) - local_patch = local_patch.reshape((block_size_x, block_size_y, block_size_z)) - - img_copy[ - noise_x : noise_x + block_size_x, noise_y : noise_y + block_size_y, noise_z : noise_z + block_size_z - ] = local_patch - - shuffled_image = img_copy - return shuffled_image - - def __call__( - self, - img: Union[np.ndarray, torch.Tensor], - # spatial_size: Optional[Union[Sequence[int], int]] = None, - # mode: Optional[Union[GridSampleMode, str]] = None, - # padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ): - """ - Args: - img: shape must be (num_channels, H, W[, D]), - - """ - - super().randomize(None) - if not self._do_transform: - return img - - if self.channel_wise: - # img = self._local_patch_shuffle(img=img) - for i, _d in enumerate(img): - img[i] = self._local_patch_shuffle( - img=img[i], blocksize_ratio=self.blocksize_ratio, number_blocks=self.number_blocks - ) - else: - raise AssertionError("If channel_wise is False, the image needs to be set to channel first") - return img diff --git a/tests/test_rand_local_patch_shuffle.py b/tests/test_rand_coarse_shuffle.py similarity index 59% rename from tests/test_rand_local_patch_shuffle.py rename to tests/test_rand_coarse_shuffle.py index 8e2eefb5d1..97d492fd24 100644 --- a/tests/test_rand_local_patch_shuffle.py +++ b/tests/test_rand_coarse_shuffle.py @@ -14,32 +14,39 @@ import numpy as np from parameterized import parameterized -from monai.transforms import LocalPatchShuffling +from monai.transforms import RandCoarseShuffle TEST_CASES = [ [ - {"number_blocks": 10, "blocksize_ratio": 1, "prob": 0.0}, + {"holes": 5, "spatial_size": 1, "max_spatial_size": -1, "prob": 0.0}, {"img": np.arange(8).reshape((1, 2, 2, 2))}, np.arange(8).reshape((1, 2, 2, 2)), ], [ - {"number_blocks": 10, "blocksize_ratio": 1, "prob": 1.0}, + {"holes": 10, "spatial_size": 1, "max_spatial_size": -1, "prob": 1.0}, {"img": np.arange(27).reshape((1, 3, 3, 3))}, - [ + np.asarray( [ - [[9, 1, 2], [3, 4, 5], [6, 7, 8]], - [[0, 10, 11], [12, 4, 14], [15, 16, 17]], - [[18, 19, 20], [21, 22, 23], [24, 25, 26]], - ] - ], + [ + [[8, 19, 26], [24, 6, 15], [0, 13, 25]], + [[17, 3, 5], [10, 1, 12], [22, 4, 11]], + [[21, 20, 23], [14, 2, 16], [18, 9, 7]], + ], + ], + ), + ], + [ + {"holes": 2, "spatial_size": 1, "max_spatial_size": -1, "prob": 1.0}, + {"img": np.arange(16).reshape((2, 2, 2, 2))}, + np.asarray([[[[6, 1], [4, 3]], [[0, 2], [7, 5]]], [[[14, 10], [9, 8]], [[12, 15], [13, 11]]]]), ], ] -class TestLocalPatchShuffle(unittest.TestCase): +class TestRandCoarseShuffle(unittest.TestCase): @parameterized.expand(TEST_CASES) def test_local_patch_shuffle(self, input_param, input_data, expected_val): - g = LocalPatchShuffling(**input_param) + g = RandCoarseShuffle(**input_param) g.set_random_state(seed=12) result = g(**input_data) np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) From e52a0fe49437fcd56fba680487598850df08e427 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Thu, 9 Sep 2021 14:32:26 +0100 Subject: [PATCH 03/89] Torch Zoom (#2916) Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/spatial/array.py | 77 +++++++++++++---------- monai/transforms/spatial/dictionary.py | 16 +++-- tests/test_rand_zoom.py | 86 +++++++++++++------------- tests/test_rand_zoomd.py | 40 ++++++------ tests/test_zoom.py | 55 ++++++++-------- tests/test_zoomd.py | 39 ++++++------ 6 files changed, 169 insertions(+), 144 deletions(-) diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index c3bd4a3433..5979b996ee 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -22,7 +22,7 @@ from monai.config.type_definitions import NdarrayOrTensor from monai.data.utils import compute_shape_offset, to_affine_nd, zoom_affine from monai.networks.layers import AffineTransform, GaussianFilter, grid_pull -from monai.transforms.croppad.array import CenterSpatialCrop +from monai.transforms.croppad.array import CenterSpatialCrop, Pad from monai.transforms.transform import Randomizable, RandomizableTransform, ThreadUnsafe, Transform from monai.transforms.utils import ( create_control_grid, @@ -47,6 +47,7 @@ ) from monai.utils.enums import TransformBackends from monai.utils.module import look_up_option +from monai.utils.type_conversion import convert_data_type nib, _ = optional_import("nibabel") @@ -555,6 +556,8 @@ class Zoom(Transform): """ + backend = [TransformBackends.TORCH] + def __init__( self, zoom: Union[Sequence[float], float], @@ -573,11 +576,11 @@ def __init__( def __call__( self, - img: np.ndarray, + img: NdarrayOrTensor, mode: Optional[Union[InterpolateMode, str]] = None, padding_mode: Optional[Union[NumpyPadMode, str]] = None, align_corners: Optional[bool] = None, - ): + ) -> torch.Tensor: """ Args: img: channel first array, must have shape: (num_channels, H[, W, ..., ]). @@ -593,31 +596,37 @@ def __call__( See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate """ + img_t: torch.Tensor + img_t, *_ = convert_data_type(img, torch.Tensor, dtype=torch.float32) # type: ignore + _zoom = ensure_tuple_rep(self.zoom, img.ndim - 1) # match the spatial image dim - zoomed = torch.nn.functional.interpolate( # type: ignore + zoomed: torch.Tensor = torch.nn.functional.interpolate( # type: ignore recompute_scale_factor=True, - input=torch.as_tensor(np.ascontiguousarray(img), dtype=torch.float).unsqueeze(0), + input=img_t.unsqueeze(0), scale_factor=list(_zoom), mode=look_up_option(self.mode if mode is None else mode, InterpolateMode).value, align_corners=self.align_corners if align_corners is None else align_corners, ) - zoomed = zoomed.squeeze(0).detach().cpu().numpy() - if not self.keep_size or np.allclose(img.shape, zoomed.shape): - return zoomed + zoomed = zoomed.squeeze(0) + + if self.keep_size and not np.allclose(img_t.shape, zoomed.shape): - pad_vec = [[0, 0]] * len(img.shape) - slice_vec = [slice(None)] * len(img.shape) - for idx, (od, zd) in enumerate(zip(img.shape, zoomed.shape)): - diff = od - zd - half = abs(diff) // 2 - if diff > 0: # need padding - pad_vec[idx] = [half, diff - half] - elif diff < 0: # need slicing - slice_vec[idx] = slice(half, half + od) + pad_vec = [(0, 0)] * len(img_t.shape) + slice_vec = [slice(None)] * len(img_t.shape) + for idx, (od, zd) in enumerate(zip(img_t.shape, zoomed.shape)): + diff = od - zd + half = abs(diff) // 2 + if diff > 0: # need padding + pad_vec[idx] = (half, diff - half) + elif diff < 0: # need slicing + slice_vec[idx] = slice(half, half + od) - padding_mode = look_up_option(self.padding_mode if padding_mode is None else padding_mode, NumpyPadMode) - zoomed = np.pad(zoomed, pad_vec, mode=padding_mode.value, **self.np_kwargs) # type: ignore - return zoomed[tuple(slice_vec)] + padding_mode = look_up_option(padding_mode or self.padding_mode, NumpyPadMode) + padder = Pad(pad_vec, padding_mode) + zoomed = padder(zoomed) + zoomed = zoomed[tuple(slice_vec)] + + return zoomed class Rotate90(Transform): @@ -886,6 +895,8 @@ class RandZoom(RandomizableTransform): """ + backend = Zoom.backend + def __init__( self, prob: float = 0.1, @@ -916,11 +927,11 @@ def randomize(self, data: Optional[Any] = None) -> None: def __call__( self, - img: np.ndarray, + img: NdarrayOrTensor, mode: Optional[Union[InterpolateMode, str]] = None, padding_mode: Optional[Union[NumpyPadMode, str]] = None, align_corners: Optional[bool] = None, - ) -> np.ndarray: + ) -> torch.Tensor: """ Args: img: channel first array, must have shape 2D: (nchannels, H, W), or 3D: (nchannels, H, W, D). @@ -937,25 +948,25 @@ def __call__( """ # match the spatial image dim self.randomize() - _dtype = np.float32 if not self._do_transform: - return img.astype(_dtype) + img_t: torch.Tensor + img_t, *_ = convert_data_type(img, dtype=torch.float32) # type: ignore + return img_t if len(self._zoom) == 1: # to keep the spatial shape ratio, use same random zoom factor for all dims self._zoom = ensure_tuple_rep(self._zoom[0], img.ndim - 1) elif len(self._zoom) == 2 and img.ndim > 3: # if 2 zoom factors provided for 3D data, use the first factor for H and W dims, second factor for D dim self._zoom = ensure_tuple_rep(self._zoom[0], img.ndim - 2) + ensure_tuple(self._zoom[-1]) - zoomer = Zoom(self._zoom, keep_size=self.keep_size, **self.np_kwargs) - return np.asarray( - zoomer( - img, - mode=look_up_option(mode or self.mode, InterpolateMode), - padding_mode=look_up_option(padding_mode or self.padding_mode, NumpyPadMode), - align_corners=self.align_corners if align_corners is None else align_corners, - ), - dtype=_dtype, + zoomer = Zoom( + self._zoom, + keep_size=self.keep_size, + mode=look_up_option(mode or self.mode, InterpolateMode), + padding_mode=look_up_option(padding_mode or self.padding_mode, NumpyPadMode), + align_corners=align_corners or self.align_corners, + **self.np_kwargs, ) + return zoomer(img) class AffineGrid(Transform): diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index b0558a6556..22dafb3f80 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -1537,6 +1537,8 @@ class Zoomd(MapTransform, InvertibleTransform): """ + backend = Zoom.backend + def __init__( self, keys: KeysCollection, @@ -1554,7 +1556,7 @@ def __init__( self.align_corners = ensure_tuple_rep(align_corners, len(self.keys)) self.zoomer = Zoom(zoom=zoom, keep_size=keep_size, **np_kwargs) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, mode, padding_mode, align_corners in self.key_iterator( d, self.mode, self.padding_mode, self.align_corners @@ -1576,7 +1578,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda ) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -1594,7 +1596,7 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar align_corners=None if align_corners == "none" else align_corners, ) # Size might be out by 1 voxel so pad - d[key] = SpatialPad(transform[InverseKeys.ORIG_SIZE], mode="edge")(d[key]) + d[key] = SpatialPad(transform[InverseKeys.ORIG_SIZE], mode="edge")(d[key]) # type: ignore # Remove the applied transform self.pop_transform(d, key) @@ -1637,6 +1639,8 @@ class RandZoomd(RandomizableTransform, MapTransform, InvertibleTransform): """ + backend = Zoom.backend + def __init__( self, keys: KeysCollection, @@ -1669,7 +1673,7 @@ def randomize(self, data: Optional[Any] = None) -> None: super().randomize(None) self._zoom = [self.R.uniform(l, h) for l, h in zip(self.min_zoom, self.max_zoom)] - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: # match the spatial dim of first item self.randomize() d = dict(data) @@ -1704,7 +1708,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda ) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -1724,7 +1728,7 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar align_corners=None if align_corners == "none" else align_corners, ) # Size might be out by 1 voxel so pad - d[key] = SpatialPad(transform[InverseKeys.ORIG_SIZE], mode="edge")(d[key]) + d[key] = SpatialPad(transform[InverseKeys.ORIG_SIZE], mode="edge")(d[key]) # type: ignore # Remove the applied transform self.pop_transform(d, key) diff --git a/tests/test_rand_zoom.py b/tests/test_rand_zoom.py index c21bc8b9e9..0ac1b92c39 100644 --- a/tests/test_rand_zoom.py +++ b/tests/test_rand_zoom.py @@ -17,7 +17,7 @@ from monai.transforms import RandZoom from monai.utils import GridSampleMode, InterpolateMode -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose VALID_CASES = [(0.8, 1.2, "nearest", False), (0.8, 1.2, InterpolateMode.NEAREST, False)] @@ -25,36 +25,32 @@ class TestRandZoom(NumpyImageTestCase2D): @parameterized.expand(VALID_CASES) def test_correct_results(self, min_zoom, max_zoom, mode, keep_size): - random_zoom = RandZoom( - prob=1.0, - min_zoom=min_zoom, - max_zoom=max_zoom, - mode=mode, - keep_size=keep_size, - ) - random_zoom.set_random_state(1234) - zoomed = random_zoom(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False)) - expected = np.stack(expected).astype(np.float32) - np.testing.assert_allclose(zoomed, expected, atol=1.0) + for p in TEST_NDARRAYS: + random_zoom = RandZoom( + prob=1.0, + min_zoom=min_zoom, + max_zoom=max_zoom, + mode=mode, + keep_size=keep_size, + ) + random_zoom.set_random_state(1234) + zoomed = random_zoom(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False)) + expected = np.stack(expected).astype(np.float32) + assert_allclose(zoomed, expected, atol=1.0) def test_keep_size(self): - random_zoom = RandZoom( - prob=1.0, - min_zoom=0.6, - max_zoom=0.7, - keep_size=True, - padding_mode="constant", - constant_values=2, - ) - zoomed = random_zoom(self.imt[0]) - self.assertTrue(np.array_equal(zoomed.shape, self.imt.shape[1:])) - zoomed = random_zoom(self.imt[0]) - self.assertTrue(np.array_equal(zoomed.shape, self.imt.shape[1:])) - zoomed = random_zoom(self.imt[0]) - self.assertTrue(np.array_equal(zoomed.shape, self.imt.shape[1:])) + for p in TEST_NDARRAYS: + im = p(self.imt[0]) + random_zoom = RandZoom(prob=1.0, min_zoom=0.6, max_zoom=0.7, keep_size=True) + zoomed = random_zoom(im) + self.assertTrue(np.array_equal(zoomed.shape, self.imt.shape[1:])) + zoomed = random_zoom(im) + self.assertTrue(np.array_equal(zoomed.shape, self.imt.shape[1:])) + zoomed = random_zoom(im) + self.assertTrue(np.array_equal(zoomed.shape, self.imt.shape[1:])) @parameterized.expand( [ @@ -64,23 +60,25 @@ def test_keep_size(self): ] ) def test_invalid_inputs(self, _, min_zoom, max_zoom, mode, raises): - with self.assertRaises(raises): - random_zoom = RandZoom(prob=1.0, min_zoom=min_zoom, max_zoom=max_zoom, mode=mode) - random_zoom(self.imt[0]) + for p in TEST_NDARRAYS: + with self.assertRaises(raises): + random_zoom = RandZoom(prob=1.0, min_zoom=min_zoom, max_zoom=max_zoom, mode=mode) + random_zoom(p(self.imt[0])) def test_auto_expand_3d(self): - random_zoom = RandZoom( - prob=1.0, - min_zoom=[0.8, 0.7], - max_zoom=[1.2, 1.3], - mode="nearest", - keep_size=False, - ) - random_zoom.set_random_state(1234) - test_data = np.random.randint(0, 2, size=[2, 2, 3, 4]) - zoomed = random_zoom(test_data) - np.testing.assert_allclose(random_zoom._zoom, (1.048844, 1.048844, 0.962637), atol=1e-2) - np.testing.assert_allclose(zoomed.shape, (2, 2, 3, 3)) + for p in TEST_NDARRAYS: + random_zoom = RandZoom( + prob=1.0, + min_zoom=[0.8, 0.7], + max_zoom=[1.2, 1.3], + mode="nearest", + keep_size=False, + ) + random_zoom.set_random_state(1234) + test_data = p(np.random.randint(0, 2, size=[2, 2, 3, 4])) + zoomed = random_zoom(test_data) + assert_allclose(random_zoom._zoom, (1.048844, 1.048844, 0.962637), atol=1e-2) + assert_allclose(zoomed.shape, (2, 2, 3, 3)) if __name__ == "__main__": diff --git a/tests/test_rand_zoomd.py b/tests/test_rand_zoomd.py index 4ccb1aad64..fafaf748bd 100644 --- a/tests/test_rand_zoomd.py +++ b/tests/test_rand_zoomd.py @@ -16,7 +16,7 @@ from scipy.ndimage import zoom as zoom_scipy from monai.transforms import RandZoomd -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose VALID_CASES = [(0.8, 1.2, "nearest", None, False)] @@ -34,14 +34,15 @@ def test_correct_results(self, min_zoom, max_zoom, mode, align_corners, keep_siz align_corners=align_corners, keep_size=keep_size, ) - random_zoom.set_random_state(1234) + for p in TEST_NDARRAYS: + random_zoom.set_random_state(1234) - zoomed = random_zoom({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False)) - expected = np.stack(expected).astype(np.float32) - np.testing.assert_allclose(expected, zoomed[key], atol=1.0) + zoomed = random_zoom({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False)) + expected = np.stack(expected).astype(np.float32) + assert_allclose(expected, zoomed[key], atol=1.0) def test_keep_size(self): key = "img" @@ -54,17 +55,19 @@ def test_keep_size(self): padding_mode="constant", constant_values=2, ) - zoomed = random_zoom({key: self.imt[0]}) - self.assertTrue(np.array_equal(zoomed[key].shape, self.imt.shape[1:])) + for p in TEST_NDARRAYS: + zoomed = random_zoom({key: p(self.imt[0])}) + np.testing.assert_array_equal(zoomed[key].shape, self.imt.shape[1:]) @parameterized.expand( [("no_min_zoom", None, 1.1, "bilinear", TypeError), ("invalid_order", 0.9, 1.1, "s", ValueError)] ) def test_invalid_inputs(self, _, min_zoom, max_zoom, mode, raises): key = "img" - with self.assertRaises(raises): - random_zoom = RandZoomd(key, prob=1.0, min_zoom=min_zoom, max_zoom=max_zoom, mode=mode) - random_zoom({key: self.imt[0]}) + for p in TEST_NDARRAYS: + with self.assertRaises(raises): + random_zoom = RandZoomd(key, prob=1.0, min_zoom=min_zoom, max_zoom=max_zoom, mode=mode) + random_zoom({key: p(self.imt[0])}) def test_auto_expand_3d(self): random_zoom = RandZoomd( @@ -75,11 +78,12 @@ def test_auto_expand_3d(self): mode="nearest", keep_size=False, ) - random_zoom.set_random_state(1234) - test_data = {"img": np.random.randint(0, 2, size=[2, 2, 3, 4])} - zoomed = random_zoom(test_data) - np.testing.assert_allclose(random_zoom._zoom, (1.048844, 1.048844, 0.962637), atol=1e-2) - np.testing.assert_allclose(zoomed["img"].shape, (2, 2, 3, 3)) + for p in TEST_NDARRAYS: + random_zoom.set_random_state(1234) + test_data = {"img": p(np.random.randint(0, 2, size=[2, 2, 3, 4]))} + zoomed = random_zoom(test_data) + assert_allclose(random_zoom._zoom, (1.048844, 1.048844, 0.962637), atol=1e-2) + assert_allclose(zoomed["img"].shape, (2, 2, 3, 3)) if __name__ == "__main__": diff --git a/tests/test_zoom.py b/tests/test_zoom.py index e6710ede29..a99e110052 100644 --- a/tests/test_zoom.py +++ b/tests/test_zoom.py @@ -12,11 +12,12 @@ import unittest import numpy as np +import torch from parameterized import parameterized from scipy.ndimage import zoom as zoom_scipy from monai.transforms import Zoom -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose VALID_CASES = [(1.5, "nearest"), (1.5, "nearest"), (0.8, "bilinear"), (0.8, "area")] @@ -26,38 +27,42 @@ class TestZoom(NumpyImageTestCase2D): @parameterized.expand(VALID_CASES) def test_correct_results(self, zoom, mode): - zoom_fn = Zoom(zoom=zoom, mode=mode, keep_size=False) - zoomed = zoom_fn(self.imt[0]) - _order = 0 - if mode.endswith("linear"): - _order = 1 - expected = [] - for channel in self.imt[0]: - expected.append(zoom_scipy(channel, zoom=zoom, mode="nearest", order=_order, prefilter=False)) - expected = np.stack(expected).astype(np.float32) - np.testing.assert_allclose(zoomed, expected, atol=1.0) + for p in TEST_NDARRAYS: + zoom_fn = Zoom(zoom=zoom, mode=mode, keep_size=False) + zoomed = zoom_fn(p(self.imt[0])) + _order = 0 + if mode.endswith("linear"): + _order = 1 + expected = [] + for channel in self.imt[0]: + expected.append(zoom_scipy(channel, zoom=zoom, mode="nearest", order=_order, prefilter=False)) + expected = np.stack(expected).astype(np.float32) + assert_allclose(zoomed, expected, atol=1.0) def test_keep_size(self): - zoom_fn = Zoom(zoom=[0.6, 0.6], keep_size=True, align_corners=True, padding_mode="constant", constant_values=2) - zoomed = zoom_fn(self.imt[0], mode="bilinear") - np.testing.assert_allclose(zoomed.shape, self.imt.shape[1:]) + for p in TEST_NDARRAYS: + zoom_fn = Zoom(zoom=[0.6, 0.6], keep_size=True, align_corners=True) + zoomed = zoom_fn(p(self.imt[0]), mode="bilinear") + assert_allclose(zoomed.shape, self.imt.shape[1:]) - zoom_fn = Zoom(zoom=[1.3, 1.3], keep_size=True) - zoomed = zoom_fn(self.imt[0]) - np.testing.assert_allclose(zoomed.shape, self.imt.shape[1:]) + zoom_fn = Zoom(zoom=[1.3, 1.3], keep_size=True) + zoomed = zoom_fn(p(self.imt[0])) + assert_allclose(zoomed.shape, self.imt.shape[1:]) @parameterized.expand(INVALID_CASES) def test_invalid_inputs(self, zoom, mode, raises): - with self.assertRaises(raises): - zoom_fn = Zoom(zoom=zoom, mode=mode) - zoom_fn(self.imt[0]) + for p in TEST_NDARRAYS: + with self.assertRaises(raises): + zoom_fn = Zoom(zoom=zoom, mode=mode) + zoom_fn(p(self.imt[0])) def test_padding_mode(self): - zoom_fn = Zoom(zoom=0.5, mode="nearest", padding_mode="constant", keep_size=True) - test_data = np.array([[[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]]]) - zoomed = zoom_fn(test_data) - expected = np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 0.0], [0.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]) - np.testing.assert_allclose(zoomed, expected) + for p in TEST_NDARRAYS: + zoom_fn = Zoom(zoom=0.5, mode="nearest", padding_mode="constant", keep_size=True) + test_data = p([[[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]]]) + zoomed = zoom_fn(test_data) + expected = p([[[0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 1.0, 0.0], [0.0, 1.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]) + torch.testing.assert_allclose(zoomed, expected) if __name__ == "__main__": diff --git a/tests/test_zoomd.py b/tests/test_zoomd.py index 1a1a905d80..1ebd7d2d08 100644 --- a/tests/test_zoomd.py +++ b/tests/test_zoomd.py @@ -16,7 +16,7 @@ from scipy.ndimage import zoom as zoom_scipy from monai.transforms import Zoomd -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose VALID_CASES = [(1.5, "nearest", False), (0.3, "bilinear", False), (0.8, "bilinear", False)] @@ -33,32 +33,35 @@ def test_correct_results(self, zoom, mode, keep_size): mode=mode, keep_size=keep_size, ) - zoomed = zoom_fn({key: self.imt[0]}) - _order = 0 - if mode.endswith("linear"): - _order = 1 - expected = [] - for channel in self.imt[0]: - expected.append(zoom_scipy(channel, zoom=zoom, mode="nearest", order=_order, prefilter=False)) - expected = np.stack(expected).astype(np.float32) - np.testing.assert_allclose(expected, zoomed[key], atol=1.0) + for p in TEST_NDARRAYS: + zoomed = zoom_fn({key: p(self.imt[0])}) + _order = 0 + if mode.endswith("linear"): + _order = 1 + expected = [] + for channel in self.imt[0]: + expected.append(zoom_scipy(channel, zoom=zoom, mode="nearest", order=_order, prefilter=False)) + expected = np.stack(expected).astype(np.float32) + assert_allclose(expected, zoomed[key], atol=1.0) def test_keep_size(self): key = "img" zoom_fn = Zoomd(key, zoom=0.6, keep_size=True, padding_mode="constant", constant_values=2) - zoomed = zoom_fn({key: self.imt[0]}) - self.assertTrue(np.array_equal(zoomed[key].shape, self.imt.shape[1:])) + for p in TEST_NDARRAYS: + zoomed = zoom_fn({key: p(self.imt[0])}) + np.testing.assert_array_equal(zoomed[key].shape, self.imt.shape[1:]) - zoom_fn = Zoomd(key, zoom=1.3, keep_size=True) - zoomed = zoom_fn({key: self.imt[0]}) - self.assertTrue(np.array_equal(zoomed[key].shape, self.imt.shape[1:])) + zoom_fn = Zoomd(key, zoom=1.3, keep_size=True) + zoomed = zoom_fn({key: self.imt[0]}) + self.assertTrue(np.array_equal(zoomed[key].shape, self.imt.shape[1:])) @parameterized.expand(INVALID_CASES) def test_invalid_inputs(self, _, zoom, mode, raises): key = "img" - with self.assertRaises(raises): - zoom_fn = Zoomd(key, zoom=zoom, mode=mode) - zoom_fn({key: self.imt[0]}) + for p in TEST_NDARRAYS: + with self.assertRaises(raises): + zoom_fn = Zoomd(key, zoom=zoom, mode=mode) + zoom_fn({key: p(self.imt[0])}) if __name__ == "__main__": From 281c17e549b3b1d76f585f55e1f83186ca1c8bcb Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Thu, 9 Sep 2021 17:46:32 +0100 Subject: [PATCH 04/89] Torch RandRotate90 (#2915) Torch RandRotate --- monai/transforms/spatial/array.py | 15 ++++--- monai/transforms/spatial/dictionary.py | 18 ++++---- tests/test_inverse_collation.py | 14 +++++- tests/test_pad_collation.py | 7 ++- tests/test_rand_rotate90.py | 62 ++++++++++++++------------ tests/test_rand_rotate90d.py | 62 ++++++++++++++------------ tests/test_rotate90.py | 54 +++++++++++----------- tests/test_rotate90d.py | 54 +++++++++++----------- 8 files changed, 159 insertions(+), 127 deletions(-) diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 5979b996ee..816e9d58f2 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -637,6 +637,8 @@ class Rotate90(Transform): """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__(self, k: int = 1, spatial_axes: Tuple[int, int] = (0, 1)) -> None: """ Args: @@ -651,14 +653,15 @@ def __init__(self, k: int = 1, spatial_axes: Tuple[int, int] = (0, 1)) -> None: raise ValueError("spatial_axes must be 2 int numbers to indicate the axes to rotate 90 degrees.") self.spatial_axes = spatial_axes_ - def __call__(self, img: np.ndarray) -> np.ndarray: + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Args: img: channel first array, must have shape: (num_channels, H[, W, ..., ]), """ - - result: np.ndarray = np.rot90(img, self.k, map_spatial_axes(img.ndim, self.spatial_axes)) - return result.astype(img.dtype) + rot90 = torch.rot90 if isinstance(img, torch.Tensor) else np.rot90 + out: NdarrayOrTensor = rot90(img, self.k, map_spatial_axes(img.ndim, self.spatial_axes)) + out, *_ = convert_data_type(out, dtype=img.dtype) + return out class RandRotate90(RandomizableTransform): @@ -667,6 +670,8 @@ class RandRotate90(RandomizableTransform): in the plane specified by `spatial_axes`. """ + backend = Rotate90.backend + def __init__(self, prob: float = 0.1, max_k: int = 3, spatial_axes: Tuple[int, int] = (0, 1)) -> None: """ Args: @@ -686,7 +691,7 @@ def randomize(self, data: Optional[Any] = None) -> None: self._rand_k = self.R.randint(self.max_k) + 1 super().randomize(None) - def __call__(self, img: np.ndarray) -> np.ndarray: + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Args: img: channel first array, must have shape: (num_channels, H[, W, ..., ]), diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index 22dafb3f80..c09d8e8011 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -382,6 +382,8 @@ class Rotate90d(MapTransform, InvertibleTransform): Dictionary-based wrapper of :py:class:`monai.transforms.Rotate90`. """ + backend = Rotate90.backend + def __init__( self, keys: KeysCollection, k: int = 1, spatial_axes: Tuple[int, int] = (0, 1), allow_missing_keys: bool = False ) -> None: @@ -395,14 +397,14 @@ def __init__( super().__init__(keys, allow_missing_keys) self.rotator = Rotate90(k, spatial_axes) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): self.push_transform(d, key) d[key] = self.rotator(d[key]) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): _ = self.get_most_recent_transform(d, key) @@ -411,9 +413,6 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar num_times_rotated = self.rotator.k num_times_to_rotate = 4 - num_times_rotated inverse_transform = Rotate90(num_times_to_rotate, spatial_axes) - # Might need to convert to numpy - if isinstance(d[key], torch.Tensor): - d[key] = torch.Tensor(d[key]).cpu().numpy() # Apply inverse d[key] = inverse_transform(d[key]) # Remove the applied transform @@ -429,6 +428,8 @@ class RandRotate90d(RandomizableTransform, MapTransform, InvertibleTransform): in the plane specified by `spatial_axes`. """ + backend = Rotate90.backend + def __init__( self, keys: KeysCollection, @@ -461,7 +462,7 @@ def randomize(self, data: Optional[Any] = None) -> None: self._rand_k = self.R.randint(self.max_k) + 1 super().randomize(None) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Mapping[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Mapping[Hashable, NdarrayOrTensor]: self.randomize() d = dict(data) @@ -472,7 +473,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Mapping[Hashable, np. self.push_transform(d, key, extra_info={"rand_k": self._rand_k}) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -482,9 +483,6 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar num_times_rotated = transform[InverseKeys.EXTRA_INFO]["rand_k"] num_times_to_rotate = 4 - num_times_rotated inverse_transform = Rotate90(num_times_to_rotate, self.spatial_axes) - # Might need to convert to numpy - if isinstance(d[key], torch.Tensor): - d[key] = torch.Tensor(d[key]).cpu().numpy() # Apply inverse d[key] = inverse_transform(d[key]) # Remove the applied transform diff --git a/tests/test_inverse_collation.py b/tests/test_inverse_collation.py index c302e04017..c5dd9f1210 100644 --- a/tests/test_inverse_collation.py +++ b/tests/test_inverse_collation.py @@ -48,7 +48,12 @@ for t in [ RandFlipd(keys=KEYS, prob=0.5, spatial_axis=[1, 2]), RandAxisFlipd(keys=KEYS, prob=0.5), - RandRotate90d(keys=KEYS, spatial_axes=(1, 2)), + Compose( + [ + RandRotate90d(keys=KEYS, spatial_axes=(1, 2)), + ToTensord(keys=KEYS), + ] + ), RandZoomd(keys=KEYS, prob=0.5, min_zoom=0.5, max_zoom=1.1, keep_size=True), RandRotated(keys=KEYS, prob=0.5, range_x=np.pi), RandAffined( @@ -67,7 +72,12 @@ for t in [ RandFlipd(keys=KEYS, prob=0.5, spatial_axis=[1]), RandAxisFlipd(keys=KEYS, prob=0.5), - RandRotate90d(keys=KEYS, prob=0.5, spatial_axes=(0, 1)), + Compose( + [ + RandRotate90d(keys=KEYS, prob=0.5, spatial_axes=(0, 1)), + ToTensord(keys=KEYS), + ] + ), RandZoomd(keys=KEYS, prob=0.5, min_zoom=0.5, max_zoom=1.1, keep_size=True), RandRotated(keys=KEYS, prob=0.5, range_x=np.pi), RandAffined( diff --git a/tests/test_pad_collation.py b/tests/test_pad_collation.py index a8c544558f..47bfa69582 100644 --- a/tests/test_pad_collation.py +++ b/tests/test_pad_collation.py @@ -20,6 +20,7 @@ from monai.data import CacheDataset, DataLoader from monai.data.utils import decollate_batch, pad_list_data_collate from monai.transforms import ( + Compose, PadListDataCollate, RandRotate, RandRotate90, @@ -29,6 +30,8 @@ RandSpatialCropd, RandZoom, RandZoomd, + ToTensor, + ToTensord, ) from monai.utils import set_determinism @@ -41,12 +44,12 @@ TESTS.append((dict, pad_collate, RandSpatialCropd("image", roi_size=[8, 7], random_size=True))) TESTS.append((dict, pad_collate, RandRotated("image", prob=1, range_x=np.pi, keep_size=False))) TESTS.append((dict, pad_collate, RandZoomd("image", prob=1, min_zoom=1.1, max_zoom=2.0, keep_size=False))) - TESTS.append((dict, pad_collate, RandRotate90d("image", prob=1, max_k=2))) + TESTS.append((dict, pad_collate, Compose([RandRotate90d("image", prob=1, max_k=2), ToTensord("image")]))) TESTS.append((list, pad_collate, RandSpatialCrop(roi_size=[8, 7], random_size=True))) TESTS.append((list, pad_collate, RandRotate(prob=1, range_x=np.pi, keep_size=False))) TESTS.append((list, pad_collate, RandZoom(prob=1, min_zoom=1.1, max_zoom=2.0, keep_size=False))) - TESTS.append((list, pad_collate, RandRotate90(prob=1, max_k=2))) + TESTS.append((list, pad_collate, Compose([RandRotate90(prob=1, max_k=2), ToTensor()]))) class _Dataset(torch.utils.data.Dataset): diff --git a/tests/test_rand_rotate90.py b/tests/test_rand_rotate90.py index 50a1b28e53..f339158f94 100644 --- a/tests/test_rand_rotate90.py +++ b/tests/test_rand_rotate90.py @@ -14,49 +14,53 @@ import numpy as np from monai.transforms import RandRotate90 -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose class TestRandRotate90(NumpyImageTestCase2D): def test_default(self): rotate = RandRotate90() - rotate.set_random_state(123) - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(123) + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 0, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) def test_k(self): rotate = RandRotate90(max_k=2) - rotate.set_random_state(234) - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(234) + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 0, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) def test_spatial_axes(self): rotate = RandRotate90(spatial_axes=(0, 1)) - rotate.set_random_state(234) - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(234) + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 0, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) def test_prob_k_spatial_axes(self): rotate = RandRotate90(prob=1.0, max_k=2, spatial_axes=(0, 1)) - rotate.set_random_state(234) - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(234) + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 1, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) if __name__ == "__main__": diff --git a/tests/test_rand_rotate90d.py b/tests/test_rand_rotate90d.py index a487b695f5..f9083afb0c 100644 --- a/tests/test_rand_rotate90d.py +++ b/tests/test_rand_rotate90d.py @@ -14,53 +14,57 @@ import numpy as np from monai.transforms import RandRotate90d -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose class TestRandRotate90d(NumpyImageTestCase2D): def test_default(self): key = None rotate = RandRotate90d(keys=key) - rotate.set_random_state(123) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(123) + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 0, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_k(self): key = "test" rotate = RandRotate90d(keys=key, max_k=2) - rotate.set_random_state(234) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(234) + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 0, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_spatial_axes(self): key = "test" rotate = RandRotate90d(keys=key, spatial_axes=(0, 1)) - rotate.set_random_state(234) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(234) + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 0, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_prob_k_spatial_axes(self): key = "test" rotate = RandRotate90d(keys=key, prob=1.0, max_k=2, spatial_axes=(0, 1)) - rotate.set_random_state(234) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotate.set_random_state(234) + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 1, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_no_key(self): key = "unknown" diff --git a/tests/test_rotate90.py b/tests/test_rotate90.py index 4ab39d5cf6..03a967a16b 100644 --- a/tests/test_rotate90.py +++ b/tests/test_rotate90.py @@ -14,45 +14,49 @@ import numpy as np from monai.transforms import Rotate90 -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose class TestRotate90(NumpyImageTestCase2D): def test_rotate90_default(self): rotate = Rotate90() - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 1, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) def test_k(self): rotate = Rotate90(k=2) - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 2, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) def test_spatial_axes(self): rotate = Rotate90(spatial_axes=(0, -1)) - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, -1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 1, (0, -1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) def test_prob_k_spatial_axes(self): rotate = Rotate90(k=2, spatial_axes=(0, 1)) - rotated = rotate(self.imt[0]) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated, expected)) + for p in TEST_NDARRAYS: + rotated = rotate(p(self.imt[0])) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 2, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) if __name__ == "__main__": diff --git a/tests/test_rotate90d.py b/tests/test_rotate90d.py index 3d71ead82a..a1fa3c977c 100644 --- a/tests/test_rotate90d.py +++ b/tests/test_rotate90d.py @@ -14,49 +14,53 @@ import numpy as np from monai.transforms import Rotate90d -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose class TestRotate90d(NumpyImageTestCase2D): def test_rotate90_default(self): key = "test" rotate = Rotate90d(keys=key) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 1, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_k(self): key = None rotate = Rotate90d(keys=key, k=2) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 2, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_spatial_axes(self): key = "test" rotate = Rotate90d(keys=key, spatial_axes=(0, 1)) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 1, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_prob_k_spatial_axes(self): key = "test" rotate = Rotate90d(keys=key, k=2, spatial_axes=(0, 1)) - rotated = rotate({key: self.imt[0]}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) - expected = np.stack(expected) - self.assertTrue(np.allclose(rotated[key], expected)) + for p in TEST_NDARRAYS: + rotated = rotate({key: p(self.imt[0])}) + expected = [] + for channel in self.imt[0]: + expected.append(np.rot90(channel, 2, (0, 1))) + expected = np.stack(expected) + assert_allclose(rotated[key], expected) def test_no_key(self): key = "unknown" From ef0981170da95ea4cbcb3bf8d06d0157ca4f385a Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Fri, 10 Sep 2021 02:58:41 -0400 Subject: [PATCH 05/89] CuPy to Tensor (#2919) * Add cupy to tensor Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Add unittest for cupy>tensor Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/utils/type_conversion.py | 2 ++ tests/test_to_tensor.py | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index b0ce187e38..3688b02d26 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -105,6 +105,8 @@ def convert_to_tensor(data, wrap_sequence: bool = False): # numpy array with 0 dims is also sequence iterable, # `ascontiguousarray` will add 1 dim if img has no dim, so we only apply on data with dims return torch.as_tensor(data if data.ndim == 0 else np.ascontiguousarray(data)) + elif has_cp and isinstance(data, cp_ndarray): + return torch.as_tensor(data) elif isinstance(data, (float, int, bool)): return torch.as_tensor(data) elif isinstance(data, Sequence) and wrap_sequence: diff --git a/tests/test_to_tensor.py b/tests/test_to_tensor.py index 6ac06983f6..3d187a1dba 100644 --- a/tests/test_to_tensor.py +++ b/tests/test_to_tensor.py @@ -12,9 +12,12 @@ import unittest from parameterized import parameterized +from torch import Tensor from monai.transforms import ToTensor -from tests.utils import TEST_NDARRAYS, assert_allclose +from tests.utils import TEST_NDARRAYS, assert_allclose, optional_import + +cp, has_cp = optional_import("cupy") im = [[1, 2], [3, 4]] @@ -33,15 +36,25 @@ class TestToTensor(unittest.TestCase): @parameterized.expand(TESTS) def test_array_input(self, test_data, expected_shape): result = ToTensor()(test_data) + self.assertTrue(isinstance(result, Tensor)) assert_allclose(result, test_data) self.assertTupleEqual(result.shape, expected_shape) @parameterized.expand(TESTS_SINGLE) def test_single_input(self, test_data): result = ToTensor()(test_data) + self.assertTrue(isinstance(result, Tensor)) assert_allclose(result, test_data) self.assertEqual(result.ndim, 0) + @unittest.skipUnless(has_cp, "CuPy is required.") + def test_cupy(self): + test_data = [[1, 2], [3, 4]] + cupy_array = cp.ascontiguousarray(cp.asarray(test_data)) + result = ToTensor()(cupy_array) + self.assertTrue(isinstance(result, Tensor)) + assert_allclose(result, test_data) + if __name__ == "__main__": unittest.main() From e2965dbfeda69158a881de213b4d69980587105d Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Fri, 10 Sep 2021 19:58:34 +0800 Subject: [PATCH 06/89] [DLMED] add dict version shuffle (#2918) Signed-off-by: Nic Ma Co-authored-by: Wenqi Li --- docs/source/transforms.rst | 6 ++ monai/transforms/__init__.py | 3 + monai/transforms/intensity/array.py | 15 +++++ monai/transforms/intensity/dictionary.py | 78 ++++++++++++++++++++++++ tests/test_rand_coarse_shuffle.py | 2 +- tests/test_rand_coarse_shuffled.py | 56 +++++++++++++++++ 6 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 tests/test_rand_coarse_shuffled.py diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index d1083a641b..b61da87551 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -977,6 +977,12 @@ Intensity (Dict) :members: :special-members: __call__ +`RandCoarseShuffled` +"""""""""""""""""""" +.. autoclass:: RandCoarseShuffled + :members: + :special-members: __call__ + `HistogramNormalized` """"""""""""""""""""" .. autoclass:: HistogramNormalized diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index b9ba303ed7..e4ec38f82d 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -144,6 +144,9 @@ RandCoarseDropoutd, RandCoarseDropoutD, RandCoarseDropoutDict, + RandCoarseShuffled, + RandCoarseShuffleD, + RandCoarseShuffleDict, RandGaussianNoised, RandGaussianNoiseD, RandGaussianNoiseDict, diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index d10c3017a3..f6d4dfff5a 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1786,6 +1786,21 @@ class RandCoarseShuffle(RandCoarseTransform): Kang, Guoliang, et al. "Patchshuffle regularization." arXiv preprint arXiv:1707.07103 (2017). https://arxiv.org/abs/1707.07103 + Args: + holes: number of regions to dropout, if `max_holes` is not None, use this arg as the minimum number to + randomly select the expected number of regions. + spatial_size: spatial size of the regions to dropout, if `max_spatial_size` is not None, use this arg + as the minimum spatial size to randomly select size for every region. + if some components of the `spatial_size` are non-positive values, the transform will use the + corresponding components of input img size. For example, `spatial_size=(32, -1)` will be adapted + to `(32, 64)` if the second spatial dimension size of img is `64`. + max_holes: if not None, define the maximum number to randomly select the expected number of regions. + max_spatial_size: if not None, define the maximum spatial size to randomly select size for every region. + if some components of the `max_spatial_size` are non-positive values, the transform will use the + corresponding components of input img size. For example, `max_spatial_size=(32, -1)` will be adapted + to `(32, 64)` if the second spatial dimension size of img is `64`. + prob: probability of applying the transform. + """ def _transform_holes(self, img: np.ndarray): diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index bc53fb6b7b..ca24980359 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -34,6 +34,7 @@ NormalizeIntensity, RandBiasField, RandCoarseDropout, + RandCoarseShuffle, RandGaussianNoise, RandKSpaceSpikeNoise, RandRicianNoise, @@ -75,6 +76,7 @@ "RandKSpaceSpikeNoised", "RandHistogramShiftd", "RandCoarseDropoutd", + "RandCoarseShuffled", "HistogramNormalized", "RandGaussianNoiseD", "RandGaussianNoiseDict", @@ -126,6 +128,8 @@ "RandRicianNoiseDict", "RandCoarseDropoutD", "RandCoarseDropoutDict", + "RandCoarseShuffleD", + "RandCoarseShuffleDict", "HistogramNormalizeD", "HistogramNormalizeDict", ] @@ -1478,6 +1482,13 @@ def __init__( prob=prob, ) + def set_random_state( + self, seed: Optional[int] = None, state: Optional[np.random.RandomState] = None + ) -> "RandCoarseDropoutd": + self.dropper.set_random_state(seed, state) + super().set_random_state(seed, state) + return self + def randomize(self, img_size: Sequence[int]) -> None: self.dropper.randomize(img_size=img_size) @@ -1492,6 +1503,72 @@ def __call__(self, data): return d +class RandCoarseShuffled(Randomizable, MapTransform): + """ + Dictionary-based wrapper of :py:class:`monai.transforms.RandCoarseShuffle`. + Expect all the data specified by `keys` have same spatial shape and will randomly dropout the same regions + for every key, if want to shuffle different regions for every key, please use this transform separately. + + Args: + keys: keys of the corresponding items to be transformed. + See also: :py:class:`monai.transforms.compose.MapTransform` + holes: number of regions to dropout, if `max_holes` is not None, use this arg as the minimum number to + randomly select the expected number of regions. + spatial_size: spatial size of the regions to dropout, if `max_spatial_size` is not None, use this arg + as the minimum spatial size to randomly select size for every region. + if some components of the `spatial_size` are non-positive values, the transform will use the + corresponding components of input img size. For example, `spatial_size=(32, -1)` will be adapted + to `(32, 64)` if the second spatial dimension size of img is `64`. + max_holes: if not None, define the maximum number to randomly select the expected number of regions. + max_spatial_size: if not None, define the maximum spatial size to randomly select size for every region. + if some components of the `max_spatial_size` are non-positive values, the transform will use the + corresponding components of input img size. For example, `max_spatial_size=(32, -1)` will be adapted + to `(32, 64)` if the second spatial dimension size of img is `64`. + prob: probability of applying the transform. + allow_missing_keys: don't raise exception if key is missing. + + """ + + def __init__( + self, + keys: KeysCollection, + holes: int, + spatial_size: Union[Sequence[int], int], + max_holes: Optional[int] = None, + max_spatial_size: Optional[Union[Sequence[int], int]] = None, + prob: float = 0.1, + allow_missing_keys: bool = False, + ): + MapTransform.__init__(self, keys, allow_missing_keys) + self.shuffle = RandCoarseShuffle( + holes=holes, + spatial_size=spatial_size, + max_holes=max_holes, + max_spatial_size=max_spatial_size, + prob=prob, + ) + + def set_random_state( + self, seed: Optional[int] = None, state: Optional[np.random.RandomState] = None + ) -> "RandCoarseShuffled": + self.shuffle.set_random_state(seed, state) + super().set_random_state(seed, state) + return self + + def randomize(self, img_size: Sequence[int]) -> None: + self.shuffle.randomize(img_size=img_size) + + def __call__(self, data): + d = dict(data) + # expect all the specified keys have same spatial shape + self.randomize(d[self.keys[0]].shape[1:]) + if self.shuffle._do_transform: + for key in self.key_iterator(d): + d[key] = self.shuffle(img=d[key]) + + return d + + class HistogramNormalized(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.HistogramNormalize`. @@ -1562,3 +1639,4 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda RandKSpaceSpikeNoiseD = RandKSpaceSpikeNoiseDict = RandKSpaceSpikeNoised RandCoarseDropoutD = RandCoarseDropoutDict = RandCoarseDropoutd HistogramNormalizeD = HistogramNormalizeDict = HistogramNormalized +RandCoarseShuffleD = RandCoarseShuffleDict = RandCoarseShuffled diff --git a/tests/test_rand_coarse_shuffle.py b/tests/test_rand_coarse_shuffle.py index 97d492fd24..0b8cdc6cf8 100644 --- a/tests/test_rand_coarse_shuffle.py +++ b/tests/test_rand_coarse_shuffle.py @@ -45,7 +45,7 @@ class TestRandCoarseShuffle(unittest.TestCase): @parameterized.expand(TEST_CASES) - def test_local_patch_shuffle(self, input_param, input_data, expected_val): + def test_shuffle(self, input_param, input_data, expected_val): g = RandCoarseShuffle(**input_param) g.set_random_state(seed=12) result = g(**input_data) diff --git a/tests/test_rand_coarse_shuffled.py b/tests/test_rand_coarse_shuffled.py new file mode 100644 index 0000000000..d2845fdaae --- /dev/null +++ b/tests/test_rand_coarse_shuffled.py @@ -0,0 +1,56 @@ +# Copyright 2020 - 2021 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 +from parameterized import parameterized + +from monai.transforms import RandCoarseShuffled + +TEST_CASES = [ + [ + {"keys": "img", "holes": 5, "spatial_size": 1, "max_spatial_size": -1, "prob": 0.0}, + {"img": np.arange(8).reshape((1, 2, 2, 2))}, + np.arange(8).reshape((1, 2, 2, 2)), + ], + [ + {"keys": "img", "holes": 10, "spatial_size": 1, "max_spatial_size": -1, "prob": 1.0}, + {"img": np.arange(27).reshape((1, 3, 3, 3))}, + np.asarray( + [ + [ + [[13, 17, 5], [6, 16, 25], [12, 15, 22]], + [[24, 7, 3], [9, 2, 23], [0, 4, 26]], + [[19, 11, 14], [1, 20, 8], [18, 10, 21]], + ] + ] + ), + ], + [ + {"keys": "img", "holes": 2, "spatial_size": 1, "max_spatial_size": -1, "prob": 1.0}, + {"img": np.arange(16).reshape((2, 2, 2, 2))}, + np.asarray([[[[7, 2], [1, 4]], [[5, 0], [3, 6]]], [[[8, 13], [10, 15]], [[14, 12], [11, 9]]]]), + ], +] + + +class TestRandCoarseShuffled(unittest.TestCase): + @parameterized.expand(TEST_CASES) + def test_shuffle(self, input_param, input_data, expected_val): + g = RandCoarseShuffled(**input_param) + g.set_random_state(seed=12) + result = g(input_data) + np.testing.assert_allclose(result["img"], expected_val, rtol=1e-4, atol=1e-4) + + +if __name__ == "__main__": + unittest.main() From 448cdcafea2cf94d6484d248361230efd7f73447 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Sat, 11 Sep 2021 06:58:22 -0400 Subject: [PATCH 07/89] Add device to ToTensor (#2926) --- monai/transforms/utility/array.py | 8 +++++--- monai/utils/type_conversion.py | 18 +++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 2eb6c447c6..add47e27ca 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -334,11 +334,15 @@ class ToTensor(Transform): backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__(self, device: Optional[torch.device] = None) -> None: + super().__init__() + self.device = device + def __call__(self, img: NdarrayOrTensor) -> torch.Tensor: """ Apply the transform to `img` and make it contiguous. """ - return convert_to_tensor(img, wrap_sequence=True) # type: ignore + return convert_to_tensor(img, wrap_sequence=True, device=self.device) # type: ignore class EnsureType(Transform): @@ -399,8 +403,6 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img` and make it contiguous. """ - if isinstance(img, torch.Tensor): - img = img.detach().cpu().numpy() return cp.ascontiguousarray(cp.asarray(img)) # type: ignore diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index 3688b02d26..47b48aa2b8 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -83,7 +83,7 @@ def get_dtype(data: Any): return type(data) -def convert_to_tensor(data, wrap_sequence: bool = False): +def convert_to_tensor(data, wrap_sequence: bool = False, device: Optional[torch.device] = None): """ Utility to convert the input data to a PyTorch Tensor. If passing a dictionary, list or tuple, recursively check every item and convert it to PyTorch Tensor. @@ -97,26 +97,26 @@ def convert_to_tensor(data, wrap_sequence: bool = False): """ if isinstance(data, torch.Tensor): - return data.contiguous() + return data.contiguous().to(device) if isinstance(data, np.ndarray): # skip array of string classes and object, refer to: # https://github.com/pytorch/pytorch/blob/v1.9.0/torch/utils/data/_utils/collate.py#L13 if re.search(r"[SaUO]", data.dtype.str) is None: # numpy array with 0 dims is also sequence iterable, # `ascontiguousarray` will add 1 dim if img has no dim, so we only apply on data with dims - return torch.as_tensor(data if data.ndim == 0 else np.ascontiguousarray(data)) + return torch.as_tensor(data if data.ndim == 0 else np.ascontiguousarray(data), device=device) elif has_cp and isinstance(data, cp_ndarray): - return torch.as_tensor(data) + return torch.as_tensor(data, device=device) elif isinstance(data, (float, int, bool)): - return torch.as_tensor(data) + return torch.as_tensor(data, device=device) elif isinstance(data, Sequence) and wrap_sequence: - return torch.as_tensor(data) + return torch.as_tensor(data, device=device) elif isinstance(data, list): - return [convert_to_tensor(i) for i in data] + return [convert_to_tensor(i, device=device) for i in data] elif isinstance(data, tuple): - return tuple(convert_to_tensor(i) for i in data) + return tuple(convert_to_tensor(i, device=device) for i in data) elif isinstance(data, dict): - return {k: convert_to_tensor(v) for k, v in data.items()} + return {k: convert_to_tensor(v, device=device) for k, v in data.items()} return data From c50235c85dca411e878c0c3508eb27a0a76b37fb Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Sun, 12 Sep 2021 11:02:20 +0800 Subject: [PATCH 08/89] 2920 Enhance padding mode for Tensor data (#2921) * [DLMED] enhance the pad mode Signed-off-by: Nic Ma * [DLMED] update all the tensor pad related Signed-off-by: Nic Ma * [DLMED] fix error tests Signed-off-by: Nic Ma * [DLMED] fix GPU tests Signed-off-by: Nic Ma * [DLMED] update according to comments Signed-off-by: Nic Ma --- docs/source/transforms.rst | 6 + monai/transforms/__init__.py | 4 +- monai/transforms/croppad/array.py | 173 +++++++++++++++---------- monai/transforms/croppad/dictionary.py | 53 ++++---- monai/transforms/spatial/array.py | 87 +++++++------ monai/transforms/spatial/dictionary.py | 41 +++--- monai/transforms/utils.py | 31 ++++- monai/utils/type_conversion.py | 14 +- tests/test_convert_data_type.py | 13 +- tests/test_divisible_pad.py | 10 +- tests/test_pad_collation.py | 4 +- tests/test_spatial_pad.py | 56 ++++---- 12 files changed, 315 insertions(+), 177 deletions(-) diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index b61da87551..add6b9b40c 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -59,6 +59,12 @@ Vanilla Transforms Crop and Pad ^^^^^^^^^^^^ +`Pad` +""""" +.. autoclass:: Pad + :members: + :special-members: __call__ + `SpatialPad` """""""""""" .. autoclass:: SpatialPad diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index e4ec38f82d..a07dee867b 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -18,6 +18,7 @@ CenterSpatialCrop, CropForeground, DivisiblePad, + Pad, RandCropByLabelClasses, RandCropByPosNegLabel, RandScaleCrop, @@ -48,7 +49,7 @@ DivisiblePadd, DivisiblePadD, DivisiblePadDict, - NumpyPadModeSequence, + PadModeSequence, RandCropByLabelClassesd, RandCropByLabelClassesD, RandCropByLabelClassesDict, @@ -490,6 +491,7 @@ allow_missing_keys_mode, compute_divisible_spatial_size, convert_inverse_interp_mode, + convert_pad_mode, copypaste_arrays, create_control_grid, create_grid, diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index 74f556cc1a..7e3bc835dd 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -27,6 +27,7 @@ from monai.transforms.transform import Randomizable, Transform from monai.transforms.utils import ( compute_divisible_spatial_size, + convert_pad_mode, generate_label_classes_crop_centers, generate_pos_neg_label_crop_centers, generate_spatial_bounding_box, @@ -35,7 +36,15 @@ map_classes_to_indices, weighted_patch_samples, ) -from monai.utils import Method, NumpyPadMode, ensure_tuple, ensure_tuple_rep, fall_back_tuple, look_up_option +from monai.utils import ( + Method, + NumpyPadMode, + PytorchPadMode, + ensure_tuple, + ensure_tuple_rep, + fall_back_tuple, + look_up_option, +) from monai.utils.enums import TransformBackends from monai.utils.type_conversion import convert_data_type @@ -61,16 +70,18 @@ class Pad(Transform): """ Perform padding for a given an amount of padding in each dimension. - If input is `torch.Tensor` and mode is `constant`, `torch.nn.functional.pad` will be used. - Otherwise, `np.pad` will be used (input converted to `np.ndarray` if necessary). - Uses np.pad so in practice, a mode needs to be provided. See numpy.lib.arraypad.pad - for additional details. + If input is `torch.Tensor`, `torch.nn.functional.pad` will be used, otherwise, `np.pad` will be used. + Args: to_pad: the amount to be padded in each dimension [(low_H, high_H), (low_W, high_W), ...]. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ backend = [TransformBackends.TORCH, TransformBackends.NUMPY] @@ -78,43 +89,50 @@ class Pad(Transform): def __init__( self, to_pad: List[Tuple[int, int]], - mode: Union[NumpyPadMode, str, None] = NumpyPadMode.CONSTANT, - **np_kwargs, + mode: Union[NumpyPadMode, PytorchPadMode, str] = NumpyPadMode.CONSTANT, + **kwargs, ) -> None: self.to_pad = to_pad - self.mode = mode or NumpyPadMode.CONSTANT - self.np_kwargs = np_kwargs + self.mode = mode + self.kwargs = kwargs @staticmethod - def _np_pad(img: np.ndarray, all_pad_width, mode, **np_kwargs) -> np.ndarray: + def _np_pad(img: np.ndarray, all_pad_width, mode, **kwargs) -> np.ndarray: img_np, *_ = convert_data_type(img, np.ndarray) - return np.pad(img_np, all_pad_width, mode=mode, **np_kwargs) # type: ignore + return np.pad(img_np, all_pad_width, mode=mode, **kwargs) # type: ignore @staticmethod - def _pt_pad(img: torch.Tensor, all_pad_width, mode, **np_kwargs) -> torch.Tensor: - pt_pad_width = [val for sublist in all_pad_width for val in sublist[::-1]][::-1] - return pad_pt(img, pt_pad_width, mode=mode, **np_kwargs) + def _pt_pad(img: torch.Tensor, all_pad_width, mode, **kwargs) -> torch.Tensor: + pt_pad_width = [val for sublist in all_pad_width[1:] for val in sublist[::-1]][::-1] + # torch.pad expects `[B, C, H, W, [D]]` shape + return pad_pt(img.unsqueeze(0), pt_pad_width, mode=mode, **kwargs).squeeze(0) - def __call__(self, img: NdarrayTensor, mode: Optional[Union[NumpyPadMode, str]] = None) -> NdarrayTensor: + def __call__( + self, + img: NdarrayTensor, + mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, + ) -> NdarrayTensor: """ Args: img: data to be transformed, assuming `img` is channel-first and padding doesn't apply to the channel dim. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} - One of the listed string values or a user supplied function. Defaults to ``self.mode``. - See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"`` or ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to `self.mode`. + See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html + """ if not np.asarray(self.to_pad).any(): # all zeros, skip padding return img - mode = mode or self.mode - mode = mode.value if isinstance(mode, NumpyPadMode) else mode - if isinstance(img, torch.Tensor) and mode == "constant" and not self.np_kwargs: + mode = convert_pad_mode(dst=img, mode=mode or self.mode).value + if isinstance(img, torch.Tensor): pad = self._pt_pad else: pad = self._np_pad # type: ignore - return pad(img, self.to_pad, mode, **self.np_kwargs) + return pad(img, self.to_pad, mode, **self.kwargs) class SpatialPad(Transform): @@ -135,12 +153,14 @@ class SpatialPad(Transform): `spatial_size=[32, 25, -1]`, the spatial size of output data will be [32, 30, 30]. method: {``"symmetric"``, ``"end"``} Pad image symmetrically on every side or only pad at the end sides. Defaults to ``"symmetric"``. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ @@ -150,13 +170,13 @@ def __init__( self, spatial_size: Union[Sequence[int], int], method: Union[Method, str] = Method.SYMMETRIC, - mode: Union[NumpyPadMode, str] = NumpyPadMode.CONSTANT, - **np_kwargs, + mode: Union[NumpyPadMode, PytorchPadMode, str] = NumpyPadMode.CONSTANT, + **kwargs, ) -> None: self.spatial_size = spatial_size self.method: Method = look_up_option(method, Method) - self.mode: NumpyPadMode = look_up_option(mode, NumpyPadMode) - self.np_kwargs = np_kwargs + self.mode = mode + self.kwargs = kwargs def _determine_data_pad_width(self, data_shape: Sequence[int]) -> List[Tuple[int, int]]: spatial_size = fall_back_tuple(self.spatial_size, data_shape) @@ -168,15 +188,22 @@ def _determine_data_pad_width(self, data_shape: Sequence[int]) -> List[Tuple[int return pad_width return [(0, max(sp_i - data_shape[i], 0)) for i, sp_i in enumerate(spatial_size)] - def __call__(self, img: NdarrayTensor, mode: Optional[Union[NumpyPadMode, str]] = None) -> NdarrayTensor: + def __call__( + self, + img: NdarrayTensor, + mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, + ) -> NdarrayTensor: """ Args: img: data to be transformed, assuming `img` is channel-first and padding doesn't apply to the channel dim. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} - One of the listed string values or a user supplied function. Defaults to ``self.mode``. + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to `self.mode`. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html + """ data_pad_width = self._determine_data_pad_width(img.shape[1:]) all_pad_width = [(0, 0)] + data_pad_width @@ -184,8 +211,7 @@ def __call__(self, img: NdarrayTensor, mode: Optional[Union[NumpyPadMode, str]] # all zeros, skip padding return img - mode = look_up_option(mode or self.mode, NumpyPadMode) - padder = Pad(all_pad_width, mode, **self.np_kwargs) + padder = Pad(all_pad_width, mode or self.mode, **self.kwargs) return padder(img) @@ -204,13 +230,14 @@ class BorderPad(Transform): for example, image shape(CHW) is [1, 4, 4], spatial_border is [1, 2, 3, 4], pad top of H dim with 1, pad bottom of H dim with 2, pad left of W dim with 3, pad right of W dim with 4. the result shape is [1, 7, 11]. - - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ @@ -219,22 +246,28 @@ class BorderPad(Transform): def __init__( self, spatial_border: Union[Sequence[int], int], - mode: Union[NumpyPadMode, str] = NumpyPadMode.CONSTANT, - **np_kwargs, + mode: Union[NumpyPadMode, PytorchPadMode, str] = NumpyPadMode.CONSTANT, + **kwargs, ) -> None: self.spatial_border = spatial_border - self.mode: NumpyPadMode = look_up_option(mode, NumpyPadMode) - self.np_kwargs = np_kwargs + self.mode = mode + self.kwargs = kwargs - def __call__(self, img: NdarrayTensor, mode: Optional[Union[NumpyPadMode, str]] = None) -> NdarrayTensor: + def __call__( + self, + img: NdarrayTensor, + mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, + ) -> NdarrayTensor: """ Args: img: data to be transformed, assuming `img` is channel-first and padding doesn't apply to the channel dim. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} - One of the listed string values or a user supplied function. Defaults to ``self.mode``. + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to `self.mode`. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html Raises: ValueError: When ``self.spatial_border`` does not contain ints. @@ -261,8 +294,7 @@ def __call__(self, img: NdarrayTensor, mode: Optional[Union[NumpyPadMode, str]] ) all_pad_width = [(0, 0)] + data_pad_width - mode = look_up_option(mode or self.mode, NumpyPadMode) - padder = Pad(all_pad_width, mode, **self.np_kwargs) + padder = Pad(all_pad_width, mode or self.mode, **self.kwargs) return padder(img) @@ -276,47 +308,56 @@ class DivisiblePad(Transform): def __init__( self, k: Union[Sequence[int], int], - mode: Union[NumpyPadMode, str] = NumpyPadMode.CONSTANT, + mode: Union[NumpyPadMode, PytorchPadMode, str] = NumpyPadMode.CONSTANT, method: Union[Method, str] = Method.SYMMETRIC, - **np_kwargs, + **kwargs, ) -> None: """ Args: k: the target k for each spatial dimension. if `k` is negative or 0, the original size is preserved. if `k` is an int, the same `k` be applied to all the input spatial dimensions. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html method: {``"symmetric"``, ``"end"``} Pad image symmetrically on every side or only pad at the end sides. Defaults to ``"symmetric"``. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. See also :py:class:`monai.transforms.SpatialPad` """ self.k = k self.mode: NumpyPadMode = NumpyPadMode(mode) self.method: Method = Method(method) - self.np_kwargs = np_kwargs + self.kwargs = kwargs - def __call__(self, img: NdarrayTensor, mode: Optional[Union[NumpyPadMode, str]] = None) -> NdarrayTensor: + def __call__( + self, + img: NdarrayTensor, + mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, + ) -> NdarrayTensor: """ Args: img: data to be transformed, assuming `img` is channel-first and padding doesn't apply to the channel dim. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} - One of the listed string values or a user supplied function. Defaults to ``self.mode``. + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to `self.mode`. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html + """ new_size = compute_divisible_spatial_size(spatial_shape=img.shape[1:], k=self.k) spatial_pad = SpatialPad( spatial_size=new_size, method=self.method, mode=mode or self.mode, - **self.np_kwargs, + **self.kwargs, ) return spatial_pad(img) diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py index 9e33ab2db1..5c846b8d04 100644 --- a/monai/transforms/croppad/dictionary.py +++ b/monai/transforms/croppad/dictionary.py @@ -49,11 +49,11 @@ weighted_patch_samples, ) from monai.utils import ImageMetaKey as Key -from monai.utils import Method, NumpyPadMode, ensure_tuple, ensure_tuple_rep, fall_back_tuple +from monai.utils import Method, NumpyPadMode, PytorchPadMode, ensure_tuple, ensure_tuple_rep, fall_back_tuple from monai.utils.enums import InverseKeys __all__ = [ - "NumpyPadModeSequence", + "PadModeSequence", "SpatialPadd", "BorderPadd", "DivisiblePadd", @@ -99,6 +99,7 @@ ] NumpyPadModeSequence = Union[Sequence[Union[NumpyPadMode, str]], NumpyPadMode, str] +PadModeSequence = Union[Sequence[Union[NumpyPadMode, PytorchPadMode, str]], NumpyPadMode, PytorchPadMode, str] class SpatialPadd(MapTransform, InvertibleTransform): @@ -114,9 +115,9 @@ def __init__( keys: KeysCollection, spatial_size: Union[Sequence[int], int], method: Union[Method, str] = Method.SYMMETRIC, - mode: NumpyPadModeSequence = NumpyPadMode.CONSTANT, + mode: PadModeSequence = NumpyPadMode.CONSTANT, allow_missing_keys: bool = False, - **np_kwargs, + **kwargs, ) -> None: """ Args: @@ -129,19 +130,21 @@ def __init__( the spatial size of output data will be [32, 30, 30]. method: {``"symmetric"``, ``"end"``} Pad image symmetrically on every side or only pad at the end sides. Defaults to ``"symmetric"``. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html It also can be a sequence of string, each element corresponds to a key in ``keys``. allow_missing_keys: don't raise exception if key is missing. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ super().__init__(keys, allow_missing_keys) self.mode = ensure_tuple_rep(mode, len(self.keys)) - self.padder = SpatialPad(spatial_size, method, **np_kwargs) + self.padder = SpatialPad(spatial_size, method, **kwargs) def __call__(self, data: Mapping[Hashable, NdarrayTensor]) -> Dict[Hashable, NdarrayTensor]: d = dict(data) @@ -183,9 +186,9 @@ def __init__( self, keys: KeysCollection, spatial_border: Union[Sequence[int], int], - mode: NumpyPadModeSequence = NumpyPadMode.CONSTANT, + mode: PadModeSequence = NumpyPadMode.CONSTANT, allow_missing_keys: bool = False, - **np_kwargs, + **kwargs, ) -> None: """ Args: @@ -202,19 +205,21 @@ def __init__( pad bottom of H dim with 2, pad left of W dim with 3, pad right of W dim with 4. the result shape is [1, 7, 11]. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html It also can be a sequence of string, each element corresponds to a key in ``keys``. allow_missing_keys: don't raise exception if key is missing. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ super().__init__(keys, allow_missing_keys) self.mode = ensure_tuple_rep(mode, len(self.keys)) - self.padder = BorderPad(spatial_border=spatial_border, **np_kwargs) + self.padder = BorderPad(spatial_border=spatial_border, **kwargs) def __call__(self, data: Mapping[Hashable, NdarrayTensor]) -> Dict[Hashable, NdarrayTensor]: d = dict(data) @@ -260,10 +265,10 @@ def __init__( self, keys: KeysCollection, k: Union[Sequence[int], int], - mode: NumpyPadModeSequence = NumpyPadMode.CONSTANT, + mode: PadModeSequence = NumpyPadMode.CONSTANT, method: Union[Method, str] = Method.SYMMETRIC, allow_missing_keys: bool = False, - **np_kwargs, + **kwargs, ) -> None: """ Args: @@ -272,23 +277,25 @@ def __init__( k: the target k for each spatial dimension. if `k` is negative or 0, the original size is preserved. if `k` is an int, the same `k` be applied to all the input spatial dimensions. - mode: {``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, ``"mean"``, - ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. One of the listed string values or a user supplied function. Defaults to ``"constant"``. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html It also can be a sequence of string, each element corresponds to a key in ``keys``. method: {``"symmetric"``, ``"end"``} Pad image symmetrically on every side or only pad at the end sides. Defaults to ``"symmetric"``. allow_missing_keys: don't raise exception if key is missing. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. See also :py:class:`monai.transforms.SpatialPad` """ super().__init__(keys, allow_missing_keys) self.mode = ensure_tuple_rep(mode, len(self.keys)) - self.padder = DivisiblePad(k=k, method=method, **np_kwargs) + self.padder = DivisiblePad(k=k, method=method, **kwargs) def __call__(self, data: Mapping[Hashable, NdarrayTensor]) -> Dict[Hashable, NdarrayTensor]: d = dict(data) diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 816e9d58f2..a9cb847b93 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -38,6 +38,7 @@ GridSamplePadMode, InterpolateMode, NumpyPadMode, + PytorchPadMode, ensure_tuple, ensure_tuple_rep, ensure_tuple_size, @@ -47,7 +48,7 @@ ) from monai.utils.enums import TransformBackends from monai.utils.module import look_up_option -from monai.utils.type_conversion import convert_data_type +from monai.utils.type_conversion import convert_data_type, convert_to_dst_type nib, _ = optional_import("nibabel") @@ -543,54 +544,60 @@ class Zoom(Transform): mode: {``"nearest"``, ``"linear"``, ``"bilinear"``, ``"bicubic"``, ``"trilinear"``, ``"area"``} The interpolation mode. Defaults to ``"area"``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate - padding_mode: {``"constant"``, ``"edge``", ``"linear_ramp``", ``"maximum``", ``"mean``", `"median``", - ``"minimum``", `"reflect``", ``"symmetric``", ``"wrap``", ``"empty``", ``"``"} + padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to ``"constant"``. The mode to pad data after zooming. - See also: https://numpy.org/doc/stable/reference/generated/numpy.pad.html + See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: None. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate keep_size: Should keep original size (padding/slicing if needed), default is True. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ - backend = [TransformBackends.TORCH] + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] def __init__( self, zoom: Union[Sequence[float], float], mode: Union[InterpolateMode, str] = InterpolateMode.AREA, - padding_mode: Union[NumpyPadMode, str] = NumpyPadMode.EDGE, + padding_mode: Union[NumpyPadMode, PytorchPadMode, str] = NumpyPadMode.EDGE, align_corners: Optional[bool] = None, keep_size: bool = True, - **np_kwargs, + **kwargs, ) -> None: self.zoom = zoom self.mode: InterpolateMode = InterpolateMode(mode) - self.padding_mode: NumpyPadMode = NumpyPadMode(padding_mode) + self.padding_mode = padding_mode self.align_corners = align_corners self.keep_size = keep_size - self.np_kwargs = np_kwargs + self.kwargs = kwargs def __call__( self, img: NdarrayOrTensor, mode: Optional[Union[InterpolateMode, str]] = None, - padding_mode: Optional[Union[NumpyPadMode, str]] = None, + padding_mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, align_corners: Optional[bool] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: channel first array, must have shape: (num_channels, H[, W, ..., ]). mode: {``"nearest"``, ``"linear"``, ``"bilinear"``, ``"bicubic"``, ``"trilinear"``, ``"area"``} The interpolation mode. Defaults to ``self.mode``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate - padding_mode: {``"constant"``, ``"edge``", ``"linear_ramp``", ``"maximum``", ``"mean``", `"median``", - ``"minimum``", `"reflect``", ``"symmetric``", ``"wrap``", ``"empty``", ``"``"} - The mode to pad data after zooming, default to ``self.padding_mode``. - See also: https://numpy.org/doc/stable/reference/generated/numpy.pad.html + padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to ``"constant"``. + The mode to pad data after zooming. + See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Defaults to ``self.align_corners``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate @@ -621,12 +628,12 @@ def __call__( elif diff < 0: # need slicing slice_vec[idx] = slice(half, half + od) - padding_mode = look_up_option(padding_mode or self.padding_mode, NumpyPadMode) - padder = Pad(pad_vec, padding_mode) + padder = Pad(pad_vec, padding_mode or self.padding_mode) zoomed = padder(zoomed) zoomed = zoomed[tuple(slice_vec)] - return zoomed + out, *_ = convert_to_dst_type(zoomed, dst=img) + return out class Rotate90(Transform): @@ -887,16 +894,19 @@ class RandZoom(RandomizableTransform): mode: {``"nearest"``, ``"linear"``, ``"bilinear"``, ``"bicubic"``, ``"trilinear"``, ``"area"``} The interpolation mode. Defaults to ``"area"``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate - padding_mode: {``"constant"``, ``"edge``", ``"linear_ramp``", ``"maximum``", ``"mean``", `"median``", - ``"minimum``", `"reflect``", ``"symmetric``", ``"wrap``", ``"empty``", ``"``"} + padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to ``"constant"``. The mode to pad data after zooming. - See also: https://numpy.org/doc/stable/reference/generated/numpy.pad.html + See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: None. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate keep_size: Should keep original size (pad if needed), default is True. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ @@ -908,10 +918,10 @@ def __init__( min_zoom: Union[Sequence[float], float] = 0.9, max_zoom: Union[Sequence[float], float] = 1.1, mode: Union[InterpolateMode, str] = InterpolateMode.AREA, - padding_mode: Union[NumpyPadMode, str] = NumpyPadMode.EDGE, + padding_mode: Union[NumpyPadMode, PytorchPadMode, str] = NumpyPadMode.EDGE, align_corners: Optional[bool] = None, keep_size: bool = True, - **np_kwargs, + **kwargs, ) -> None: RandomizableTransform.__init__(self, prob) self.min_zoom = ensure_tuple(min_zoom) @@ -919,10 +929,10 @@ def __init__( if len(self.min_zoom) != len(self.max_zoom): raise AssertionError("min_zoom and max_zoom must have same length.") self.mode: InterpolateMode = look_up_option(mode, InterpolateMode) - self.padding_mode: NumpyPadMode = look_up_option(padding_mode, NumpyPadMode) + self.padding_mode = padding_mode self.align_corners = align_corners self.keep_size = keep_size - self.np_kwargs = np_kwargs + self.kwargs = kwargs self._zoom: Sequence[float] = [1.0] @@ -934,19 +944,22 @@ def __call__( self, img: NdarrayOrTensor, mode: Optional[Union[InterpolateMode, str]] = None, - padding_mode: Optional[Union[NumpyPadMode, str]] = None, + padding_mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, align_corners: Optional[bool] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: channel first array, must have shape 2D: (nchannels, H, W), or 3D: (nchannels, H, W, D). mode: {``"nearest"``, ``"linear"``, ``"bilinear"``, ``"bicubic"``, ``"trilinear"``, ``"area"``} The interpolation mode. Defaults to ``self.mode``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate - padding_mode: {``"constant"``, ``"edge``", ``"linear_ramp``", ``"maximum``", ``"mean``", `"median``", - ``"minimum``", `"reflect``", ``"symmetric``", ``"wrap``", ``"empty``", ``"``"} - The mode to pad data after zooming, default to ``self.padding_mode``. - See also: https://numpy.org/doc/stable/reference/generated/numpy.pad.html + padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to ``"constant"``. + The mode to pad data after zooming. + See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Defaults to ``self.align_corners``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate @@ -967,9 +980,9 @@ def __call__( self._zoom, keep_size=self.keep_size, mode=look_up_option(mode or self.mode, InterpolateMode), - padding_mode=look_up_option(padding_mode or self.padding_mode, NumpyPadMode), + padding_mode=padding_mode or self.padding_mode, align_corners=align_corners or self.align_corners, - **self.np_kwargs, + **self.kwargs, ) return zoomer(img) diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index c09d8e8011..96fe21db12 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -50,6 +50,7 @@ GridSamplePadMode, InterpolateMode, NumpyPadMode, + PytorchPadMode, ensure_tuple, ensure_tuple_rep, fall_back_tuple, @@ -115,7 +116,7 @@ GridSampleModeSequence = Union[Sequence[Union[GridSampleMode, str]], GridSampleMode, str] GridSamplePadModeSequence = Union[Sequence[Union[GridSamplePadMode, str]], GridSamplePadMode, str] InterpolateModeSequence = Union[Sequence[Union[InterpolateMode, str]], InterpolateMode, str] -NumpyPadModeSequence = Union[Sequence[Union[NumpyPadMode, str]], NumpyPadMode, str] +PadModeSequence = Union[Sequence[Union[NumpyPadMode, PytorchPadMode, str]], NumpyPadMode, PytorchPadMode, str] class Spacingd(MapTransform, InvertibleTransform): @@ -1520,18 +1521,21 @@ class Zoomd(MapTransform, InvertibleTransform): The interpolation mode. Defaults to ``"area"``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate It also can be a sequence of string, each element corresponds to a key in ``keys``. - padding_mode: {``"constant"``, ``"edge``", ``"linear_ramp``", ``"maximum``", ``"mean``", `"median``", - ``"minimum``", `"reflect``", ``"symmetric``", ``"wrap``", ``"empty``", ``"``"} + padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to ``"constant"``. The mode to pad data after zooming. - See also: https://numpy.org/doc/stable/reference/generated/numpy.pad.html + See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: None. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate It also can be a sequence of bool or None, each element corresponds to a key in ``keys``. keep_size: Should keep original size (pad if needed), default is True. allow_missing_keys: don't raise exception if key is missing. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. - more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + kwargs: other arguments for the `np.pad` or `torch.pad` function. + note that `np.pad` treats channel dimension as the first dimension. """ @@ -1542,17 +1546,17 @@ def __init__( keys: KeysCollection, zoom: Union[Sequence[float], float], mode: InterpolateModeSequence = InterpolateMode.AREA, - padding_mode: NumpyPadModeSequence = NumpyPadMode.EDGE, + padding_mode: PadModeSequence = NumpyPadMode.EDGE, align_corners: Union[Sequence[Optional[bool]], Optional[bool]] = None, keep_size: bool = True, allow_missing_keys: bool = False, - **np_kwargs, + **kwargs, ) -> None: super().__init__(keys, allow_missing_keys) self.mode = ensure_tuple_rep(mode, len(self.keys)) self.padding_mode = ensure_tuple_rep(padding_mode, len(self.keys)) self.align_corners = ensure_tuple_rep(align_corners, len(self.keys)) - self.zoomer = Zoom(zoom=zoom, keep_size=keep_size, **np_kwargs) + self.zoomer = Zoom(zoom=zoom, keep_size=keep_size, **kwargs) def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) @@ -1622,17 +1626,20 @@ class RandZoomd(RandomizableTransform, MapTransform, InvertibleTransform): The interpolation mode. Defaults to ``"area"``. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate It also can be a sequence of string, each element corresponds to a key in ``keys``. - padding_mode: {``"constant"``, ``"edge``", ``"linear_ramp``", ``"maximum``", ``"mean``", `"median``", - ``"minimum``", `"reflect``", ``"symmetric``", ``"wrap``", ``"empty``", ``"``"} + padding_mode: available modes for numpy array:{``"constant"``, ``"edge"``, ``"linear_ramp"``, ``"maximum"``, + ``"mean"``, ``"median"``, ``"minimum"``, ``"reflect"``, ``"symmetric"``, ``"wrap"``, ``"empty"``} + available modes for PyTorch Tensor: {``"constant"``, ``"reflect"``, ``"replicate"``, ``"circular"``}. + One of the listed string values or a user supplied function. Defaults to ``"constant"``. The mode to pad data after zooming. - See also: https://numpy.org/doc/stable/reference/generated/numpy.pad.html + See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html + https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html align_corners: This only has an effect when mode is 'linear', 'bilinear', 'bicubic' or 'trilinear'. Default: None. See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate It also can be a sequence of bool or None, each element corresponds to a key in ``keys``. keep_size: Should keep original size (pad if needed), default is True. allow_missing_keys: don't raise exception if key is missing. - np_kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. + kwargs: other args for `np.pad` API, note that `np.pad` treats channel dimension as the first dimension. more details: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html """ @@ -1646,11 +1653,11 @@ def __init__( min_zoom: Union[Sequence[float], float] = 0.9, max_zoom: Union[Sequence[float], float] = 1.1, mode: InterpolateModeSequence = InterpolateMode.AREA, - padding_mode: NumpyPadModeSequence = NumpyPadMode.EDGE, + padding_mode: PadModeSequence = NumpyPadMode.EDGE, align_corners: Union[Sequence[Optional[bool]], Optional[bool]] = None, keep_size: bool = True, allow_missing_keys: bool = False, - **np_kwargs, + **kwargs, ) -> None: MapTransform.__init__(self, keys, allow_missing_keys) RandomizableTransform.__init__(self, prob) @@ -1663,7 +1670,7 @@ def __init__( self.padding_mode = ensure_tuple_rep(padding_mode, len(self.keys)) self.align_corners = ensure_tuple_rep(align_corners, len(self.keys)) self.keep_size = keep_size - self.np_kwargs = np_kwargs + self.kwargs = kwargs self._zoom: Sequence[float] = [1.0] @@ -1683,7 +1690,7 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N elif len(self._zoom) == 2 and img_dims > 3: # if 2 zoom factors provided for 3D data, use the first factor for H and W dims, second factor for D dim self._zoom = ensure_tuple_rep(self._zoom[0], img_dims - 2) + ensure_tuple(self._zoom[-1]) - zoomer = Zoom(self._zoom, keep_size=self.keep_size, **self.np_kwargs) + zoomer = Zoom(self._zoom, keep_size=self.keep_size, **self.kwargs) for key, mode, padding_mode, align_corners in self.key_iterator( d, self.mode, self.padding_mode, self.align_corners ): diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 9618723430..f0be87de0b 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -22,7 +22,7 @@ import monai import monai.transforms.transform from monai.config import DtypeLike, IndexSelection -from monai.config.type_definitions import NdarrayOrTensor +from monai.config.type_definitions import NdarrayOrTensor, NdarrayTensor from monai.networks.layers import GaussianFilter from monai.transforms.compose import Compose, OneOf from monai.transforms.transform import MapTransform, Transform @@ -30,12 +30,15 @@ GridSampleMode, InterpolateMode, InverseKeys, + NumpyPadMode, + PytorchPadMode, deprecated_arg, ensure_tuple, ensure_tuple_rep, ensure_tuple_size, fall_back_tuple, issequenceiterable, + look_up_option, min_version, optional_import, ) @@ -85,6 +88,7 @@ "get_number_image_type_conversions", "get_transform_backends", "print_transform_backends", + "convert_pad_mode", ] @@ -1259,5 +1263,30 @@ def print_table_column(name, torch, numpy, color=Colors.none): print_color(f"Number of uncategorised: {n_uncategorized}", Colors.red) +def convert_pad_mode(dst: NdarrayTensor, mode: Union[NumpyPadMode, PytorchPadMode, str]): + """ + Utility to convert padding mode between numpy array and PyTorch Tensor. + + Args: + dst: target data to convert padding mode for, should be numpy array or PyTorch Tensor. + mode: current padding mode. + + """ + mode = mode.value if isinstance(mode, (NumpyPadMode, PytorchPadMode)) else mode + if isinstance(dst, torch.Tensor): + if mode == "wrap": + mode = "circular" + if mode == "edge": + mode = "replicate" + return look_up_option(mode, PytorchPadMode) + if isinstance(dst, np.ndarray): + if mode == "circular": + mode = "wrap" + if mode == "replicate": + mode = "edge" + return look_up_option(mode, NumpyPadMode) + raise ValueError(f"unsupported data type: {type(dst)}.") + + if __name__ == "__main__": print_transform_backends() diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index 47b48aa2b8..b51ff6a9c8 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -206,7 +206,9 @@ def convert_data_type( def convert_to_dst_type(src: Any, dst: NdarrayOrTensor) -> Tuple[NdarrayOrTensor, type, Optional[torch.device]]: """ - Convert `src` to the same `torch.Tensor`/`np.ndarray` and data type as `dst`. + If `dst` is `torch.Tensor` or its subclass, convert `src` to `torch.Tensor` with the same data type as `dst`, + if `dst` is `numpy.ndarray` or its subclass, convert to `numpy.ndarray` with the same data type as `dst`, + otherwise, convert to the type of `dst` directly. See Also: :func:`convert_data_type` @@ -214,4 +216,12 @@ def convert_to_dst_type(src: Any, dst: NdarrayOrTensor) -> Tuple[NdarrayOrTensor device = None if isinstance(dst, torch.Tensor): device = dst.device - return convert_data_type(data=src, output_type=type(dst), device=device, dtype=dst.dtype) + + output_type: Any + if isinstance(dst, torch.Tensor): + output_type = torch.Tensor + elif isinstance(dst, np.ndarray): + output_type = np.ndarray + else: + output_type = type(dst) + return convert_data_type(data=src, output_type=output_type, device=device, dtype=dst.dtype) diff --git a/tests/test_convert_data_type.py b/tests/test_convert_data_type.py index a7fc64f950..e48f6e8854 100644 --- a/tests/test_convert_data_type.py +++ b/tests/test_convert_data_type.py @@ -25,6 +25,10 @@ TESTS.append((in_type(np.array(1.0)), out_type(np.array(1.0)))) # type: ignore +class TestTensor(torch.Tensor): + pass + + class TestConvertDataType(unittest.TestCase): @parameterized.expand(TESTS) def test_convert_data_type(self, in_image, im_out): @@ -49,7 +53,8 @@ def test_ill_arg(self): class TestConvertDataSame(unittest.TestCase): - @parameterized.expand(TESTS) + # add test for subclass of Tensor + @parameterized.expand(TESTS + [(np.array(1.0), TestTensor(np.array(1.0)))]) def test_convert_data_type(self, in_image, im_out): converted_im, orig_type, orig_device = convert_to_dst_type(in_image, im_out) # check input is unchanged @@ -57,7 +62,11 @@ def test_convert_data_type(self, in_image, im_out): if isinstance(in_image, torch.Tensor): self.assertEqual(in_image.device, orig_device) # check output is desired type - self.assertEqual(type(converted_im), type(im_out)) + if isinstance(im_out, torch.Tensor): + output_type = torch.Tensor + else: + output_type = np.ndarray + self.assertEqual(type(converted_im), output_type) # check dtype is unchanged if isinstance(in_type, (np.ndarray, torch.Tensor)): self.assertEqual(converted_im.dtype, im_out.dtype) diff --git a/tests/test_divisible_pad.py b/tests/test_divisible_pad.py index ca15b4b347..810d08252c 100644 --- a/tests/test_divisible_pad.py +++ b/tests/test_divisible_pad.py @@ -50,11 +50,13 @@ def test_pad_shape(self, input_param, input_data, expected_val): self.assertAlmostEqual(result.shape, expected_val.shape) def test_pad_kwargs(self): - padder = DivisiblePad(k=5, mode="constant", constant_values=((0, 0), (1, 1), (2, 2))) for p in TEST_NDARRAYS: - result = padder(p(np.zeros((3, 8, 4)))) - result = result.cpu() if isinstance(result, torch.Tensor) else result - torch.testing.assert_allclose(result[:, :1, :4], np.ones((3, 1, 4)), rtol=1e-7, atol=0) + input_data = p(np.zeros((3, 8, 4))) + if isinstance(input_data, np.ndarray): + result = DivisiblePad(k=5, mode="constant", constant_values=((0, 0), (1, 1), (2, 2)))(input_data) + np.testing.assert_allclose(result[:, :1, :4], np.ones((3, 1, 4)), rtol=1e-7, atol=0) + else: + result = DivisiblePad(k=5, mode="constant", value=2)(input_data).cpu() torch.testing.assert_allclose(result[:, :, 4:5], np.ones((3, 10, 1)) + 1, rtol=1e-7, atol=0) diff --git a/tests/test_pad_collation.py b/tests/test_pad_collation.py index 47bfa69582..eda36f4761 100644 --- a/tests/test_pad_collation.py +++ b/tests/test_pad_collation.py @@ -38,8 +38,8 @@ TESTS: List[Tuple] = [] for pad_collate in [ - lambda x: pad_list_data_collate(batch=x, method="end", mode="constant", constant_values=1), - PadListDataCollate(method="end", mode="constant", constant_values=1), + lambda x: pad_list_data_collate(batch=x, method="end", mode="constant"), + PadListDataCollate(method="end", mode="constant"), ]: TESTS.append((dict, pad_collate, RandSpatialCropd("image", roi_size=[8, 7], random_size=True))) TESTS.append((dict, pad_collate, RandRotated("image", prob=1, range_x=np.pi, keep_size=False))) diff --git a/tests/test_spatial_pad.py b/tests/test_spatial_pad.py index 86d010bbad..3d237c6681 100644 --- a/tests/test_spatial_pad.py +++ b/tests/test_spatial_pad.py @@ -17,34 +17,41 @@ from parameterized import parameterized from monai.transforms import SpatialPad -from monai.utils.enums import NumpyPadMode +from monai.utils.enums import NumpyPadMode, PytorchPadMode from monai.utils.misc import set_determinism from tests.utils import TEST_NDARRAYS TESTS = [] -# Numpy modes -MODES: List = [ +MODES = [] + +# Test modes +NP_MODES: List = [ "constant", "edge", - "linear_ramp", - "maximum", - "mean", - "median", - "minimum", - "reflect", - "symmetric", + # `reflect` mode is not supported in some PyTorch versions, skip the test + # "reflect", "wrap", - "empty", ] -MODES += [NumpyPadMode(i) for i in MODES] +MODES += NP_MODES +MODES += [NumpyPadMode(i) for i in NP_MODES] + +PT_MODES: list = [ + "constant", + "replicate", + "circular", + # `reflect` mode is not supported in some PyTorch versions, skip the test + # "reflect", +] +MODES += PT_MODES +MODES += [PytorchPadMode(i) for i in PT_MODES] for mode in MODES: TESTS.append( [ - {"spatial_size": [50, 50], "method": "end", "mode": mode}, - (1, 2, 2), - (1, 50, 50), + {"spatial_size": [3, 4], "method": "end", "mode": mode}, + (1, 2, 3), + (1, 3, 4), ] ) @@ -86,14 +93,19 @@ def test_pad_shape(self, input_param, input_shape, expected_shape): torch.testing.assert_allclose(results[0], results[-1], atol=0, rtol=1e-5) def test_pad_kwargs(self): - padder = SpatialPad( - spatial_size=[15, 8], method="end", mode="constant", constant_values=((0, 0), (1, 1), (2, 2)) - ) for p in TEST_NDARRAYS: - result = padder(p(np.zeros((3, 8, 4)))) - if isinstance(result, torch.Tensor): - result = result.cpu().numpy() - torch.testing.assert_allclose(result[:, 8:, :4], np.ones((3, 7, 4)), rtol=1e-7, atol=0) + input_data = p(np.zeros((3, 8, 4))) + if isinstance(input_data, torch.Tensor): + result = ( + SpatialPad(spatial_size=[15, 8], method="end", mode="constant", value=2)(img=input_data) + .cpu() + .numpy() + ) + else: + result = SpatialPad( + spatial_size=[15, 8], method="end", mode="constant", constant_values=((0, 0), (1, 1), (2, 2)) + )(img=input_data) + torch.testing.assert_allclose(result[:, 8:, :4], np.ones((3, 7, 4)), rtol=1e-7, atol=0) torch.testing.assert_allclose(result[:, :, 4:], np.ones((3, 15, 4)) + 1, rtol=1e-7, atol=0) From 1c2608fa3c84807b1fa8fdfcf41dcfa676514a74 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Mon, 13 Sep 2021 15:37:28 +0100 Subject: [PATCH 09/89] fixes #2939 (#2940) Signed-off-by: Wenqi Li --- monai/_extensions/loader.py | 2 +- monai/data/grid_dataset.py | 2 +- monai/data/utils.py | 4 ++-- monai/transforms/inverse_batch_transform.py | 2 +- monai/utils/aliases.py | 4 ++-- tests/utils.py | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/monai/_extensions/loader.py b/monai/_extensions/loader.py index 5f77480ecc..6c68fe08c7 100644 --- a/monai/_extensions/loader.py +++ b/monai/_extensions/loader.py @@ -34,7 +34,7 @@ def timeout(time, message): except KeyboardInterrupt as e: if timer is not None and timer.is_alive(): raise e # interrupt from user? - raise TimeoutError(message) + raise TimeoutError(message) from e finally: if timer is not None: try: diff --git a/monai/data/grid_dataset.py b/monai/data/grid_dataset.py index 5b2a4d7abd..5c330f10e4 100644 --- a/monai/data/grid_dataset.py +++ b/monai/data/grid_dataset.py @@ -141,7 +141,7 @@ def __iter__(self): try: iter_end = len(self.dataset) # TODO: support iterable self.dataset except TypeError: - raise NotImplementedError("image dataset must implement `len()`.") + raise NotImplementedError("image dataset must implement `len()`.") from None if worker_info is not None: # split workload diff --git a/monai/data/utils.py b/monai/data/utils.py index aab23217dc..a5cb5057d4 100644 --- a/monai/data/utils.py +++ b/monai/data/utils.py @@ -283,7 +283,7 @@ def list_data_collate(batch: Sequence): + "`DataLoader` with `collate_fn=pad_list_data_collate` might solve this problem (check its " + "documentation)." ) - raise RuntimeError(re_str) + raise RuntimeError(re_str) from re except TypeError as re: re_str = str(re) if "numpy" in re_str and "Tensor" in re_str: @@ -294,7 +294,7 @@ def list_data_collate(batch: Sequence): + "creating your `DataLoader` with `collate_fn=pad_list_data_collate` might solve this problem " + "(check its documentation)." ) - raise TypeError(re_str) + raise TypeError(re_str) from re def decollate_batch(batch, detach: bool = True): diff --git a/monai/transforms/inverse_batch_transform.py b/monai/transforms/inverse_batch_transform.py index d9c6790840..b485e5bac4 100644 --- a/monai/transforms/inverse_batch_transform.py +++ b/monai/transforms/inverse_batch_transform.py @@ -99,7 +99,7 @@ def __call__(self, data: Dict[str, Any]) -> Any: re_str = str(re) if "equal size" in re_str: re_str += "\nMONAI hint: try creating `BatchInverseTransform` with `collate_fn=lambda x: x`." - raise RuntimeError(re_str) + raise RuntimeError(re_str) from re class Decollated(MapTransform): diff --git a/monai/utils/aliases.py b/monai/utils/aliases.py index 2b7b29eeb5..a08dab4f95 100644 --- a/monai/utils/aliases.py +++ b/monai/utils/aliases.py @@ -70,8 +70,8 @@ def resolve_name(name): try: mod = importlib.import_module(modname) obj = getattr(mod, declname, None) - except ModuleNotFoundError: - raise ValueError(f"Module {modname!r} not found.") + except ModuleNotFoundError as not_found_err: + raise ValueError(f"Module {modname!r} not found.") from not_found_err if obj is None: raise ValueError(f"Module {modname!r} does not have member {declname!r}.") diff --git a/tests/utils.py b/tests/utils.py index 1375cd2d72..3364085e13 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -74,7 +74,7 @@ def test_pretrained_networks(network, input_param, device): try: net = network(**input_param).to(device) except (URLError, HTTPError, ContentTooShortError) as e: - raise unittest.SkipTest(e) + raise unittest.SkipTest(e) from e return net From 76dc5c2774b46ee447ec11cb41ec834a0c84654c Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Mon, 13 Sep 2021 16:30:10 +0100 Subject: [PATCH 10/89] enhance docstring (#2938) Signed-off-by: Wenqi Li --- monai/networks/nets/autoencoder.py | 4 ++++ monai/networks/nets/varautoencoder.py | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/monai/networks/nets/autoencoder.py b/monai/networks/nets/autoencoder.py index 08b84d0566..ed5e351779 100644 --- a/monai/networks/nets/autoencoder.py +++ b/monai/networks/nets/autoencoder.py @@ -22,6 +22,10 @@ class AutoEncoder(nn.Module): + """ + Base class for the architecture implementing :py:class:`monai.networks.nets.VarAutoEncoder`. + """ + @deprecated_arg( name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." ) diff --git a/monai/networks/nets/varautoencoder.py b/monai/networks/nets/varautoencoder.py index 31e187106f..3baa59531a 100644 --- a/monai/networks/nets/varautoencoder.py +++ b/monai/networks/nets/varautoencoder.py @@ -28,6 +28,23 @@ class VarAutoEncoder(AutoEncoder): """ Variational Autoencoder based on the paper - https://arxiv.org/abs/1312.6114 + .. code-block:: python + + from monai.networks.nets import VarAutoEncoder + + model = VarAutoEncoder( + dimensions=2, + in_shape=(32, 32), # image spatial shape + out_channels=1, + latent_size=2, + channels=(16, 32, 64), + strides=(1, 2, 2), + ) + + see also: + - Variational autoencoder network with MedNIST Dataset + https://github.com/Project-MONAI/tutorials/blob/master/modules/varautoencoder_mednist.ipynb + .. deprecated:: 0.6.0 ``dimensions`` is deprecated, use ``spatial_dims`` instead. """ From 8651b622df76b75a9477538e985a14896f827150 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Tue, 14 Sep 2021 00:59:04 +0800 Subject: [PATCH 11/89] [DLMED] enhance scale intensity transforms (#2941) Signed-off-by: Nic Ma --- monai/transforms/intensity/array.py | 23 ++++++++++++++++++----- monai/transforms/intensity/dictionary.py | 9 +++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index f6d4dfff5a..311534aa8b 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -379,7 +379,11 @@ class ScaleIntensity(Transform): backend = [TransformBackends.TORCH, TransformBackends.NUMPY] def __init__( - self, minv: Optional[float] = 0.0, maxv: Optional[float] = 1.0, factor: Optional[float] = None + self, + minv: Optional[float] = 0.0, + maxv: Optional[float] = 1.0, + factor: Optional[float] = None, + dtype: DtypeLike = np.float32, ) -> None: """ Args: @@ -387,10 +391,12 @@ def __init__( maxv: maximum value of output data. factor: factor scale by ``v = v * (1 + factor)``. In order to use this parameter, please set `minv` and `maxv` into None. + dtype: output data type, defaults to float32. """ self.minv = minv self.maxv = maxv self.factor = factor + self.dtype = dtype def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ @@ -401,10 +407,10 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ if self.minv is not None and self.maxv is not None: - return rescale_array(img, self.minv, self.maxv, img.dtype) + return rescale_array(img, self.minv, self.maxv, dtype=self.dtype) if self.factor is not None: out = img * (1 + self.factor) - out, *_ = convert_data_type(out, dtype=img.dtype) + out, *_ = convert_data_type(out, dtype=self.dtype) return out raise ValueError("Incompatible values: minv=None or maxv=None and factor=None.") @@ -417,12 +423,18 @@ class RandScaleIntensity(RandomizableTransform): backend = ScaleIntensity.backend - def __init__(self, factors: Union[Tuple[float, float], float], prob: float = 0.1) -> None: + def __init__( + self, + factors: Union[Tuple[float, float], float], + prob: float = 0.1, + dtype: DtypeLike = np.float32, + ) -> None: """ Args: factors: factor range to randomly scale by ``v = v * (1 + factor)``. if single number, factor value is picked from (-factors, factors). prob: probability of scale. + dtype: output data type, defaults to float32. """ RandomizableTransform.__init__(self, prob) @@ -433,6 +445,7 @@ def __init__(self, factors: Union[Tuple[float, float], float], prob: float = 0.1 else: self.factors = (min(factors), max(factors)) self.factor = self.factors[0] + self.dtype = dtype def randomize(self, data: Optional[Any] = None) -> None: self.factor = self.R.uniform(low=self.factors[0], high=self.factors[1]) @@ -445,7 +458,7 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: self.randomize() if not self._do_transform: return img - scaler = ScaleIntensity(minv=None, maxv=None, factor=self.factor) + scaler = ScaleIntensity(minv=None, maxv=None, factor=self.factor, dtype=self.dtype) return scaler(img) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index ca24980359..22b1edd5fd 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -488,6 +488,7 @@ def __init__( minv: Optional[float] = 0.0, maxv: Optional[float] = 1.0, factor: Optional[float] = None, + dtype: DtypeLike = np.float32, allow_missing_keys: bool = False, ) -> None: """ @@ -498,11 +499,12 @@ def __init__( maxv: maximum value of output data. factor: factor scale by ``v = v * (1 + factor)``. In order to use this parameter, please set `minv` and `maxv` into None. + dtype: output data type, defaults to float32. allow_missing_keys: don't raise exception if key is missing. """ super().__init__(keys, allow_missing_keys) - self.scaler = ScaleIntensity(minv, maxv, factor) + self.scaler = ScaleIntensity(minv, maxv, factor, dtype) def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) @@ -523,6 +525,7 @@ def __init__( keys: KeysCollection, factors: Union[Tuple[float, float], float], prob: float = 0.1, + dtype: DtypeLike = np.float32, allow_missing_keys: bool = False, ) -> None: """ @@ -533,6 +536,7 @@ def __init__( if single number, factor value is picked from (-factors, factors). prob: probability of rotating. (Default 0.1, with 10% probability it returns a rotated array.) + dtype: output data type, defaults to float32. allow_missing_keys: don't raise exception if key is missing. """ @@ -546,6 +550,7 @@ def __init__( else: self.factors = (min(factors), max(factors)) self.factor = self.factors[0] + self.dtype = dtype def randomize(self, data: Optional[Any] = None) -> None: self.factor = self.R.uniform(low=self.factors[0], high=self.factors[1]) @@ -556,7 +561,7 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N self.randomize() if not self._do_transform: return d - scaler = ScaleIntensity(minv=None, maxv=None, factor=self.factor) + scaler = ScaleIntensity(minv=None, maxv=None, factor=self.factor, dtype=self.dtype) for key in self.key_iterator(d): d[key] = scaler(d[key]) return d From 132aa373d773f7a7a104eeb09da55e612036b190 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Mon, 13 Sep 2021 19:20:09 +0100 Subject: [PATCH 12/89] 2715 enhance resnet downsampling block (#2937) * con1_padding -> conv1_padding Signed-off-by: Wenqi Li * simpler init. Signed-off-by: Wenqi Li * fixes 2715 Signed-off-by: Wenqi Li * adds 3d tests Signed-off-by: Wenqi Li * fixes flake8 error Signed-off-by: Wenqi Li --- monai/networks/nets/resnet.py | 39 ++++++++++++++++++++--------------- tests/test_resnet.py | 14 ++++++++++++- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/monai/networks/nets/resnet.py b/monai/networks/nets/resnet.py index a5e6b7ab81..3b86dc3d62 100644 --- a/monai/networks/nets/resnet.py +++ b/monai/networks/nets/resnet.py @@ -14,9 +14,10 @@ import torch import torch.nn as nn -import torch.nn.functional as F from monai.networks.layers.factories import Conv, Norm, Pool +from monai.networks.layers.utils import get_pool_layer +from monai.utils.module import look_up_option __all__ = ["ResNet", "resnet10", "resnet18", "resnet34", "resnet50", "resnet101", "resnet152", "resnet200"] @@ -162,7 +163,9 @@ class ResNet(nn.Module): conv1_t_size: size of first convolution layer, determines kernel and padding. conv1_t_stride: stride of first convolution layer. no_max_pool: bool argument to determine if to use maxpool layer. - shortcut_type: which downsample block to use. + shortcut_type: which downsample block to use. Options are 'A', 'B', default to 'B'. + - 'A': using `self._downsample_basic_block`. + - 'B': kernel_size 1 conv + norm. widen_factor: widen output for each layer. num_classes: number of output (classifications) """ @@ -198,7 +201,7 @@ def __init__( ] block_avgpool = get_avgpool() - conv1_kernel, conv1_stride, con1_padding = get_conv1(conv1_t_size, conv1_t_stride) + conv1_kernel, conv1_stride, conv1_padding = get_conv1(conv1_t_size, conv1_t_stride) block_inplanes = [int(x * widen_factor) for x in block_inplanes] self.in_planes = block_inplanes[0] @@ -209,7 +212,7 @@ def __init__( self.in_planes, kernel_size=conv1_kernel[spatial_dims], stride=conv1_stride[spatial_dims], - padding=con1_padding[spatial_dims], + padding=conv1_padding[spatial_dims], bias=False, ) self.bn1 = norm_type(self.in_planes) @@ -234,14 +237,9 @@ def __init__( nn.init.constant_(torch.as_tensor(m.bias), 0) def _downsample_basic_block(self, x: torch.Tensor, planes: int, stride: int, spatial_dims: int = 3) -> torch.Tensor: - assert spatial_dims == 3 - out: torch.Tensor = F.avg_pool3d(x, kernel_size=1, stride=stride) - zero_pads = torch.zeros(out.size(0), planes - out.size(1), out.size(2), out.size(3), out.size(4)) - if isinstance(out.data, torch.FloatTensor): - zero_pads = zero_pads.cuda() - + out: torch.Tensor = get_pool_layer(("avg", {"kernel_size": 1, "stride": stride}), spatial_dims=spatial_dims)(x) + zero_pads = torch.zeros(out.size(0), planes - out.size(1), *out.shape[2:], dtype=out.dtype, device=out.device) out = torch.cat([out.data, zero_pads], dim=1) - return out def _make_layer( @@ -259,9 +257,12 @@ def _make_layer( downsample: Union[nn.Module, partial, None] = None if stride != 1 or self.in_planes != planes * block.expansion: - if shortcut_type == "A": + if look_up_option(shortcut_type, {"A", "B"}) == "A": downsample = partial( - self._downsample_basic_block, planes=planes * block.expansion, kernel_size=1, stride=stride + self._downsample_basic_block, + planes=planes * block.expansion, + stride=stride, + spatial_dims=spatial_dims, ) else: downsample = nn.Sequential( @@ -269,12 +270,16 @@ def _make_layer( norm_type(planes * block.expansion), ) - layers = [] - layers.append( + layers = [ block( - in_planes=self.in_planes, planes=planes, spatial_dims=spatial_dims, stride=stride, downsample=downsample + in_planes=self.in_planes, + planes=planes, + spatial_dims=spatial_dims, + stride=stride, + downsample=downsample, ) - ) + ] + self.in_planes = planes * block.expansion for _i in range(1, blocks): layers.append(block(self.in_planes, planes, spatial_dims=spatial_dims)) diff --git a/tests/test_resnet.py b/tests/test_resnet.py index c4ba5c2e16..16cd6f4865 100644 --- a/tests/test_resnet.py +++ b/tests/test_resnet.py @@ -42,14 +42,26 @@ (2, 3), ] +TEST_CASE_2_A = [ # 2D, batch 2, 1 input channel, shortcut type A + {"pretrained": False, "spatial_dims": 2, "n_input_channels": 1, "num_classes": 3, "shortcut_type": "A"}, + (2, 1, 32, 64), + (2, 3), +] + TEST_CASE_3 = [ # 1D, batch 1, 2 input channels {"pretrained": False, "spatial_dims": 1, "n_input_channels": 2, "num_classes": 3}, (1, 2, 32), (1, 3), ] +TEST_CASE_3_A = [ # 1D, batch 1, 2 input channels + {"pretrained": False, "spatial_dims": 1, "n_input_channels": 2, "num_classes": 3, "shortcut_type": "A"}, + (1, 2, 32), + (1, 3), +] + TEST_CASES = [] -for case in [TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]: +for case in [TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_2_A, TEST_CASE_3_A]: for model in [resnet10, resnet18, resnet34, resnet50, resnet101, resnet152, resnet200]: TEST_CASES.append([model, *case]) From 8765fc7db6ab79457aebac88165f338d639d7a4e Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Mon, 13 Sep 2021 22:34:28 +0100 Subject: [PATCH 13/89] ThresholdIntensity, ThresholdIntensityd (#2944) * ThresholdIntensity, ThresholdIntensityd Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/__init__.py | 2 +- monai/transforms/intensity/array.py | 12 +++-- monai/transforms/intensity/dictionary.py | 4 +- .../utils_pytorch_numpy_unification.py | 15 ++++++ tests/test_threshold_intensity.py | 19 +++---- tests/test_threshold_intensityd.py | 52 +++++++++++-------- 6 files changed, 68 insertions(+), 36 deletions(-) diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index a07dee867b..9575a412b4 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -524,4 +524,4 @@ weighted_patch_samples, zero_margins, ) -from .utils_pytorch_numpy_unification import in1d, moveaxis +from .utils_pytorch_numpy_unification import in1d, moveaxis, where diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 311534aa8b..b6fa1f72b7 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -28,6 +28,7 @@ from monai.networks.layers import GaussianFilter, HilbertTransform, SavitzkyGolayFilter from monai.transforms.transform import RandomizableTransform, Transform from monai.transforms.utils import Fourier, equalize_hist, is_positive, rescale_array +from monai.transforms.utils_pytorch_numpy_unification import where from monai.utils import ( PT_BEFORE_1_7, InvalidPyTorchVersionError, @@ -655,6 +656,8 @@ class ThresholdIntensity(Transform): cval: value to fill the remaining parts of the image, default is 0. """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__(self, threshold: float, above: bool = True, cval: float = 0.0) -> None: if not isinstance(threshold, (int, float)): raise ValueError("threshold must be a float or int number.") @@ -662,13 +665,14 @@ def __init__(self, threshold: float, above: bool = True, cval: float = 0.0) -> N self.above = above self.cval = cval - def __call__(self, img: np.ndarray) -> np.ndarray: + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`. """ - return np.asarray( - np.where(img > self.threshold if self.above else img < self.threshold, img, self.cval), dtype=img.dtype - ) + mask = img > self.threshold if self.above else img < self.threshold + res = where(mask, img, self.cval) + res, *_ = convert_data_type(res, dtype=img.dtype) + return res class ScaleIntensityRange(Transform): diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index 22b1edd5fd..cccf3e2a90 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -664,6 +664,8 @@ class ThresholdIntensityd(MapTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = ThresholdIntensity.backend + def __init__( self, keys: KeysCollection, @@ -675,7 +677,7 @@ def __init__( super().__init__(keys, allow_missing_keys) self.filter = ThresholdIntensity(threshold, above, cval) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): d[key] = self.filter(d[key]) diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 2eebe3eda3..70ecb2848d 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -17,6 +17,7 @@ __all__ = [ "moveaxis", "in1d", + "where", ] @@ -50,3 +51,17 @@ def in1d(x, y): if isinstance(x, np.ndarray): return np.in1d(x, y) return (x[..., None] == torch.tensor(y, device=x.device)).any(-1).view(-1) + + +def where(condition: NdarrayOrTensor, x, y) -> NdarrayOrTensor: + """ + Note that `torch.where` may convert y.dtype to x.dtype. + """ + result: NdarrayOrTensor + if isinstance(condition, np.ndarray): + result = np.where(condition, x, y) + else: + x = torch.as_tensor(x, device=condition.device) + y = torch.as_tensor(y, device=condition.device, dtype=x.dtype) + result = torch.where(condition, x, y) + return result diff --git a/tests/test_threshold_intensity.py b/tests/test_threshold_intensity.py index a6d3895709..0614514456 100644 --- a/tests/test_threshold_intensity.py +++ b/tests/test_threshold_intensity.py @@ -15,20 +15,21 @@ from parameterized import parameterized from monai.transforms import ThresholdIntensity +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [{"threshold": 5, "above": True, "cval": 0}, (0, 0, 0, 0, 0, 0, 6, 7, 8, 9)] - -TEST_CASE_2 = [{"threshold": 5, "above": False, "cval": 0}, (0, 1, 2, 3, 4, 0, 0, 0, 0, 0)] - -TEST_CASE_3 = [{"threshold": 5, "above": True, "cval": 5}, (5, 5, 5, 5, 5, 5, 6, 7, 8, 9)] +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append([p, {"threshold": 5, "above": True, "cval": 0}, (0, 0, 0, 0, 0, 0, 6, 7, 8, 9)]) + TESTS.append([p, {"threshold": 5, "above": False, "cval": 0}, (0, 1, 2, 3, 4, 0, 0, 0, 0, 0)]) + TESTS.append([p, {"threshold": 5, "above": True, "cval": 5}, (5, 5, 5, 5, 5, 5, 6, 7, 8, 9)]) class TestThresholdIntensity(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) - def test_value(self, input_param, expected_value): - test_data = np.arange(10) + @parameterized.expand(TESTS) + def test_value(self, in_type, input_param, expected_value): + test_data = in_type(np.arange(10)) result = ThresholdIntensity(**input_param)(test_data) - np.testing.assert_allclose(result, expected_value) + assert_allclose(result, expected_value) if __name__ == "__main__": diff --git a/tests/test_threshold_intensityd.py b/tests/test_threshold_intensityd.py index efcfcfe604..398f9cfe91 100644 --- a/tests/test_threshold_intensityd.py +++ b/tests/test_threshold_intensityd.py @@ -15,31 +15,41 @@ from parameterized import parameterized from monai.transforms import ThresholdIntensityd - -TEST_CASE_1 = [ - {"keys": ["image", "label", "extra"], "threshold": 5, "above": True, "cval": 0}, - (0, 0, 0, 0, 0, 0, 6, 7, 8, 9), -] - -TEST_CASE_2 = [ - {"keys": ["image", "label", "extra"], "threshold": 5, "above": False, "cval": 0}, - (0, 1, 2, 3, 4, 0, 0, 0, 0, 0), -] - -TEST_CASE_3 = [ - {"keys": ["image", "label", "extra"], "threshold": 5, "above": True, "cval": 5}, - (5, 5, 5, 5, 5, 5, 6, 7, 8, 9), -] +from tests.utils import TEST_NDARRAYS, assert_allclose + +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + p, + {"keys": ["image", "label", "extra"], "threshold": 5, "above": True, "cval": 0}, + (0, 0, 0, 0, 0, 0, 6, 7, 8, 9), + ] + ) + TESTS.append( + [ + p, + {"keys": ["image", "label", "extra"], "threshold": 5, "above": False, "cval": 0}, + (0, 1, 2, 3, 4, 0, 0, 0, 0, 0), + ] + ) + TESTS.append( + [ + p, + {"keys": ["image", "label", "extra"], "threshold": 5, "above": True, "cval": 5}, + (5, 5, 5, 5, 5, 5, 6, 7, 8, 9), + ] + ) class TestThresholdIntensityd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) - def test_value(self, input_param, expected_value): - test_data = {"image": np.arange(10), "label": np.arange(10), "extra": np.arange(10)} + @parameterized.expand(TESTS) + def test_value(self, in_type, input_param, expected_value): + test_data = {"image": in_type(np.arange(10)), "label": in_type(np.arange(10)), "extra": in_type(np.arange(10))} result = ThresholdIntensityd(**input_param)(test_data) - np.testing.assert_allclose(result["image"], expected_value) - np.testing.assert_allclose(result["label"], expected_value) - np.testing.assert_allclose(result["extra"], expected_value) + assert_allclose(result["image"], expected_value) + assert_allclose(result["label"], expected_value) + assert_allclose(result["extra"], expected_value) if __name__ == "__main__": From 01feacbb70700ced80d0ba9784fe2ea729d8b959 Mon Sep 17 00:00:00 2001 From: Andres Diaz-Pinto Date: Mon, 13 Sep 2021 23:36:34 +0100 Subject: [PATCH 14/89] Add dropout arg in DynUNet init (#2947) * Add dropout arg in DynUNet init Signed-off-by: Andres --- monai/networks/blocks/dynunet_block.py | 21 +++++++++++++++++++-- monai/networks/blocks/dynunet_block_v1.py | 10 ++++++++++ monai/networks/nets/dynunet.py | 15 +++++++++------ monai/networks/nets/dynunet_v1.py | 3 +++ tests/test_dynunet.py | 16 +++++++++------- 5 files changed, 50 insertions(+), 15 deletions(-) diff --git a/monai/networks/blocks/dynunet_block.py b/monai/networks/blocks/dynunet_block.py index bb654d841c..fc37fc8999 100644 --- a/monai/networks/blocks/dynunet_block.py +++ b/monai/networks/blocks/dynunet_block.py @@ -33,6 +33,7 @@ class UnetResBlock(nn.Module): kernel_size: convolution kernel size. stride: convolution stride. norm_name: feature normalization type and arguments. + dropout: dropout probability """ @@ -44,6 +45,7 @@ def __init__( kernel_size: Union[Sequence[int], int], stride: Union[Sequence[int], int], norm_name: Union[Tuple, str], + dropout: Optional[Union[Tuple, str, float]] = None, ): super(UnetResBlock, self).__init__() self.conv1 = get_conv_layer( @@ -52,6 +54,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=stride, + dropout=dropout, conv_only=True, ) self.conv2 = get_conv_layer( @@ -60,6 +63,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=1, + dropout=dropout, conv_only=True, ) self.conv3 = get_conv_layer( @@ -68,6 +72,7 @@ def __init__( out_channels, kernel_size=1, stride=stride, + dropout=dropout, conv_only=True, ) self.lrelu = get_act_layer(("leakyrelu", {"inplace": True, "negative_slope": 0.01})) @@ -107,6 +112,7 @@ class UnetBasicBlock(nn.Module): kernel_size: convolution kernel size. stride: convolution stride. norm_name: feature normalization type and arguments. + dropout: dropout probability """ @@ -118,6 +124,7 @@ def __init__( kernel_size: Union[Sequence[int], int], stride: Union[Sequence[int], int], norm_name: Union[Tuple, str], + dropout: Optional[Union[Tuple, str, float]] = None, ): super(UnetBasicBlock, self).__init__() self.conv1 = get_conv_layer( @@ -126,6 +133,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=stride, + dropout=dropout, conv_only=True, ) self.conv2 = get_conv_layer( @@ -134,6 +142,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=1, + dropout=dropout, conv_only=True, ) self.lrelu = get_act_layer(("leakyrelu", {"inplace": True, "negative_slope": 0.01})) @@ -164,6 +173,7 @@ class UnetUpBlock(nn.Module): stride: convolution stride. upsample_kernel_size: convolution kernel size for transposed convolution layers. norm_name: feature normalization type and arguments. + dropout: dropout probability """ @@ -176,6 +186,7 @@ def __init__( stride: Union[Sequence[int], int], upsample_kernel_size: Union[Sequence[int], int], norm_name: Union[Tuple, str], + dropout: Optional[Union[Tuple, str, float]] = None, ): super(UnetUpBlock, self).__init__() upsample_stride = upsample_kernel_size @@ -185,6 +196,7 @@ def __init__( out_channels, kernel_size=upsample_kernel_size, stride=upsample_stride, + dropout=dropout, conv_only=True, is_transposed=True, ) @@ -194,6 +206,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=1, + dropout=dropout, norm_name=norm_name, ) @@ -206,10 +219,12 @@ def forward(self, inp, skip): class UnetOutBlock(nn.Module): - def __init__(self, spatial_dims: int, in_channels: int, out_channels: int): + def __init__( + self, spatial_dims: int, in_channels: int, out_channels: int, dropout: Optional[Union[Tuple, str, float]] = None + ): super(UnetOutBlock, self).__init__() self.conv = get_conv_layer( - spatial_dims, in_channels, out_channels, kernel_size=1, stride=1, bias=True, conv_only=True + spatial_dims, in_channels, out_channels, kernel_size=1, stride=1, dropout=dropout, bias=True, conv_only=True ) def forward(self, inp): @@ -224,6 +239,7 @@ def get_conv_layer( stride: Union[Sequence[int], int] = 1, act: Optional[Union[Tuple, str]] = Act.PRELU, norm: Union[Tuple, str] = Norm.INSTANCE, + dropout: Optional[Union[Tuple, str, float]] = None, bias: bool = False, conv_only: bool = True, is_transposed: bool = False, @@ -240,6 +256,7 @@ def get_conv_layer( kernel_size=kernel_size, act=act, norm=norm, + dropout=dropout, bias=bias, conv_only=conv_only, is_transposed=is_transposed, diff --git a/monai/networks/blocks/dynunet_block_v1.py b/monai/networks/blocks/dynunet_block_v1.py index d5d9bbf3dc..b5b88dd0df 100644 --- a/monai/networks/blocks/dynunet_block_v1.py +++ b/monai/networks/blocks/dynunet_block_v1.py @@ -32,6 +32,7 @@ def __init__( kernel_size: Union[Sequence[int], int], stride: Union[Sequence[int], int], norm_name: str, + dropout: float = 0.0, ): nn.Module.__init__(self) self.conv1 = get_conv_layer( @@ -40,6 +41,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=stride, + dropout=dropout, conv_only=True, ) self.conv2 = get_conv_layer( @@ -48,6 +50,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=1, + dropout=dropout, conv_only=True, ) self.conv3 = get_conv_layer( @@ -56,6 +59,7 @@ def __init__( out_channels, kernel_size=1, stride=stride, + dropout=dropout, conv_only=True, ) self.lrelu = get_act_layer(("leakyrelu", {"inplace": True, "negative_slope": 0.01})) @@ -81,6 +85,7 @@ def __init__( kernel_size: Union[Sequence[int], int], stride: Union[Sequence[int], int], norm_name: str, + dropout: float = 0.0, ): nn.Module.__init__(self) self.conv1 = get_conv_layer( @@ -89,6 +94,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=stride, + dropout=dropout, conv_only=True, ) self.conv2 = get_conv_layer( @@ -97,6 +103,7 @@ def __init__( out_channels, kernel_size=kernel_size, stride=1, + dropout=dropout, conv_only=True, ) self.lrelu = get_act_layer(("leakyrelu", {"inplace": True, "negative_slope": 0.01})) @@ -118,6 +125,7 @@ def __init__( stride: Union[Sequence[int], int], upsample_kernel_size: Union[Sequence[int], int], norm_name: str, + dropout: float = 0.0, ): nn.Module.__init__(self) upsample_stride = upsample_kernel_size @@ -127,6 +135,7 @@ def __init__( out_channels, kernel_size=upsample_kernel_size, stride=upsample_stride, + dropout=dropout, conv_only=True, is_transposed=True, ) @@ -137,6 +146,7 @@ def __init__( kernel_size=kernel_size, stride=1, norm_name=norm_name, + dropout=dropout, ) diff --git a/monai/networks/nets/dynunet.py b/monai/networks/nets/dynunet.py index 4af70b22c7..d65cd9f5f4 100644 --- a/monai/networks/nets/dynunet.py +++ b/monai/networks/nets/dynunet.py @@ -86,6 +86,7 @@ class DynUNet(nn.Module): strides: convolution strides for each blocks. upsample_kernel_size: convolution kernel size for transposed convolution layers. The values should equal to strides[1:]. + dropout: dropout ratio. Defaults to no dropout. norm_name: feature normalization type and arguments. Defaults to ``INSTANCE``. deep_supervision: whether to add deep supervision head before output. Defaults to ``False``. If ``True``, in training mode, the forward function will output not only the last feature @@ -115,6 +116,7 @@ def __init__( kernel_size: Sequence[Union[Sequence[int], int]], strides: Sequence[Union[Sequence[int], int]], upsample_kernel_size: Sequence[Union[Sequence[int], int]], + dropout: Optional[Union[Tuple, str, float]] = None, norm_name: Union[Tuple, str] = ("INSTANCE", {"affine": True}), deep_supervision: bool = False, deep_supr_num: int = 1, @@ -128,6 +130,7 @@ def __init__( self.strides = strides self.upsample_kernel_size = upsample_kernel_size self.norm_name = norm_name + self.dropout = dropout self.conv_block = UnetResBlock if res_block else UnetBasicBlock self.filters = [min(2 ** (5 + i), 320 if spatial_dims == 3 else 512) for i in range(len(strides))] self.input_block = self.get_input_block() @@ -184,7 +187,7 @@ def create_skips(index, downsamples, upsamples, superheads, bottleneck): def check_kernel_stride(self): kernels, strides = self.kernel_size, self.strides error_msg = "length of kernel_size and strides should be the same, and no less than 3." - if not (len(kernels) == len(strides) and len(kernels) >= 3): + if len(kernels) != len(strides) or len(kernels) < 3: raise AssertionError(error_msg) for idx, k_i in enumerate(kernels): @@ -225,6 +228,7 @@ def get_input_block(self): self.kernel_size[0], self.strides[0], self.norm_name, + dropout=self.dropout, ) def get_bottleneck(self): @@ -235,14 +239,11 @@ def get_bottleneck(self): self.kernel_size[-1], self.strides[-1], self.norm_name, + dropout=self.dropout, ) def get_output_block(self, idx: int): - return UnetOutBlock( - self.spatial_dims, - self.filters[idx], - self.out_channels, - ) + return UnetOutBlock(self.spatial_dims, self.filters[idx], self.out_channels, dropout=self.dropout) def get_downsamples(self): inp, out = self.filters[:-2], self.filters[1:-1] @@ -276,6 +277,7 @@ def get_module_list( "kernel_size": kernel, "stride": stride, "norm_name": self.norm_name, + "dropout": self.dropout, "upsample_kernel_size": up_kernel, } layer = conv_block(**params) @@ -289,6 +291,7 @@ def get_module_list( "kernel_size": kernel, "stride": stride, "norm_name": self.norm_name, + "dropout": self.dropout, } layer = conv_block(**params) layers.append(layer) diff --git a/monai/networks/nets/dynunet_v1.py b/monai/networks/nets/dynunet_v1.py index feb05d1762..c6a54807e4 100644 --- a/monai/networks/nets/dynunet_v1.py +++ b/monai/networks/nets/dynunet_v1.py @@ -38,6 +38,7 @@ class DynUNetV1(DynUNet): kernel_size: convolution kernel size. strides: convolution strides for each blocks. upsample_kernel_size: convolution kernel size for transposed convolution layers. + dropout: dropout ratio. Defaults to no dropout. norm_name: [``"batch"``, ``"instance"``, ``"group"``]. Defaults to "instance". deep_supervision: whether to add deep supervision head before output. Defaults to ``False``. deep_supr_num: number of feature maps that will output during deep supervision head. Defaults to 1. @@ -57,6 +58,7 @@ def __init__( kernel_size: Sequence[Union[Sequence[int], int]], strides: Sequence[Union[Sequence[int], int]], upsample_kernel_size: Sequence[Union[Sequence[int], int]], + dropout: float = 0.0, norm_name: str = "instance", deep_supervision: bool = False, deep_supr_num: int = 1, @@ -70,6 +72,7 @@ def __init__( self.strides = strides self.upsample_kernel_size = upsample_kernel_size self.norm_name = norm_name + self.dropout = dropout self.conv_block = _UnetResBlockV1 if res_block else _UnetBasicBlockV1 # type: ignore self.filters = [min(2 ** (5 + i), 320 if spatial_dims == 3 else 512) for i in range(len(strides))] self.input_block = self.get_input_block() diff --git a/tests/test_dynunet.py b/tests/test_dynunet.py index 81ed239461..18fe146a40 100644 --- a/tests/test_dynunet.py +++ b/tests/test_dynunet.py @@ -26,14 +26,14 @@ expected_shape: Sequence[Any] TEST_CASE_DYNUNET_2D = [] +out_channels = 2 +in_size = 64 +spatial_dims = 2 for kernel_size in [(3, 3, 3, 1), ((3, 1), 1, (3, 3), (1, 1))]: for strides in [(1, 1, 1, 1), (2, 2, 2, 1)]: + expected_shape = (1, out_channels, *[in_size // strides[0]] * spatial_dims) for in_channels in [2, 3]: for res_block in [True, False]: - out_channels = 2 - in_size = 64 - spatial_dims = 2 - expected_shape = (1, out_channels, *[in_size // strides[0]] * spatial_dims) test_case = [ { "spatial_dims": spatial_dims, @@ -45,6 +45,7 @@ "norm_name": "batch", "deep_supervision": False, "res_block": res_block, + "dropout": None, }, (1, in_channels, in_size, in_size), expected_shape, @@ -52,11 +53,11 @@ TEST_CASE_DYNUNET_2D.append(test_case) TEST_CASE_DYNUNET_3D = [] # in 3d cases, also test anisotropic kernel/strides +in_channels = 1 +in_size = 64 for out_channels in [2, 3]: + expected_shape = (1, out_channels, 64, 32, 64) for res_block in [True, False]: - in_channels = 1 - in_size = 64 - expected_shape = (1, out_channels, 64, 32, 64) test_case = [ { "spatial_dims": 3, @@ -68,6 +69,7 @@ "norm_name": ("INSTANCE", {"affine": True}), "deep_supervision": False, "res_block": res_block, + "dropout": ("alphadropout", {"p": 0.25}), }, (1, in_channels, in_size, in_size, in_size), expected_shape, From 7ab0711dbd6a67139430a747e7e27e166db599ba Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Tue, 14 Sep 2021 07:54:10 +0800 Subject: [PATCH 15/89] 2925 Add device option to EnsureType (#2942) * [DLMED] add device option Signed-off-by: Nic Ma * look up options for types Signed-off-by: Wenqi Li * adds unit tests Signed-off-by: Wenqi Li Co-authored-by: Wenqi Li --- monai/transforms/utility/array.py | 14 ++++++-------- monai/transforms/utility/dictionary.py | 11 +++++++++-- tests/test_ensure_type.py | 2 +- tests/test_ensure_typed.py | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index add47e27ca..7f94b50044 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -354,19 +354,17 @@ class EnsureType(Transform): Args: data_type: target data type to convert, should be "tensor" or "numpy". + device: for Tensor data type, specify the target device. """ backend = [TransformBackends.TORCH, TransformBackends.NUMPY] - def __init__(self, data_type: str = "tensor") -> None: - data_type = data_type.lower() - if data_type not in ("tensor", "numpy"): - raise ValueError("`data type` must be 'tensor' or 'numpy'.") - - self.data_type = data_type + def __init__(self, data_type: str = "tensor", device: Optional[torch.device] = None) -> None: + self.data_type = look_up_option(data_type.lower(), {"tensor", "numpy"}) + self.device = device - def __call__(self, data: NdarrayOrTensor) -> NdarrayOrTensor: + def __call__(self, data: NdarrayOrTensor): """ Args: data: input data can be PyTorch Tensor, numpy array, list, dictionary, int, float, bool, str, etc. @@ -375,7 +373,7 @@ def __call__(self, data: NdarrayOrTensor) -> NdarrayOrTensor: if applicable. """ - return convert_to_tensor(data) if self.data_type == "tensor" else convert_to_numpy(data) # type: ignore + return convert_to_tensor(data, device=self.device) if self.data_type == "tensor" else convert_to_numpy(data) class ToNumpy(Transform): diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index e9bcce93b0..2fdf20c1fe 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -486,16 +486,23 @@ class EnsureTyped(MapTransform, InvertibleTransform): backend = EnsureType.backend - def __init__(self, keys: KeysCollection, data_type: str = "tensor", allow_missing_keys: bool = False) -> None: + def __init__( + self, + keys: KeysCollection, + data_type: str = "tensor", + device: Optional[torch.device] = None, + allow_missing_keys: bool = False, + ) -> None: """ Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` data_type: target data type to convert, should be "tensor" or "numpy". + device: for Tensor data type, specify the target device. allow_missing_keys: don't raise exception if key is missing. """ super().__init__(keys, allow_missing_keys) - self.converter = EnsureType(data_type=data_type) + self.converter = EnsureType(data_type=data_type, device=device) def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) diff --git a/tests/test_ensure_type.py b/tests/test_ensure_type.py index 8feb96ed37..86bc3db703 100644 --- a/tests/test_ensure_type.py +++ b/tests/test_ensure_type.py @@ -36,7 +36,7 @@ def test_single_input(self): test_datas.append(test_datas[-1].cuda()) for test_data in test_datas: for dtype in ("tensor", "numpy"): - result = EnsureType(data_type=dtype)(test_data) + result = EnsureType(data_type=dtype, device="cpu")(test_data) self.assertTrue(isinstance(result, torch.Tensor if dtype == "tensor" else np.ndarray)) if isinstance(test_data, bool): self.assertFalse(result) diff --git a/tests/test_ensure_typed.py b/tests/test_ensure_typed.py index 96f482afc2..e4c72d37e2 100644 --- a/tests/test_ensure_typed.py +++ b/tests/test_ensure_typed.py @@ -75,7 +75,7 @@ def test_dict(self): "extra": None, } for dtype in ("tensor", "numpy"): - result = EnsureTyped(keys="data", data_type=dtype)({"data": test_data})["data"] + result = EnsureTyped(keys="data", data_type=dtype, device="cpu")({"data": test_data})["data"] self.assertTrue(isinstance(result, dict)) self.assertTrue(isinstance(result["img"], torch.Tensor if dtype == "tensor" else np.ndarray)) torch.testing.assert_allclose(result["img"], torch.as_tensor([1.0, 2.0])) From f26a712539b1613a05955e4397820d4c73544280 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Tue, 14 Sep 2021 13:00:06 +0100 Subject: [PATCH 16/89] ScaleIntensityRange, ScaleIntensityRanged, ScaleIntensityRangePercentiles, ScaleIntensityRangePercentilesd (#2943) ScaleIntensityRange, ScaleIntensityRanged, ScaleIntensityRangePercentiles, ScaleIntensityRangePercentilesd --- monai/transforms/__init__.py | 2 +- monai/transforms/intensity/array.py | 18 ++++--- monai/transforms/intensity/dictionary.py | 8 ++- .../utils_pytorch_numpy_unification.py | 54 +++++++++++++++++++ tests/test_scale_intensity_range.py | 13 +++-- .../test_scale_intensity_range_percentiles.py | 10 ++-- tests/test_scale_intensity_ranged.py | 13 +++-- tests/test_utils_pytorch_numpy_unification.py | 46 ++++++++++++++++ 8 files changed, 137 insertions(+), 27 deletions(-) create mode 100644 tests/test_utils_pytorch_numpy_unification.py diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index 9575a412b4..8a32b9e0b8 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -524,4 +524,4 @@ weighted_patch_samples, zero_margins, ) -from .utils_pytorch_numpy_unification import in1d, moveaxis, where +from .utils_pytorch_numpy_unification import clip, in1d, moveaxis, percentile, where diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index b6fa1f72b7..6c45f0d52b 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -28,7 +28,7 @@ from monai.networks.layers import GaussianFilter, HilbertTransform, SavitzkyGolayFilter from monai.transforms.transform import RandomizableTransform, Transform from monai.transforms.utils import Fourier, equalize_hist, is_positive, rescale_array -from monai.transforms.utils_pytorch_numpy_unification import where +from monai.transforms.utils_pytorch_numpy_unification import clip, percentile, where from monai.utils import ( PT_BEFORE_1_7, InvalidPyTorchVersionError, @@ -688,6 +688,8 @@ class ScaleIntensityRange(Transform): clip: whether to perform clip after scaling. """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__(self, a_min: float, a_max: float, b_min: float, b_max: float, clip: bool = False) -> None: self.a_min = a_min self.a_max = a_max @@ -695,7 +697,7 @@ def __init__(self, a_min: float, a_max: float, b_min: float, b_max: float, clip: self.b_max = b_max self.clip = clip - def __call__(self, img: np.ndarray): + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`. """ @@ -706,7 +708,7 @@ def __call__(self, img: np.ndarray): img = (img - self.a_min) / (self.a_max - self.a_min) img = img * (self.b_max - self.b_min) + self.b_min if self.clip: - img = np.asarray(np.clip(img, self.b_min, self.b_max)) + img = clip(img, self.b_min, self.b_max) return img @@ -835,6 +837,8 @@ class ScaleIntensityRangePercentiles(Transform): relative: whether to scale to the corresponding percentiles of [b_min, b_max]. """ + backend = ScaleIntensityRange.backend + def __init__( self, lower: float, upper: float, b_min: float, b_max: float, clip: bool = False, relative: bool = False ) -> None: @@ -849,12 +853,12 @@ def __init__( self.clip = clip self.relative = relative - def __call__(self, img: np.ndarray): + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`. """ - a_min = np.percentile(img, self.lower) - a_max = np.percentile(img, self.upper) + a_min: float = percentile(img, self.lower) # type: ignore + a_max: float = percentile(img, self.upper) # type: ignore b_min = self.b_min b_max = self.b_max @@ -866,7 +870,7 @@ def __call__(self, img: np.ndarray): img = scalar(img) if self.clip: - img = np.asarray(np.clip(img, self.b_min, self.b_max)) + img = clip(img, self.b_min, self.b_max) return img diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index cccf3e2a90..07a6045870 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -699,6 +699,8 @@ class ScaleIntensityRanged(MapTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = ScaleIntensityRange.backend + def __init__( self, keys: KeysCollection, @@ -712,7 +714,7 @@ def __init__( super().__init__(keys, allow_missing_keys) self.scaler = ScaleIntensityRange(a_min, a_max, b_min, b_max, clip) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): d[key] = self.scaler(d[key]) @@ -816,6 +818,8 @@ class ScaleIntensityRangePercentilesd(MapTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = ScaleIntensityRangePercentiles.backend + def __init__( self, keys: KeysCollection, @@ -830,7 +834,7 @@ def __init__( super().__init__(keys, allow_missing_keys) self.scaler = ScaleIntensityRangePercentiles(lower, upper, b_min, b_max, clip, relative) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): d[key] = self.scaler(d[key]) diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 70ecb2848d..0fb8e34ef0 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -9,6 +9,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import Union + import numpy as np import torch @@ -17,6 +19,8 @@ __all__ = [ "moveaxis", "in1d", + "clip", + "percentile", "where", ] @@ -53,6 +57,56 @@ def in1d(x, y): return (x[..., None] == torch.tensor(y, device=x.device)).any(-1).view(-1) +def clip(a: NdarrayOrTensor, a_min, a_max) -> NdarrayOrTensor: + """`np.clip` with equivalent implementation for torch.""" + result: NdarrayOrTensor + if isinstance(a, np.ndarray): + result = np.clip(a, a_min, a_max) + else: + result = torch.clip(a, a_min, a_max) + return result + + +def percentile(x: NdarrayOrTensor, q) -> Union[NdarrayOrTensor, float, int]: + """`np.percentile` with equivalent implementation for torch. + + Pytorch uses `quantile`, but this functionality is only available from v1.7. + For earlier methods, we calculate it ourselves. This doesn't do interpolation, + so is the equivalent of ``numpy.percentile(..., interpolation="nearest")``. + + Args: + x: input data + q: percentile to compute (should in range 0 <= q <= 100) + + Returns: + Resulting value (scalar) + """ + if np.isscalar(q): + if not 0 <= q <= 100: + raise ValueError + else: + if any(q < 0) or any(q > 100): + raise ValueError + result: Union[NdarrayOrTensor, float, int] + if isinstance(x, np.ndarray): + result = np.percentile(x, q) + else: + q = torch.tensor(q, device=x.device) + if hasattr(torch, "quantile"): + result = torch.quantile(x, q / 100.0) + else: + # Note that ``kthvalue()`` works one-based, i.e., the first sorted value + # corresponds to k=1, not k=0. Thus, we need the `1 +`. + k = 1 + (0.01 * q * (x.numel() - 1)).round().int() + if k.numel() > 1: + r = [x.view(-1).kthvalue(int(_k)).values.item() for _k in k] + result = torch.tensor(r, device=x.device) + else: + result = x.view(-1).kthvalue(int(k)).values.item() + + return result + + def where(condition: NdarrayOrTensor, x, y) -> NdarrayOrTensor: """ Note that `torch.where` may convert y.dtype to x.dtype. diff --git a/tests/test_scale_intensity_range.py b/tests/test_scale_intensity_range.py index cba07d9157..d64f09ae82 100644 --- a/tests/test_scale_intensity_range.py +++ b/tests/test_scale_intensity_range.py @@ -11,19 +11,18 @@ import unittest -import numpy as np - from monai.transforms import ScaleIntensityRange -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose class IntensityScaleIntensityRange(NumpyImageTestCase2D): def test_image_scale_intensity_range(self): scaler = ScaleIntensityRange(a_min=20, a_max=108, b_min=50, b_max=80) - scaled = scaler(self.imt) - expected = (self.imt - 20) / 88 - expected = expected * 30 + 50 - self.assertTrue(np.allclose(scaled, expected)) + for p in TEST_NDARRAYS: + scaled = scaler(p(self.imt)) + expected = (self.imt - 20) / 88 + expected = expected * 30 + 50 + assert_allclose(scaled, expected) if __name__ == "__main__": diff --git a/tests/test_scale_intensity_range_percentiles.py b/tests/test_scale_intensity_range_percentiles.py index 015162c8de..5cd19581b3 100644 --- a/tests/test_scale_intensity_range_percentiles.py +++ b/tests/test_scale_intensity_range_percentiles.py @@ -14,7 +14,7 @@ import numpy as np from monai.transforms.intensity.array import ScaleIntensityRangePercentiles -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose class TestScaleIntensityRangePercentiles(NumpyImageTestCase2D): @@ -30,7 +30,9 @@ def test_scaling(self): expected = (img - a_min) / (a_max - a_min) expected = (expected * (b_max - b_min)) + b_min scaler = ScaleIntensityRangePercentiles(lower=lower, upper=upper, b_min=b_min, b_max=b_max) - self.assertTrue(np.allclose(expected, scaler(img))) + for p in TEST_NDARRAYS: + result = scaler(p(img)) + assert_allclose(expected, result) def test_relative_scaling(self): img = self.imt @@ -47,7 +49,9 @@ def test_relative_scaling(self): expected_img = (img - expected_a_min) / (expected_a_max - expected_a_min) expected_img = (expected_img * (expected_b_max - expected_b_min)) + expected_b_min - self.assertTrue(np.allclose(expected_img, scaler(img))) + for p in TEST_NDARRAYS: + result = scaler(p(img)) + assert_allclose(expected_img, result) def test_invalid_instantiation(self): self.assertRaises(ValueError, ScaleIntensityRangePercentiles, lower=-10, upper=99, b_min=0, b_max=255) diff --git a/tests/test_scale_intensity_ranged.py b/tests/test_scale_intensity_ranged.py index a8cac414e8..b4d8cbf65a 100644 --- a/tests/test_scale_intensity_ranged.py +++ b/tests/test_scale_intensity_ranged.py @@ -11,20 +11,19 @@ import unittest -import numpy as np - from monai.transforms import ScaleIntensityRanged -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose class IntensityScaleIntensityRanged(NumpyImageTestCase2D): def test_image_scale_intensity_ranged(self): key = "img" scaler = ScaleIntensityRanged(keys=key, a_min=20, a_max=108, b_min=50, b_max=80) - scaled = scaler({key: self.imt}) - expected = (self.imt - 20) / 88 - expected = expected * 30 + 50 - self.assertTrue(np.allclose(scaled[key], expected)) + for p in TEST_NDARRAYS: + scaled = scaler({key: p(self.imt)}) + expected = (self.imt - 20) / 88 + expected = expected * 30 + 50 + assert_allclose(scaled[key], expected) if __name__ == "__main__": diff --git a/tests/test_utils_pytorch_numpy_unification.py b/tests/test_utils_pytorch_numpy_unification.py new file mode 100644 index 0000000000..f05235187c --- /dev/null +++ b/tests/test_utils_pytorch_numpy_unification.py @@ -0,0 +1,46 @@ +# Copyright 2020 - 2021 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 monai.transforms.utils_pytorch_numpy_unification import percentile +from tests.utils import TEST_NDARRAYS, assert_allclose, set_determinism + + +class TestPytorchNumpyUnification(unittest.TestCase): + def setUp(self) -> None: + set_determinism(0) + + def test_percentile(self): + for size in (1, 100): + q = np.random.randint(0, 100, size=size) + results = [] + for p in TEST_NDARRAYS: + arr = p(np.arange(100 * 101).reshape(1, 100, 101).astype(np.float32)) + results.append(percentile(arr, q)) + # pre torch 1.7, no `quantile`. Our own method doesn't interpolate, + # so we can only be accurate to 0.5 + atol = 0.5 if not hasattr(torch, "quantile") else 1e-4 + assert_allclose(results[0], results[-1], atol=atol) + + def test_fails(self): + for p in TEST_NDARRAYS: + for q in (-1, 101): + arr = p(np.arange(100 * 101).reshape(1, 100, 101).astype(np.float32)) + with self.assertRaises(ValueError): + percentile(arr, q) + + +if __name__ == "__main__": + unittest.main() From f77a7997d0b6cbfd1562415a22e0f63fa434ffe8 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Tue, 14 Sep 2021 14:25:52 +0100 Subject: [PATCH 17/89] Rotate, Rotated, RandRotate, RandRotated (#2945) Rotate, Rotated, RandRotate, RandRotated --- monai/transforms/spatial/array.py | 43 ++++--- monai/transforms/spatial/dictionary.py | 40 ++++-- tests/test_rand_rotate.py | 91 ++++++++------ tests/test_rand_rotated.py | 164 ++++++++++++++----------- tests/test_rotate.py | 77 ++++++------ tests/test_rotated.py | 50 ++++---- 6 files changed, 271 insertions(+), 194 deletions(-) diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index a9cb847b93..3e3afab5d8 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -441,6 +441,8 @@ class Rotate(Transform, ThreadUnsafe): the output data type is always ``np.float32``. """ + backend = [TransformBackends.TORCH] + def __init__( self, angle: Union[Sequence[float], float], @@ -448,7 +450,7 @@ def __init__( mode: Union[GridSampleMode, str] = GridSampleMode.BILINEAR, padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.BORDER, align_corners: bool = False, - dtype: DtypeLike = np.float64, + dtype: Union[DtypeLike, torch.dtype] = np.float64, ) -> None: self.angle = angle self.keep_size = keep_size @@ -460,12 +462,12 @@ def __init__( def __call__( self, - img: np.ndarray, + img: NdarrayOrTensor, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, align_corners: Optional[bool] = None, - dtype: DtypeLike = None, - ) -> np.ndarray: + dtype: Union[DtypeLike, torch.dtype] = None, + ) -> torch.Tensor: """ Args: img: channel first array, must have shape: [chns, H, W] or [chns, H, W, D]. @@ -488,7 +490,11 @@ def __call__( """ _dtype = dtype or self.dtype or img.dtype - im_shape = np.asarray(img.shape[1:]) # spatial dimensions + + img_t: torch.Tensor + img_t, *_ = convert_data_type(img, torch.Tensor, dtype=_dtype) # type: ignore + + im_shape = np.asarray(img_t.shape[1:]) # spatial dimensions input_ndim = len(im_shape) if input_ndim not in (2, 3): raise ValueError(f"Unsupported img dimension: {input_ndim}, available options are [2, 3].") @@ -506,6 +512,9 @@ def __call__( shift_1 = create_translate(input_ndim, (-(output_shape - 1) / 2).tolist()) transform = shift @ transform @ shift_1 + transform_t: torch.Tensor + transform_t, *_ = convert_to_dst_type(transform, img_t) # type: ignore + xform = AffineTransform( normalized=False, mode=look_up_option(mode or self.mode, GridSampleMode), @@ -513,13 +522,13 @@ def __call__( align_corners=self.align_corners if align_corners is None else align_corners, reverse_indexing=True, ) - output = xform( - torch.as_tensor(np.ascontiguousarray(img).astype(_dtype)).unsqueeze(0), - torch.as_tensor(np.ascontiguousarray(transform).astype(_dtype)), + output: torch.Tensor = xform( + img_t.unsqueeze(0), + transform_t, spatial_size=output_shape, ) self._rotation_matrix = transform - return np.asarray(output.squeeze(0).detach().cpu().numpy(), dtype=np.float32) + return output.squeeze(0).detach().float() def get_rotation_matrix(self) -> Optional[np.ndarray]: """ @@ -738,6 +747,8 @@ class RandRotate(RandomizableTransform): the output data type is always ``np.float32``. """ + backend = Rotate.backend + def __init__( self, range_x: Union[Tuple[float, float], float] = 0.0, @@ -748,7 +759,7 @@ def __init__( mode: Union[GridSampleMode, str] = GridSampleMode.BILINEAR, padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.BORDER, align_corners: bool = False, - dtype: DtypeLike = np.float64, + dtype: Union[DtypeLike, torch.dtype] = np.float64, ) -> None: RandomizableTransform.__init__(self, prob) self.range_x = ensure_tuple(range_x) @@ -779,12 +790,12 @@ def randomize(self, data: Optional[Any] = None) -> None: def __call__( self, - img: np.ndarray, + img: NdarrayOrTensor, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, align_corners: Optional[bool] = None, - dtype: DtypeLike = None, - ) -> np.ndarray: + dtype: Union[DtypeLike, torch.dtype] = None, + ) -> torch.Tensor: """ Args: img: channel first array, must have shape 2D: (nchannels, H, W), or 3D: (nchannels, H, W, D). @@ -802,7 +813,9 @@ def __call__( """ self.randomize() if not self._do_transform: - return img + img_t: torch.Tensor + img_t, *_ = convert_data_type(img, torch.Tensor) # type: ignore + return img_t rotator = Rotate( angle=self.x if img.ndim == 3 else (self.x, self.y, self.z), keep_size=self.keep_size, @@ -811,7 +824,7 @@ def __call__( align_corners=self.align_corners if align_corners is None else align_corners, dtype=dtype or self.dtype or img.dtype, ) - return np.array(rotator(img)) + return rotator(img) class RandFlip(RandomizableTransform): diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index 96fe21db12..903512e9b8 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -57,6 +57,7 @@ ) from monai.utils.enums import InverseKeys from monai.utils.module import optional_import +from monai.utils.type_conversion import convert_data_type, convert_to_dst_type nib, _ = optional_import("nibabel") @@ -1287,6 +1288,8 @@ class Rotated(MapTransform, InvertibleTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = Rotate.backend + def __init__( self, keys: KeysCollection, @@ -1295,7 +1298,7 @@ def __init__( mode: GridSampleModeSequence = GridSampleMode.BILINEAR, padding_mode: GridSamplePadModeSequence = GridSamplePadMode.BORDER, align_corners: Union[Sequence[bool], bool] = False, - dtype: Union[Sequence[DtypeLike], DtypeLike] = np.float64, + dtype: Union[Sequence[Union[DtypeLike, torch.dtype]], Union[DtypeLike, torch.dtype]] = np.float64, allow_missing_keys: bool = False, ) -> None: super().__init__(keys, allow_missing_keys) @@ -1306,7 +1309,7 @@ def __init__( self.align_corners = ensure_tuple_rep(align_corners, len(self.keys)) self.dtype = ensure_tuple_rep(dtype, len(self.keys)) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, mode, padding_mode, align_corners, dtype in self.key_iterator( d, self.mode, self.padding_mode, self.align_corners, self.dtype @@ -1333,7 +1336,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda ) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key, dtype in self.key_iterator(d, self.dtype): transform = self.get_most_recent_transform(d, key) @@ -1351,12 +1354,17 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar align_corners=False if align_corners == "none" else align_corners, reverse_indexing=True, ) + img_t: torch.Tensor + img_t, *_ = convert_data_type(d[key], torch.Tensor, dtype=dtype) # type: ignore + transform_t: torch.Tensor + transform_t, *_ = convert_to_dst_type(inv_rot_mat, img_t) # type: ignore + output = xform( - torch.as_tensor(np.ascontiguousarray(d[key]).astype(dtype)).unsqueeze(0), - torch.as_tensor(np.ascontiguousarray(inv_rot_mat).astype(dtype)), + img_t.unsqueeze(0), + transform_t, spatial_size=transform[InverseKeys.ORIG_SIZE], ) - d[key] = np.asarray(output.squeeze(0).detach().cpu().numpy(), dtype=np.float32) + d[key] = output.squeeze(0).detach().float() # Remove the applied transform self.pop_transform(d, key) @@ -1398,6 +1406,8 @@ class RandRotated(RandomizableTransform, MapTransform, InvertibleTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = Rotate.backend + def __init__( self, keys: KeysCollection, @@ -1409,7 +1419,7 @@ def __init__( mode: GridSampleModeSequence = GridSampleMode.BILINEAR, padding_mode: GridSamplePadModeSequence = GridSamplePadMode.BORDER, align_corners: Union[Sequence[bool], bool] = False, - dtype: Union[Sequence[DtypeLike], DtypeLike] = np.float64, + dtype: Union[Sequence[Union[DtypeLike, torch.dtype]], Union[DtypeLike, torch.dtype]] = np.float64, allow_missing_keys: bool = False, ) -> None: MapTransform.__init__(self, keys, allow_missing_keys) @@ -1440,7 +1450,7 @@ def randomize(self, data: Optional[Any] = None) -> None: self.y = self.R.uniform(low=self.range_y[0], high=self.range_y[1]) self.z = self.R.uniform(low=self.range_z[0], high=self.range_z[1]) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: self.randomize() d = dict(data) angle: Union[Sequence[float], float] = self.x if d[self.keys[0]].ndim == 3 else (self.x, self.y, self.z) @@ -1462,6 +1472,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda ) rot_mat = rotator.get_rotation_matrix() else: + d[key], *_ = convert_data_type(d[key], torch.Tensor) rot_mat = np.eye(d[key].ndim) self.push_transform( d, @@ -1476,7 +1487,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda ) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key, dtype in self.key_iterator(d, self.dtype): transform = self.get_most_recent_transform(d, key) @@ -1496,12 +1507,17 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar align_corners=False if align_corners == "none" else align_corners, reverse_indexing=True, ) + img_t: torch.Tensor + img_t, *_ = convert_data_type(d[key], torch.Tensor, dtype=dtype) # type: ignore + transform_t: torch.Tensor + transform_t, *_ = convert_to_dst_type(inv_rot_mat, img_t) # type: ignore + output: torch.Tensor output = xform( - torch.as_tensor(np.ascontiguousarray(d[key]).astype(dtype)).unsqueeze(0), - torch.as_tensor(np.ascontiguousarray(inv_rot_mat).astype(dtype)), + img_t.unsqueeze(0), + transform_t, spatial_size=transform[InverseKeys.ORIG_SIZE], ) - d[key] = np.asarray(output.squeeze(0).detach().cpu().numpy(), dtype=np.float32) + d[key] = output.squeeze(0).detach().float() # Remove the applied transform self.pop_transform(d, key) diff --git a/tests/test_rand_rotate.py b/tests/test_rand_rotate.py index 0ff8508a0f..4817e81735 100644 --- a/tests/test_rand_rotate.py +++ b/tests/test_rand_rotate.py @@ -10,25 +10,60 @@ # limitations under the License. import unittest +from typing import List, Tuple import numpy as np import scipy.ndimage +import torch from parameterized import parameterized from monai.transforms import RandRotate -from tests.utils import NumpyImageTestCase2D, NumpyImageTestCase3D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, NumpyImageTestCase3D +TEST_CASES_2D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_2D.append((p, np.pi / 2, True, "bilinear", "border", False)) + TEST_CASES_2D.append((p, np.pi / 4, True, "nearest", "border", False)) + TEST_CASES_2D.append((p, np.pi, False, "nearest", "zeros", True)) + TEST_CASES_2D.append((p, (-np.pi / 4, 0), False, "nearest", "zeros", True)) -class TestRandRotate2D(NumpyImageTestCase2D): - @parameterized.expand( - [ - (np.pi / 2, True, "bilinear", "border", False), - (np.pi / 4, True, "nearest", "border", False), - (np.pi, False, "nearest", "zeros", True), - ((-np.pi / 4, 0), False, "nearest", "zeros", True), - ] +TEST_CASES_3D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_3D.append( + (p, np.pi / 2, -np.pi / 6, (0.0, np.pi), False, "bilinear", "border", False, (1, 87, 104, 109)) + ) + TEST_CASES_3D.append( + ( + p, + np.pi / 4, + (-np.pi / 9, np.pi / 4.5), + (np.pi / 9, np.pi / 6), + False, + "nearest", + "border", + True, + (1, 89, 105, 104), + ) + ) + TEST_CASES_3D.append( + ( + p, + 0.0, + (2 * np.pi, 2.06 * np.pi), + (-np.pi / 180, np.pi / 180), + True, + "nearest", + "zeros", + True, + (1, 48, 64, 80), + ) ) - def test_correct_results(self, degrees, keep_size, mode, padding_mode, align_corners): + TEST_CASES_3D.append((p, (-np.pi / 4, 0), 0, 0, False, "nearest", "zeros", False, (1, 48, 77, 90))) + + +class TestRandRotate2D(NumpyImageTestCase2D): + @parameterized.expand(TEST_CASES_2D) + def test_correct_results(self, im_type, degrees, keep_size, mode, padding_mode, align_corners): rotate_fn = RandRotate( range_x=degrees, prob=1.0, @@ -38,7 +73,7 @@ def test_correct_results(self, degrees, keep_size, mode, padding_mode, align_cor align_corners=align_corners, ) rotate_fn.set_random_state(243) - rotated = rotate_fn(self.imt[0]) + rotated = rotate_fn(im_type(self.imt[0])) _order = 0 if mode == "nearest" else 1 if mode == "border": @@ -52,38 +87,14 @@ def test_correct_results(self, degrees, keep_size, mode, padding_mode, align_cor self.imt[0, 0], -np.rad2deg(angle), (0, 1), not keep_size, order=_order, mode=_mode, prefilter=False ) expected = np.stack(expected).astype(np.float32) + rotated = rotated.cpu() if isinstance(rotated, torch.Tensor) else rotated good = np.sum(np.isclose(expected, rotated[0], atol=1e-3)) self.assertLessEqual(np.abs(good - expected.size), 5, "diff at most 5 pixels") class TestRandRotate3D(NumpyImageTestCase3D): - @parameterized.expand( - [ - (np.pi / 2, -np.pi / 6, (0.0, np.pi), False, "bilinear", "border", False, (1, 87, 104, 109)), - ( - np.pi / 4, - (-np.pi / 9, np.pi / 4.5), - (np.pi / 9, np.pi / 6), - False, - "nearest", - "border", - True, - (1, 89, 105, 104), - ), - ( - 0.0, - (2 * np.pi, 2.06 * np.pi), - (-np.pi / 180, np.pi / 180), - True, - "nearest", - "zeros", - True, - (1, 48, 64, 80), - ), - ((-np.pi / 4, 0), 0, 0, False, "nearest", "zeros", False, (1, 48, 77, 90)), - ] - ) - def test_correct_results(self, x, y, z, keep_size, mode, padding_mode, align_corners, expected): + @parameterized.expand(TEST_CASES_3D) + def test_correct_results(self, im_type, x, y, z, keep_size, mode, padding_mode, align_corners, expected): rotate_fn = RandRotate( range_x=x, range_y=y, @@ -95,8 +106,8 @@ def test_correct_results(self, x, y, z, keep_size, mode, padding_mode, align_cor align_corners=align_corners, ) rotate_fn.set_random_state(243) - rotated = rotate_fn(self.imt[0]) - np.testing.assert_allclose(rotated.shape, expected) + rotated = rotate_fn(im_type(self.imt[0])) + torch.testing.assert_allclose(rotated.shape, expected, rtol=1e-7, atol=0) if __name__ == "__main__": diff --git a/tests/test_rand_rotated.py b/tests/test_rand_rotated.py index 47b4b7107e..4c9a27f668 100644 --- a/tests/test_rand_rotated.py +++ b/tests/test_rand_rotated.py @@ -10,26 +10,104 @@ # limitations under the License. import unittest +from typing import List, Tuple import numpy as np import scipy.ndimage +import torch from parameterized import parameterized from monai.transforms import RandRotated from monai.utils import GridSampleMode, GridSamplePadMode -from tests.utils import NumpyImageTestCase2D, NumpyImageTestCase3D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, NumpyImageTestCase3D +TEST_CASES_2D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_2D.append((p, np.pi / 2, True, "bilinear", "border", False)) + TEST_CASES_2D.append((p, np.pi / 4, True, "nearest", "border", False)) + TEST_CASES_2D.append((p, np.pi, False, "nearest", "zeros", True)) + TEST_CASES_2D.append((p, (-np.pi / 4, 0), False, "nearest", "zeros", True)) -class TestRandRotated2D(NumpyImageTestCase2D): - @parameterized.expand( - [ - (np.pi / 2, True, "bilinear", "border", False), - (np.pi / 4, True, "nearest", "border", False), - (np.pi, False, "nearest", "zeros", True), - ((-np.pi / 4, 0), False, "nearest", "zeros", True), - ] + +TEST_CASES_3D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_3D.append( + (p, np.pi / 2, -np.pi / 6, (0.0, np.pi), False, "bilinear", "border", False, (1, 87, 104, 109)) ) - def test_correct_results(self, degrees, keep_size, mode, padding_mode, align_corners): + TEST_CASES_3D.append( + ( + p, + np.pi / 2, + -np.pi / 6, + (0.0, np.pi), + False, + GridSampleMode.NEAREST, + GridSamplePadMode.BORDER, + False, + (1, 87, 104, 109), + ) + ) + TEST_CASES_3D.append( + ( + p, + np.pi / 4, + (-np.pi / 9, np.pi / 4.5), + (np.pi / 9, np.pi / 6), + False, + "nearest", + "border", + True, + (1, 89, 105, 104), + ) + ) + TEST_CASES_3D.append( + ( + p, + np.pi / 4, + (-np.pi / 9, np.pi / 4.5), + (np.pi / 9, np.pi / 6), + False, + GridSampleMode.NEAREST, + GridSamplePadMode.BORDER, + True, + (1, 89, 105, 104), + ) + ) + TEST_CASES_3D.append( + ( + p, + 0.0, + (2 * np.pi, 2.06 * np.pi), + (-np.pi / 180, np.pi / 180), + True, + "nearest", + "zeros", + True, + (1, 48, 64, 80), + ) + ) + TEST_CASES_3D.append( + ( + p, + 0.0, + (2 * np.pi, 2.06 * np.pi), + (-np.pi / 180, np.pi / 180), + True, + GridSampleMode.NEAREST, + GridSamplePadMode.ZEROS, + True, + (1, 48, 64, 80), + ) + ) + TEST_CASES_3D.append((p, (-np.pi / 4, 0), 0, 0, False, "nearest", "zeros", False, (1, 48, 77, 90))) + TEST_CASES_3D.append( + (p, (-np.pi / 4, 0), 0, 0, False, GridSampleMode.NEAREST, GridSamplePadMode.ZEROS, False, (1, 48, 77, 90)) + ) + + +class TestRandRotated2D(NumpyImageTestCase2D): + @parameterized.expand(TEST_CASES_2D) + def test_correct_results(self, im_type, degrees, keep_size, mode, padding_mode, align_corners): rotate_fn = RandRotated( "img", range_x=degrees, @@ -40,7 +118,7 @@ def test_correct_results(self, degrees, keep_size, mode, padding_mode, align_cor align_corners=align_corners, ) rotate_fn.set_random_state(243) - rotated = rotate_fn({"img": self.imt[0], "seg": self.segn[0]}) + rotated = rotate_fn({"img": im_type(self.imt[0]), "seg": im_type(self.segn[0])}) _order = 0 if mode == "nearest" else 1 if padding_mode == "border": @@ -53,70 +131,16 @@ def test_correct_results(self, degrees, keep_size, mode, padding_mode, align_cor expected = scipy.ndimage.rotate( self.imt[0, 0], -np.rad2deg(angle), (0, 1), not keep_size, order=_order, mode=_mode, prefilter=False ) + for k, v in rotated.items(): + rotated[k] = v.cpu() if isinstance(v, torch.Tensor) else v expected = np.stack(expected).astype(np.float32) good = np.sum(np.isclose(expected, rotated["img"][0], atol=1e-3)) self.assertLessEqual(np.abs(good - expected.size), 5, "diff at most 5 pixels") class TestRandRotated3D(NumpyImageTestCase3D): - @parameterized.expand( - [ - (np.pi / 2, -np.pi / 6, (0.0, np.pi), False, "bilinear", "border", False, (1, 87, 104, 109)), - ( - np.pi / 2, - -np.pi / 6, - (0.0, np.pi), - False, - GridSampleMode.NEAREST, - GridSamplePadMode.BORDER, - False, - (1, 87, 104, 109), - ), - ( - np.pi / 4, - (-np.pi / 9, np.pi / 4.5), - (np.pi / 9, np.pi / 6), - False, - "nearest", - "border", - True, - (1, 89, 105, 104), - ), - ( - np.pi / 4, - (-np.pi / 9, np.pi / 4.5), - (np.pi / 9, np.pi / 6), - False, - GridSampleMode.NEAREST, - GridSamplePadMode.BORDER, - True, - (1, 89, 105, 104), - ), - ( - 0.0, - (2 * np.pi, 2.06 * np.pi), - (-np.pi / 180, np.pi / 180), - True, - "nearest", - "zeros", - True, - (1, 48, 64, 80), - ), - ( - 0.0, - (2 * np.pi, 2.06 * np.pi), - (-np.pi / 180, np.pi / 180), - True, - GridSampleMode.NEAREST, - GridSamplePadMode.ZEROS, - True, - (1, 48, 64, 80), - ), - ((-np.pi / 4, 0), 0, 0, False, "nearest", "zeros", False, (1, 48, 77, 90)), - ((-np.pi / 4, 0), 0, 0, False, GridSampleMode.NEAREST, GridSamplePadMode.ZEROS, False, (1, 48, 77, 90)), - ] - ) - def test_correct_shapes(self, x, y, z, keep_size, mode, padding_mode, align_corners, expected): + @parameterized.expand(TEST_CASES_3D) + def test_correct_shapes(self, im_type, x, y, z, keep_size, mode, padding_mode, align_corners, expected): rotate_fn = RandRotated( "img", range_x=x, @@ -129,7 +153,7 @@ def test_correct_shapes(self, x, y, z, keep_size, mode, padding_mode, align_corn align_corners=align_corners, ) rotate_fn.set_random_state(243) - rotated = rotate_fn({"img": self.imt[0], "seg": self.segn[0]}) + rotated = rotate_fn({"img": im_type(self.imt[0]), "seg": im_type(self.segn[0])}) np.testing.assert_allclose(rotated["img"].shape, expected) diff --git a/tests/test_rotate.py b/tests/test_rotate.py index 436c952d4b..16a9c6d124 100644 --- a/tests/test_rotate.py +++ b/tests/test_rotate.py @@ -10,42 +10,44 @@ # limitations under the License. import unittest +from typing import List, Tuple import numpy as np import scipy.ndimage +import torch from parameterized import parameterized from monai.transforms import Rotate -from tests.utils import NumpyImageTestCase2D, NumpyImageTestCase3D - -TEST_CASES_2D = [ - (np.pi / 6, False, "bilinear", "border", False), - (np.pi / 4, True, "bilinear", "border", False), - (-np.pi / 4.5, True, "nearest", "reflection", False), - (np.pi, False, "nearest", "zeros", False), - (-np.pi / 2, False, "bilinear", "zeros", True), -] - -TEST_CASES_3D = [ - (-np.pi / 2, True, "nearest", "border", False), - (np.pi / 4, True, "bilinear", "border", False), - (-np.pi / 4.5, True, "nearest", "reflection", False), - (np.pi, False, "nearest", "zeros", False), - (-np.pi / 2, False, "bilinear", "zeros", False), -] - -TEST_CASES_SHAPE_3D = [ - ([-np.pi / 2, 1.0, 2.0], "nearest", "border", False), - ([np.pi / 4, 0, 0], "bilinear", "border", False), - ([-np.pi / 4.5, -20, 20], "nearest", "reflection", False), -] +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, NumpyImageTestCase3D + +TEST_CASES_2D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_2D.append((p, np.pi / 6, False, "bilinear", "border", False)) + TEST_CASES_2D.append((p, np.pi / 4, True, "bilinear", "border", False)) + TEST_CASES_2D.append((p, -np.pi / 4.5, True, "nearest", "reflection", False)) + TEST_CASES_2D.append((p, np.pi, False, "nearest", "zeros", False)) + TEST_CASES_2D.append((p, -np.pi / 2, False, "bilinear", "zeros", True)) + +TEST_CASES_3D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_3D.append((p, -np.pi / 2, True, "nearest", "border", False)) + TEST_CASES_3D.append((p, np.pi / 4, True, "bilinear", "border", False)) + TEST_CASES_3D.append((p, -np.pi / 4.5, True, "nearest", "reflection", False)) + TEST_CASES_3D.append((p, np.pi, False, "nearest", "zeros", False)) + TEST_CASES_3D.append((p, -np.pi / 2, False, "bilinear", "zeros", False)) + +TEST_CASES_SHAPE_3D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_SHAPE_3D.append((p, [-np.pi / 2, 1.0, 2.0], "nearest", "border", False)) + TEST_CASES_SHAPE_3D.append((p, [np.pi / 4, 0, 0], "bilinear", "border", False)) + TEST_CASES_SHAPE_3D.append((p, [-np.pi / 4.5, -20, 20], "nearest", "reflection", False)) class TestRotate2D(NumpyImageTestCase2D): @parameterized.expand(TEST_CASES_2D) - def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corners): + def test_correct_results(self, im_type, angle, keep_size, mode, padding_mode, align_corners): rotate_fn = Rotate(angle, keep_size, mode, padding_mode, align_corners) - rotated = rotate_fn(self.imt[0]) + rotated = rotate_fn(im_type(self.imt[0])) if keep_size: np.testing.assert_allclose(self.imt[0].shape, rotated.shape) _order = 0 if mode == "nearest" else 1 @@ -70,15 +72,16 @@ def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corne ) ) expected = np.stack(expected).astype(np.float32) + rotated = rotated.cpu() if isinstance(rotated, torch.Tensor) else rotated good = np.sum(np.isclose(expected, rotated, atol=1e-3)) self.assertLessEqual(np.abs(good - expected.size), 5, "diff at most 5 pixels") class TestRotate3D(NumpyImageTestCase3D): @parameterized.expand(TEST_CASES_3D) - def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corners): + def test_correct_results(self, im_type, angle, keep_size, mode, padding_mode, align_corners): rotate_fn = Rotate([angle, 0, 0], keep_size, mode, padding_mode, align_corners) - rotated = rotate_fn(self.imt[0]) + rotated = rotate_fn(im_type(self.imt[0])) if keep_size: np.testing.assert_allclose(self.imt[0].shape, rotated.shape) _order = 0 if mode == "nearest" else 1 @@ -103,23 +106,25 @@ def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corne ) ) expected = np.stack(expected).astype(np.float32) + rotated = rotated.cpu() if isinstance(rotated, torch.Tensor) else rotated n_good = np.sum(np.isclose(expected, rotated, atol=1e-3)) self.assertLessEqual(expected.size - n_good, 5, "diff at most 5 pixels") @parameterized.expand(TEST_CASES_SHAPE_3D) - def test_correct_shape(self, angle, mode, padding_mode, align_corners): + def test_correct_shape(self, im_type, angle, mode, padding_mode, align_corners): rotate_fn = Rotate(angle, True, align_corners=align_corners) - rotated = rotate_fn(self.imt[0], mode=mode, padding_mode=padding_mode) + rotated = rotate_fn(im_type(self.imt[0]), mode=mode, padding_mode=padding_mode) np.testing.assert_allclose(self.imt[0].shape, rotated.shape) def test_ill_case(self): - rotate_fn = Rotate(10, True) - with self.assertRaises(ValueError): # wrong shape - rotate_fn(self.imt) - - rotate_fn = Rotate(10, keep_size=False) - with self.assertRaises(ValueError): # wrong mode - rotate_fn(self.imt[0], mode="trilinear") + for p in TEST_NDARRAYS: + rotate_fn = Rotate(10, True) + with self.assertRaises(ValueError): # wrong shape + rotate_fn(p(self.imt)) + + rotate_fn = Rotate(10, keep_size=False) + with self.assertRaises(ValueError): # wrong mode + rotate_fn(p(self.imt[0]), mode="trilinear") if __name__ == "__main__": diff --git a/tests/test_rotated.py b/tests/test_rotated.py index 2ea421101b..cd27dd5406 100644 --- a/tests/test_rotated.py +++ b/tests/test_rotated.py @@ -10,36 +10,38 @@ # limitations under the License. import unittest +from typing import List, Tuple import numpy as np import scipy.ndimage +import torch from parameterized import parameterized from monai.transforms import Rotated -from tests.utils import NumpyImageTestCase2D, NumpyImageTestCase3D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, NumpyImageTestCase3D -TEST_CASES_2D = [ - (-np.pi / 6, False, "bilinear", "border", False), - (-np.pi / 4, True, "bilinear", "border", False), - (np.pi / 4.5, True, "nearest", "reflection", False), - (-np.pi, False, "nearest", "zeros", False), - (np.pi / 2, False, "bilinear", "zeros", True), -] +TEST_CASES_2D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_2D.append((p, -np.pi / 6, False, "bilinear", "border", False)) + TEST_CASES_2D.append((p, -np.pi / 4, True, "bilinear", "border", False)) + TEST_CASES_2D.append((p, np.pi / 4.5, True, "nearest", "reflection", False)) + TEST_CASES_2D.append((p, -np.pi, False, "nearest", "zeros", False)) + TEST_CASES_2D.append((p, np.pi / 2, False, "bilinear", "zeros", True)) -TEST_CASES_3D = [ - (-np.pi / 6, False, "bilinear", "border", False), - (-np.pi / 4, True, "bilinear", "border", False), - (np.pi / 4.5, True, "nearest", "reflection", False), - (-np.pi, False, "nearest", "zeros", False), - (np.pi / 2, False, "bilinear", "zeros", True), -] +TEST_CASES_3D: List[Tuple] = [] +for p in TEST_NDARRAYS: + TEST_CASES_3D.append((p, -np.pi / 6, False, "bilinear", "border", False)) + TEST_CASES_3D.append((p, -np.pi / 4, True, "bilinear", "border", False)) + TEST_CASES_3D.append((p, np.pi / 4.5, True, "nearest", "reflection", False)) + TEST_CASES_3D.append((p, -np.pi, False, "nearest", "zeros", False)) + TEST_CASES_3D.append((p, np.pi / 2, False, "bilinear", "zeros", True)) class TestRotated2D(NumpyImageTestCase2D): @parameterized.expand(TEST_CASES_2D) - def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corners): + def test_correct_results(self, im_type, angle, keep_size, mode, padding_mode, align_corners): rotate_fn = Rotated(("img", "seg"), angle, keep_size, (mode, "nearest"), padding_mode, align_corners) - rotated = rotate_fn({"img": self.imt[0], "seg": self.segn[0]}) + rotated = rotate_fn({"img": im_type(self.imt[0]), "seg": im_type(self.segn[0])}) if keep_size: np.testing.assert_allclose(self.imt[0].shape, rotated["img"].shape) _order = 0 if mode == "nearest" else 1 @@ -52,6 +54,8 @@ def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corne expected = scipy.ndimage.rotate( self.imt[0, 0], -np.rad2deg(angle), (0, 1), not keep_size, order=_order, mode=_mode, prefilter=False ) + for k, v in rotated.items(): + rotated[k] = v.cpu() if isinstance(v, torch.Tensor) else v good = np.sum(np.isclose(expected, rotated["img"][0], atol=1e-3)) self.assertLessEqual(np.abs(good - expected.size), 5, "diff at most 5 pixels") @@ -64,9 +68,9 @@ def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corne class TestRotated3D(NumpyImageTestCase3D): @parameterized.expand(TEST_CASES_3D) - def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corners): + def test_correct_results(self, im_type, angle, keep_size, mode, padding_mode, align_corners): rotate_fn = Rotated(("img", "seg"), [0, angle, 0], keep_size, (mode, "nearest"), padding_mode, align_corners) - rotated = rotate_fn({"img": self.imt[0], "seg": self.segn[0]}) + rotated = rotate_fn({"img": im_type(self.imt[0]), "seg": im_type(self.segn[0])}) if keep_size: np.testing.assert_allclose(self.imt[0].shape, rotated["img"].shape) _order = 0 if mode == "nearest" else 1 @@ -79,6 +83,8 @@ def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corne expected = scipy.ndimage.rotate( self.imt[0, 0], np.rad2deg(angle), (0, 2), not keep_size, order=_order, mode=_mode, prefilter=False ) + for k, v in rotated.items(): + rotated[k] = v.cpu() if isinstance(v, torch.Tensor) else v good = np.sum(np.isclose(expected.astype(np.float32), rotated["img"][0], atol=1e-3)) self.assertLessEqual(np.abs(good - expected.size), 5, "diff at most 5 voxels.") @@ -91,9 +97,9 @@ def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corne class TestRotated3DXY(NumpyImageTestCase3D): @parameterized.expand(TEST_CASES_3D) - def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corners): + def test_correct_results(self, im_type, angle, keep_size, mode, padding_mode, align_corners): rotate_fn = Rotated(("img", "seg"), [0, 0, angle], keep_size, (mode, "nearest"), padding_mode, align_corners) - rotated = rotate_fn({"img": self.imt[0], "seg": self.segn[0]}) + rotated = rotate_fn({"img": im_type(self.imt[0]), "seg": im_type(self.segn[0])}) if keep_size: np.testing.assert_allclose(self.imt[0].shape, rotated["img"].shape) _order = 0 if mode == "nearest" else 1 @@ -106,6 +112,8 @@ def test_correct_results(self, angle, keep_size, mode, padding_mode, align_corne expected = scipy.ndimage.rotate( self.imt[0, 0], -np.rad2deg(angle), (0, 1), not keep_size, order=_order, mode=_mode, prefilter=False ) + for k, v in rotated.items(): + rotated[k] = v.cpu() if isinstance(v, torch.Tensor) else v good = np.sum(np.isclose(expected, rotated["img"][0], atol=1e-3)) self.assertLessEqual(np.abs(good - expected.size), 5, "diff at most 5 voxels") From a14ed1bfe5bbc03bbb818659fbb0b1667e072516 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Tue, 14 Sep 2021 17:15:16 +0100 Subject: [PATCH 18/89] AffineGrid, RandAffineGrid, Resample, Affine, RandAffine, Affined, RandAffined, Rand2dElastic, Rand3dElastic, Rand2dElasticd, Rand3dElasticd (#2922) * AffineGrid, RandAffineGrid, Resample Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * Affine, RandAffine, Affined, RandAffined Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * deprecate as_tensor_output Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * fixes Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * remove plotting Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * Rand2dElastic, Rand3dElastic, Rand2dElasticd, Rand3dElasticd Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * CropForeground Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * fix Invertd Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/networks/layers/spatial_transforms.py | 9 +- monai/transforms/croppad/array.py | 2 + monai/transforms/croppad/dictionary.py | 5 +- monai/transforms/spatial/array.py | 171 +++++----- monai/transforms/spatial/dictionary.py | 74 ++-- tests/test_affine.py | 179 ++++++---- tests/test_affine_grid.py | 160 +++++---- tests/test_affined.py | 193 +++++++---- tests/test_inverse_collation.py | 2 - tests/test_rand_affine.py | 222 ++++++------ tests/test_rand_affine_grid.py | 322 ++++++++--------- tests/test_rand_affined.py | 360 ++++++++++---------- tests/test_rand_elastic_2d.py | 151 ++++---- tests/test_rand_elastic_3d.py | 130 ++++--- tests/test_rand_elasticd_2d.py | 248 +++++++------- tests/test_rand_elasticd_3d.py | 212 +++++++----- tests/test_resampler.py | 181 +++++++--- tests/utils.py | 6 +- 18 files changed, 1469 insertions(+), 1158 deletions(-) diff --git a/monai/networks/layers/spatial_transforms.py b/monai/networks/layers/spatial_transforms.py index 511c24fcb0..6b5acb166a 100644 --- a/monai/networks/layers/spatial_transforms.py +++ b/monai/networks/layers/spatial_transforms.py @@ -46,7 +46,9 @@ def backward(ctx, grad): return None, grads[0], None, None, None -def grid_pull(input: torch.Tensor, grid: torch.Tensor, interpolation="linear", bound="zero", extrapolate: bool = True): +def grid_pull( + input: torch.Tensor, grid: torch.Tensor, interpolation="linear", bound="zero", extrapolate: bool = True +) -> torch.Tensor: """ Sample an image with respect to a deformation field. @@ -112,8 +114,9 @@ def grid_pull(input: torch.Tensor, grid: torch.Tensor, interpolation="linear", b _C.InterpolationType.__members__[i] if isinstance(i, str) else _C.InterpolationType(i) for i in ensure_tuple(interpolation) ] - - return _GridPull.apply(input, grid, interpolation, bound, extrapolate) + out: torch.Tensor + out = _GridPull.apply(input, grid, interpolation, bound, extrapolate) # type: ignore + return out class _GridPush(torch.autograd.Function): diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index 7e3bc835dd..4d2a62b390 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -754,6 +754,8 @@ def __call__(self, img: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = N Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't change the channel dim. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore + box_start, box_end = self.compute_bounding_box(img) cropped = self.crop_pad(img, box_start, box_end, mode) diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py index 5c846b8d04..233f1b6edf 100644 --- a/monai/transforms/croppad/dictionary.py +++ b/monai/transforms/croppad/dictionary.py @@ -51,6 +51,7 @@ from monai.utils import ImageMetaKey as Key from monai.utils import Method, NumpyPadMode, PytorchPadMode, ensure_tuple, ensure_tuple_rep, fall_back_tuple from monai.utils.enums import InverseKeys +from monai.utils.type_conversion import convert_data_type __all__ = [ "PadModeSequence", @@ -848,7 +849,9 @@ def __init__( def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: d = dict(data) - box_start, box_end = self.cropper.compute_bounding_box(img=d[self.source_key]) + img: np.ndarray + img, *_ = convert_data_type(d[self.source_key], np.ndarray) # type: ignore + box_start, box_end = self.cropper.compute_bounding_box(img=img) d[self.start_coord_key] = box_start d[self.end_coord_key] = box_end for key, m in self.key_iterator(d, self.mode): diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 3e3afab5d8..2053070028 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -46,6 +46,7 @@ issequenceiterable, optional_import, ) +from monai.utils.deprecated import deprecated_arg from monai.utils.enums import TransformBackends from monai.utils.module import look_up_option from monai.utils.type_conversion import convert_data_type, convert_to_dst_type @@ -1021,14 +1022,15 @@ class AffineGrid(Transform): pixel/voxel relative to the center of the input image. Defaults to no translation. scale_params: scale factor for every spatial dims. a tuple of 2 floats for 2D, a tuple of 3 floats for 3D. Defaults to `1.0`. - as_tensor_output: whether to output tensor instead of numpy array, defaults to True. - device: device to store the output grid data. affine: If applied, ignore the params (`rotate_params`, etc.) and use the supplied matrix. Should be square with each side = num of image spatial dimensions + 1. """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, rotate_params: Optional[Union[Sequence[float], float]] = None, @@ -1037,23 +1039,20 @@ def __init__( scale_params: Optional[Union[Sequence[float], float]] = None, as_tensor_output: bool = True, device: Optional[torch.device] = None, - affine: Optional[Union[np.ndarray, torch.Tensor]] = None, + affine: Optional[NdarrayOrTensor] = None, ) -> None: self.rotate_params = rotate_params self.shear_params = shear_params self.translate_params = translate_params self.scale_params = scale_params - - self.as_tensor_output = as_tensor_output self.device = device - self.affine = affine def __call__( self, spatial_size: Optional[Sequence[int]] = None, - grid: Optional[Union[np.ndarray, torch.Tensor]] = None, - ) -> Tuple[Union[np.ndarray, torch.Tensor], Union[np.ndarray, torch.Tensor]]: + grid: Optional[NdarrayOrTensor] = None, + ) -> Tuple[NdarrayOrTensor, NdarrayOrTensor]: """ Args: spatial_size: output grid size. @@ -1069,7 +1068,7 @@ def __call__( else: raise ValueError("Incompatible values: grid=None and spatial_size=None.") - affine: Union[torch.Tensor, np.ndarray] + affine: NdarrayOrTensor if self.affine is None: spatial_dims = len(grid.shape) - 1 affine = np.eye(spatial_dims + 1) @@ -1084,17 +1083,13 @@ def __call__( else: affine = self.affine - if isinstance(affine, np.ndarray): - affine = torch.as_tensor(np.ascontiguousarray(affine)) + if self.device not in (None, torch.device("cpu"), "cpu"): + grid, *_ = convert_data_type(grid, torch.Tensor, device=self.device) + grid, *_ = convert_data_type(grid, dtype=float) + affine, *_ = convert_to_dst_type(affine, grid) - grid = torch.tensor(grid) if not isinstance(grid, torch.Tensor) else grid.detach().clone() - if self.device: - affine = affine.to(self.device) - grid = grid.to(self.device) - grid = (affine.float() @ grid.reshape((grid.shape[0], -1)).float()).reshape([-1] + list(grid.shape[1:])) - if grid is None or not isinstance(grid, torch.Tensor): - raise ValueError("Unknown grid.") - return grid if self.as_tensor_output else np.asarray(grid.cpu().numpy()), affine + grid = (affine @ grid.reshape((grid.shape[0], -1))).reshape([-1] + list(grid.shape[1:])) + return grid, affine class RandAffineGrid(Randomizable, Transform): @@ -1103,6 +1098,7 @@ class RandAffineGrid(Randomizable, Transform): """ + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, rotate_range: RandRange = None, @@ -1136,8 +1132,6 @@ def __init__( scale_range: scaling range with format matching `rotate_range`. it defines the range to randomly select the scale factor to translate for every spatial dims. A value of 1.0 is added to the result. This allows 0 to correspond to no change (i.e., a scaling of 1.0). - as_tensor_output: whether to output tensor instead of numpy array. - defaults to True. device: device to store the output grid data. See also: @@ -1156,9 +1150,8 @@ def __init__( self.translate_params: Optional[List[float]] = None self.scale_params: Optional[List[float]] = None - self.as_tensor_output = as_tensor_output self.device = device - self.affine: Optional[Union[np.ndarray, torch.Tensor]] = None + self.affine: Optional[NdarrayOrTensor] = None def _get_rand_param(self, param_range, add_scalar: float = 0.0): out_param = [] @@ -1180,8 +1173,8 @@ def randomize(self, data: Optional[Any] = None) -> None: def __call__( self, spatial_size: Optional[Sequence[int]] = None, - grid: Optional[Union[np.ndarray, torch.Tensor]] = None, - ) -> Union[np.ndarray, torch.Tensor]: + grid: Optional[NdarrayOrTensor] = None, + ) -> NdarrayOrTensor: """ Args: spatial_size: output grid size. @@ -1196,13 +1189,13 @@ def __call__( shear_params=self.shear_params, translate_params=self.translate_params, scale_params=self.scale_params, - as_tensor_output=self.as_tensor_output, device=self.device, ) - grid, self.affine = affine_grid(spatial_size, grid) - return grid + _grid: NdarrayOrTensor + _grid, self.affine = affine_grid(spatial_size, grid) + return _grid - def get_transformation_matrix(self) -> Optional[Union[np.ndarray, torch.Tensor]]: + def get_transformation_matrix(self) -> Optional[NdarrayOrTensor]: """Get the most recently applied transformation matrix""" return self.affine @@ -1258,11 +1251,15 @@ def __call__(self, spatial_size: Sequence[int]): class Resample(Transform): + + backend = [TransformBackends.TORCH] + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, mode: Union[GridSampleMode, str] = GridSampleMode.BILINEAR, padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.BORDER, - as_tensor_output: bool = False, + as_tensor_output: bool = True, device: Optional[torch.device] = None, ) -> None: """ @@ -1276,21 +1273,19 @@ def __init__( padding_mode: {``"zeros"``, ``"border"``, ``"reflection"``} Padding mode for outside grid values. Defaults to ``"border"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample - as_tensor_output: whether to return a torch tensor. Defaults to False. device: device on which the tensor will be allocated. """ self.mode: GridSampleMode = look_up_option(mode, GridSampleMode) self.padding_mode: GridSamplePadMode = look_up_option(padding_mode, GridSamplePadMode) - self.as_tensor_output = as_tensor_output self.device = device def __call__( self, - img: Union[np.ndarray, torch.Tensor], - grid: Optional[Union[np.ndarray, torch.Tensor]] = None, + img: NdarrayOrTensor, + grid: Optional[NdarrayOrTensor] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> Union[np.ndarray, torch.Tensor]: + ) -> torch.Tensor: """ Args: img: shape must be (num_channels, H, W[, D]). @@ -1302,18 +1297,14 @@ def __call__( Padding mode for outside grid values. Defaults to ``self.padding_mode``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample """ - - if not isinstance(img, torch.Tensor): - img = torch.as_tensor(np.ascontiguousarray(img)) if grid is None: - raise AssertionError("Error, grid argument must be supplied as an ndarray or tensor ") - grid = torch.tensor(grid) if not isinstance(grid, torch.Tensor) else grid.detach().clone() - if self.device: - img = img.to(self.device) - grid = grid.to(self.device) + raise ValueError("Unknown grid.") + img_t: torch.Tensor + img_t, *_ = convert_data_type(img, torch.Tensor, device=self.device, dtype=torch.float32) # type: ignore + grid, *_ = convert_to_dst_type(grid, img_t) if USE_COMPILED: - for i, dim in enumerate(img.shape[1:]): + for i, dim in enumerate(img_t.shape[1:]): grid[i] += (dim - 1.0) / 2.0 grid = grid[:-1] / grid[-1:] grid = grid.permute(list(range(grid.ndimension()))[1:] + [0]) @@ -1328,29 +1319,28 @@ def __call__( bound = 1 _interp_mode = look_up_option(self.mode if mode is None else mode, GridSampleMode).value out = grid_pull( - img.unsqueeze(0).float(), - grid.unsqueeze(0).float(), + img_t.unsqueeze(0), + grid.unsqueeze(0), bound=bound, extrapolate=True, interpolation=1 if _interp_mode == "bilinear" else _interp_mode, )[0] else: - for i, dim in enumerate(img.shape[1:]): + for i, dim in enumerate(img_t.shape[1:]): grid[i] = 2.0 * grid[i] / (dim - 1.0) grid = grid[:-1] / grid[-1:] - index_ordering: List[int] = list(range(img.ndimension() - 2, -1, -1)) + index_ordering: List[int] = list(range(img_t.ndimension() - 2, -1, -1)) grid = grid[index_ordering] grid = grid.permute(list(range(grid.ndimension()))[1:] + [0]) out = torch.nn.functional.grid_sample( - img.unsqueeze(0).float(), - grid.unsqueeze(0).float(), + img_t.unsqueeze(0), + grid.unsqueeze(0), mode=self.mode.value if mode is None else GridSampleMode(mode).value, padding_mode=self.padding_mode.value if padding_mode is None else GridSamplePadMode(padding_mode).value, align_corners=True, )[0] - if self.as_tensor_output: - return torch.as_tensor(out) - return np.asarray(out.cpu().numpy()) + + return out class Affine(Transform): @@ -1360,6 +1350,9 @@ class Affine(Transform): """ + backend = list(set(AffineGrid.backend) & set(Resample.backend)) + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, rotate_params: Optional[Union[Sequence[float], float]] = None, @@ -1369,7 +1362,7 @@ def __init__( spatial_size: Optional[Union[Sequence[int], int]] = None, mode: Union[GridSampleMode, str] = GridSampleMode.BILINEAR, padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.REFLECTION, - as_tensor_output: bool = False, + as_tensor_output: bool = True, device: Optional[torch.device] = None, image_only: bool = False, ) -> None: @@ -1405,8 +1398,6 @@ def __init__( padding_mode: {``"zeros"``, ``"border"``, ``"reflection"``} Padding mode for outside grid values. Defaults to ``"reflection"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. image_only: if True return only the image volume, otherwise return (image, affine). """ @@ -1415,22 +1406,21 @@ def __init__( shear_params=shear_params, translate_params=translate_params, scale_params=scale_params, - as_tensor_output=True, device=device, ) self.image_only = image_only - self.resampler = Resample(as_tensor_output=as_tensor_output, device=device) + self.resampler = Resample(device=device) self.spatial_size = spatial_size self.mode: GridSampleMode = look_up_option(mode, GridSampleMode) self.padding_mode: GridSamplePadMode = look_up_option(padding_mode, GridSamplePadMode) def __call__( self, - img: Union[np.ndarray, torch.Tensor], + img: NdarrayOrTensor, spatial_size: Optional[Union[Sequence[int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ): + ) -> Union[torch.Tensor, Tuple[torch.Tensor, NdarrayOrTensor]]: """ Args: img: shape must be (num_channels, H, W[, D]), @@ -1460,6 +1450,9 @@ class RandAffine(RandomizableTransform): """ + backend = Affine.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, prob: float = 0.1, @@ -1515,8 +1508,6 @@ def __init__( cache_grid: whether to cache the identity sampling grid. If the spatial size is not dynamically defined by input image, enabling this option could accelerate the transform. - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. See also: @@ -1530,10 +1521,9 @@ def __init__( shear_range=shear_range, translate_range=translate_range, scale_range=scale_range, - as_tensor_output=True, device=device, ) - self.resampler = Resample(as_tensor_output=as_tensor_output, device=device) + self.resampler = Resample(device=device) self.spatial_size = spatial_size self.cache_grid = cache_grid @@ -1590,11 +1580,11 @@ def randomize(self, data: Optional[Any] = None) -> None: def __call__( self, - img: Union[np.ndarray, torch.Tensor], + img: NdarrayOrTensor, spatial_size: Optional[Union[Sequence[int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> Union[np.ndarray, torch.Tensor]: + ) -> torch.Tensor: """ Args: img: shape must be (num_channels, H, W[, D]), @@ -1612,18 +1602,18 @@ def __call__( """ self.randomize() # if not doing transform and spatial size doesn't change, nothing to do - # except convert to float and convert numpy/torch + # except convert to float and device sp_size = fall_back_tuple(spatial_size or self.spatial_size, img.shape[1:]) do_resampling = self._do_transform or (sp_size != ensure_tuple(img.shape[1:])) if not do_resampling: - img = img.float() if isinstance(img, torch.Tensor) else img.astype("float32") - return torch.Tensor(img) if self.resampler.as_tensor_output else np.array(img) + img, *_ = convert_data_type(img, dtype=torch.float32, device=self.resampler.device) grid = self.get_identity_grid(sp_size) if self._do_transform: grid = self.rand_affine_grid(grid=grid) - return self.resampler( + out: torch.Tensor = self.resampler( img=img, grid=grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode ) + return out class Rand2DElastic(RandomizableTransform): @@ -1633,6 +1623,9 @@ class Rand2DElastic(RandomizableTransform): """ + backend = Resample.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, spacing: Union[Tuple[float, float], float], @@ -1687,8 +1680,6 @@ def __init__( padding_mode: {``"zeros"``, ``"border"``, ``"reflection"``} Padding mode for outside grid values. Defaults to ``"reflection"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. See also: @@ -1704,10 +1695,9 @@ def __init__( shear_range=shear_range, translate_range=translate_range, scale_range=scale_range, - as_tensor_output=True, device=device, ) - self.resampler = Resample(as_tensor_output=as_tensor_output, device=device) + self.resampler = Resample(device=device) self.spatial_size = spatial_size self.mode: GridSampleMode = look_up_option(mode, GridSampleMode) @@ -1728,11 +1718,11 @@ def randomize(self, spatial_size: Sequence[int]) -> None: def __call__( self, - img: Union[np.ndarray, torch.Tensor], + img: NdarrayOrTensor, spatial_size: Optional[Union[Tuple[int, int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> Union[np.ndarray, torch.Tensor]: + ) -> torch.Tensor: """ Args: img: shape must be (num_channels, H, W), @@ -1761,7 +1751,10 @@ def __call__( grid = CenterSpatialCrop(roi_size=sp_size)(grid[0]) else: grid = create_grid(spatial_size=sp_size) - return self.resampler(img, grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode) + out: torch.Tensor = self.resampler( + img, grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode + ) + return out class Rand3DElastic(RandomizableTransform): @@ -1771,6 +1764,9 @@ class Rand3DElastic(RandomizableTransform): """ + backend = Resample.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, sigma_range: Tuple[float, float], @@ -1828,8 +1824,6 @@ def __init__( padding_mode: {``"zeros"``, ``"border"``, ``"reflection"``} Padding mode for outside grid values. Defaults to ``"reflection"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. See also: @@ -1837,8 +1831,14 @@ def __init__( - :py:class:`Affine` for the affine transformation parameters configurations. """ RandomizableTransform.__init__(self, prob) - self.rand_affine_grid = RandAffineGrid(rotate_range, shear_range, translate_range, scale_range, True, device) - self.resampler = Resample(as_tensor_output=as_tensor_output, device=device) + self.rand_affine_grid = RandAffineGrid( + rotate_range=rotate_range, + shear_range=shear_range, + translate_range=translate_range, + scale_range=scale_range, + device=device, + ) + self.resampler = Resample(device=device) self.sigma_range = sigma_range self.magnitude_range = magnitude_range @@ -1868,11 +1868,11 @@ def randomize(self, grid_size: Sequence[int]) -> None: def __call__( self, - img: Union[np.ndarray, torch.Tensor], + img: NdarrayOrTensor, spatial_size: Optional[Union[Tuple[int, int, int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> Union[np.ndarray, torch.Tensor]: + ) -> torch.Tensor: """ Args: img: shape must be (num_channels, H, W, D), @@ -1897,7 +1897,10 @@ def __call__( offset = torch.as_tensor(self.rand_offset, device=self.device).unsqueeze(0) grid[:3] += gaussian(offset)[0] * self.magnitude grid = self.rand_affine_grid(grid=grid) - return self.resampler(img, grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode) + out: torch.Tensor = self.resampler( + img, grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode + ) + return out class AddCoordinateChannels(Transform): diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index 903512e9b8..801f4316de 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -55,6 +55,7 @@ ensure_tuple_rep, fall_back_tuple, ) +from monai.utils.deprecated import deprecated_arg from monai.utils.enums import InverseKeys from monai.utils.module import optional_import from monai.utils.type_conversion import convert_data_type, convert_to_dst_type @@ -574,6 +575,9 @@ class Affined(MapTransform, InvertibleTransform): Dictionary-based wrapper of :py:class:`monai.transforms.Affine`. """ + backend = Affine.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, keys: KeysCollection, @@ -584,7 +588,7 @@ def __init__( spatial_size: Optional[Union[Sequence[int], int]] = None, mode: GridSampleModeSequence = GridSampleMode.BILINEAR, padding_mode: GridSamplePadModeSequence = GridSamplePadMode.REFLECTION, - as_tensor_output: bool = False, + as_tensor_output: bool = True, device: Optional[torch.device] = None, allow_missing_keys: bool = False, ) -> None: @@ -621,8 +625,6 @@ def __init__( Padding mode for outside grid values. Defaults to ``"reflection"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample It also can be a sequence of string, each element corresponds to a key in ``keys``. - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. allow_missing_keys: don't raise exception if key is missing. @@ -637,15 +639,12 @@ def __init__( translate_params=translate_params, scale_params=scale_params, spatial_size=spatial_size, - as_tensor_output=as_tensor_output, device=device, ) self.mode = ensure_tuple_rep(mode, len(self.keys)) self.padding_mode = ensure_tuple_rep(padding_mode, len(self.keys)) - def __call__( - self, data: Mapping[Hashable, Union[np.ndarray, torch.Tensor]] - ) -> Dict[Hashable, Union[np.ndarray, torch.Tensor]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, mode, padding_mode in self.key_iterator(d, self.mode, self.padding_mode): orig_size = d[key].shape[1:] @@ -662,7 +661,7 @@ def __call__( ) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): @@ -678,10 +677,7 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar grid, _ = affine_grid(orig_size) # type: ignore # Apply inverse transform - out = self.affine.resampler(d[key], grid, mode, padding_mode) - - # Convert to numpy - d[key] = out if isinstance(out, np.ndarray) else out.cpu().numpy() + d[key] = self.affine.resampler(d[key], grid, mode, padding_mode) # Remove the applied transform self.pop_transform(d, key) @@ -694,6 +690,9 @@ class RandAffined(RandomizableTransform, MapTransform, InvertibleTransform): Dictionary-based wrapper of :py:class:`monai.transforms.RandAffine`. """ + backend = Affine.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, keys: KeysCollection, @@ -754,8 +753,6 @@ def __init__( cache_grid: whether to cache the identity sampling grid. If the spatial size is not dynamically defined by input image, enabling this option could accelerate the transform. - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. allow_missing_keys: don't raise exception if key is missing. @@ -773,7 +770,6 @@ def __init__( scale_range=scale_range, spatial_size=spatial_size, cache_grid=cache_grid, - as_tensor_output=as_tensor_output, device=device, ) self.mode = ensure_tuple_rep(mode, len(self.keys)) @@ -790,18 +786,19 @@ def randomize(self, data: Optional[Any] = None) -> None: super().randomize(None) self.rand_affine.randomize() - def __call__( - self, data: Mapping[Hashable, Union[np.ndarray, torch.Tensor]] - ) -> Dict[Hashable, Union[np.ndarray, torch.Tensor]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) self.randomize() + device = self.rand_affine.resampler.device + sp_size = fall_back_tuple(self.rand_affine.spatial_size, data[self.keys[0]].shape[1:]) # change image size or do random transform do_resampling = self._do_transform or (sp_size != ensure_tuple(data[self.keys[0]].shape[1:])) - # to be consistent with the self._do_transform case (dtype and device) - affine = torch.as_tensor(np.eye(len(sp_size) + 1), device=self.rand_affine.rand_affine_grid.device) + affine: NdarrayOrTensor = np.eye(len(sp_size) + 1, dtype=np.float64) + if device not in (None, torch.device("cpu"), "cpu"): + affine, *_ = convert_data_type(affine, torch.Tensor, device=device) grid = None if do_resampling: # need to prepare grid grid = self.rand_affine.get_identity_grid(sp_size) @@ -822,23 +819,21 @@ def __call__( # do the transform if do_resampling: d[key] = self.rand_affine.resampler(d[key], grid, mode=mode, padding_mode=padding_mode) - # if not doing transform and and spatial size is unchanged, only need to do numpy/torch conversion + + # if not doing transform and spatial size is unchanged, only need to do convert to torch else: - if self.rand_affine.resampler.as_tensor_output and not isinstance(d[key], torch.Tensor): - d[key] = torch.Tensor(d[key]) - elif not self.rand_affine.resampler.as_tensor_output and isinstance(d[key], torch.Tensor): - d[key] = d[key].detach().cpu().numpy() # type: ignore[union-attr] + d[key], *_ = convert_data_type(d[key], torch.Tensor, dtype=torch.float32, device=device) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) # if transform was not performed and spatial size is None, nothing to do. if not transform[InverseKeys.DO_TRANSFORM] and self.rand_affine.spatial_size is None: - out: Union[np.ndarray, torch.Tensor] = d[key] + out: NdarrayOrTensor = d[key] else: orig_size = transform[InverseKeys.ORIG_SIZE] # Create inverse transform @@ -851,10 +846,7 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar grid, _ = affine_grid(orig_size) # type: ignore # Apply inverse transform - out = self.rand_affine.resampler(d[key], grid, mode, padding_mode) - - # Convert to numpy - d[key] = out if isinstance(out, np.ndarray) else out.cpu().numpy() + d[key] = self.rand_affine.resampler(d[key], grid, mode, padding_mode) # Remove the applied transform self.pop_transform(d, key) @@ -867,6 +859,9 @@ class Rand2DElasticd(RandomizableTransform, MapTransform): Dictionary-based wrapper of :py:class:`monai.transforms.Rand2DElastic`. """ + backend = Rand2DElastic.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, keys: KeysCollection, @@ -927,8 +922,6 @@ def __init__( Padding mode for outside grid values. Defaults to ``"reflection"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample It also can be a sequence of string, each element corresponds to a key in ``keys``. - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. allow_missing_keys: don't raise exception if key is missing. @@ -947,7 +940,6 @@ def __init__( translate_range=translate_range, scale_range=scale_range, spatial_size=spatial_size, - as_tensor_output=as_tensor_output, device=device, ) self.mode = ensure_tuple_rep(mode, len(self.keys)) @@ -964,9 +956,7 @@ def randomize(self, spatial_size: Sequence[int]) -> None: super().randomize(None) self.rand_2d_elastic.randomize(spatial_size) - def __call__( - self, data: Mapping[Hashable, Union[np.ndarray, torch.Tensor]] - ) -> Dict[Hashable, Union[np.ndarray, torch.Tensor]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) sp_size = fall_back_tuple(self.rand_2d_elastic.spatial_size, data[self.keys[0]].shape[1:]) @@ -996,6 +986,9 @@ class Rand3DElasticd(RandomizableTransform, MapTransform): Dictionary-based wrapper of :py:class:`monai.transforms.Rand3DElastic`. """ + backend = Rand3DElastic.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, keys: KeysCollection, @@ -1058,8 +1051,6 @@ def __init__( Padding mode for outside grid values. Defaults to ``"reflection"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample It also can be a sequence of string, each element corresponds to a key in ``keys``. - as_tensor_output: the computation is implemented using pytorch tensors, this option specifies - whether to convert it back to numpy arrays. device: device on which the tensor will be allocated. allow_missing_keys: don't raise exception if key is missing. @@ -1078,7 +1069,6 @@ def __init__( translate_range=translate_range, scale_range=scale_range, spatial_size=spatial_size, - as_tensor_output=as_tensor_output, device=device, ) self.mode = ensure_tuple_rep(mode, len(self.keys)) @@ -1095,9 +1085,7 @@ def randomize(self, grid_size: Sequence[int]) -> None: super().randomize(None) self.rand_3d_elastic.randomize(grid_size) - def __call__( - self, data: Mapping[Hashable, Union[np.ndarray, torch.Tensor]] - ) -> Dict[Hashable, Union[np.ndarray, torch.Tensor]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) sp_size = fall_back_tuple(self.rand_3d_elastic.spatial_size, data[self.keys[0]].shape[1:]) diff --git a/tests/test_affine.py b/tests/test_affine.py index dd82d72e23..bd89f1a436 100644 --- a/tests/test_affine.py +++ b/tests/test_affine.py @@ -16,78 +16,139 @@ from parameterized import parameterized from monai.transforms import Affine +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(9).reshape((1, 3, 3)), "spatial_size": (-1, 0)}, - np.arange(9).reshape(1, 3, 3), - ], - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None, image_only=True), - {"img": np.arange(9).reshape((1, 3, 3)), "spatial_size": (-1, 0)}, - np.arange(9).reshape(1, 3, 3), - ], - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(4).reshape((1, 2, 2))}, - np.arange(4).reshape(1, 2, 2), - ], - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(4).reshape((1, 2, 2)), "spatial_size": (4, 4)}, - np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]), - ], - [ - dict(rotate_params=[np.pi / 2], padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(4).reshape((1, 2, 2)), "spatial_size": (4, 4)}, - np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 0.0, 0.0], [0.0, 3.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]), - ], - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(27).reshape((1, 3, 3, 3)), "spatial_size": (-1, 0, 0)}, - np.arange(27).reshape(1, 3, 3, 3), - ], - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(8).reshape((1, 2, 2, 2)), "spatial_size": (4, 4, 4)}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( [ - [ - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.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, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 4.0, 5.0, 0.0], [0.0, 6.0, 7.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - ] + dict(padding_mode="zeros", device=device), + {"img": p(np.arange(9).reshape((1, 3, 3))), "spatial_size": (-1, 0)}, + p(np.arange(9).reshape(1, 3, 3)), ] - ), - ], - [ - dict(rotate_params=[np.pi / 2], padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(8).reshape((1, 2, 2, 2)), "spatial_size": (4, 4, 4)}, - np.array( + ) + TESTS.append( [ - [ - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 0.0, 0.0], [0.0, 3.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 6.0, 4.0, 0.0], [0.0, 7.0, 5.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - ] + dict(padding_mode="zeros", device=device, image_only=True), + {"img": p(np.arange(9).reshape((1, 3, 3))), "spatial_size": (-1, 0)}, + p(np.arange(9).reshape(1, 3, 3)), ] - ), - ], -] + ) + TESTS.append( + [ + dict(padding_mode="zeros", device=device), + {"img": p(np.arange(4).reshape((1, 2, 2)))}, + p(np.arange(4).reshape(1, 2, 2)), + ] + ) + TESTS.append( + [ + dict(padding_mode="zeros", device=device), + {"img": p(np.arange(4).reshape((1, 2, 2))), "spatial_size": (4, 4)}, + p(np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]]])), + ] + ) + TESTS.append( + [ + dict(rotate_params=[np.pi / 2], padding_mode="zeros", device=device), + {"img": p(np.arange(4).reshape((1, 2, 2))), "spatial_size": (4, 4)}, + p(np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 0.0, 0.0], [0.0, 3.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]]])), + ] + ) + TESTS.append( + [ + dict(padding_mode="zeros", device=device), + {"img": p(np.arange(27).reshape((1, 3, 3, 3))), "spatial_size": (-1, 0, 0)}, + p(np.arange(27).reshape(1, 3, 3, 3)), + ] + ) + TESTS.append( + [ + dict(padding_mode="zeros", device=device), + {"img": p(np.arange(8).reshape((1, 2, 2, 2))), "spatial_size": (4, 4, 4)}, + p( + np.array( + [ + [ + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.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, 0.0], + [0.0, 2.0, 3.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 4.0, 5.0, 0.0], + [0.0, 6.0, 7.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + ] + ] + ) + ), + ] + ) + TESTS.append( + [ + dict(rotate_params=[np.pi / 2], padding_mode="zeros", device=device), + {"img": p(np.arange(8).reshape((1, 2, 2, 2))), "spatial_size": (4, 4, 4)}, + p( + np.array( + [ + [ + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 2.0, 0.0, 0.0], + [0.0, 3.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 6.0, 4.0, 0.0], + [0.0, 7.0, 5.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + ] + ] + ) + ), + ] + ) class TestAffine(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_affine(self, input_param, input_data, expected_val): g = Affine(**input_param) result = g(**input_data) if isinstance(result, tuple): result = result[0] - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_affine_grid.py b/tests/test_affine_grid.py index 24772b9a21..ac7c2741b0 100644 --- a/tests/test_affine_grid.py +++ b/tests/test_affine_grid.py @@ -16,88 +16,106 @@ from parameterized import parameterized from monai.transforms import AffineGrid +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - {"as_tensor_output": False, "device": torch.device("cpu:0")}, - {"spatial_size": (2, 2)}, - np.array([[[-0.5, -0.5], [0.5, 0.5]], [[-0.5, 0.5], [-0.5, 0.5]], [[1.0, 1.0], [1.0, 1.0]]]), - ], - [ - {"as_tensor_output": True, "device": None}, - {"spatial_size": (2, 2)}, - torch.tensor([[[-0.5, -0.5], [0.5, 0.5]], [[-0.5, 0.5], [-0.5, 0.5]], [[1.0, 1.0], [1.0, 1.0]]]), - ], - [{"as_tensor_output": False, "device": None}, {"grid": np.ones((3, 3, 3))}, np.ones((3, 3, 3))], - [{"as_tensor_output": True, "device": torch.device("cpu:0")}, {"grid": np.ones((3, 3, 3))}, torch.ones((3, 3, 3))], - [{"as_tensor_output": False, "device": None}, {"grid": torch.ones((3, 3, 3))}, np.ones((3, 3, 3))], - [ - {"as_tensor_output": True, "device": torch.device("cpu:0")}, - {"grid": torch.ones((3, 3, 3))}, - torch.ones((3, 3, 3)), - ], - [ - { - "rotate_params": (1.0, 1.0), - "scale_params": (-20, 10), - "as_tensor_output": True, - "device": torch.device("cpu:0"), - }, - {"grid": torch.ones((3, 3, 3))}, - torch.tensor( +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( [ - [[-19.2208, -19.2208, -19.2208], [-19.2208, -19.2208, -19.2208], [-19.2208, -19.2208, -19.2208]], - [[-11.4264, -11.4264, -11.4264], [-11.4264, -11.4264, -11.4264], [-11.4264, -11.4264, -11.4264]], - [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], + {"device": device}, + {"spatial_size": (2, 2)}, + np.array([[[-0.5, -0.5], [0.5, 0.5]], [[-0.5, 0.5], [-0.5, 0.5]], [[1.0, 1.0], [1.0, 1.0]]]), ] - ), - ], - [ - { - "rotate_params": (1.0, 1.0, 1.0), - "scale_params": (-20, 10), - "as_tensor_output": True, - "device": torch.device("cpu:0"), - }, - {"grid": torch.ones((4, 3, 3, 3))}, - torch.tensor( + ) + + TESTS.append([{"device": device}, {"grid": p(np.ones((3, 3, 3)))}, p(np.ones((3, 3, 3)))]) + TESTS.append([{"device": device}, {"grid": p(torch.ones((3, 3, 3)))}, p(np.ones((3, 3, 3)))]) + TESTS.append( + [ + { + "rotate_params": (1.0, 1.0), + "scale_params": (-20, 10), + "device": device, + }, + {"grid": p(torch.ones((3, 3, 3)))}, + p( + torch.tensor( + [ + [ + [-19.2208, -19.2208, -19.2208], + [-19.2208, -19.2208, -19.2208], + [-19.2208, -19.2208, -19.2208], + ], + [ + [-11.4264, -11.4264, -11.4264], + [-11.4264, -11.4264, -11.4264], + [-11.4264, -11.4264, -11.4264], + ], + [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], + ] + ) + ), + ] + ) + TESTS.append( [ - [ - [[-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435]], - [[-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435]], - [[-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435]], - ], - [ - [[-20.2381, -20.2381, -20.2381], [-20.2381, -20.2381, -20.2381], [-20.2381, -20.2381, -20.2381]], - [[-20.2381, -20.2381, -20.2381], [-20.2381, -20.2381, -20.2381], [-20.2381, -20.2381, -20.2381]], - [[-20.2381, -20.2381, -20.2381], [-20.2381, -20.2381, -20.2381], [-20.2381, -20.2381, -20.2381]], - ], - [ - [[-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844]], - [[-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844]], - [[-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844]], - ], - [ - [[1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000]], - [[1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000]], - [[1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000]], - ], + { + "rotate_params": (1.0, 1.0, 1.0), + "scale_params": (-20, 10), + "device": device, + }, + {"grid": p(torch.ones((4, 3, 3, 3)))}, + p( + torch.tensor( + [ + [ + [[-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435]], + [[-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435]], + [[-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435], [-9.5435, -9.5435, -9.5435]], + ], + [ + [ + [-20.2381, -20.2381, -20.2381], + [-20.2381, -20.2381, -20.2381], + [-20.2381, -20.2381, -20.2381], + ], + [ + [-20.2381, -20.2381, -20.2381], + [-20.2381, -20.2381, -20.2381], + [-20.2381, -20.2381, -20.2381], + ], + [ + [-20.2381, -20.2381, -20.2381], + [-20.2381, -20.2381, -20.2381], + [-20.2381, -20.2381, -20.2381], + ], + ], + [ + [[-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844]], + [[-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844]], + [[-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844], [-0.5844, -0.5844, -0.5844]], + ], + [ + [[1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000]], + [[1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000]], + [[1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000]], + ], + ] + ) + ), ] - ), - ], -] + ) class TestAffineGrid(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_affine_grid(self, input_param, input_data, expected_val): g = AffineGrid(**input_param) result, _ = g(**input_data) - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected_val.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + if "device" in input_data: + self.assertEqual(result.device, input_data[device]) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_affined.py b/tests/test_affined.py index 850f12905d..142cedc8d9 100644 --- a/tests/test_affined.py +++ b/tests/test_affined.py @@ -16,85 +16,142 @@ from parameterized import parameterized from monai.transforms import Affined +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - dict(keys="img", padding_mode="zeros", as_tensor_output=False, spatial_size=(-1, 0), device=None), - {"img": np.arange(9).reshape((1, 3, 3))}, - np.arange(9).reshape(1, 3, 3), - ], - [ - dict(keys="img", padding_mode="zeros", as_tensor_output=False, device=None), - {"img": np.arange(4).reshape((1, 2, 2))}, - np.arange(4).reshape(1, 2, 2), - ], - [ - dict(keys="img", padding_mode="zeros", spatial_size=(4, 4), as_tensor_output=False, device=None), - {"img": np.arange(4).reshape((1, 2, 2))}, - np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]), - ], - [ - dict( - keys="img", - rotate_params=[np.pi / 2], - padding_mode="zeros", - spatial_size=(4, 4), - as_tensor_output=False, - device=None, - ), - {"img": np.arange(4).reshape((1, 2, 2))}, - np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 0.0, 0.0], [0.0, 3.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]), - ], - [ - dict(keys="img", padding_mode="zeros", spatial_size=(-1, 0, 0), as_tensor_output=False, device=None), - {"img": np.arange(27).reshape((1, 3, 3, 3))}, - np.arange(27).reshape(1, 3, 3, 3), - ], - [ - dict(keys="img", padding_mode="zeros", spatial_size=(4, 4, 4), as_tensor_output=False, device=None), - {"img": np.arange(8).reshape((1, 2, 2, 2))}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( [ - [ - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.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, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 4.0, 5.0, 0.0], [0.0, 6.0, 7.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - ] + dict(keys="img", padding_mode="zeros", spatial_size=(-1, 0), device=device), + {"img": p(np.arange(9).reshape((1, 3, 3)))}, + p(np.arange(9).reshape(1, 3, 3)), ] - ), - ], - [ - dict( - keys="img", - rotate_params=[np.pi / 2], - padding_mode="zeros", - spatial_size=(4, 4, 4), - as_tensor_output=False, - device=None, - ), - {"img": np.arange(8).reshape((1, 2, 2, 2))}, - np.array( + ) + TESTS.append( [ - [ - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 0.0, 0.0], [0.0, 3.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 6.0, 4.0, 0.0], [0.0, 7.0, 5.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - ] + dict(keys="img", padding_mode="zeros", device=device), + {"img": p(np.arange(4).reshape((1, 2, 2)))}, + p(np.arange(4).reshape(1, 2, 2)), ] - ), - ], -] + ) + TESTS.append( + [ + dict(keys="img", padding_mode="zeros", spatial_size=(4, 4), device=device), + {"img": p(np.arange(4).reshape((1, 2, 2)))}, + p(np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]]])), + ] + ) + TESTS.append( + [ + dict( + keys="img", + rotate_params=[np.pi / 2], + padding_mode="zeros", + spatial_size=(4, 4), + device=device, + ), + {"img": p(np.arange(4).reshape((1, 2, 2)))}, + p(np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 0.0, 0.0], [0.0, 3.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0]]])), + ] + ) + TESTS.append( + [ + dict(keys="img", padding_mode="zeros", spatial_size=(-1, 0, 0), device=device), + {"img": p(np.arange(27).reshape((1, 3, 3, 3)))}, + p(np.arange(27).reshape(1, 3, 3, 3)), + ] + ) + TESTS.append( + [ + dict(keys="img", padding_mode="zeros", spatial_size=(4, 4, 4), device=device), + {"img": p(np.arange(8).reshape((1, 2, 2, 2)))}, + p( + np.array( + [ + [ + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.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, 0.0], + [0.0, 2.0, 3.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 4.0, 5.0, 0.0], + [0.0, 6.0, 7.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + ] + ] + ) + ), + ] + ) + TESTS.append( + [ + dict( + keys="img", + rotate_params=[np.pi / 2], + padding_mode="zeros", + spatial_size=(4, 4, 4), + device=device, + ), + {"img": p(np.arange(8).reshape((1, 2, 2, 2)))}, + p( + np.array( + [ + [ + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 2.0, 0.0, 0.0], + [0.0, 3.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 6.0, 4.0, 0.0], + [0.0, 7.0, 5.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + ] + ] + ) + ), + ] + ) class TestAffined(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_affine(self, input_param, input_data, expected_val): g = Affined(**input_param) result = g(input_data)["img"] - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_inverse_collation.py b/tests/test_inverse_collation.py index c5dd9f1210..fb6a3a1e80 100644 --- a/tests/test_inverse_collation.py +++ b/tests/test_inverse_collation.py @@ -61,7 +61,6 @@ prob=0.5, rotate_range=np.pi, device=torch.device("cuda" if torch.cuda.is_available() else "cpu"), - as_tensor_output=False, ), ] ] @@ -85,7 +84,6 @@ prob=0.5, rotate_range=np.pi, device=torch.device("cuda" if torch.cuda.is_available() else "cpu"), - as_tensor_output=False, ), ] ] diff --git a/tests/test_rand_affine.py b/tests/test_rand_affine.py index 1e1a23bc09..c88aa538ed 100644 --- a/tests/test_rand_affine.py +++ b/tests/test_rand_affine.py @@ -16,114 +16,132 @@ from parameterized import parameterized from monai.transforms import RandAffine +from monai.utils.type_conversion import convert_data_type +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - dict(as_tensor_output=False, device=None), - {"img": torch.arange(27).reshape((3, 3, 3))}, - np.arange(27).reshape((3, 3, 3)), - ], - [ - dict(as_tensor_output=False, device=None, spatial_size=-1), - {"img": torch.arange(27).reshape((3, 3, 3))}, - np.arange(27).reshape((3, 3, 3)), - ], - [ - dict(as_tensor_output=False, device=None), - {"img": torch.arange(27).reshape((3, 3, 3)), "spatial_size": (2, 2)}, - np.array([[[2.0, 3.0], [5.0, 6.0]], [[11.0, 12.0], [14.0, 15.0]], [[20.0, 21.0], [23.0, 24.0]]]), - ], - [ - dict(as_tensor_output=True, device=None), - {"img": torch.ones((1, 3, 3, 3)), "spatial_size": (2, 2, 2)}, - torch.ones((1, 2, 2, 2)), - ], - [ - dict(as_tensor_output=True, device=None, spatial_size=(2, 2, 2), cache_grid=True), - {"img": torch.ones((1, 3, 3, 3))}, - torch.ones((1, 2, 2, 2)), - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - as_tensor_output=True, - padding_mode="zeros", - spatial_size=(2, 2, 2), - device=None, - ), - {"img": torch.ones((1, 3, 3, 3)), "mode": "bilinear"}, - torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]]), - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - as_tensor_output=True, - padding_mode="zeros", - spatial_size=(2, 2, 2), - cache_grid=True, - device=None, - ), - {"img": torch.ones((1, 3, 3, 3)), "mode": "bilinear"}, - torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]]), - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - scale_range=[0.1, 0.2], - as_tensor_output=True, - device=None, - ), - {"img": torch.arange(64).reshape((1, 8, 8)), "spatial_size": (3, 3)}, - torch.tensor([[[18.7362, 15.5820, 12.4278], [27.3988, 24.2446, 21.0904], [36.0614, 32.9072, 29.7530]]]), - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - scale_range=[0.1, 0.2], - spatial_size=(3, 3), - cache_grid=True, - as_tensor_output=True, - device=None, - ), - {"img": torch.arange(64).reshape((1, 8, 8))}, - torch.tensor([[[18.7362, 15.5820, 12.4278], [27.3988, 24.2446, 21.0904], [36.0614, 32.9072, 29.7530]]]), - ], -] +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( + [ + dict(device=device), + {"img": p(torch.arange(27).reshape((3, 3, 3)))}, + p(np.arange(27).reshape((3, 3, 3))), + ] + ) + TESTS.append( + [ + dict(device=device, spatial_size=-1), + {"img": p(torch.arange(27).reshape((3, 3, 3)))}, + p(np.arange(27).reshape((3, 3, 3))), + ] + ) + TESTS.append( + [ + dict(device=device), + {"img": p(torch.arange(27).reshape((3, 3, 3))), "spatial_size": (2, 2)}, + p(np.array([[[2.0, 3.0], [5.0, 6.0]], [[11.0, 12.0], [14.0, 15.0]], [[20.0, 21.0], [23.0, 24.0]]])), + ] + ) + TESTS.append( + [ + dict(device=device), + {"img": p(torch.ones((1, 3, 3, 3))), "spatial_size": (2, 2, 2)}, + p(torch.ones((1, 2, 2, 2))), + ] + ) + TESTS.append( + [ + dict(device=device, spatial_size=(2, 2, 2), cache_grid=True), + {"img": p(torch.ones((1, 3, 3, 3)))}, + p(torch.ones((1, 2, 2, 2))), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + padding_mode="zeros", + spatial_size=(2, 2, 2), + device=device, + ), + {"img": p(torch.ones((1, 3, 3, 3))), "mode": "bilinear"}, + p(torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]])), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + padding_mode="zeros", + spatial_size=(2, 2, 2), + cache_grid=True, + device=device, + ), + {"img": p(torch.ones((1, 3, 3, 3))), "mode": "bilinear"}, + p(torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]])), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + scale_range=[0.1, 0.2], + device=device, + ), + {"img": p(torch.arange(64).reshape((1, 8, 8))), "spatial_size": (3, 3)}, + p( + torch.tensor( + [[[18.7362, 15.5820, 12.4278], [27.3988, 24.2446, 21.0904], [36.0614, 32.9072, 29.7530]]] + ) + ), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + scale_range=[0.1, 0.2], + spatial_size=(3, 3), + cache_grid=True, + device=device, + ), + {"img": p(torch.arange(64).reshape((1, 8, 8)))}, + p( + torch.tensor( + [[[18.7362, 15.5820, 12.4278], [27.3988, 24.2446, 21.0904], [36.0614, 32.9072, 29.7530]]] + ) + ), + ] + ) -ARR_NUMPY = np.arange(9 * 10).reshape(1, 9, 10) -ARR_TORCH = torch.Tensor(ARR_NUMPY) TEST_CASES_SKIPPED_CONSISTENCY = [] -for im in (ARR_NUMPY, ARR_TORCH): - for as_tensor_output in (True, False): - for in_dtype_is_int in (True, False): - TEST_CASES_SKIPPED_CONSISTENCY.append((im, as_tensor_output, in_dtype_is_int)) +for p in TEST_NDARRAYS: + for in_dtype in (np.int32, np.float32): + TEST_CASES_SKIPPED_CONSISTENCY.append((p(np.arange(9 * 10).reshape(1, 9, 10)), in_dtype)) class TestRandAffine(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_affine(self, input_param, input_data, expected_val): g = RandAffine(**input_param) g.set_random_state(123) result = g(**input_data) if input_param.get("cache_grid", False): self.assertTrue(g._cached_grid is not None) - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected_val.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) def test_ill_cache(self): with self.assertWarns(UserWarning): @@ -132,15 +150,11 @@ def test_ill_cache(self): RandAffine(cache_grid=True, spatial_size=(1, 1, -1)) @parameterized.expand(TEST_CASES_SKIPPED_CONSISTENCY) - def test_skipped_transform_consistency(self, im, as_tensor_output, in_dtype_is_int): - t1 = RandAffine(prob=0, as_tensor_output=as_tensor_output) - t2 = RandAffine(prob=1, spatial_size=(10, 11), as_tensor_output=as_tensor_output) + def test_skipped_transform_consistency(self, im, in_dtype): + t1 = RandAffine(prob=0) + t2 = RandAffine(prob=1, spatial_size=(10, 11)) - # change dtype to int32 or float32 - if in_dtype_is_int: - im = im.astype("int32") if isinstance(im, np.ndarray) else im.int() - else: - im = im.astype("float32") if isinstance(im, np.ndarray) else im.float() + im, *_ = convert_data_type(im, dtype=in_dtype) out1 = t1(im) out2 = t2(im) diff --git a/tests/test_rand_affine_grid.py b/tests/test_rand_affine_grid.py index 605d0a30ba..64c32c8d75 100644 --- a/tests/test_rand_affine_grid.py +++ b/tests/test_rand_affine_grid.py @@ -16,182 +16,192 @@ from parameterized import parameterized from monai.transforms import RandAffineGrid +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [{"as_tensor_output": False, "device": None}, {"grid": torch.ones((3, 3, 3))}, np.ones((3, 3, 3))], - [ - {"rotate_range": (1, 2), "translate_range": (3, 3, 3)}, - {"grid": torch.arange(0, 27).reshape((3, 3, 3))}, - torch.tensor( - np.array( - [ - [ - [-32.81998, -33.910976, -35.001972], - [-36.092968, -37.183964, -38.27496], - [-39.36596, -40.456955, -41.54795], - ], - [[2.1380205, 3.1015975, 4.0651755], [5.028752, 5.9923296, 6.955907], [7.919484, 8.883063, 9.84664]], - [[18.0, 19.0, 20.0], [21.0, 22.0, 23.0], [24.0, 25.0, 26.0]], - ] - ) - ), - ], - [ - {"translate_range": (3, 3, 3), "as_tensor_output": False, "device": torch.device("cpu:0")}, - {"spatial_size": (3, 3, 3)}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append([{"device": device}, {"grid": p(torch.ones((3, 3, 3)))}, p(np.ones((3, 3, 3)))]) + TESTS.append( [ - [ - [ - [0.17881513, 0.17881513, 0.17881513], - [0.17881513, 0.17881513, 0.17881513], - [0.17881513, 0.17881513, 0.17881513], - ], - [ - [1.1788151, 1.1788151, 1.1788151], - [1.1788151, 1.1788151, 1.1788151], - [1.1788151, 1.1788151, 1.1788151], - ], - [ - [2.1788151, 2.1788151, 2.1788151], - [2.1788151, 2.1788151, 2.1788151], - [2.1788151, 2.1788151, 2.1788151], - ], - ], - [ - [ - [-2.283164, -2.283164, -2.283164], - [-1.283164, -1.283164, -1.283164], - [-0.28316402, -0.28316402, -0.28316402], - ], - [ - [-2.283164, -2.283164, -2.283164], - [-1.283164, -1.283164, -1.283164], - [-0.28316402, -0.28316402, -0.28316402], - ], - [ - [-2.283164, -2.283164, -2.283164], - [-1.283164, -1.283164, -1.283164], - [-0.28316402, -0.28316402, -0.28316402], - ], - ], - [ - [ - [-2.6388912, -1.6388912, -0.6388912], - [-2.6388912, -1.6388912, -0.6388912], - [-2.6388912, -1.6388912, -0.6388912], - ], - [ - [-2.6388912, -1.6388912, -0.6388912], - [-2.6388912, -1.6388912, -0.6388912], - [-2.6388912, -1.6388912, -0.6388912], - ], - [ - [-2.6388912, -1.6388912, -0.6388912], - [-2.6388912, -1.6388912, -0.6388912], - [-2.6388912, -1.6388912, -0.6388912], - ], - ], - [ - [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], - [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], - [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], - ], - ] - ), - ], - [ - {"rotate_range": (1.0, 1.0, 1.0), "shear_range": (0.1,), "scale_range": (1.2,)}, - {"grid": torch.arange(0, 108).reshape((4, 3, 3, 3))}, - torch.tensor( - np.array( - [ - [ - [ - [-9.4201e00, -8.1672e00, -6.9143e00], - [-5.6614e00, -4.4085e00, -3.1556e00], - [-1.9027e00, -6.4980e-01, 6.0310e-01], - ], - [ - [1.8560e00, 3.1089e00, 4.3618e00], - [5.6147e00, 6.8676e00, 8.1205e00], - [9.3734e00, 1.0626e01, 1.1879e01], - ], + {"rotate_range": (1, 2), "translate_range": (3, 3, 3)}, + {"grid": p(torch.arange(0, 27).reshape((3, 3, 3)))}, + p( + np.array( [ - [1.3132e01, 1.4385e01, 1.5638e01], - [1.6891e01, 1.8144e01, 1.9397e01], - [2.0650e01, 2.1902e01, 2.3155e01], - ], - ], - [ - [ - [9.9383e-02, -4.8845e-01, -1.0763e00], - [-1.6641e00, -2.2519e00, -2.8398e00], - [-3.4276e00, -4.0154e00, -4.6032e00], - ], - [ - [-5.1911e00, -5.7789e00, -6.3667e00], - [-6.9546e00, -7.5424e00, -8.1302e00], - [-8.7180e00, -9.3059e00, -9.8937e00], - ], - [ - [-1.0482e01, -1.1069e01, -1.1657e01], - [-1.2245e01, -1.2833e01, -1.3421e01], - [-1.4009e01, -1.4596e01, -1.5184e01], - ], - ], + [ + [-32.81998, -33.910976, -35.001972], + [-36.092968, -37.183964, -38.27496], + [-39.36596, -40.456955, -41.54795], + ], + [ + [2.1380205, 3.1015975, 4.0651755], + [5.028752, 5.9923296, 6.955907], + [7.919484, 8.883063, 9.84664], + ], + [[18.0, 19.0, 20.0], [21.0, 22.0, 23.0], [24.0, 25.0, 26.0]], + ] + ) + ), + ] + ) + TESTS.append( + [ + {"translate_range": (3, 3, 3), "device": device}, + {"spatial_size": (3, 3, 3)}, + np.array( [ [ - [5.9635e01, 6.1199e01, 6.2764e01], - [6.4328e01, 6.5892e01, 6.7456e01], - [6.9021e01, 7.0585e01, 7.2149e01], - ], - [ - [7.3714e01, 7.5278e01, 7.6842e01], - [7.8407e01, 7.9971e01, 8.1535e01], - [8.3099e01, 8.4664e01, 8.6228e01], + [ + [0.17881513, 0.17881513, 0.17881513], + [0.17881513, 0.17881513, 0.17881513], + [0.17881513, 0.17881513, 0.17881513], + ], + [ + [1.1788151, 1.1788151, 1.1788151], + [1.1788151, 1.1788151, 1.1788151], + [1.1788151, 1.1788151, 1.1788151], + ], + [ + [2.1788151, 2.1788151, 2.1788151], + [2.1788151, 2.1788151, 2.1788151], + [2.1788151, 2.1788151, 2.1788151], + ], ], [ - [8.7792e01, 8.9357e01, 9.0921e01], - [9.2485e01, 9.4049e01, 9.5614e01], - [9.7178e01, 9.8742e01, 1.0031e02], + [ + [-2.283164, -2.283164, -2.283164], + [-1.283164, -1.283164, -1.283164], + [-0.28316402, -0.28316402, -0.28316402], + ], + [ + [-2.283164, -2.283164, -2.283164], + [-1.283164, -1.283164, -1.283164], + [-0.28316402, -0.28316402, -0.28316402], + ], + [ + [-2.283164, -2.283164, -2.283164], + [-1.283164, -1.283164, -1.283164], + [-0.28316402, -0.28316402, -0.28316402], + ], ], - ], - [ [ - [8.1000e01, 8.2000e01, 8.3000e01], - [8.4000e01, 8.5000e01, 8.6000e01], - [8.7000e01, 8.8000e01, 8.9000e01], + [ + [-2.6388912, -1.6388912, -0.6388912], + [-2.6388912, -1.6388912, -0.6388912], + [-2.6388912, -1.6388912, -0.6388912], + ], + [ + [-2.6388912, -1.6388912, -0.6388912], + [-2.6388912, -1.6388912, -0.6388912], + [-2.6388912, -1.6388912, -0.6388912], + ], + [ + [-2.6388912, -1.6388912, -0.6388912], + [-2.6388912, -1.6388912, -0.6388912], + [-2.6388912, -1.6388912, -0.6388912], + ], ], [ - [9.0000e01, 9.1000e01, 9.2000e01], - [9.3000e01, 9.4000e01, 9.5000e01], - [9.6000e01, 9.7000e01, 9.8000e01], + [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], + [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], + [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], ], + ] + ), + ] + ) + TESTS.append( + [ + {"device": device, "rotate_range": (1.0, 1.0, 1.0), "shear_range": (0.1,), "scale_range": (1.2,)}, + {"grid": p(torch.arange(0, 108).reshape((4, 3, 3, 3)))}, + p( + np.array( [ - [9.9000e01, 1.0000e02, 1.0100e02], - [1.0200e02, 1.0300e02, 1.0400e02], - [1.0500e02, 1.0600e02, 1.0700e02], - ], - ], - ] - ) - ), - ], -] + [ + [ + [-9.4201e00, -8.1672e00, -6.9143e00], + [-5.6614e00, -4.4085e00, -3.1556e00], + [-1.9027e00, -6.4980e-01, 6.0310e-01], + ], + [ + [1.8560e00, 3.1089e00, 4.3618e00], + [5.6147e00, 6.8676e00, 8.1205e00], + [9.3734e00, 1.0626e01, 1.1879e01], + ], + [ + [1.3132e01, 1.4385e01, 1.5638e01], + [1.6891e01, 1.8144e01, 1.9397e01], + [2.0650e01, 2.1902e01, 2.3155e01], + ], + ], + [ + [ + [9.9383e-02, -4.8845e-01, -1.0763e00], + [-1.6641e00, -2.2519e00, -2.8398e00], + [-3.4276e00, -4.0154e00, -4.6032e00], + ], + [ + [-5.1911e00, -5.7789e00, -6.3667e00], + [-6.9546e00, -7.5424e00, -8.1302e00], + [-8.7180e00, -9.3059e00, -9.8937e00], + ], + [ + [-1.0482e01, -1.1069e01, -1.1657e01], + [-1.2245e01, -1.2833e01, -1.3421e01], + [-1.4009e01, -1.4596e01, -1.5184e01], + ], + ], + [ + [ + [5.9635e01, 6.1199e01, 6.2764e01], + [6.4328e01, 6.5892e01, 6.7456e01], + [6.9021e01, 7.0585e01, 7.2149e01], + ], + [ + [7.3714e01, 7.5278e01, 7.6842e01], + [7.8407e01, 7.9971e01, 8.1535e01], + [8.3099e01, 8.4664e01, 8.6228e01], + ], + [ + [8.7792e01, 8.9357e01, 9.0921e01], + [9.2485e01, 9.4049e01, 9.5614e01], + [9.7178e01, 9.8742e01, 1.0031e02], + ], + ], + [ + [ + [8.1000e01, 8.2000e01, 8.3000e01], + [8.4000e01, 8.5000e01, 8.6000e01], + [8.7000e01, 8.8000e01, 8.9000e01], + ], + [ + [9.0000e01, 9.1000e01, 9.2000e01], + [9.3000e01, 9.4000e01, 9.5000e01], + [9.6000e01, 9.7000e01, 9.8000e01], + ], + [ + [9.9000e01, 1.0000e02, 1.0100e02], + [1.0200e02, 1.0300e02, 1.0400e02], + [1.0500e02, 1.0600e02, 1.0700e02], + ], + ], + ] + ) + ), + ] + ) class TestRandAffineGrid(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_affine_grid(self, input_param, input_data, expected_val): g = RandAffineGrid(**input_param) g.set_random_state(123) result = g(**input_data) - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected_val.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + if "device" in input_data: + self.assertEqual(result.device, input_data[device]) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_rand_affined.py b/tests/test_rand_affined.py index d2f8a60665..bec9602d62 100644 --- a/tests/test_rand_affined.py +++ b/tests/test_rand_affined.py @@ -17,179 +17,188 @@ from monai.transforms import RandAffined from monai.utils import GridSampleMode +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - dict(as_tensor_output=False, device=None, spatial_size=None, keys=("img", "seg")), - {"img": torch.arange(27).reshape((3, 3, 3)), "seg": torch.arange(27).reshape((3, 3, 3))}, - np.arange(27).reshape((3, 3, 3)), - ], - [ - dict(as_tensor_output=False, device=None, spatial_size=(2, 2), keys=("img", "seg")), - {"img": torch.ones((3, 3, 3)), "seg": torch.ones((3, 3, 3))}, - np.ones((3, 2, 2)), - ], - [ - dict(as_tensor_output=False, device=None, spatial_size=(2, 2), cache_grid=True, keys=("img", "seg")), - {"img": torch.ones((3, 3, 3)), "seg": torch.ones((3, 3, 3))}, - np.ones((3, 2, 2)), - ], - [ - dict(as_tensor_output=True, device=None, spatial_size=(2, 2, 2), keys=("img", "seg")), - {"img": torch.ones((1, 3, 3, 3)), "seg": torch.ones((1, 3, 3, 3))}, - torch.ones((1, 2, 2, 2)), - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - as_tensor_output=True, - spatial_size=(2, 2, 2), - padding_mode="zeros", - device=None, - keys=("img", "seg"), - mode="bilinear", - ), - {"img": torch.ones((1, 3, 3, 3)), "seg": torch.ones((1, 3, 3, 3))}, - torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]]), - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - as_tensor_output=False, - spatial_size=(2, 2, 2), - padding_mode="zeros", - device=None, - cache_grid=True, - keys=("img", "seg"), - mode="bilinear", - ), - {"img": torch.ones((1, 3, 3, 3)), "seg": torch.ones((1, 3, 3, 3))}, - np.array([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]]), - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - scale_range=[0.1, 0.2], - as_tensor_output=True, - spatial_size=(3, 3), - keys=("img", "seg"), - device=None, - ), - {"img": torch.arange(64).reshape((1, 8, 8)), "seg": torch.arange(64).reshape((1, 8, 8))}, - torch.tensor([[[18.7362, 15.5820, 12.4278], [27.3988, 24.2446, 21.0904], [36.0614, 32.9072, 29.7530]]]), - ], - [ - dict( - prob=0.9, - mode=("bilinear", "nearest"), - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - scale_range=[0.1, 0.2], - as_tensor_output=False, - spatial_size=(3, 3), - keys=("img", "seg"), - device=torch.device("cpu:0"), - ), - {"img": torch.arange(64).reshape((1, 8, 8)), "seg": torch.arange(64).reshape((1, 8, 8))}, - { - "img": np.array( - [ - [ - [18.736153, 15.581954, 12.4277525], - [27.398798, 24.244598, 21.090399], - [36.061443, 32.90724, 29.753046], - ] - ] - ), - "seg": np.array([[[19.0, 20.0, 12.0], [27.0, 28.0, 20.0], [35.0, 36.0, 29.0]]]), - }, - ], - [ - dict( - prob=0.9, - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - as_tensor_output=True, - spatial_size=(2, 2, 2), - padding_mode="zeros", - device=None, - keys=("img", "seg"), - mode=GridSampleMode.BILINEAR, - ), - {"img": torch.ones((1, 3, 3, 3)), "seg": torch.ones((1, 3, 3, 3))}, - torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]]), - ], - [ - dict( - prob=0.9, - mode=(GridSampleMode.BILINEAR, GridSampleMode.NEAREST), - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - scale_range=[0.1, 0.2], - as_tensor_output=False, - spatial_size=(3, 3), - keys=("img", "seg"), - device=torch.device("cpu:0"), - ), - {"img": torch.arange(64).reshape((1, 8, 8)), "seg": torch.arange(64).reshape((1, 8, 8))}, - { - "img": np.array( - [ - [ - [18.736153, 15.581954, 12.4277525], - [27.398798, 24.244598, 21.090399], - [36.061443, 32.90724, 29.753046], - ] - ] - ), - "seg": np.array([[[19.0, 20.0, 12.0], [27.0, 28.0, 20.0], [35.0, 36.0, 29.0]]]), - }, - ], - [ - dict( - prob=0.9, - mode=(GridSampleMode.BILINEAR, GridSampleMode.NEAREST), - rotate_range=(np.pi / 2,), - shear_range=[1, 2], - translate_range=[2, 1], - scale_range=[0.1, 0.2], - as_tensor_output=False, - spatial_size=(3, 3), - cache_grid=True, - keys=("img", "seg"), - device=torch.device("cpu:0"), - ), - {"img": torch.arange(64).reshape((1, 8, 8)), "seg": torch.arange(64).reshape((1, 8, 8))}, - { - "img": np.array( - [ - [ - [18.736153, 15.581954, 12.4277525], - [27.398798, 24.244598, 21.090399], - [36.061443, 32.90724, 29.753046], - ] - ] - ), - "seg": np.array([[[19.0, 20.0, 12.0], [27.0, 28.0, 20.0], [35.0, 36.0, 29.0]]]), - }, - ], -] +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( + [ + dict(device=device, spatial_size=None, keys=("img", "seg")), + {"img": p(torch.arange(27).reshape((3, 3, 3))), "seg": p(torch.arange(27).reshape((3, 3, 3)))}, + p(np.arange(27).reshape((3, 3, 3))), + ] + ) + TESTS.append( + [ + dict(device=device, spatial_size=(2, 2), keys=("img", "seg")), + {"img": p(torch.ones((3, 3, 3))), "seg": p(torch.ones((3, 3, 3)))}, + p(np.ones((3, 2, 2))), + ] + ) + TESTS.append( + [ + dict(device=device, spatial_size=(2, 2), cache_grid=True, keys=("img", "seg")), + {"img": p(torch.ones((3, 3, 3))), "seg": p(torch.ones((3, 3, 3)))}, + p(np.ones((3, 2, 2))), + ] + ) + TESTS.append( + [ + dict(device=device, spatial_size=(2, 2, 2), keys=("img", "seg")), + {"img": p(torch.ones((1, 3, 3, 3))), "seg": p(torch.ones((1, 3, 3, 3)))}, + p(torch.ones((1, 2, 2, 2))), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + spatial_size=(2, 2, 2), + padding_mode="zeros", + device=device, + keys=("img", "seg"), + mode="bilinear", + ), + {"img": p(torch.ones((1, 3, 3, 3))), "seg": p(torch.ones((1, 3, 3, 3)))}, + p(torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]])), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + scale_range=[0.1, 0.2], + spatial_size=(3, 3), + keys=("img", "seg"), + device=device, + ), + {"img": p(torch.arange(64).reshape((1, 8, 8))), "seg": p(torch.arange(64).reshape((1, 8, 8)))}, + p( + torch.tensor( + [[[18.7362, 15.5820, 12.4278], [27.3988, 24.2446, 21.0904], [36.0614, 32.9072, 29.7530]]] + ) + ), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + mode=("bilinear", "nearest"), + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + scale_range=[0.1, 0.2], + spatial_size=(3, 3), + keys=("img", "seg"), + device=device, + ), + {"img": p(torch.arange(64).reshape((1, 8, 8))), "seg": p(torch.arange(64).reshape((1, 8, 8)))}, + { + "img": p( + np.array( + [ + [ + [18.736153, 15.581954, 12.4277525], + [27.398798, 24.244598, 21.090399], + [36.061443, 32.90724, 29.753046], + ] + ] + ) + ), + "seg": p(np.array([[[19.0, 20.0, 12.0], [27.0, 28.0, 20.0], [35.0, 36.0, 29.0]]])), + }, + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + spatial_size=(2, 2, 2), + padding_mode="zeros", + device=device, + keys=("img", "seg"), + mode=GridSampleMode.BILINEAR, + ), + {"img": p(torch.ones((1, 3, 3, 3))), "seg": p(torch.ones((1, 3, 3, 3)))}, + p(torch.tensor([[[[0.3658, 1.0000], [1.0000, 1.0000]], [[1.0000, 1.0000], [1.0000, 0.9333]]]])), + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + mode=(GridSampleMode.BILINEAR, GridSampleMode.NEAREST), + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + scale_range=[0.1, 0.2], + spatial_size=(3, 3), + keys=("img", "seg"), + device=device, + ), + {"img": p(torch.arange(64).reshape((1, 8, 8))), "seg": p(torch.arange(64).reshape((1, 8, 8)))}, + { + "img": p( + np.array( + [ + [ + [18.736153, 15.581954, 12.4277525], + [27.398798, 24.244598, 21.090399], + [36.061443, 32.90724, 29.753046], + ] + ] + ) + ), + "seg": p(np.array([[[19.0, 20.0, 12.0], [27.0, 28.0, 20.0], [35.0, 36.0, 29.0]]])), + }, + ] + ) + TESTS.append( + [ + dict( + prob=0.9, + mode=(GridSampleMode.BILINEAR, GridSampleMode.NEAREST), + rotate_range=(np.pi / 2,), + shear_range=[1, 2], + translate_range=[2, 1], + scale_range=[0.1, 0.2], + spatial_size=(3, 3), + cache_grid=True, + keys=("img", "seg"), + device=device, + ), + {"img": p(torch.arange(64).reshape((1, 8, 8))), "seg": p(torch.arange(64).reshape((1, 8, 8)))}, + { + "img": p( + np.array( + [ + [ + [18.736153, 15.581954, 12.4277525], + [27.398798, 24.244598, 21.090399], + [36.061443, 32.90724, 29.753046], + ] + ] + ) + ), + "seg": p(np.array([[[19.0, 20.0, 12.0], [27.0, 28.0, 20.0], [35.0, 36.0, 29.0]]])), + }, + ] + ) class TestRandAffined(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_affined(self, input_param, input_data, expected_val): g = RandAffined(**input_param).set_random_state(123) res = g(input_data) @@ -200,23 +209,16 @@ def test_rand_affined(self, input_param, input_data, expected_val): if "_transforms" in key: continue expected = expected_val[key] if isinstance(expected_val, dict) else expected_val - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected, rtol=1e-4, atol=1e-4) def test_ill_cache(self): with self.assertWarns(UserWarning): # spatial size is None - RandAffined( - as_tensor_output=False, device=None, spatial_size=None, prob=1.0, cache_grid=True, keys=("img", "seg") - ) + RandAffined(device=device, spatial_size=None, prob=1.0, cache_grid=True, keys=("img", "seg")) with self.assertWarns(UserWarning): # spatial size is dynamic RandAffined( - as_tensor_output=False, - device=None, + device=device, spatial_size=(2, -1), prob=1.0, cache_grid=True, diff --git a/tests/test_rand_elastic_2d.py b/tests/test_rand_elastic_2d.py index fbfb7d5761..c414eb1ffd 100644 --- a/tests/test_rand_elastic_2d.py +++ b/tests/test_rand_elastic_2d.py @@ -16,90 +16,101 @@ from parameterized import parameterized from monai.transforms import Rand2DElastic +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - {"spacing": (0.3, 0.3), "magnitude_range": (1.0, 2.0), "prob": 0.0, "as_tensor_output": False, "device": None}, - {"img": torch.ones((3, 3, 3)), "spatial_size": (2, 2)}, - np.ones((3, 2, 2)), - ], - [ - {"spacing": (0.3, 0.3), "magnitude_range": (1.0, 2.0), "prob": 0.0, "as_tensor_output": False, "device": None}, - {"img": torch.arange(27).reshape((3, 3, 3))}, - np.arange(27).reshape((3, 3, 3)), - ], - [ - { - "spacing": (0.3, 0.3), - "magnitude_range": (1.0, 2.0), - "prob": 0.9, - "as_tensor_output": False, - "device": None, - "padding_mode": "zeros", - }, - {"img": torch.ones((3, 3, 3)), "spatial_size": (2, 2), "mode": "bilinear"}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( [ - [[0.45531988, 0.0], [0.0, 0.71558857]], - [[0.45531988, 0.0], [0.0, 0.71558857]], - [[0.45531988, 0.0], [0.0, 0.71558857]], + {"spacing": (0.3, 0.3), "magnitude_range": (1.0, 2.0), "prob": 0.0, "device": device}, + {"img": p(torch.ones((3, 3, 3))), "spatial_size": (2, 2)}, + p(np.ones((3, 2, 2))), ] - ), - ], - [ - { - "spacing": (1.0, 1.0), - "magnitude_range": (1.0, 1.0), - "scale_range": [1.2, 2.2], - "prob": 0.9, - "padding_mode": "border", - "as_tensor_output": True, - "device": None, - "spatial_size": (2, 2), - }, - {"img": torch.arange(27).reshape((3, 3, 3))}, - torch.tensor( + ) + TESTS.append( [ - [[3.0793, 2.6141], [4.0568, 5.9978]], - [[12.0793, 11.6141], [13.0568, 14.9978]], - [[21.0793, 20.6141], [22.0568, 23.9978]], + {"spacing": (0.3, 0.3), "magnitude_range": (1.0, 2.0), "prob": 0.0, "device": device}, + {"img": p(torch.arange(27).reshape((3, 3, 3)))}, + p(np.arange(27).reshape((3, 3, 3))), ] - ), - ], - [ - { - "spacing": (0.3, 0.3), - "magnitude_range": (0.1, 0.2), - "translate_range": [-0.01, 0.01], - "scale_range": [0.01, 0.02], - "prob": 0.9, - "as_tensor_output": False, - "device": "cuda" if torch.cuda.is_available() else "cpu", - "spatial_size": (2, 2), - }, - {"img": torch.arange(27).reshape((3, 3, 3))}, - np.array( + ) + TESTS.append( [ - [[1.3584113, 1.9251312], [5.626623, 6.642721]], - [[10.358411, 10.925131], [14.626623, 15.642721]], - [[19.358412, 19.92513], [23.626623, 24.642721]], + { + "spacing": (0.3, 0.3), + "magnitude_range": (1.0, 2.0), + "prob": 0.9, + "device": device, + "padding_mode": "zeros", + }, + {"img": p(torch.ones((3, 3, 3))), "spatial_size": (2, 2), "mode": "bilinear"}, + p( + np.array( + [ + [[0.45531988, 0.0], [0.0, 0.71558857]], + [[0.45531988, 0.0], [0.0, 0.71558857]], + [[0.45531988, 0.0], [0.0, 0.71558857]], + ] + ) + ), ] - ), - ], -] + ) + TESTS.append( + [ + { + "spacing": (1.0, 1.0), + "magnitude_range": (1.0, 1.0), + "scale_range": [1.2, 2.2], + "prob": 0.9, + "padding_mode": "border", + "device": device, + "spatial_size": (2, 2), + }, + {"img": p(torch.arange(27).reshape((3, 3, 3)))}, + p( + torch.tensor( + [ + [[3.0793, 2.6141], [4.0568, 5.9978]], + [[12.0793, 11.6141], [13.0568, 14.9978]], + [[21.0793, 20.6141], [22.0568, 23.9978]], + ] + ) + ), + ] + ) + TESTS.append( + [ + { + "spacing": (0.3, 0.3), + "magnitude_range": (0.1, 0.2), + "translate_range": [-0.01, 0.01], + "scale_range": [0.01, 0.02], + "prob": 0.9, + "device": device, + "spatial_size": (2, 2), + }, + {"img": p(torch.arange(27).reshape((3, 3, 3)))}, + p( + np.array( + [ + [[1.3584113, 1.9251312], [5.626623, 6.642721]], + [[10.358411, 10.925131], [14.626623, 15.642721]], + [[19.358412, 19.92513], [23.626623, 24.642721]], + ] + ) + ), + ] + ) class TestRand2DElastic(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_2d_elastic(self, input_param, input_data, expected_val): g = Rand2DElastic(**input_param) g.set_random_state(123) result = g(**input_data) - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected_val.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_rand_elastic_3d.py b/tests/test_rand_elastic_3d.py index c63282d571..d44324746f 100644 --- a/tests/test_rand_elastic_3d.py +++ b/tests/test_rand_elastic_3d.py @@ -16,69 +16,89 @@ from parameterized import parameterized from monai.transforms import Rand3DElastic +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - { - "magnitude_range": (0.3, 2.3), - "sigma_range": (1.0, 20.0), - "prob": 0.0, - "as_tensor_output": False, - "device": None, - "spatial_size": -1, - }, - {"img": torch.arange(72).reshape((2, 3, 3, 4))}, - np.arange(72).reshape((2, 3, 3, 4)), - ], - [ - { - "magnitude_range": (0.3, 2.3), - "sigma_range": (1.0, 20.0), - "prob": 0.0, - "as_tensor_output": False, - "device": None, - }, - {"img": torch.ones((2, 3, 3, 3)), "spatial_size": (2, 2, 2)}, - np.ones((2, 2, 2, 2)), - ], - [ - { - "magnitude_range": (0.3, 0.3), - "sigma_range": (1.0, 2.0), - "prob": 0.9, - "as_tensor_output": False, - "device": None, - }, - {"img": torch.arange(27).reshape((1, 3, 3, 3)), "spatial_size": (2, 2, 2)}, - np.array([[[[6.4939356, 7.50289], [9.518351, 10.522849]], [[15.512375, 16.523542], [18.531467, 19.53646]]]]), - ], - [ - { - "magnitude_range": (0.3, 0.3), - "sigma_range": (1.0, 2.0), - "prob": 0.9, - "rotate_range": [1, 1, 1], - "as_tensor_output": False, - "device": "cuda" if torch.cuda.is_available() else "cpu", - "spatial_size": (2, 2, 2), - }, - {"img": torch.arange(27).reshape((1, 3, 3, 3)), "mode": "bilinear"}, - np.array([[[[5.0069294, 9.463932], [9.287769, 13.739735]], [[12.319424, 16.777205], [16.594296, 21.045748]]]]), - ], -] +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( + [ + { + "magnitude_range": (0.3, 2.3), + "sigma_range": (1.0, 20.0), + "prob": 0.0, + "device": device, + "spatial_size": -1, + }, + {"img": p(torch.arange(72).reshape((2, 3, 3, 4)))}, + p(np.arange(72).reshape((2, 3, 3, 4))), + ] + ) + TESTS.append( + [ + { + "magnitude_range": (0.3, 2.3), + "sigma_range": (1.0, 20.0), + "prob": 0.0, + "device": device, + }, + {"img": p(torch.ones((2, 3, 3, 3))), "spatial_size": (2, 2, 2)}, + p(np.ones((2, 2, 2, 2))), + ] + ) + TESTS.append( + [ + { + "magnitude_range": (0.3, 0.3), + "sigma_range": (1.0, 2.0), + "prob": 0.9, + "device": device, + }, + {"img": p(torch.arange(27).reshape((1, 3, 3, 3))), "spatial_size": (2, 2, 2)}, + p( + np.array( + [ + [ + [[6.4939356, 7.50289], [9.518351, 10.522849]], + [[15.512375, 16.523542], [18.531467, 19.53646]], + ] + ] + ) + ), + ] + ) + TESTS.append( + [ + { + "magnitude_range": (0.3, 0.3), + "sigma_range": (1.0, 2.0), + "prob": 0.9, + "rotate_range": [1, 1, 1], + "device": device, + "spatial_size": (2, 2, 2), + }, + {"img": p(torch.arange(27).reshape((1, 3, 3, 3))), "mode": "bilinear"}, + p( + np.array( + [ + [ + [[5.0069294, 9.463932], [9.287769, 13.739735]], + [[12.319424, 16.777205], [16.594296, 21.045748]], + ] + ] + ) + ), + ] + ) class TestRand3DElastic(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_3d_elastic(self, input_param, input_data, expected_val): g = Rand3DElastic(**input_param) g.set_random_state(123) result = g(**input_data) - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected_val.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_rand_elasticd_2d.py b/tests/test_rand_elasticd_2d.py index f8eb026088..84f18120e1 100644 --- a/tests/test_rand_elasticd_2d.py +++ b/tests/test_rand_elasticd_2d.py @@ -16,127 +16,147 @@ from parameterized import parameterized from monai.transforms import Rand2DElasticd +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - { - "keys": ("img", "seg"), - "spacing": (0.3, 0.3), - "magnitude_range": (1.0, 2.0), - "prob": 0.0, - "as_tensor_output": False, - "device": None, - "spatial_size": (2, 2), - }, - {"img": torch.ones((3, 3, 3)), "seg": torch.ones((3, 3, 3))}, - np.ones((3, 2, 2)), - ], - [ - { - "keys": ("img", "seg"), - "spacing": (0.3, 0.3), - "magnitude_range": (0.3, 0.3), - "prob": 0.0, - "as_tensor_output": False, - "device": None, - "spatial_size": -1, - }, - {"img": torch.arange(4).reshape((1, 2, 2)), "seg": torch.arange(4).reshape((1, 2, 2))}, - np.arange(4).reshape((1, 2, 2)), - ], - [ - { - "keys": ("img", "seg"), - "spacing": (0.3, 0.3), - "magnitude_range": (1.0, 2.0), - "prob": 0.9, - "as_tensor_output": False, - "padding_mode": "zeros", - "device": None, - "spatial_size": (2, 2), - "mode": "bilinear", - }, - {"img": torch.ones((3, 3, 3)), "seg": torch.ones((3, 3, 3))}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( [ - [[0.45531988, 0.0], [0.0, 0.71558857]], - [[0.45531988, 0.0], [0.0, 0.71558857]], - [[0.45531988, 0.0], [0.0, 0.71558857]], + { + "keys": ("img", "seg"), + "spacing": (0.3, 0.3), + "magnitude_range": (1.0, 2.0), + "prob": 0.0, + "device": device, + "spatial_size": (2, 2), + }, + {"img": p(torch.ones((3, 3, 3))), "seg": p(torch.ones((3, 3, 3)))}, + p(np.ones((3, 2, 2))), ] - ), - ], - [ - { - "keys": ("img", "seg"), - "spacing": (1.0, 1.0), - "magnitude_range": (1.0, 1.0), - "scale_range": [1.2, 2.2], - "prob": 0.9, - "padding_mode": "border", - "as_tensor_output": True, - "device": None, - "spatial_size": (2, 2), - }, - {"img": torch.arange(27).reshape((3, 3, 3)), "seg": torch.arange(27).reshape((3, 3, 3))}, - torch.tensor( + ) + TESTS.append( [ - [[3.0793, 2.6141], [4.0568, 5.9978]], - [[12.0793, 11.6141], [13.0568, 14.9978]], - [[21.0793, 20.6141], [22.0568, 23.9978]], + { + "keys": ("img", "seg"), + "spacing": (0.3, 0.3), + "magnitude_range": (0.3, 0.3), + "prob": 0.0, + "device": device, + "spatial_size": -1, + }, + {"img": p(torch.arange(4).reshape((1, 2, 2))), "seg": p(torch.arange(4).reshape((1, 2, 2)))}, + p(np.arange(4).reshape((1, 2, 2))), ] - ), - ], - [ - { - "keys": ("img", "seg"), - "spacing": (0.3, 0.3), - "magnitude_range": (0.1, 0.2), - "translate_range": [-0.01, 0.01], - "scale_range": [0.01, 0.02], - "prob": 0.9, - "as_tensor_output": False, - "device": None, - "spatial_size": (2, 2), - }, - {"img": torch.arange(27).reshape((3, 3, 3)), "seg": torch.arange(27).reshape((3, 3, 3))}, - np.array( + ) + TESTS.append( [ - [[1.3584113, 1.9251312], [5.626623, 6.642721]], - [[10.358411, 10.925131], [14.626623, 15.642721]], - [[19.358412, 19.92513], [23.626623, 24.642721]], + { + "keys": ("img", "seg"), + "spacing": (0.3, 0.3), + "magnitude_range": (1.0, 2.0), + "prob": 0.9, + "padding_mode": "zeros", + "device": device, + "spatial_size": (2, 2), + "mode": "bilinear", + }, + {"img": p(torch.ones((3, 3, 3))), "seg": p(torch.ones((3, 3, 3)))}, + p( + np.array( + [ + [[0.45531988, 0.0], [0.0, 0.71558857]], + [[0.45531988, 0.0], [0.0, 0.71558857]], + [[0.45531988, 0.0], [0.0, 0.71558857]], + ] + ) + ), ] - ), - ], - [ - { - "keys": ("img", "seg"), - "mode": ("bilinear", "nearest"), - "spacing": (0.3, 0.3), - "magnitude_range": (0.1, 0.2), - "translate_range": [-0.01, 0.01], - "scale_range": [0.01, 0.02], - "prob": 0.9, - "as_tensor_output": True, - "device": None, - "spatial_size": (2, 2), - }, - {"img": torch.arange(27).reshape((3, 3, 3)), "seg": torch.arange(27).reshape((3, 3, 3))}, - { - "img": torch.tensor( - [ - [[1.3584, 1.9251], [5.6266, 6.6427]], - [[10.3584, 10.9251], [14.6266, 15.6427]], - [[19.3584, 19.9251], [23.6266, 24.6427]], - ] - ), - "seg": torch.tensor([[[0.0, 2.0], [6.0, 8.0]], [[9.0, 11.0], [15.0, 17.0]], [[18.0, 20.0], [24.0, 26.0]]]), - }, - ], -] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "spacing": (1.0, 1.0), + "magnitude_range": (1.0, 1.0), + "scale_range": [1.2, 2.2], + "prob": 0.9, + "padding_mode": "border", + "device": device, + "spatial_size": (2, 2), + }, + {"img": p(torch.arange(27).reshape((3, 3, 3))), "seg": p(torch.arange(27).reshape((3, 3, 3)))}, + p( + torch.tensor( + [ + [[3.0793, 2.6141], [4.0568, 5.9978]], + [[12.0793, 11.6141], [13.0568, 14.9978]], + [[21.0793, 20.6141], [22.0568, 23.9978]], + ] + ) + ), + ] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "spacing": (0.3, 0.3), + "magnitude_range": (0.1, 0.2), + "translate_range": [-0.01, 0.01], + "scale_range": [0.01, 0.02], + "prob": 0.9, + "device": device, + "spatial_size": (2, 2), + }, + {"img": p(torch.arange(27).reshape((3, 3, 3))), "seg": p(torch.arange(27).reshape((3, 3, 3)))}, + p( + np.array( + [ + [[1.3584113, 1.9251312], [5.626623, 6.642721]], + [[10.358411, 10.925131], [14.626623, 15.642721]], + [[19.358412, 19.92513], [23.626623, 24.642721]], + ] + ) + ), + ] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "mode": ("bilinear", "nearest"), + "spacing": (0.3, 0.3), + "magnitude_range": (0.1, 0.2), + "translate_range": [-0.01, 0.01], + "scale_range": [0.01, 0.02], + "prob": 0.9, + "device": device, + "spatial_size": (2, 2), + }, + {"img": p(torch.arange(27).reshape((3, 3, 3))), "seg": p(torch.arange(27).reshape((3, 3, 3)))}, + { + "img": p( + torch.tensor( + [ + [[1.3584, 1.9251], [5.6266, 6.6427]], + [[10.3584, 10.9251], [14.6266, 15.6427]], + [[19.3584, 19.9251], [23.6266, 24.6427]], + ] + ) + ), + "seg": p( + torch.tensor( + [[[0.0, 2.0], [6.0, 8.0]], [[9.0, 11.0], [15.0, 17.0]], [[18.0, 20.0], [24.0, 26.0]]] + ) + ), + }, + ] + ) class TestRand2DElasticd(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_2d_elasticd(self, input_param, input_data, expected_val): g = Rand2DElasticd(**input_param) g.set_random_state(123) @@ -144,11 +164,7 @@ def test_rand_2d_elasticd(self, input_param, input_data, expected_val): for key in res: result = res[key] expected = expected_val[key] if isinstance(expected_val, dict) else expected_val - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_rand_elasticd_3d.py b/tests/test_rand_elasticd_3d.py index 47ab814882..5f8a5f47ed 100644 --- a/tests/test_rand_elasticd_3d.py +++ b/tests/test_rand_elasticd_3d.py @@ -16,98 +16,128 @@ from parameterized import parameterized from monai.transforms import Rand3DElasticd +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - { - "keys": ("img", "seg"), - "magnitude_range": (0.3, 2.3), - "sigma_range": (1.0, 20.0), - "prob": 0.0, - "as_tensor_output": False, - "device": None, - "spatial_size": (2, 2, 2), - }, - {"img": torch.ones((2, 3, 3, 3)), "seg": torch.ones((2, 3, 3, 3))}, - np.ones((2, 2, 2, 2)), - ], - [ - { - "keys": ("img", "seg"), - "magnitude_range": (0.3, 2.3), - "sigma_range": (1.0, 20.0), - "prob": 0.0, - "as_tensor_output": False, - "device": None, - "spatial_size": (2, -1, -1), - }, - {"img": torch.ones((2, 3, 3, 3)), "seg": torch.ones((2, 3, 3, 3))}, - np.ones((2, 2, 3, 3)), - ], - [ - { - "keys": ("img", "seg"), - "magnitude_range": (0.3, 2.3), - "sigma_range": (1.0, 20.0), - "prob": 0.0, - "as_tensor_output": False, - "device": None, - "spatial_size": -1, - }, - {"img": torch.arange(8).reshape((1, 2, 2, 2)), "seg": torch.arange(8).reshape((1, 2, 2, 2))}, - np.arange(8).reshape((1, 2, 2, 2)), - ], - [ - { - "keys": ("img", "seg"), - "magnitude_range": (0.3, 0.3), - "sigma_range": (1.0, 2.0), - "prob": 0.9, - "as_tensor_output": False, - "device": None, - "spatial_size": (2, 2, 2), - }, - {"img": torch.arange(27).reshape((1, 3, 3, 3)), "seg": torch.arange(27).reshape((1, 3, 3, 3))}, - np.array([[[[6.4939356, 7.50289], [9.518351, 10.522849]], [[15.512375, 16.523542], [18.531467, 19.53646]]]]), - ], - [ - { - "keys": ("img", "seg"), - "magnitude_range": (0.3, 0.3), - "sigma_range": (1.0, 2.0), - "prob": 0.9, - "rotate_range": [1, 1, 1], - "as_tensor_output": False, - "device": None, - "spatial_size": (2, 2, 2), - "mode": "bilinear", - }, - {"img": torch.arange(27).reshape((1, 3, 3, 3)), "seg": torch.arange(27).reshape((1, 3, 3, 3))}, - np.array([[[[5.0069294, 9.463932], [9.287769, 13.739735]], [[12.319424, 16.777205], [16.594296, 21.045748]]]]), - ], - [ - { - "keys": ("img", "seg"), - "mode": ("bilinear", "nearest"), - "magnitude_range": (0.3, 0.3), - "sigma_range": (1.0, 2.0), - "prob": 0.9, - "rotate_range": [1, 1, 1], - "as_tensor_output": True, - "device": torch.device("cpu:0"), - "spatial_size": (2, 2, 2), - }, - {"img": torch.arange(27).reshape((1, 3, 3, 3)), "seg": torch.arange(27).reshape((1, 3, 3, 3))}, - { - "img": torch.tensor([[[[5.0069, 9.4639], [9.2878, 13.7397]], [[12.3194, 16.7772], [16.5943, 21.0457]]]]), - "seg": torch.tensor([[[[4.0, 14.0], [7.0, 14.0]], [[9.0, 19.0], [12.0, 22.0]]]]), - }, - ], -] +TESTS = [] +for p in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( + [ + { + "keys": ("img", "seg"), + "magnitude_range": (0.3, 2.3), + "sigma_range": (1.0, 20.0), + "prob": 0.0, + "device": device, + "spatial_size": (2, 2, 2), + }, + {"img": p(torch.ones((2, 3, 3, 3))), "seg": p(torch.ones((2, 3, 3, 3)))}, + p(np.ones((2, 2, 2, 2))), + ] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "magnitude_range": (0.3, 2.3), + "sigma_range": (1.0, 20.0), + "prob": 0.0, + "device": device, + "spatial_size": (2, -1, -1), + }, + {"img": p(torch.ones((2, 3, 3, 3))), "seg": p(torch.ones((2, 3, 3, 3)))}, + p(np.ones((2, 2, 3, 3))), + ] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "magnitude_range": (0.3, 2.3), + "sigma_range": (1.0, 20.0), + "prob": 0.0, + "device": device, + "spatial_size": -1, + }, + {"img": p(torch.arange(8).reshape((1, 2, 2, 2))), "seg": p(torch.arange(8).reshape((1, 2, 2, 2)))}, + p(np.arange(8).reshape((1, 2, 2, 2))), + ] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "magnitude_range": (0.3, 0.3), + "sigma_range": (1.0, 2.0), + "prob": 0.9, + "device": device, + "spatial_size": (2, 2, 2), + }, + {"img": p(torch.arange(27).reshape((1, 3, 3, 3))), "seg": p(torch.arange(27).reshape((1, 3, 3, 3)))}, + p( + np.array( + [ + [ + [[6.4939356, 7.50289], [9.518351, 10.522849]], + [[15.512375, 16.523542], [18.531467, 19.53646]], + ] + ] + ) + ), + ] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "magnitude_range": (0.3, 0.3), + "sigma_range": (1.0, 2.0), + "prob": 0.9, + "rotate_range": [1, 1, 1], + "device": device, + "spatial_size": (2, 2, 2), + "mode": "bilinear", + }, + {"img": p(torch.arange(27).reshape((1, 3, 3, 3))), "seg": p(torch.arange(27).reshape((1, 3, 3, 3)))}, + p( + np.array( + [ + [ + [[5.0069294, 9.463932], [9.287769, 13.739735]], + [[12.319424, 16.777205], [16.594296, 21.045748]], + ] + ] + ) + ), + ] + ) + TESTS.append( + [ + { + "keys": ("img", "seg"), + "mode": ("bilinear", "nearest"), + "magnitude_range": (0.3, 0.3), + "sigma_range": (1.0, 2.0), + "prob": 0.9, + "rotate_range": [1, 1, 1], + "device": device, + "spatial_size": (2, 2, 2), + }, + {"img": p(torch.arange(27).reshape((1, 3, 3, 3))), "seg": p(torch.arange(27).reshape((1, 3, 3, 3)))}, + { + "img": p( + torch.tensor( + [[[[5.0069, 9.4639], [9.2878, 13.7397]], [[12.3194, 16.7772], [16.5943, 21.0457]]]] + ) + ), + "seg": p(torch.tensor([[[[4.0, 14.0], [7.0, 14.0]], [[9.0, 19.0], [12.0, 22.0]]]])), + }, + ] + ) class TestRand3DElasticd(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_3d_elasticd(self, input_param, input_data, expected_val): g = Rand3DElasticd(**input_param) g.set_random_state(123) @@ -115,11 +145,7 @@ def test_rand_3d_elasticd(self, input_param, input_data, expected_val): for key in res: result = res[key] expected = expected_val[key] if isinstance(expected_val, dict) else expected_val - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_resampler.py b/tests/test_resampler.py index 2be94acebd..af23421ecc 100644 --- a/tests/test_resampler.py +++ b/tests/test_resampler.py @@ -17,69 +17,146 @@ from monai.transforms import Resample from monai.transforms.utils import create_grid +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"grid": create_grid((2, 2)), "img": np.arange(4).reshape((1, 2, 2))}, - np.array([[[0.0, 1.0], [2.0, 3.0]]]), - ], - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"grid": create_grid((4, 4)), "img": np.arange(4).reshape((1, 2, 2))}, - np.array([[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]]]), - ], - [ - dict(padding_mode="border", as_tensor_output=False, device=None), - {"grid": create_grid((4, 4)), "img": np.arange(4).reshape((1, 2, 2))}, - np.array([[[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3, 3.0], [2.0, 2.0, 3.0, 3.0]]]), - ], - [ - dict(padding_mode="reflection", as_tensor_output=False, device=None), - {"grid": create_grid((4, 4)), "img": np.arange(4).reshape((1, 2, 2)), "mode": "nearest"}, - np.array([[[3.0, 2.0, 3.0, 2.0], [1.0, 0.0, 1.0, 0.0], [3.0, 2.0, 3.0, 2.0], [1.0, 0.0, 1.0, 0.0]]]), - ], - [ - dict(padding_mode="zeros", as_tensor_output=False, device=None), - {"grid": create_grid((4, 4, 4)), "img": np.arange(8).reshape((1, 2, 2, 2)), "mode": "bilinear"}, - np.array( - [ +TESTS = [] +for p in TEST_NDARRAYS: + for q in TEST_NDARRAYS: + for device in [None, "cpu", "cuda"] if torch.cuda.is_available() else [None, "cpu"]: + TESTS.append( [ - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.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, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 4.0, 5.0, 0.0], [0.0, 6.0, 7.0, 0.0], [0.0, 0.0, 0.0, 0.0]], - [[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], + dict(padding_mode="zeros", device=device), + {"grid": p(create_grid((2, 2))), "img": q(np.arange(4).reshape((1, 2, 2)))}, + q(np.array([[[0.0, 1.0], [2.0, 3.0]]])), ] - ] - ), - ], - [ - dict(padding_mode="border", as_tensor_output=False, device=None), - {"grid": create_grid((4, 4, 4)), "img": np.arange(8).reshape((1, 2, 2, 2)), "mode": "bilinear"}, - np.array( - [ + ) + TESTS.append( [ - [[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3.0, 3.0], [2.0, 2.0, 3.0, 3.0]], - [[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3.0, 3.0], [2.0, 2.0, 3.0, 3.0]], - [[4.0, 4.0, 5.0, 5.0], [4.0, 4.0, 5.0, 5.0], [6.0, 6.0, 7.0, 7.0], [6.0, 6.0, 7.0, 7.0]], - [[4.0, 4.0, 5.0, 5.0], [4.0, 4.0, 5.0, 5.0], [6.0, 6.0, 7.0, 7.0], [6.0, 6.0, 7.0, 7.0]], + dict(padding_mode="zeros", device=device), + {"grid": p(create_grid((4, 4))), "img": q(np.arange(4).reshape((1, 2, 2)))}, + q( + np.array( + [[[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 2.0, 3.0, 0.0], [0.0, 0.0, 0.0, 0.0]]] + ) + ), ] - ] - ), - ], -] + ) + TESTS.append( + [ + dict(padding_mode="border", device=device), + {"grid": p(create_grid((4, 4))), "img": q(np.arange(4).reshape((1, 2, 2)))}, + q( + np.array( + [[[0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3, 3.0], [2.0, 2.0, 3.0, 3.0]]] + ) + ), + ] + ) + TESTS.append( + [ + dict(padding_mode="reflection", device=device), + {"grid": p(create_grid((4, 4))), "img": q(np.arange(4).reshape((1, 2, 2))), "mode": "nearest"}, + q( + np.array( + [[[3.0, 2.0, 3.0, 2.0], [1.0, 0.0, 1.0, 0.0], [3.0, 2.0, 3.0, 2.0], [1.0, 0.0, 1.0, 0.0]]] + ) + ), + ] + ) + TESTS.append( + [ + dict(padding_mode="zeros", device=device), + { + "grid": p(create_grid((4, 4, 4))), + "img": q(np.arange(8).reshape((1, 2, 2, 2))), + "mode": "bilinear", + }, + q( + np.array( + [ + [ + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.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, 0.0], + [0.0, 2.0, 3.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 4.0, 5.0, 0.0], + [0.0, 6.0, 7.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + ] + ] + ) + ), + ] + ) + TESTS.append( + [ + dict(padding_mode="border", device=device), + { + "grid": p(create_grid((4, 4, 4))), + "img": q(np.arange(8).reshape((1, 2, 2, 2))), + "mode": "bilinear", + }, + q( + np.array( + [ + [ + [ + [0.0, 0.0, 1.0, 1.0], + [0.0, 0.0, 1.0, 1.0], + [2.0, 2.0, 3.0, 3.0], + [2.0, 2.0, 3.0, 3.0], + ], + [ + [0.0, 0.0, 1.0, 1.0], + [0.0, 0.0, 1.0, 1.0], + [2.0, 2.0, 3.0, 3.0], + [2.0, 2.0, 3.0, 3.0], + ], + [ + [4.0, 4.0, 5.0, 5.0], + [4.0, 4.0, 5.0, 5.0], + [6.0, 6.0, 7.0, 7.0], + [6.0, 6.0, 7.0, 7.0], + ], + [ + [4.0, 4.0, 5.0, 5.0], + [4.0, 4.0, 5.0, 5.0], + [6.0, 6.0, 7.0, 7.0], + [6.0, 6.0, 7.0, 7.0], + ], + ] + ] + ) + ), + ] + ) class TestResample(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_resample(self, input_param, input_data, expected_val): g = Resample(**input_param) result = g(**input_data) - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected_val.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + if "device" in input_data: + self.assertEqual(result.device, input_data["device"]) + assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/utils.py b/tests/utils.py index 3364085e13..94f7f55fe0 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -64,9 +64,11 @@ def assert_allclose(a: NdarrayOrTensor, b: NdarrayOrTensor, *args, **kwargs): Args: a (NdarrayOrTensor): Pytorch Tensor or numpy array for comparison b (NdarrayOrTensor): Pytorch Tensor or numpy array to compare against + args: extra arguments to pass on to `np.testing.assert_allclose` + kwargs: extra arguments to pass on to `np.testing.assert_allclose` """ - a = a.cpu() if isinstance(a, torch.Tensor) else a - b = b.cpu() if isinstance(b, torch.Tensor) else b + a = a.cpu().numpy() if isinstance(a, torch.Tensor) else a + b = b.cpu().numpy() if isinstance(b, torch.Tensor) else b np.testing.assert_allclose(a, b, *args, **kwargs) From 7c45d0195e7b32f75ceb61bc98d630851ddf812f Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Tue, 14 Sep 2021 20:22:24 +0100 Subject: [PATCH 19/89] All transforms support torch and numpy (#2949) * transforms convert to the necessary type Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/croppad/array.py | 18 ++++++++++++++++++ monai/transforms/intensity/array.py | 16 +++++++++++++++- monai/transforms/spatial/array.py | 6 ++++++ monai/transforms/utility/array.py | 15 ++++++++++++++- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index 4d2a62b390..d3cec35d93 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -421,6 +421,7 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]): Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ + img, *_ = convert_data_type(img, np.ndarray) sd = min(len(self.slices), len(img.shape[1:])) # spatial dims slices = [slice(None)] + self.slices[:sd] return img[tuple(slices)] @@ -449,6 +450,7 @@ def __call__(self, img: np.ndarray): Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore roi_size = fall_back_tuple(self.roi_size, img.shape[1:]) center = [i // 2 for i in img.shape[1:]] cropper = SpatialCrop(roi_center=center, roi_size=roi_size) @@ -469,6 +471,7 @@ def __init__(self, roi_scale: Union[Sequence[float], float]): self.roi_scale = roi_scale def __call__(self, img: np.ndarray): + img, *_ = convert_data_type(img, np.ndarray) # type: ignore img_size = img.shape[1:] ndim = len(img_size) roi_size = [ceil(r * s) for r, s in zip(ensure_tuple_rep(self.roi_scale, ndim), img_size)] @@ -530,6 +533,7 @@ def __call__(self, img: np.ndarray): Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize(img.shape[1:]) if self._size is None: raise AssertionError @@ -576,6 +580,7 @@ def __call__(self, img: np.ndarray): Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore img_size = img.shape[1:] ndim = len(img_size) self.roi_size = [ceil(r * s) for r, s in zip(ensure_tuple_rep(self.roi_scale, ndim), img_size)] @@ -645,6 +650,7 @@ def __call__(self, img: np.ndarray) -> List[np.ndarray]: Apply the transform to `img`, assuming `img` is channel-first and cropping doesn't change the channel dim. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore return [self.cropper(img) for _ in range(self.num_samples)] @@ -801,12 +807,16 @@ def __call__(self, img: np.ndarray, weight_map: Optional[np.ndarray] = None) -> Returns: A list of image patches """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore if weight_map is None: weight_map = self.weight_map if weight_map is None: raise ValueError("weight map must be provided for weighted patch sampling.") if img.shape[1:] != weight_map.shape[1:]: raise ValueError(f"image and weight map spatial shape mismatch: {img.shape[1:]} vs {weight_map.shape[1:]}.") + + weight_map, *_ = convert_data_type(weight_map, np.ndarray) # type: ignore + self.randomize(weight_map) _spatial_size = fall_back_tuple(self.spatial_size, weight_map.shape[1:]) results = [] @@ -942,6 +952,9 @@ def __call__( if image is None: image = self.image + image, *_ = convert_data_type(image, np.ndarray) # type: ignore + label, *_ = convert_data_type(label, np.ndarray) # type: ignore + self.randomize(label, fg_indices, bg_indices, image) results: List[np.ndarray] = [] if self.centers is not None: @@ -1075,6 +1088,9 @@ def __call__( if image is None: image = self.image + image, *_ = convert_data_type(image, np.ndarray) # type: ignore + label, *_ = convert_data_type(label, np.ndarray) # type: ignore + self.randomize(label, indices, image) results: List[np.ndarray] = [] if self.centers is not None: @@ -1127,6 +1143,7 @@ def __call__(self, img: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = N If None, defaults to the ``mode`` in construction. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore return self.padder(self.cropper(img), mode=mode) @@ -1161,6 +1178,7 @@ def __call__(self, img: np.ndarray) -> np.ndarray: """ See also: :py:class:`monai.transforms.utils.generate_spatial_bounding_box`. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore bbox = [] for channel in range(img.shape[0]): diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 6c45f0d52b..a1423c8ee5 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -531,6 +531,7 @@ def __call__(self, img: np.ndarray): """ Apply the transform to `img`. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize(data=img) if not self._do_transform: return img @@ -731,6 +732,7 @@ def __call__(self, img: np.ndarray): """ Apply the transform to `img`. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore epsilon = 1e-7 img_min = img.min() img_range = img.max() - img_min @@ -773,6 +775,7 @@ def __call__(self, img: np.ndarray): """ Apply the transform to `img`. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize() if self.gamma_value is None: raise ValueError("gamma_value is not set.") @@ -910,10 +913,13 @@ def __call__(self, img: np.ndarray, mask_data: Optional[np.ndarray] = None) -> n - ValueError: When ``mask_data`` and ``img`` channels differ and ``mask_data`` is not single channel. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore mask_data = self.mask_data if mask_data is None else mask_data if mask_data is None: raise ValueError("must provide the mask_data when initializing the transform or at runtime.") + mask_data, *_ = convert_data_type(mask_data, np.ndarray) # type: ignore + mask_data = np.asarray(self.select_fn(mask_data)) if mask_data.shape[0] != 1 and mask_data.shape[0] != img.shape[0]: raise ValueError( @@ -936,7 +942,7 @@ class SavitzkyGolaySmooth(Transform): or ``'circular'``. Default: ``'zeros'``. See ``torch.nn.Conv1d()`` for more information. """ - backend = [TransformBackends.NUMPY] + backend = [TransformBackends.TORCH] def __init__(self, window_length: int, order: int, axis: int = 1, mode: str = "zeros"): @@ -1000,6 +1006,7 @@ def __call__(self, img: np.ndarray): np.ndarray containing envelope of data in img along the specified axis. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore # add one to transform axis because a batch axis will be added at dimension 0 hilbert_transform = HilbertTransform(self.axis + 1, self.n) # convert to Tensor and add Batch axis expected by HilbertTransform @@ -1026,6 +1033,7 @@ def __init__(self, sigma: Union[Sequence[float], float] = 1.0, approx: str = "er self.approx = approx def __call__(self, img: np.ndarray): + img, *_ = convert_data_type(img, np.ndarray) # type: ignore gaussian_filter = GaussianFilter(img.ndim - 1, self.sigma, approx=self.approx) input_data = torch.as_tensor(np.ascontiguousarray(img), dtype=torch.float).unsqueeze(0) return gaussian_filter(input_data).squeeze(0).detach().numpy() @@ -1070,6 +1078,7 @@ def randomize(self, data: Optional[Any] = None) -> None: self.z = self.R.uniform(low=self.sigma_z[0], high=self.sigma_z[1]) def __call__(self, img: np.ndarray): + img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize() if not self._do_transform: return img @@ -1117,6 +1126,7 @@ def __init__( self.approx = approx def __call__(self, img: np.ndarray): + img, *_ = convert_data_type(img, np.ndarray) # type: ignore gaussian_filter1 = GaussianFilter(img.ndim - 1, self.sigma1, approx=self.approx) gaussian_filter2 = GaussianFilter(img.ndim - 1, self.sigma2, approx=self.approx) input_data = torch.as_tensor(np.ascontiguousarray(img), dtype=torch.float).unsqueeze(0) @@ -1183,6 +1193,7 @@ def randomize(self, data: Optional[Any] = None) -> None: self.a = self.R.uniform(low=self.alpha[0], high=self.alpha[1]) def __call__(self, img: np.ndarray): + img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize() if not self._do_transform: return img @@ -1227,6 +1238,7 @@ def randomize(self, data: Optional[Any] = None) -> None: ) def __call__(self, img: np.ndarray) -> np.ndarray: + img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize() if not self._do_transform: return img @@ -1713,6 +1725,7 @@ def _transform_holes(self, img: np.ndarray) -> np.ndarray: raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.") def __call__(self, img: np.ndarray): + img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize(img.shape[1:]) if self._do_transform: img = self._transform_holes(img=img) @@ -1871,6 +1884,7 @@ def __init__( self.dtype = dtype def __call__(self, img: np.ndarray, mask: Optional[np.ndarray] = None) -> np.ndarray: + img, *_ = convert_data_type(img, np.ndarray) # type: ignore return equalize_hist( img=img, mask=mask if mask is not None else self.mask, diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 2053070028..c0bb686149 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -171,6 +171,7 @@ def __call__( data_array (resampled into `self.pixdim`), original affine, current affine. """ + data_array, *_ = convert_data_type(data_array, np.ndarray) # type: ignore _dtype = dtype or self.dtype or data_array.dtype sr = data_array.ndim - 1 if sr <= 0: @@ -275,6 +276,7 @@ def __call__( data_array (reoriented in `self.axcodes`), original axcodes, current axcodes. """ + data_array, *_ = convert_data_type(data_array, np.ndarray) # type: ignore sr = data_array.ndim - 1 if sr <= 0: raise ValueError("data_array must have at least one spatial dimension.") @@ -392,6 +394,7 @@ def __call__( ValueError: When ``self.spatial_size`` length is less than ``img`` spatial dimensions. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore if self.size_mode == "all": input_ndim = img.ndim - 1 # spatial ndim output_ndim = len(ensure_tuple(self.spatial_size)) @@ -1098,6 +1101,8 @@ class RandAffineGrid(Randomizable, Transform): """ + backend = AffineGrid.backend + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, @@ -1930,6 +1935,7 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]): Args: img: data to be transformed, assuming `img` is channel first. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore if max(self.spatial_channels) > img.ndim - 1: raise ValueError( f"input has {img.ndim-1} spatial dimensions, cannot add AddCoordinateChannels channel for " diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 7f94b50044..e53f0e1fe3 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -777,6 +777,9 @@ def __call__( output_shape: expected shape of output indices. if None, use `self.output_shape` instead. """ + label, *_ = convert_data_type(label, np.ndarray) # type: ignore + if image is not None: + image, *_ = convert_data_type(image, np.ndarray) # type: ignore if output_shape is None: output_shape = self.output_shape fg_indices, bg_indices = map_binary_to_indices(label, image, self.image_threshold) @@ -826,6 +829,10 @@ def __call__( output_shape: expected shape of output indices. if None, use `self.output_shape` instead. """ + label, *_ = convert_data_type(label, np.ndarray) # type: ignore + if image is not None: + image, *_ = convert_data_type(image, np.ndarray) # type: ignore + if output_shape is None: output_shape = self.output_shape indices = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) @@ -846,6 +853,7 @@ class ConvertToMultiChannelBasedOnBratsClasses(Transform): """ def __call__(self, img: np.ndarray) -> np.ndarray: + img, *_ = convert_data_type(img, np.ndarray) # type: ignore # if img has channel dim, squeeze it if img.ndim == 4 and img.shape[0] == 1: img = np.squeeze(img, axis=0) @@ -912,6 +920,9 @@ def __call__( if label.shape[0] != 1: raise ValueError("Only supports single channel labels!") + img, *_ = convert_data_type(img, np.ndarray) # type: ignore + label, *_ = convert_data_type(label, np.ndarray) # type: ignore + # Generate extreme points self.randomize(label[0, :]) @@ -948,6 +959,7 @@ def __call__(self, img: torch.Tensor): img: PyTorch Tensor data for the TorchVision transform. """ + img, *_ = convert_data_type(img, torch.Tensor) # type: ignore return self.trans(img) @@ -978,7 +990,7 @@ def __init__(self, orig_labels: Sequence, target_labels: Sequence, dtype: DtypeL self.dtype = dtype def __call__(self, img: np.ndarray): - img = np.asarray(img) + img, *_ = convert_data_type(img, np.ndarray) # type: ignore img_flat = img.flatten() try: out_flat = np.copy(img_flat).astype(self.dtype) @@ -1034,6 +1046,7 @@ def __call__( mask must have the same shape as input `img`. """ + img, *_ = convert_data_type(img, np.ndarray) # type: ignore if meta_data is None: meta_data = {} From ff9c80fb4fc62cb17b6880a8a5d9f7f07e53bb14 Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Wed, 15 Sep 2021 01:09:42 -0400 Subject: [PATCH 20/89] Add dtype to ToCupy (#2950) * Add dtype to ToCuPy Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Add unittests to include dtype Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Implement convert_to_cupy Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Addressed all comments Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Addressed all comments Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Add dtype for Sequence Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/transforms/utility/array.py | 23 +++++++++-- monai/transforms/utility/dictionary.py | 16 ++++---- monai/utils/__init__.py | 1 + monai/utils/type_conversion.py | 43 ++++++++++++++++++++ tests/test_to_cupy.py | 54 ++++++++++++++++++++------ 5 files changed, 114 insertions(+), 23 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index e53f0e1fe3..4bc09b59a5 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -32,7 +32,15 @@ map_classes_to_indices, ) from monai.transforms.utils_pytorch_numpy_unification import in1d, moveaxis -from monai.utils import convert_to_numpy, convert_to_tensor, ensure_tuple, look_up_option, min_version, optional_import +from monai.utils import ( + convert_to_cupy, + convert_to_numpy, + convert_to_tensor, + ensure_tuple, + look_up_option, + min_version, + optional_import, +) from monai.utils.enums import TransformBackends from monai.utils.misc import is_module_ver_at_least from monai.utils.type_conversion import convert_data_type @@ -393,15 +401,22 @@ def __call__(self, img: NdarrayOrTensor) -> np.ndarray: class ToCupy(Transform): """ Converts the input data to CuPy array, can support list or tuple of numbers, NumPy and PyTorch Tensor. + + Args: + dtype: data type specifier. It is inferred from the input by default. """ backend = [TransformBackends.TORCH, TransformBackends.NUMPY] - def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: + def __init__(self, dtype=None) -> None: + super().__init__() + self.dtype = dtype + + def __call__(self, data: NdarrayOrTensor): """ - Apply the transform to `img` and make it contiguous. + Create a CuPy array from `data` and make it contiguous """ - return cp.ascontiguousarray(cp.asarray(img)) # type: ignore + return convert_to_cupy(data, self.dtype) class ToPIL(Transform): diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 2fdf20c1fe..4bc8ff1afa 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -549,19 +549,19 @@ def __call__(self, data: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: class ToCupyd(MapTransform): """ Dictionary-based wrapper of :py:class:`monai.transforms.ToCupy`. + + Args: + keys: keys of the corresponding items to be transformed. + See also: :py:class:`monai.transforms.compose.MapTransform` + allow_missing_keys: don't raise exception if key is missing. + dtype: data type specifier. It is inferred from the input by default. """ backend = ToCupy.backend - def __init__(self, keys: KeysCollection, allow_missing_keys: bool = False) -> None: - """ - Args: - keys: keys of the corresponding items to be transformed. - See also: :py:class:`monai.transforms.compose.MapTransform` - allow_missing_keys: don't raise exception if key is missing. - """ + def __init__(self, keys: KeysCollection, allow_missing_keys: bool = False, dtype=None) -> None: super().__init__(keys, allow_missing_keys) - self.converter = ToCupy() + self.converter = ToCupy(dtype=dtype) def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) diff --git a/monai/utils/__init__.py b/monai/utils/__init__.py index aa8f02f815..dc3922933d 100644 --- a/monai/utils/__init__.py +++ b/monai/utils/__init__.py @@ -77,6 +77,7 @@ from .state_cacher import StateCacher from .type_conversion import ( convert_data_type, + convert_to_cupy, convert_to_dst_type, convert_to_numpy, convert_to_tensor, diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index b51ff6a9c8..8a54986633 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -16,6 +16,7 @@ "get_equivalent_dtype", "convert_data_type", "get_dtype", + "convert_to_cupy", "convert_to_numpy", "convert_to_tensor", "convert_to_dst_type", @@ -154,6 +155,42 @@ def convert_to_numpy(data, wrap_sequence: bool = False): return data +def convert_to_cupy(data, dtype, wrap_sequence: bool = True): + """ + Utility to convert the input data to a cupy array. If passing a dictionary, list or tuple, + recursively check every item and convert it to cupy array. + + Args: + data: input data can be PyTorch Tensor, numpy array, cupy array, list, dictionary, int, float, bool, str, etc. + Tensor, numpy array, cupy array, float, int, bool are converted to cupy arrays + + for dictionary, list or tuple, convert every item to a numpy array if applicable. + wrap_sequence: if `False`, then lists will recursively call this function. E.g., `[1, 2]` -> `[array(1), array(2)]`. + If `True`, then `[1, 2]` -> `array([1, 2])`. + """ + + # direct calls + if isinstance(data, (cp_ndarray, np.ndarray, torch.Tensor, float, int, bool)): + data = cp.asarray(data, dtype) + # recursive calls + elif isinstance(data, Sequence) and wrap_sequence: + return cp.asarray(data, dtype) + elif isinstance(data, list): + return [convert_to_cupy(i, dtype) for i in data] + elif isinstance(data, tuple): + return tuple(convert_to_cupy(i, dtype) for i in data) + elif isinstance(data, dict): + return {k: convert_to_cupy(v, dtype) for k, v in data.items()} + # make it contiguous + if isinstance(data, cp.ndarray): + if data.ndim > 0: + data = cp.ascontiguousarray(data) + else: + raise ValueError(f"The input data type [{type(data)}] cannot be converted into cupy arrays!") + + return data + + def convert_data_type( data: Any, output_type: Optional[type] = None, @@ -178,6 +215,8 @@ def convert_data_type( orig_type = torch.Tensor elif isinstance(data, np.ndarray): orig_type = np.ndarray + elif has_cp and isinstance(data, cp.ndarray): + orig_type = cp.ndarray else: orig_type = type(data) @@ -199,6 +238,10 @@ def convert_data_type( data = convert_to_numpy(data) if data is not None and dtype != data.dtype: data = data.astype(dtype) + elif has_cp and output_type is cp.ndarray: + if data is not None: + data = convert_to_cupy(data, dtype) + else: raise ValueError(f"Unsupported output type: {output_type}") return data, orig_type, orig_device diff --git a/tests/test_to_cupy.py b/tests/test_to_cupy.py index 8b00e12539..0fd9607339 100644 --- a/tests/test_to_cupy.py +++ b/tests/test_to_cupy.py @@ -22,49 +22,81 @@ cp, has_cp = optional_import("cupy") +@skipUnless(has_cp, "CuPy is required.") class TestToCupy(unittest.TestCase): - @skipUnless(has_cp, "CuPy is required.") def test_cupy_input(self): - test_data = cp.array([[1, 2], [3, 4]]) + test_data = cp.array([[1, 2], [3, 4]], dtype=cp.float32) test_data = cp.rot90(test_data) self.assertFalse(test_data.flags["C_CONTIGUOUS"]) result = ToCupy()(test_data) + self.assertTrue(result.dtype == cp.float32) + self.assertTrue(isinstance(result, cp.ndarray)) + self.assertTrue(result.flags["C_CONTIGUOUS"]) + cp.testing.assert_allclose(result, test_data) + + def test_cupy_input_dtype(self): + test_data = cp.array([[1, 2], [3, 4]], dtype=cp.float32) + test_data = cp.rot90(test_data) + self.assertFalse(test_data.flags["C_CONTIGUOUS"]) + result = ToCupy(cp.uint8)(test_data) + self.assertTrue(result.dtype == cp.uint8) self.assertTrue(isinstance(result, cp.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) cp.testing.assert_allclose(result, test_data) - @skipUnless(has_cp, "CuPy is required.") def test_numpy_input(self): - test_data = np.array([[1, 2], [3, 4]]) + test_data = np.array([[1, 2], [3, 4]], dtype=np.float32) test_data = np.rot90(test_data) self.assertFalse(test_data.flags["C_CONTIGUOUS"]) result = ToCupy()(test_data) + self.assertTrue(result.dtype == cp.float32) + self.assertTrue(isinstance(result, cp.ndarray)) + self.assertTrue(result.flags["C_CONTIGUOUS"]) + cp.testing.assert_allclose(result, test_data) + + def test_numpy_input_dtype(self): + test_data = np.array([[1, 2], [3, 4]], dtype=np.float32) + test_data = np.rot90(test_data) + self.assertFalse(test_data.flags["C_CONTIGUOUS"]) + result = ToCupy(np.uint8)(test_data) + self.assertTrue(result.dtype == cp.uint8) self.assertTrue(isinstance(result, cp.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) cp.testing.assert_allclose(result, test_data) - @skipUnless(has_cp, "CuPy is required.") def test_tensor_input(self): - test_data = torch.tensor([[1, 2], [3, 4]]) + test_data = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32) test_data = test_data.rot90() self.assertFalse(test_data.is_contiguous()) result = ToCupy()(test_data) + self.assertTrue(result.dtype == cp.float32) self.assertTrue(isinstance(result, cp.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - cp.testing.assert_allclose(result, test_data.numpy()) + cp.testing.assert_allclose(result, test_data) - @skipUnless(has_cp, "CuPy is required.") @skip_if_no_cuda def test_tensor_cuda_input(self): - test_data = torch.tensor([[1, 2], [3, 4]]).cuda() + test_data = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32).cuda() test_data = test_data.rot90() self.assertFalse(test_data.is_contiguous()) result = ToCupy()(test_data) + self.assertTrue(result.dtype == cp.float32) self.assertTrue(isinstance(result, cp.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - cp.testing.assert_allclose(result, test_data.cpu().numpy()) + cp.testing.assert_allclose(result, test_data) + + @skip_if_no_cuda + def test_tensor_cuda_input_dtype(self): + test_data = torch.tensor([[1, 2], [3, 4]], dtype=torch.uint8).cuda() + test_data = test_data.rot90() + self.assertFalse(test_data.is_contiguous()) + + result = ToCupy(dtype="float32")(test_data) + self.assertTrue(result.dtype == cp.float32) + self.assertTrue(isinstance(result, cp.ndarray)) + self.assertTrue(result.flags["C_CONTIGUOUS"]) + cp.testing.assert_allclose(result, test_data) - @skipUnless(has_cp, "CuPy is required.") def test_list_tuple(self): test_data = [[1, 2], [3, 4]] result = ToCupy()(test_data) From c624ffcb51c8417115ff810f52f78956bc414340 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Wed, 15 Sep 2021 22:01:59 +0800 Subject: [PATCH 21/89] 2948 Enhance the transform to delete items (#2952) * [DLMED] update according to comments Signed-off-by: Nic Ma * [DLMED] remove unnecessary arg Signed-off-by: Nic Ma * [DLMED] fix style issue Signed-off-by: Nic Ma --- monai/transforms/utility/dictionary.py | 33 +++++++++++++++++++++++++- tests/test_delete_itemsd.py | 25 +++++++++++++++---- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 4bc8ff1afa..3a5be20e8b 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -17,6 +17,7 @@ import copy import logging +import re from copy import deepcopy from typing import Any, Callable, Dict, Hashable, List, Mapping, Optional, Sequence, Tuple, Union @@ -637,8 +638,38 @@ class DeleteItemsd(MapTransform): It will remove the key-values and copy the others to construct a new dictionary. """ + def __init__( + self, + keys: KeysCollection, + sep: str = ".", + use_re: Union[Sequence[bool], bool] = False, + ) -> None: + """ + Args: + keys: keys of the corresponding items to delete, can be "A{sep}B{sep}C" + to delete key `C` in nested dictionary, `C` can be regular expression. + See also: :py:class:`monai.transforms.compose.MapTransform` + sep: the separator tag to define nested dictionary keys, default to ".". + use_re: whether the specified key is a regular expression, it also can be + a list of bool values, map the to keys. + """ + super().__init__(keys) + self.sep = sep + self.use_re = ensure_tuple_rep(use_re, len(self.keys)) + def __call__(self, data): - return {key: val for key, val in data.items() if key not in self.key_iterator(data)} + def _delete_item(keys, d, use_re: bool = False): + key = keys[0] + if len(keys) > 1: + d[key] = _delete_item(keys[1:], d[key], use_re) + return d + return {k: v for k, v in d.items() if (use_re and not re.search(key, k)) or (not use_re and k != key)} + + d = dict(data) + for key, use_re in zip(self.keys, self.use_re): + d = _delete_item(key.split(self.sep), d, use_re) + + return d class SelectItemsd(MapTransform): diff --git a/tests/test_delete_itemsd.py b/tests/test_delete_itemsd.py index 7426e39ff0..b7cd104c46 100644 --- a/tests/test_delete_itemsd.py +++ b/tests/test_delete_itemsd.py @@ -19,19 +19,36 @@ TEST_CASE_1 = [{"keys": [str(i) for i in range(30)]}, 20] +TEST_CASE_2 = [{"keys": ["image/" + str(i) for i in range(30)], "sep": "/"}, 20] + +TEST_CASE_3 = [{"keys": "meta_dict%0008\\|[0-9]", "sep": "%", "use_re": True}] + class TestDeleteItemsd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1]) + @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) def test_memory(self, input_param, expected_key_size): - input_data = {} + input_data = {"image": {}} if "sep" in input_param else {} for i in range(50): - input_data[str(i)] = [time.time()] * 100000 + if "sep" in input_param: + input_data["image"][str(i)] = [time.time()] * 100000 + else: + input_data[str(i)] = [time.time()] * 100000 result = DeleteItemsd(**input_param)(input_data) - self.assertEqual(len(result.keys()), expected_key_size) + if "sep" in input_param: + self.assertEqual(len(result["image"].keys()), expected_key_size) + else: + self.assertEqual(len(result.keys()), expected_key_size) self.assertGreaterEqual( sys.getsizeof(input_data) * float(expected_key_size) / len(input_data), sys.getsizeof(result) ) + @parameterized.expand([TEST_CASE_3]) + def test_re(self, input_param): + input_data = {"image": [1, 2, 3], "meta_dict": {"0008|0005": 1, "0008|1050": 2, "0008test": 3}} + result = DeleteItemsd(**input_param)(input_data) + self.assertEqual(result["meta_dict"]["0008test"], 3) + self.assertTrue(len(result["meta_dict"]), 1) + if __name__ == "__main__": unittest.main() From 2f4b5827d954bf2d1031be44cb90ed11e400a742 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Thu, 16 Sep 2021 02:42:19 +0800 Subject: [PATCH 22/89] 2951 Optimize type_conversion logic (#2955) * [DLMED] enhance type conversion Signed-off-by: Nic Ma * [DLMED] fix CI test Signed-off-by: Nic Ma * [DLMED] add more unit tests Signed-off-by: Nic Ma * [DLMED] fix flake8 Signed-off-by: Nic Ma --- monai/transforms/utility/array.py | 30 +++++++-- monai/transforms/utility/dictionary.py | 30 ++++++--- monai/utils/type_conversion.py | 85 +++++++++++++------------- tests/test_ensure_type.py | 4 +- tests/test_ensure_typed.py | 9 ++- tests/test_to_numpy.py | 3 +- tests/test_to_tensor.py | 10 +-- 7 files changed, 108 insertions(+), 63 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 4bc09b59a5..9109fb04c5 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -33,17 +33,18 @@ ) from monai.transforms.utils_pytorch_numpy_unification import in1d, moveaxis from monai.utils import ( + convert_data_type, convert_to_cupy, convert_to_numpy, convert_to_tensor, ensure_tuple, + get_equivalent_dtype, look_up_option, min_version, optional_import, ) from monai.utils.enums import TransformBackends from monai.utils.misc import is_module_ver_at_least -from monai.utils.type_conversion import convert_data_type PILImageImage, has_pil = optional_import("PIL.Image", name="Image") pil_image_fromarray, _ = optional_import("PIL.Image", name="fromarray") @@ -342,15 +343,16 @@ class ToTensor(Transform): backend = [TransformBackends.TORCH, TransformBackends.NUMPY] - def __init__(self, device: Optional[torch.device] = None) -> None: + def __init__(self, dtype: Optional[torch.dtype] = None, device: Optional[torch.device] = None) -> None: super().__init__() + self.dtype = dtype self.device = device def __call__(self, img: NdarrayOrTensor) -> torch.Tensor: """ Apply the transform to `img` and make it contiguous. """ - return convert_to_tensor(img, wrap_sequence=True, device=self.device) # type: ignore + return convert_to_tensor(img, dtype=self.dtype, device=self.device, wrap_sequence=True) # type: ignore class EnsureType(Transform): @@ -362,14 +364,21 @@ class EnsureType(Transform): Args: data_type: target data type to convert, should be "tensor" or "numpy". + dtype: target data content type to convert, for example: np.float32, torch.float, etc. device: for Tensor data type, specify the target device. """ backend = [TransformBackends.TORCH, TransformBackends.NUMPY] - def __init__(self, data_type: str = "tensor", device: Optional[torch.device] = None) -> None: + def __init__( + self, + data_type: str = "tensor", + dtype: Optional[Union[DtypeLike, torch.dtype]] = None, + device: Optional[torch.device] = None, + ) -> None: self.data_type = look_up_option(data_type.lower(), {"tensor", "numpy"}) + self.dtype = dtype self.device = device def __call__(self, data: NdarrayOrTensor): @@ -381,7 +390,12 @@ def __call__(self, data: NdarrayOrTensor): if applicable. """ - return convert_to_tensor(data, device=self.device) if self.data_type == "tensor" else convert_to_numpy(data) + if self.data_type == "tensor": + dtype_ = get_equivalent_dtype(self.dtype, torch.Tensor) + return convert_to_tensor(data, dtype=dtype_, device=self.device) + else: + dtype_ = get_equivalent_dtype(self.dtype, np.ndarray) + return convert_to_numpy(data, dtype=dtype_) class ToNumpy(Transform): @@ -391,11 +405,15 @@ class ToNumpy(Transform): backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__(self, dtype: Optional[DtypeLike] = None) -> None: + super().__init__() + self.dtype = dtype + def __call__(self, img: NdarrayOrTensor) -> np.ndarray: """ Apply the transform to `img` and make it contiguous. """ - return convert_to_numpy(img) # type: ignore + return convert_to_numpy(img, dtype=self.dtype) # type: ignore class ToCupy(Transform): diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 3a5be20e8b..a3c51fe3f2 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -443,15 +443,23 @@ class ToTensord(MapTransform, InvertibleTransform): backend = ToTensor.backend - def __init__(self, keys: KeysCollection, allow_missing_keys: bool = False) -> None: + def __init__( + self, + keys: KeysCollection, + dtype: Optional[torch.dtype] = None, + device: Optional[torch.device] = None, + allow_missing_keys: bool = False, + ) -> None: """ Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` + dtype: target data content type to convert, for example: torch.float, etc. + device: specify the target device to put the Tensor data. allow_missing_keys: don't raise exception if key is missing. """ super().__init__(keys, allow_missing_keys) - self.converter = ToTensor() + self.converter = ToTensor(dtype=dtype, device=device) def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) @@ -491,6 +499,7 @@ def __init__( self, keys: KeysCollection, data_type: str = "tensor", + dtype: Optional[Union[DtypeLike, torch.dtype]] = None, device: Optional[torch.device] = None, allow_missing_keys: bool = False, ) -> None: @@ -499,11 +508,12 @@ def __init__( keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` data_type: target data type to convert, should be "tensor" or "numpy". + dtype: target data content type to convert, for example: np.float32, torch.float, etc. device: for Tensor data type, specify the target device. allow_missing_keys: don't raise exception if key is missing. """ super().__init__(keys, allow_missing_keys) - self.converter = EnsureType(data_type=data_type, device=device) + self.converter = EnsureType(data_type=data_type, dtype=dtype, device=device) def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) @@ -530,15 +540,21 @@ class ToNumpyd(MapTransform): backend = ToNumpy.backend - def __init__(self, keys: KeysCollection, allow_missing_keys: bool = False) -> None: + def __init__( + self, + keys: KeysCollection, + dtype: Optional[DtypeLike] = None, + allow_missing_keys: bool = False, + ) -> None: """ Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` + dtype: target data type when converting to numpy array. allow_missing_keys: don't raise exception if key is missing. """ super().__init__(keys, allow_missing_keys) - self.converter = ToNumpy() + self.converter = ToNumpy(dtype=dtype) def __call__(self, data: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: d = dict(data) @@ -554,13 +570,13 @@ class ToCupyd(MapTransform): Args: keys: keys of the corresponding items to be transformed. See also: :py:class:`monai.transforms.compose.MapTransform` - allow_missing_keys: don't raise exception if key is missing. dtype: data type specifier. It is inferred from the input by default. + allow_missing_keys: don't raise exception if key is missing. """ backend = ToCupy.backend - def __init__(self, keys: KeysCollection, allow_missing_keys: bool = False, dtype=None) -> None: + def __init__(self, keys: KeysCollection, dtype=None, allow_missing_keys: bool = False) -> None: super().__init__(keys, allow_missing_keys) self.converter = ToCupy(dtype=dtype) diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index 8a54986633..773f1cbc37 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -61,6 +61,8 @@ def get_equivalent_dtype(dtype, data_type): im = torch.tensor(1) dtype = get_equivalent_dtype(np.float32, type(im)) """ + if dtype is None: + return None if data_type is torch.Tensor: if type(dtype) is torch.dtype: return dtype @@ -84,7 +86,12 @@ def get_dtype(data: Any): return type(data) -def convert_to_tensor(data, wrap_sequence: bool = False, device: Optional[torch.device] = None): +def convert_to_tensor( + data, + dtype: Optional[torch.dtype] = None, + device: Optional[torch.device] = None, + wrap_sequence: bool = False, +): """ Utility to convert the input data to a PyTorch Tensor. If passing a dictionary, list or tuple, recursively check every item and convert it to PyTorch Tensor. @@ -93,36 +100,41 @@ def convert_to_tensor(data, wrap_sequence: bool = False, device: Optional[torch. data: input data can be PyTorch Tensor, numpy array, list, dictionary, int, float, bool, str, etc. will convert Tensor, Numpy array, float, int, bool to Tensors, strings and objects keep the original. for dictionary, list or tuple, convert every item to a Tensor if applicable. - wrap_sequence: if `False`, then lists will recursively call this function. E.g., `[1, 2]` -> `[tensor(1), tensor(2)]`. - If `True`, then `[1, 2]` -> `tensor([1, 2])`. + dtype: target data type to when converting to Tensor. + device: target device to put the converted Tensor data. + wrap_sequence: if `False`, then lists will recursively call this function. + E.g., `[1, 2]` -> `[tensor(1), tensor(2)]`. If `True`, then `[1, 2]` -> `tensor([1, 2])`. """ if isinstance(data, torch.Tensor): - return data.contiguous().to(device) + return data.to(dtype=dtype, device=device, memory_format=torch.contiguous_format) # type: ignore if isinstance(data, np.ndarray): # skip array of string classes and object, refer to: # https://github.com/pytorch/pytorch/blob/v1.9.0/torch/utils/data/_utils/collate.py#L13 if re.search(r"[SaUO]", data.dtype.str) is None: # numpy array with 0 dims is also sequence iterable, # `ascontiguousarray` will add 1 dim if img has no dim, so we only apply on data with dims - return torch.as_tensor(data if data.ndim == 0 else np.ascontiguousarray(data), device=device) - elif has_cp and isinstance(data, cp_ndarray): - return torch.as_tensor(data, device=device) - elif isinstance(data, (float, int, bool)): - return torch.as_tensor(data, device=device) - elif isinstance(data, Sequence) and wrap_sequence: - return torch.as_tensor(data, device=device) + if data.ndim > 0: + data = np.ascontiguousarray(data) + return torch.as_tensor(data, dtype=dtype, device=device) # type: ignore + elif ( + has_cp + and isinstance(data, cp_ndarray) + or isinstance(data, (float, int, bool)) + or (isinstance(data, Sequence) and wrap_sequence) + ): + return torch.as_tensor(data, dtype=dtype, device=device) # type: ignore elif isinstance(data, list): - return [convert_to_tensor(i, device=device) for i in data] + return [convert_to_tensor(i, dtype=dtype, device=device) for i in data] elif isinstance(data, tuple): - return tuple(convert_to_tensor(i, device=device) for i in data) + return tuple(convert_to_tensor(i, dtype=dtype, device=device) for i in data) elif isinstance(data, dict): - return {k: convert_to_tensor(v, device=device) for k, v in data.items()} + return {k: convert_to_tensor(v, dtype=dtype, device=device) for k, v in data.items()} return data -def convert_to_numpy(data, wrap_sequence: bool = False): +def convert_to_numpy(data, dtype: Optional[DtypeLike] = None, wrap_sequence: bool = False): """ Utility to convert the input data to a numpy array. If passing a dictionary, list or tuple, recursively check every item and convert it to numpy array. @@ -131,23 +143,22 @@ def convert_to_numpy(data, wrap_sequence: bool = False): data: input data can be PyTorch Tensor, numpy array, list, dictionary, int, float, bool, str, etc. will convert Tensor, Numpy array, float, int, bool to numpy arrays, strings and objects keep the original. for dictionary, list or tuple, convert every item to a numpy array if applicable. + dtype: target data type when converting to numpy array. wrap_sequence: if `False`, then lists will recursively call this function. E.g., `[1, 2]` -> `[array(1), array(2)]`. If `True`, then `[1, 2]` -> `array([1, 2])`. """ if isinstance(data, torch.Tensor): - data = data.detach().cpu().numpy() + data = data.detach().to(dtype=get_equivalent_dtype(dtype, torch.Tensor), device="cpu").numpy() elif has_cp and isinstance(data, cp_ndarray): - data = cp.asnumpy(data) - elif isinstance(data, (float, int, bool)): - data = np.asarray(data) - elif isinstance(data, Sequence) and wrap_sequence: - return np.asarray(data) + data = cp.asnumpy(data).astype(dtype) + elif isinstance(data, (np.ndarray, float, int, bool)) or (isinstance(data, Sequence) and wrap_sequence): + data = np.asarray(data, dtype=dtype) elif isinstance(data, list): - return [convert_to_numpy(i) for i in data] + return [convert_to_numpy(i, dtype=dtype) for i in data] elif isinstance(data, tuple): - return tuple(convert_to_numpy(i) for i in data) + return tuple(convert_to_numpy(i, dtype=dtype) for i in data) elif isinstance(data, dict): - return {k: convert_to_numpy(v) for k, v in data.items()} + return {k: convert_to_numpy(v, dtype=dtype) for k, v in data.items()} if isinstance(data, np.ndarray) and data.ndim > 0: data = np.ascontiguousarray(data) @@ -165,16 +176,16 @@ def convert_to_cupy(data, dtype, wrap_sequence: bool = True): Tensor, numpy array, cupy array, float, int, bool are converted to cupy arrays for dictionary, list or tuple, convert every item to a numpy array if applicable. + dtype: target data type when converting to Cupy array. wrap_sequence: if `False`, then lists will recursively call this function. E.g., `[1, 2]` -> `[array(1), array(2)]`. If `True`, then `[1, 2]` -> `array([1, 2])`. """ # direct calls - if isinstance(data, (cp_ndarray, np.ndarray, torch.Tensor, float, int, bool)): + if isinstance(data, (cp_ndarray, np.ndarray, torch.Tensor, float, int, bool)) or ( + isinstance(data, Sequence) and wrap_sequence + ): data = cp.asarray(data, dtype) - # recursive calls - elif isinstance(data, Sequence) and wrap_sequence: - return cp.asarray(data, dtype) elif isinstance(data, list): return [convert_to_cupy(i, dtype) for i in data] elif isinstance(data, tuple): @@ -224,24 +235,14 @@ def convert_data_type( output_type = output_type or orig_type - dtype = get_equivalent_dtype(dtype or get_dtype(data), output_type) + dtype_ = get_equivalent_dtype(dtype or get_dtype(data), output_type) if output_type is torch.Tensor: - if orig_type is not torch.Tensor: - data = convert_to_tensor(data) - if dtype != data.dtype: - data = data.to(dtype) - if device is not None: - data = data.to(device) + data = convert_to_tensor(data, dtype=dtype_, device=device) elif output_type is np.ndarray: - if orig_type is not np.ndarray: - data = convert_to_numpy(data) - if data is not None and dtype != data.dtype: - data = data.astype(dtype) + data = convert_to_numpy(data, dtype=dtype_) elif has_cp and output_type is cp.ndarray: - if data is not None: - data = convert_to_cupy(data, dtype) - + data = convert_to_cupy(data, dtype=dtype_) else: raise ValueError(f"Unsupported output type: {output_type}") return data, orig_type, orig_device diff --git a/tests/test_ensure_type.py b/tests/test_ensure_type.py index 86bc3db703..f09c022f74 100644 --- a/tests/test_ensure_type.py +++ b/tests/test_ensure_type.py @@ -25,7 +25,9 @@ def test_array_input(self): test_datas.append(test_datas[-1].cuda()) for test_data in test_datas: for dtype in ("tensor", "NUMPY"): - result = EnsureType(data_type=dtype)(test_data) + result = EnsureType(dtype, dtype=np.float32 if dtype == "NUMPY" else None, device="cpu")(test_data) + if dtype == "NUMPY": + self.assertTrue(result.dtype == np.float32) self.assertTrue(isinstance(result, torch.Tensor if dtype == "tensor" else np.ndarray)) assert_allclose(result, test_data) self.assertTupleEqual(result.shape, (2, 2)) diff --git a/tests/test_ensure_typed.py b/tests/test_ensure_typed.py index e4c72d37e2..5e3e941f59 100644 --- a/tests/test_ensure_typed.py +++ b/tests/test_ensure_typed.py @@ -25,7 +25,14 @@ def test_array_input(self): test_datas.append(test_datas[-1].cuda()) for test_data in test_datas: for dtype in ("tensor", "NUMPY"): - result = EnsureTyped(keys="data", data_type=dtype)({"data": test_data})["data"] + result = EnsureTyped( + keys="data", + data_type=dtype, + dtype=np.float32 if dtype == "NUMPY" else None, + device="cpu", + )({"data": test_data})["data"] + if dtype == "NUMPY": + self.assertTrue(result.dtype == np.float32) self.assertTrue(isinstance(result, torch.Tensor if dtype == "tensor" else np.ndarray)) assert_allclose(result, test_data) self.assertTupleEqual(result.shape, (2, 2)) diff --git a/tests/test_to_numpy.py b/tests/test_to_numpy.py index b48727c01d..09940e33ba 100644 --- a/tests/test_to_numpy.py +++ b/tests/test_to_numpy.py @@ -37,8 +37,9 @@ def test_numpy_input(self): test_data = np.array([[1, 2], [3, 4]]) test_data = np.rot90(test_data) self.assertFalse(test_data.flags["C_CONTIGUOUS"]) - result = ToNumpy()(test_data) + result = ToNumpy(dtype="float32")(test_data) self.assertTrue(isinstance(result, np.ndarray)) + self.assertTrue(result.dtype == np.float32) self.assertTrue(result.flags["C_CONTIGUOUS"]) assert_allclose(result, test_data) diff --git a/tests/test_to_tensor.py b/tests/test_to_tensor.py index 3d187a1dba..74acb1016c 100644 --- a/tests/test_to_tensor.py +++ b/tests/test_to_tensor.py @@ -11,8 +11,8 @@ import unittest +import torch from parameterized import parameterized -from torch import Tensor from monai.transforms import ToTensor from tests.utils import TEST_NDARRAYS, assert_allclose, optional_import @@ -35,15 +35,15 @@ class TestToTensor(unittest.TestCase): @parameterized.expand(TESTS) def test_array_input(self, test_data, expected_shape): - result = ToTensor()(test_data) - self.assertTrue(isinstance(result, Tensor)) + result = ToTensor(dtype=torch.float32, device="cpu")(test_data) + self.assertTrue(isinstance(result, torch.Tensor)) assert_allclose(result, test_data) self.assertTupleEqual(result.shape, expected_shape) @parameterized.expand(TESTS_SINGLE) def test_single_input(self, test_data): result = ToTensor()(test_data) - self.assertTrue(isinstance(result, Tensor)) + self.assertTrue(isinstance(result, torch.Tensor)) assert_allclose(result, test_data) self.assertEqual(result.ndim, 0) @@ -52,7 +52,7 @@ def test_cupy(self): test_data = [[1, 2], [3, 4]] cupy_array = cp.ascontiguousarray(cp.asarray(test_data)) result = ToTensor()(cupy_array) - self.assertTrue(isinstance(result, Tensor)) + self.assertTrue(isinstance(result, torch.Tensor)) assert_allclose(result, test_data) From 0f17aa991592fc6e635e86da3061b5dd3d669597 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Wed, 15 Sep 2021 22:03:08 +0100 Subject: [PATCH 23/89] 2231 Fixes tutorial 353 (#2954) * fixes tutorial 353 Signed-off-by: Wenqi Li * adding type tests Signed-off-by: Wenqi Li * improves type checks Signed-off-by: Wenqi Li * fixes flake8 Signed-off-by: Wenqi Li * fixes as channel first Signed-off-by: Wenqi Li * type test option Signed-off-by: Wenqi Li * ndarray suuport Signed-off-by: Wenqi Li * fixes unit tests Signed-off-by: Wenqi Li update Signed-off-by: Wenqi Li * bash option for windows test Signed-off-by: Wenqi Li * fixes unit tests Signed-off-by: Wenqi Li * enhance norm intensity tests Signed-off-by: Wenqi Li * fixes merge tests Signed-off-by: Wenqi Li --- .github/workflows/pythonapp.yml | 1 + monai/transforms/spatial/array.py | 35 ++++++++-------- monai/transforms/spatial/dictionary.py | 10 +---- monai/utils/type_conversion.py | 14 +++++-- tests/test_affine_grid.py | 2 +- tests/test_as_channel_first.py | 2 +- tests/test_ensure_type.py | 4 +- tests/test_ensure_typed.py | 4 +- tests/test_flip.py | 6 +-- tests/test_flipd.py | 6 +-- tests/test_inverse_collation.py | 5 +-- tests/test_label_to_mask.py | 2 +- tests/test_label_to_maskd.py | 2 +- tests/test_normalize_intensity.py | 42 ++++++++----------- tests/test_normalize_intensityd.py | 10 ++--- tests/test_rand_affine_grid.py | 2 +- tests/test_rand_axis_flip.py | 6 +-- tests/test_rand_axis_flipd.py | 6 +-- tests/test_rand_flip.py | 6 +-- tests/test_rand_flipd.py | 6 +-- tests/test_rand_rotate90.py | 24 ++++------- tests/test_rand_rotate90d.py | 24 ++++------- tests/test_rand_scale_intensity.py | 2 +- tests/test_rand_scale_intensityd.py | 4 +- tests/test_rand_shift_intensityd.py | 4 +- tests/test_rand_zoom.py | 10 +++-- tests/test_rand_zoomd.py | 10 +++-- tests/test_rotate90.py | 24 ++++------- tests/test_rotate90d.py | 24 ++++------- tests/test_scale_intensity.py | 4 +- tests/test_scale_intensity_range.py | 2 +- .../test_scale_intensity_range_percentiles.py | 4 +- tests/test_scale_intensity_ranged.py | 2 +- tests/test_scale_intensityd.py | 8 ++-- tests/test_shift_intensityd.py | 2 +- tests/test_threshold_intensity.py | 2 +- tests/test_threshold_intensityd.py | 6 +-- tests/test_to_numpy.py | 14 +++---- tests/test_to_numpyd.py | 8 ++-- tests/test_to_pil.py | 2 +- tests/test_to_pild.py | 6 +-- tests/test_to_tensor.py | 6 +-- tests/test_transpose.py | 2 +- tests/test_transposed.py | 6 +-- tests/test_utils_pytorch_numpy_unification.py | 2 +- tests/test_zoom.py | 2 +- tests/test_zoomd.py | 16 +++---- tests/utils.py | 37 ++++++++++++---- 48 files changed, 195 insertions(+), 233 deletions(-) diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml index 3f18263e9e..73197915cf 100644 --- a/.github/workflows/pythonapp.yml +++ b/.github/workflows/pythonapp.yml @@ -152,6 +152,7 @@ jobs: python -c 'import torch; print(torch.__version__); print(torch.rand(5,3))' python -c "import monai; monai.config.print_config()" ./runtests.sh --min + shell: bash env: QUICKTEST: True diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index c0bb686149..c49f4e6479 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -471,7 +471,7 @@ def __call__( padding_mode: Optional[Union[GridSamplePadMode, str]] = None, align_corners: Optional[bool] = None, dtype: Union[DtypeLike, torch.dtype] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: channel first array, must have shape: [chns, H, W] or [chns, H, W, D]. @@ -526,13 +526,11 @@ def __call__( align_corners=self.align_corners if align_corners is None else align_corners, reverse_indexing=True, ) - output: torch.Tensor = xform( - img_t.unsqueeze(0), - transform_t, - spatial_size=output_shape, - ) + output: torch.Tensor = xform(img_t.unsqueeze(0), transform_t, spatial_size=output_shape).squeeze(0) self._rotation_matrix = transform - return output.squeeze(0).detach().float() + out: NdarrayOrTensor + out, *_ = convert_to_dst_type(output, dst=img, dtype=output.dtype) + return out def get_rotation_matrix(self) -> Optional[np.ndarray]: """ @@ -799,7 +797,7 @@ def __call__( padding_mode: Optional[Union[GridSamplePadMode, str]] = None, align_corners: Optional[bool] = None, dtype: Union[DtypeLike, torch.dtype] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: channel first array, must have shape 2D: (nchannels, H, W), or 3D: (nchannels, H, W, D). @@ -1290,7 +1288,7 @@ def __call__( grid: Optional[NdarrayOrTensor] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: shape must be (num_channels, H, W[, D]). @@ -1344,8 +1342,9 @@ def __call__( padding_mode=self.padding_mode.value if padding_mode is None else GridSamplePadMode(padding_mode).value, align_corners=True, )[0] - - return out + out_val: NdarrayOrTensor + out_val, *_ = convert_to_dst_type(out, dst=img, dtype=out.dtype) + return out_val class Affine(Transform): @@ -1425,7 +1424,7 @@ def __call__( spatial_size: Optional[Union[Sequence[int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> Union[torch.Tensor, Tuple[torch.Tensor, NdarrayOrTensor]]: + ) -> Union[NdarrayOrTensor, Tuple[NdarrayOrTensor, NdarrayOrTensor]]: """ Args: img: shape must be (num_channels, H, W[, D]), @@ -1589,7 +1588,7 @@ def __call__( spatial_size: Optional[Union[Sequence[int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: shape must be (num_channels, H, W[, D]), @@ -1615,7 +1614,7 @@ def __call__( grid = self.get_identity_grid(sp_size) if self._do_transform: grid = self.rand_affine_grid(grid=grid) - out: torch.Tensor = self.resampler( + out: NdarrayOrTensor = self.resampler( img=img, grid=grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode ) return out @@ -1727,7 +1726,7 @@ def __call__( spatial_size: Optional[Union[Tuple[int, int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: shape must be (num_channels, H, W), @@ -1756,7 +1755,7 @@ def __call__( grid = CenterSpatialCrop(roi_size=sp_size)(grid[0]) else: grid = create_grid(spatial_size=sp_size) - out: torch.Tensor = self.resampler( + out: NdarrayOrTensor = self.resampler( img, grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode ) return out @@ -1877,7 +1876,7 @@ def __call__( spatial_size: Optional[Union[Tuple[int, int, int], int]] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, - ) -> torch.Tensor: + ) -> NdarrayOrTensor: """ Args: img: shape must be (num_channels, H, W, D), @@ -1902,7 +1901,7 @@ def __call__( offset = torch.as_tensor(self.rand_offset, device=self.device).unsqueeze(0) grid[:3] += gaussian(offset)[0] * self.magnitude grid = self.rand_affine_grid(grid=grid) - out: torch.Tensor = self.resampler( + out: NdarrayOrTensor = self.resampler( img, grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode ) return out diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index 801f4316de..d794e51e80 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -820,10 +820,6 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N if do_resampling: d[key] = self.rand_affine.resampler(d[key], grid, mode=mode, padding_mode=padding_mode) - # if not doing transform and spatial size is unchanged, only need to do convert to torch - else: - d[key], *_ = convert_data_type(d[key], torch.Tensor, dtype=torch.float32, device=device) - return d def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: @@ -1442,10 +1438,7 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N self.randomize() d = dict(data) angle: Union[Sequence[float], float] = self.x if d[self.keys[0]].ndim == 3 else (self.x, self.y, self.z) - rotator = Rotate( - angle=angle, - keep_size=self.keep_size, - ) + rotator = Rotate(angle=angle, keep_size=self.keep_size) for key, mode, padding_mode, align_corners, dtype in self.key_iterator( d, self.mode, self.padding_mode, self.align_corners, self.dtype ): @@ -1460,7 +1453,6 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N ) rot_mat = rotator.get_rotation_matrix() else: - d[key], *_ = convert_data_type(d[key], torch.Tensor) rot_mat = np.eye(d[key].ndim) self.push_transform( d, diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index 773f1cbc37..3636dbc6c0 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -248,11 +248,14 @@ def convert_data_type( return data, orig_type, orig_device -def convert_to_dst_type(src: Any, dst: NdarrayOrTensor) -> Tuple[NdarrayOrTensor, type, Optional[torch.device]]: +def convert_to_dst_type( + src: Any, dst: NdarrayOrTensor, dtype: Optional[Union[DtypeLike, torch.dtype]] = None +) -> Tuple[NdarrayOrTensor, type, Optional[torch.device]]: """ - If `dst` is `torch.Tensor` or its subclass, convert `src` to `torch.Tensor` with the same data type as `dst`, - if `dst` is `numpy.ndarray` or its subclass, convert to `numpy.ndarray` with the same data type as `dst`, + If `dst` is an instance of `torch.Tensor` or its subclass, convert `src` to `torch.Tensor` with the same data type as `dst`, + if `dst` is an instance of `numpy.ndarray` or its subclass, convert to `numpy.ndarray` with the same data type as `dst`, otherwise, convert to the type of `dst` directly. + `dtype` is an optional argument if the target `dtype` is different from the original `dst`'s data type. See Also: :func:`convert_data_type` @@ -261,6 +264,9 @@ def convert_to_dst_type(src: Any, dst: NdarrayOrTensor) -> Tuple[NdarrayOrTensor if isinstance(dst, torch.Tensor): device = dst.device + if dtype is None: + dtype = dst.dtype + output_type: Any if isinstance(dst, torch.Tensor): output_type = torch.Tensor @@ -268,4 +274,4 @@ def convert_to_dst_type(src: Any, dst: NdarrayOrTensor) -> Tuple[NdarrayOrTensor output_type = np.ndarray else: output_type = type(dst) - return convert_data_type(data=src, output_type=output_type, device=device, dtype=dst.dtype) + return convert_data_type(data=src, output_type=output_type, device=device, dtype=dtype) diff --git a/tests/test_affine_grid.py b/tests/test_affine_grid.py index ac7c2741b0..972cf20a1f 100644 --- a/tests/test_affine_grid.py +++ b/tests/test_affine_grid.py @@ -115,7 +115,7 @@ def test_affine_grid(self, input_param, input_data, expected_val): result, _ = g(**input_data) if "device" in input_data: self.assertEqual(result.device, input_data[device]) - assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, type_test=False, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_as_channel_first.py b/tests/test_as_channel_first.py index 0d1b1c7d3a..918e576011 100644 --- a/tests/test_as_channel_first.py +++ b/tests/test_as_channel_first.py @@ -34,7 +34,7 @@ def test_value(self, in_type, input_param, expected_shape): if isinstance(test_data, torch.Tensor): test_data = test_data.cpu().numpy() expected = np.moveaxis(test_data, input_param["channel_dim"], 0) - assert_allclose(expected, result) + assert_allclose(result, expected, type_test=False) if __name__ == "__main__": diff --git a/tests/test_ensure_type.py b/tests/test_ensure_type.py index f09c022f74..64094b2360 100644 --- a/tests/test_ensure_type.py +++ b/tests/test_ensure_type.py @@ -29,7 +29,7 @@ def test_array_input(self): if dtype == "NUMPY": self.assertTrue(result.dtype == np.float32) self.assertTrue(isinstance(result, torch.Tensor if dtype == "tensor" else np.ndarray)) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) self.assertTupleEqual(result.shape, (2, 2)) def test_single_input(self): @@ -43,7 +43,7 @@ def test_single_input(self): if isinstance(test_data, bool): self.assertFalse(result) else: - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) self.assertEqual(result.ndim, 0) def test_string(self): diff --git a/tests/test_ensure_typed.py b/tests/test_ensure_typed.py index 5e3e941f59..a78df6cb3f 100644 --- a/tests/test_ensure_typed.py +++ b/tests/test_ensure_typed.py @@ -34,7 +34,7 @@ def test_array_input(self): if dtype == "NUMPY": self.assertTrue(result.dtype == np.float32) self.assertTrue(isinstance(result, torch.Tensor if dtype == "tensor" else np.ndarray)) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) self.assertTupleEqual(result.shape, (2, 2)) def test_single_input(self): @@ -48,7 +48,7 @@ def test_single_input(self): if isinstance(test_data, bool): self.assertFalse(result) else: - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) self.assertEqual(result.ndim, 0) def test_string(self): diff --git a/tests/test_flip.py b/tests/test_flip.py index 404a3def7d..8547f8aeb4 100644 --- a/tests/test_flip.py +++ b/tests/test_flip.py @@ -34,12 +34,10 @@ def test_correct_results(self, _, spatial_axis): for p in TEST_NDARRAYS: im = p(self.imt[0]) flip = Flip(spatial_axis=spatial_axis) - expected = [] - for channel in self.imt[0]: - expected.append(np.flip(channel, spatial_axis)) + expected = [np.flip(channel, spatial_axis) for channel in self.imt[0]] expected = np.stack(expected) result = flip(im) - assert_allclose(expected, result) + assert_allclose(result, p(expected)) if __name__ == "__main__": diff --git a/tests/test_flipd.py b/tests/test_flipd.py index 1676723800..2fa783f8ad 100644 --- a/tests/test_flipd.py +++ b/tests/test_flipd.py @@ -33,12 +33,10 @@ def test_invalid_cases(self, _, spatial_axis, raises): def test_correct_results(self, _, spatial_axis): for p in TEST_NDARRAYS: flip = Flipd(keys="img", spatial_axis=spatial_axis) - expected = [] - for channel in self.imt[0]: - expected.append(np.flip(channel, spatial_axis)) + expected = [np.flip(channel, spatial_axis) for channel in self.imt[0]] expected = np.stack(expected) result = flip({"img": p(self.imt[0])})["img"] - assert_allclose(expected, result) + assert_allclose(result, p(expected)) if __name__ == "__main__": diff --git a/tests/test_inverse_collation.py b/tests/test_inverse_collation.py index fb6a3a1e80..bc0fc3ff1b 100644 --- a/tests/test_inverse_collation.py +++ b/tests/test_inverse_collation.py @@ -115,10 +115,7 @@ def tearDown(self): @parameterized.expand(TESTS_2D + TESTS_3D) def test_collation(self, _, transform, collate_fn, ndim): - if ndim == 3: - data = self.data_3d - else: - data = self.data_2d + data = self.data_3d if ndim == 3 else self.data_2d if collate_fn: modified_transform = transform else: diff --git a/tests/test_label_to_mask.py b/tests/test_label_to_mask.py index 9caa7252f3..6c8f935fbc 100644 --- a/tests/test_label_to_mask.py +++ b/tests/test_label_to_mask.py @@ -64,7 +64,7 @@ def test_value(self, argments, image, expected_data): self.assertEqual(type(result), type(image)) if isinstance(result, torch.Tensor): self.assertEqual(result.device, image.device) - assert_allclose(result, expected_data) + assert_allclose(result, expected_data, type_test=False) if __name__ == "__main__": diff --git a/tests/test_label_to_maskd.py b/tests/test_label_to_maskd.py index b8f0d3c171..b2073e8ac3 100644 --- a/tests/test_label_to_maskd.py +++ b/tests/test_label_to_maskd.py @@ -65,7 +65,7 @@ def test_value(self, argments, input_data, expected_data): self.assertEqual(type(r), type(i)) if isinstance(r, torch.Tensor): self.assertEqual(r.device, i.device) - assert_allclose(r, expected_data) + assert_allclose(r, expected_data, type_test=False) if __name__ == "__main__": diff --git a/tests/test_normalize_intensity.py b/tests/test_normalize_intensity.py index 2755eb4c25..41c6b053ec 100644 --- a/tests/test_normalize_intensity.py +++ b/tests/test_normalize_intensity.py @@ -31,51 +31,51 @@ "divisor": u(np.array([0.5, 0.5, 0.5, 0.5])), "nonzero": True, }, - np.array([0.0, 3.0, 0.0, 4.0]), - np.array([0.0, -1.0, 0.0, 1.0]), + p(np.array([0.0, 3.0, 0.0, 4.0])), + p(np.array([0.0, -1.0, 0.0, 1.0])), ] ) - TESTS.append([p, {"nonzero": True}, np.array([0.0, 0.0, 0.0, 0.0]), np.array([0.0, 0.0, 0.0, 0.0])]) - TESTS.append([p, {"nonzero": False}, np.array([0.0, 0.0, 0.0, 0.0]), np.array([0.0, 0.0, 0.0, 0.0])]) - TESTS.append([p, {"nonzero": False}, np.array([1, 1, 1, 1]), np.array([0.0, 0.0, 0.0, 0.0])]) + TESTS.append([p, {"nonzero": True}, p(np.array([0.0, 0.0, 0.0, 0.0])), p(np.array([0.0, 0.0, 0.0, 0.0]))]) + TESTS.append([p, {"nonzero": False}, p(np.array([0.0, 0.0, 0.0, 0.0])), p(np.array([0.0, 0.0, 0.0, 0.0]))]) + TESTS.append([p, {"nonzero": False}, p(np.array([1, 1, 1, 1])), p(np.array([0.0, 0.0, 0.0, 0.0]))]) TESTS.append( [ p, {"nonzero": False, "channel_wise": True, "subtrahend": [1, 2, 3]}, - np.ones((3, 2, 2)), - np.array([[[0.0, 0.0], [0.0, 0.0]], [[-1.0, -1.0], [-1.0, -1.0]], [[-2.0, -2.0], [-2.0, -2.0]]]), + p(np.ones((3, 2, 2))), + p(np.array([[[0.0, 0.0], [0.0, 0.0]], [[-1.0, -1.0], [-1.0, -1.0]], [[-2.0, -2.0], [-2.0, -2.0]]])), ] ) TESTS.append( [ p, {"nonzero": True, "channel_wise": True, "subtrahend": [1, 2, 3], "divisor": [0, 0, 2]}, - np.ones((3, 2, 2)), - np.array([[[0.0, 0.0], [0.0, 0.0]], [[-1.0, -1.0], [-1.0, -1.0]], [[-1.0, -1.0], [-1.0, -1.0]]]), + p(np.ones((3, 2, 2))), + p(np.array([[[0.0, 0.0], [0.0, 0.0]], [[-1.0, -1.0], [-1.0, -1.0]], [[-1.0, -1.0], [-1.0, -1.0]]])), ] ) TESTS.append( [ p, {"nonzero": True, "channel_wise": False, "subtrahend": 2, "divisor": 0}, - np.ones((3, 2, 2)), - np.ones((3, 2, 2)) * -1.0, + p(np.ones((3, 2, 2))), + p(np.ones((3, 2, 2)) * -1.0), ] ) TESTS.append( [ p, {"nonzero": True, "channel_wise": False, "subtrahend": np.ones((3, 2, 2)) * 0.5, "divisor": 0}, - np.ones((3, 2, 2)), - np.ones((3, 2, 2)) * 0.5, + p(np.ones((3, 2, 2))), + p(np.ones((3, 2, 2)) * 0.5), ] ) TESTS.append( [ p, {"nonzero": True, "channel_wise": True, "subtrahend": np.ones((3, 2, 2)) * 0.5, "divisor": [0, 1, 0]}, - np.ones((3, 2, 2)), - np.ones((3, 2, 2)) * 0.5, + p(np.ones((3, 2, 2))), + p(np.ones((3, 2, 2)) * 0.5), ] ) @@ -91,17 +91,14 @@ def test_default(self, im_type): self.assertEqual(im.device, normalized.device) self.assertTrue(normalized.dtype in (np.float32, torch.float32)) expected = (self.imt - np.mean(self.imt)) / np.std(self.imt) - assert_allclose(expected, normalized, rtol=1e-3) + assert_allclose(normalized, expected, type_test=False, rtol=1e-3) @parameterized.expand(TESTS) def test_nonzero(self, in_type, input_param, input_data, expected_data): normalizer = NormalizeIntensity(**input_param) im = in_type(input_data) normalized = normalizer(im) - self.assertEqual(type(im), type(normalized)) - if isinstance(normalized, torch.Tensor): - self.assertEqual(im.device, normalized.device) - assert_allclose(expected_data, normalized) + assert_allclose(normalized, in_type(expected_data)) @parameterized.expand([[p] for p in TEST_NDARRAYS]) def test_channel_wise(self, im_type): @@ -109,10 +106,7 @@ def test_channel_wise(self, im_type): input_data = im_type(np.array([[0.0, 3.0, 0.0, 4.0], [0.0, 4.0, 0.0, 5.0]])) expected = np.array([[0.0, -1.0, 0.0, 1.0], [0.0, -1.0, 0.0, 1.0]]) normalized = normalizer(input_data) - self.assertEqual(type(input_data), type(normalized)) - if isinstance(normalized, torch.Tensor): - self.assertEqual(input_data.device, normalized.device) - assert_allclose(expected, normalized) + assert_allclose(normalized, im_type(expected)) @parameterized.expand([[p] for p in TEST_NDARRAYS]) def test_value_errors(self, im_type): diff --git a/tests/test_normalize_intensityd.py b/tests/test_normalize_intensityd.py index e2cec5407a..60b1d05456 100644 --- a/tests/test_normalize_intensityd.py +++ b/tests/test_normalize_intensityd.py @@ -25,7 +25,7 @@ [ {"keys": ["img"], "nonzero": True}, {"img": p(np.array([0.0, 3.0, 0.0, 4.0]))}, - np.array([0.0, -1.0, 0.0, 1.0]), + p(np.array([0.0, -1.0, 0.0, 1.0])), ] ) TESTS.append( @@ -37,14 +37,14 @@ "nonzero": True, }, {"img": p(np.array([0.0, 3.0, 0.0, 4.0]))}, - np.array([0.0, -1.0, 0.0, 1.0]), + p(np.array([0.0, -1.0, 0.0, 1.0])), ] ) TESTS.append( [ {"keys": ["img"], "nonzero": True}, {"img": p(np.array([0.0, 0.0, 0.0, 0.0]))}, - np.array([0.0, 0.0, 0.0, 0.0]), + p(np.array([0.0, 0.0, 0.0, 0.0])), ] ) @@ -60,7 +60,7 @@ def test_image_normalize_intensityd(self, im_type): self.assertEqual(type(im), type(normalized)) if isinstance(normalized, torch.Tensor): self.assertEqual(im.device, normalized.device) - assert_allclose(normalized, expected, rtol=1e-3) + assert_allclose(normalized, im_type(expected), rtol=1e-3) @parameterized.expand(TESTS) def test_nonzero(self, input_param, input_data, expected_data): @@ -82,7 +82,7 @@ def test_channel_wise(self, im_type): if isinstance(normalized, torch.Tensor): self.assertEqual(input_data[key].device, normalized.device) expected = np.array([[0.0, -1.0, 0.0, 1.0], [0.0, -1.0, 0.0, 1.0]]) - assert_allclose(normalized, expected) + assert_allclose(normalized, im_type(expected)) if __name__ == "__main__": diff --git a/tests/test_rand_affine_grid.py b/tests/test_rand_affine_grid.py index 64c32c8d75..4fb534aba1 100644 --- a/tests/test_rand_affine_grid.py +++ b/tests/test_rand_affine_grid.py @@ -201,7 +201,7 @@ def test_rand_affine_grid(self, input_param, input_data, expected_val): result = g(**input_data) if "device" in input_data: self.assertEqual(result.device, input_data[device]) - assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, type_test=False, rtol=1e-4, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_rand_axis_flip.py b/tests/test_rand_axis_flip.py index c05c3a1e0d..1772ef4987 100644 --- a/tests/test_rand_axis_flip.py +++ b/tests/test_rand_axis_flip.py @@ -22,10 +22,8 @@ def test_correct_results(self): for p in TEST_NDARRAYS: flip = RandAxisFlip(prob=1.0) result = flip(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.flip(channel, flip._axis)) - assert_allclose(np.stack(expected), result) + expected = [np.flip(channel, flip._axis) for channel in self.imt[0]] + assert_allclose(result, p(np.stack(expected))) if __name__ == "__main__": diff --git a/tests/test_rand_axis_flipd.py b/tests/test_rand_axis_flipd.py index 7bef0baa63..37a17db69f 100644 --- a/tests/test_rand_axis_flipd.py +++ b/tests/test_rand_axis_flipd.py @@ -23,10 +23,8 @@ def test_correct_results(self): flip = RandAxisFlipd(keys="img", prob=1.0) result = flip({"img": p(self.imt[0])})["img"] - expected = [] - for channel in self.imt[0]: - expected.append(np.flip(channel, flip._axis)) - assert_allclose(np.stack(expected), result) + expected = [np.flip(channel, flip._axis) for channel in self.imt[0]] + assert_allclose(result, p(np.stack(expected))) if __name__ == "__main__": diff --git a/tests/test_rand_flip.py b/tests/test_rand_flip.py index b3c514cb1f..df49d60861 100644 --- a/tests/test_rand_flip.py +++ b/tests/test_rand_flip.py @@ -34,12 +34,10 @@ def test_correct_results(self, _, spatial_axis): for p in TEST_NDARRAYS: im = p(self.imt[0]) flip = RandFlip(prob=1.0, spatial_axis=spatial_axis) - expected = [] - for channel in self.imt[0]: - expected.append(np.flip(channel, spatial_axis)) + expected = [np.flip(channel, spatial_axis) for channel in self.imt[0]] expected = np.stack(expected) result = flip(im) - assert_allclose(expected, result) + assert_allclose(result, p(expected)) if __name__ == "__main__": diff --git a/tests/test_rand_flipd.py b/tests/test_rand_flipd.py index 8972024fd8..c2869537cb 100644 --- a/tests/test_rand_flipd.py +++ b/tests/test_rand_flipd.py @@ -26,11 +26,9 @@ def test_correct_results(self, _, spatial_axis): for p in TEST_NDARRAYS: flip = RandFlipd(keys="img", prob=1.0, spatial_axis=spatial_axis) result = flip({"img": p(self.imt[0])})["img"] - expected = [] - for channel in self.imt[0]: - expected.append(np.flip(channel, spatial_axis)) + expected = [np.flip(channel, spatial_axis) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(expected, result) + assert_allclose(result, p(expected)) if __name__ == "__main__": diff --git a/tests/test_rand_rotate90.py b/tests/test_rand_rotate90.py index f339158f94..9fc025fbbe 100644 --- a/tests/test_rand_rotate90.py +++ b/tests/test_rand_rotate90.py @@ -23,44 +23,36 @@ def test_default(self): for p in TEST_NDARRAYS: rotate.set_random_state(123) rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) + expected = [np.rot90(channel, 0, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) def test_k(self): rotate = RandRotate90(max_k=2) for p in TEST_NDARRAYS: rotate.set_random_state(234) rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) + expected = [np.rot90(channel, 0, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) def test_spatial_axes(self): rotate = RandRotate90(spatial_axes=(0, 1)) for p in TEST_NDARRAYS: rotate.set_random_state(234) rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) + expected = [np.rot90(channel, 0, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) def test_prob_k_spatial_axes(self): rotate = RandRotate90(prob=1.0, max_k=2, spatial_axes=(0, 1)) for p in TEST_NDARRAYS: rotate.set_random_state(234) rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) + expected = [np.rot90(channel, 1, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) if __name__ == "__main__": diff --git a/tests/test_rand_rotate90d.py b/tests/test_rand_rotate90d.py index f9083afb0c..3071aa82c8 100644 --- a/tests/test_rand_rotate90d.py +++ b/tests/test_rand_rotate90d.py @@ -24,11 +24,9 @@ def test_default(self): for p in TEST_NDARRAYS: rotate.set_random_state(123) rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) + expected = [np.rot90(channel, 0, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_k(self): key = "test" @@ -36,11 +34,9 @@ def test_k(self): for p in TEST_NDARRAYS: rotate.set_random_state(234) rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) + expected = [np.rot90(channel, 0, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_spatial_axes(self): key = "test" @@ -48,11 +44,9 @@ def test_spatial_axes(self): for p in TEST_NDARRAYS: rotate.set_random_state(234) rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 0, (0, 1))) + expected = [np.rot90(channel, 0, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_prob_k_spatial_axes(self): key = "test" @@ -60,11 +54,9 @@ def test_prob_k_spatial_axes(self): for p in TEST_NDARRAYS: rotate.set_random_state(234) rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) + expected = [np.rot90(channel, 1, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_no_key(self): key = "unknown" diff --git a/tests/test_rand_scale_intensity.py b/tests/test_rand_scale_intensity.py index 750d88bfad..b863e2f874 100644 --- a/tests/test_rand_scale_intensity.py +++ b/tests/test_rand_scale_intensity.py @@ -25,7 +25,7 @@ def test_value(self): result = scaler(p(self.imt)) np.random.seed(0) expected = p((self.imt * (1 + np.random.uniform(low=-0.5, high=0.5))).astype(np.float32)) - assert_allclose(result, expected, rtol=1e-7, atol=0) + assert_allclose(result, p(expected), rtol=1e-7, atol=0) if __name__ == "__main__": diff --git a/tests/test_rand_scale_intensityd.py b/tests/test_rand_scale_intensityd.py index a8d2e63f65..fdcbd7146a 100644 --- a/tests/test_rand_scale_intensityd.py +++ b/tests/test_rand_scale_intensityd.py @@ -19,14 +19,14 @@ class TestRandScaleIntensityd(NumpyImageTestCase2D): def test_value(self): + key = "img" for p in TEST_NDARRAYS: - key = "img" scaler = RandScaleIntensityd(keys=[key], factors=0.5, prob=1.0) scaler.set_random_state(seed=0) result = scaler({key: p(self.imt)}) np.random.seed(0) expected = (self.imt * (1 + np.random.uniform(low=-0.5, high=0.5))).astype(np.float32) - assert_allclose(result[key], expected) + assert_allclose(result[key], p(expected)) if __name__ == "__main__": diff --git a/tests/test_rand_shift_intensityd.py b/tests/test_rand_shift_intensityd.py index 6766236146..c5dfb66722 100644 --- a/tests/test_rand_shift_intensityd.py +++ b/tests/test_rand_shift_intensityd.py @@ -19,14 +19,14 @@ class TestRandShiftIntensityd(NumpyImageTestCase2D): def test_value(self): + key = "img" for p in TEST_NDARRAYS: - key = "img" shifter = RandShiftIntensityd(keys=[key], offsets=1.0, prob=1.0) shifter.set_random_state(seed=0) result = shifter({key: p(self.imt)}) np.random.seed(0) expected = self.imt + np.random.uniform(low=-1.0, high=1.0) - assert_allclose(result[key], expected) + assert_allclose(result[key], p(expected)) def test_factor(self): key = "img" diff --git a/tests/test_rand_zoom.py b/tests/test_rand_zoom.py index 0ac1b92c39..6ccb265cca 100644 --- a/tests/test_rand_zoom.py +++ b/tests/test_rand_zoom.py @@ -35,11 +35,13 @@ def test_correct_results(self, min_zoom, max_zoom, mode, keep_size): ) random_zoom.set_random_state(1234) zoomed = random_zoom(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False)) + expected = [ + zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False) + for channel in self.imt[0] + ] + expected = np.stack(expected).astype(np.float32) - assert_allclose(zoomed, expected, atol=1.0) + assert_allclose(zoomed, p(expected), atol=1.0) def test_keep_size(self): for p in TEST_NDARRAYS: diff --git a/tests/test_rand_zoomd.py b/tests/test_rand_zoomd.py index fafaf748bd..842d207ca6 100644 --- a/tests/test_rand_zoomd.py +++ b/tests/test_rand_zoomd.py @@ -38,11 +38,13 @@ def test_correct_results(self, min_zoom, max_zoom, mode, align_corners, keep_siz random_zoom.set_random_state(1234) zoomed = random_zoom({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False)) + expected = [ + zoom_scipy(channel, zoom=random_zoom._zoom, mode="nearest", order=0, prefilter=False) + for channel in self.imt[0] + ] + expected = np.stack(expected).astype(np.float32) - assert_allclose(expected, zoomed[key], atol=1.0) + assert_allclose(zoomed[key], p(expected), atol=1.0) def test_keep_size(self): key = "img" diff --git a/tests/test_rotate90.py b/tests/test_rotate90.py index 03a967a16b..9857b26fe8 100644 --- a/tests/test_rotate90.py +++ b/tests/test_rotate90.py @@ -22,41 +22,33 @@ def test_rotate90_default(self): rotate = Rotate90() for p in TEST_NDARRAYS: rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) + expected = [np.rot90(channel, 1, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) def test_k(self): rotate = Rotate90(k=2) for p in TEST_NDARRAYS: rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) + expected = [np.rot90(channel, 2, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) def test_spatial_axes(self): rotate = Rotate90(spatial_axes=(0, -1)) for p in TEST_NDARRAYS: rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, -1))) + expected = [np.rot90(channel, 1, (0, -1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) def test_prob_k_spatial_axes(self): rotate = Rotate90(k=2, spatial_axes=(0, 1)) for p in TEST_NDARRAYS: rotated = rotate(p(self.imt[0])) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) + expected = [np.rot90(channel, 2, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated, expected, rtol=1.0e-5, atol=1.0e-8) + assert_allclose(rotated, p(expected), rtol=1.0e-5, atol=1.0e-8) if __name__ == "__main__": diff --git a/tests/test_rotate90d.py b/tests/test_rotate90d.py index a1fa3c977c..a2a4a27521 100644 --- a/tests/test_rotate90d.py +++ b/tests/test_rotate90d.py @@ -23,44 +23,36 @@ def test_rotate90_default(self): rotate = Rotate90d(keys=key) for p in TEST_NDARRAYS: rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) + expected = [np.rot90(channel, 1, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_k(self): key = None rotate = Rotate90d(keys=key, k=2) for p in TEST_NDARRAYS: rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) + expected = [np.rot90(channel, 2, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_spatial_axes(self): key = "test" rotate = Rotate90d(keys=key, spatial_axes=(0, 1)) for p in TEST_NDARRAYS: rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 1, (0, 1))) + expected = [np.rot90(channel, 1, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_prob_k_spatial_axes(self): key = "test" rotate = Rotate90d(keys=key, k=2, spatial_axes=(0, 1)) for p in TEST_NDARRAYS: rotated = rotate({key: p(self.imt[0])}) - expected = [] - for channel in self.imt[0]: - expected.append(np.rot90(channel, 2, (0, 1))) + expected = [np.rot90(channel, 2, (0, 1)) for channel in self.imt[0]] expected = np.stack(expected) - assert_allclose(rotated[key], expected) + assert_allclose(rotated[key], p(expected)) def test_no_key(self): key = "unknown" diff --git a/tests/test_scale_intensity.py b/tests/test_scale_intensity.py index c2485af616..24c6900ba5 100644 --- a/tests/test_scale_intensity.py +++ b/tests/test_scale_intensity.py @@ -26,14 +26,14 @@ def test_range_scale(self): maxa = self.imt.max() norm = (self.imt - mina) / (maxa - mina) expected = p((norm * (2.0 - 1.0)) + 1.0) - assert_allclose(result, expected, rtol=1e-7, atol=0) + assert_allclose(result, expected, type_test=False, rtol=1e-7, atol=0) def test_factor_scale(self): for p in TEST_NDARRAYS: scaler = ScaleIntensity(minv=None, maxv=None, factor=0.1) result = scaler(p(self.imt)) expected = p((self.imt * (1 + 0.1)).astype(np.float32)) - assert_allclose(result, expected, rtol=1e-7, atol=0) + assert_allclose(result, p(expected), rtol=1e-7, atol=0) if __name__ == "__main__": diff --git a/tests/test_scale_intensity_range.py b/tests/test_scale_intensity_range.py index d64f09ae82..d06bfd3596 100644 --- a/tests/test_scale_intensity_range.py +++ b/tests/test_scale_intensity_range.py @@ -22,7 +22,7 @@ def test_image_scale_intensity_range(self): scaled = scaler(p(self.imt)) expected = (self.imt - 20) / 88 expected = expected * 30 + 50 - assert_allclose(scaled, expected) + assert_allclose(scaled, p(expected)) if __name__ == "__main__": diff --git a/tests/test_scale_intensity_range_percentiles.py b/tests/test_scale_intensity_range_percentiles.py index 5cd19581b3..5ba3a1e1ee 100644 --- a/tests/test_scale_intensity_range_percentiles.py +++ b/tests/test_scale_intensity_range_percentiles.py @@ -32,7 +32,7 @@ def test_scaling(self): scaler = ScaleIntensityRangePercentiles(lower=lower, upper=upper, b_min=b_min, b_max=b_max) for p in TEST_NDARRAYS: result = scaler(p(img)) - assert_allclose(expected, result) + assert_allclose(result, p(expected)) def test_relative_scaling(self): img = self.imt @@ -51,7 +51,7 @@ def test_relative_scaling(self): for p in TEST_NDARRAYS: result = scaler(p(img)) - assert_allclose(expected_img, result) + assert_allclose(result, p(expected_img)) def test_invalid_instantiation(self): self.assertRaises(ValueError, ScaleIntensityRangePercentiles, lower=-10, upper=99, b_min=0, b_max=255) diff --git a/tests/test_scale_intensity_ranged.py b/tests/test_scale_intensity_ranged.py index b4d8cbf65a..dc064a7708 100644 --- a/tests/test_scale_intensity_ranged.py +++ b/tests/test_scale_intensity_ranged.py @@ -23,7 +23,7 @@ def test_image_scale_intensity_ranged(self): scaled = scaler({key: p(self.imt)}) expected = (self.imt - 20) / 88 expected = expected * 30 + 50 - assert_allclose(scaled[key], expected) + assert_allclose(scaled[key], p(expected)) if __name__ == "__main__": diff --git a/tests/test_scale_intensityd.py b/tests/test_scale_intensityd.py index 6e13dbc272..ce298f20af 100644 --- a/tests/test_scale_intensityd.py +++ b/tests/test_scale_intensityd.py @@ -19,23 +19,23 @@ class TestScaleIntensityd(NumpyImageTestCase2D): def test_range_scale(self): + key = "img" for p in TEST_NDARRAYS: - key = "img" scaler = ScaleIntensityd(keys=[key], minv=1.0, maxv=2.0) result = scaler({key: p(self.imt)}) mina = np.min(self.imt) maxa = np.max(self.imt) norm = (self.imt - mina) / (maxa - mina) expected = (norm * (2.0 - 1.0)) + 1.0 - assert_allclose(result[key], expected) + assert_allclose(result[key], p(expected)) def test_factor_scale(self): + key = "img" for p in TEST_NDARRAYS: - key = "img" scaler = ScaleIntensityd(keys=[key], minv=None, maxv=None, factor=0.1) result = scaler({key: p(self.imt)}) expected = (self.imt * (1 + 0.1)).astype(np.float32) - assert_allclose(result[key], expected) + assert_allclose(result[key], p(expected)) if __name__ == "__main__": diff --git a/tests/test_shift_intensityd.py b/tests/test_shift_intensityd.py index 0396857781..66aad23b1e 100644 --- a/tests/test_shift_intensityd.py +++ b/tests/test_shift_intensityd.py @@ -24,7 +24,7 @@ def test_value(self): shifter = ShiftIntensityd(keys=[key], offset=1.0) result = shifter({key: p(self.imt)}) expected = self.imt + 1.0 - assert_allclose(result[key], expected) + assert_allclose(result[key], p(expected)) def test_factor(self): key = "img" diff --git a/tests/test_threshold_intensity.py b/tests/test_threshold_intensity.py index 0614514456..075a650ec0 100644 --- a/tests/test_threshold_intensity.py +++ b/tests/test_threshold_intensity.py @@ -29,7 +29,7 @@ class TestThresholdIntensity(unittest.TestCase): def test_value(self, in_type, input_param, expected_value): test_data = in_type(np.arange(10)) result = ThresholdIntensity(**input_param)(test_data) - assert_allclose(result, expected_value) + assert_allclose(result, in_type(expected_value)) if __name__ == "__main__": diff --git a/tests/test_threshold_intensityd.py b/tests/test_threshold_intensityd.py index 398f9cfe91..a2a9fdcf2b 100644 --- a/tests/test_threshold_intensityd.py +++ b/tests/test_threshold_intensityd.py @@ -47,9 +47,9 @@ class TestThresholdIntensityd(unittest.TestCase): def test_value(self, in_type, input_param, expected_value): test_data = {"image": in_type(np.arange(10)), "label": in_type(np.arange(10)), "extra": in_type(np.arange(10))} result = ThresholdIntensityd(**input_param)(test_data) - assert_allclose(result["image"], expected_value) - assert_allclose(result["label"], expected_value) - assert_allclose(result["extra"], expected_value) + assert_allclose(result["image"], in_type(expected_value)) + assert_allclose(result["label"], in_type(expected_value)) + assert_allclose(result["extra"], in_type(expected_value)) if __name__ == "__main__": diff --git a/tests/test_to_numpy.py b/tests/test_to_numpy.py index 09940e33ba..c7631540b8 100644 --- a/tests/test_to_numpy.py +++ b/tests/test_to_numpy.py @@ -31,7 +31,7 @@ def test_cupy_input(self): result = ToNumpy()(test_data) self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data.get()) + assert_allclose(result, test_data.get(), type_test=False) def test_numpy_input(self): test_data = np.array([[1, 2], [3, 4]]) @@ -41,7 +41,7 @@ def test_numpy_input(self): self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.dtype == np.float32) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) def test_tensor_input(self): test_data = torch.tensor([[1, 2], [3, 4]]) @@ -50,7 +50,7 @@ def test_tensor_input(self): result = ToNumpy()(test_data) self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) @skip_if_no_cuda def test_tensor_cuda_input(self): @@ -60,21 +60,21 @@ def test_tensor_cuda_input(self): result = ToNumpy()(test_data) self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) def test_list_tuple(self): test_data = [[1, 2], [3, 4]] result = ToNumpy()(test_data) - assert_allclose(result, np.asarray(test_data)) + assert_allclose(result, np.asarray(test_data), type_test=False) test_data = ((1, 2), (3, 4)) result = ToNumpy()(test_data) - assert_allclose(result, np.asarray(test_data)) + assert_allclose(result, np.asarray(test_data), type_test=False) def test_single_value(self): for test_data in [5, np.array(5), torch.tensor(5)]: result = ToNumpy()(test_data) self.assertTrue(isinstance(result, np.ndarray)) - assert_allclose(result, np.asarray(test_data)) + assert_allclose(result, np.asarray(test_data), type_test=False) self.assertEqual(result.ndim, 0) diff --git a/tests/test_to_numpyd.py b/tests/test_to_numpyd.py index 5acaef39c7..0b0b032ef2 100644 --- a/tests/test_to_numpyd.py +++ b/tests/test_to_numpyd.py @@ -31,7 +31,7 @@ def test_cupy_input(self): result = ToNumpyd(keys="img")({"img": test_data})["img"] self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data.get()) + assert_allclose(result, test_data.get(), type_test=False) def test_numpy_input(self): test_data = np.array([[1, 2], [3, 4]]) @@ -40,7 +40,7 @@ def test_numpy_input(self): result = ToNumpyd(keys="img")({"img": test_data})["img"] self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) def test_tensor_input(self): test_data = torch.tensor([[1, 2], [3, 4]]) @@ -49,7 +49,7 @@ def test_tensor_input(self): result = ToNumpyd(keys="img")({"img": test_data})["img"] self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) @skip_if_no_cuda def test_tensor_cuda_input(self): @@ -59,7 +59,7 @@ def test_tensor_cuda_input(self): result = ToNumpyd(keys="img")({"img": test_data})["img"] self.assertTrue(isinstance(result, np.ndarray)) self.assertTrue(result.flags["C_CONTIGUOUS"]) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) if __name__ == "__main__": diff --git a/tests/test_to_pil.py b/tests/test_to_pil.py index 5690645dd8..b4581053c0 100644 --- a/tests/test_to_pil.py +++ b/tests/test_to_pil.py @@ -43,7 +43,7 @@ class TestToPIL(unittest.TestCase): def test_value(self, test_data): result = ToPIL()(test_data) self.assertTrue(isinstance(result, PILImageImage)) - assert_allclose(np.array(result), test_data) + assert_allclose(np.array(result), test_data, type_test=False) if __name__ == "__main__": diff --git a/tests/test_to_pild.py b/tests/test_to_pild.py index 3a15b1e507..3b83fa5258 100644 --- a/tests/test_to_pild.py +++ b/tests/test_to_pild.py @@ -30,9 +30,7 @@ PILImageImage, _ = optional_import("PIL.Image", name="Image") im = [[1.0, 2.0], [3.0, 4.0]] -TESTS = [] -for p in TEST_NDARRAYS: - TESTS.append([{"keys": "image"}, {"image": p(im)}]) +TESTS = [[{"keys": "image"}, {"image": p(im)}] for p in TEST_NDARRAYS] if has_pil: TESTS.append([{"keys": "image"}, {"image": pil_image_fromarray(np.array(im))}]) @@ -43,7 +41,7 @@ class TestToPIL(unittest.TestCase): def test_values(self, input_param, test_data): result = ToPILd(**input_param)(test_data)[input_param["keys"]] self.assertTrue(isinstance(result, PILImageImage)) - assert_allclose(np.array(result), test_data[input_param["keys"]]) + assert_allclose(np.array(result), test_data[input_param["keys"]], type_test=False) if __name__ == "__main__": diff --git a/tests/test_to_tensor.py b/tests/test_to_tensor.py index 74acb1016c..b065595e89 100644 --- a/tests/test_to_tensor.py +++ b/tests/test_to_tensor.py @@ -37,14 +37,14 @@ class TestToTensor(unittest.TestCase): def test_array_input(self, test_data, expected_shape): result = ToTensor(dtype=torch.float32, device="cpu")(test_data) self.assertTrue(isinstance(result, torch.Tensor)) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) self.assertTupleEqual(result.shape, expected_shape) @parameterized.expand(TESTS_SINGLE) def test_single_input(self, test_data): result = ToTensor()(test_data) self.assertTrue(isinstance(result, torch.Tensor)) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) self.assertEqual(result.ndim, 0) @unittest.skipUnless(has_cp, "CuPy is required.") @@ -53,7 +53,7 @@ def test_cupy(self): cupy_array = cp.ascontiguousarray(cp.asarray(test_data)) result = ToTensor()(cupy_array) self.assertTrue(isinstance(result, torch.Tensor)) - assert_allclose(result, test_data) + assert_allclose(result, test_data, type_test=False) if __name__ == "__main__": diff --git a/tests/test_transpose.py b/tests/test_transpose.py index 10882c9dd8..16cca49e1c 100644 --- a/tests/test_transpose.py +++ b/tests/test_transpose.py @@ -42,7 +42,7 @@ def test_transpose(self, im, indices): if isinstance(im, torch.Tensor): im = im.cpu().numpy() out2 = np.transpose(im, indices) - assert_allclose(out1, out2) + assert_allclose(out1, out2, type_test=False) if __name__ == "__main__": diff --git a/tests/test_transposed.py b/tests/test_transposed.py index 88ecd0c872..2f9558b74e 100644 --- a/tests/test_transposed.py +++ b/tests/test_transposed.py @@ -57,13 +57,13 @@ def test_transpose(self, im, indices): if isinstance(im, torch.Tensor): im = im.cpu().numpy() out_gt = np.transpose(im, indices) - assert_allclose(out_im1, out_gt) - assert_allclose(out_im2, out_gt) + assert_allclose(out_im1, out_gt, type_test=False) + assert_allclose(out_im2, out_gt, type_test=False) # test inverse fwd_inv_data = tr.inverse(out_data) for i, j in zip(data.values(), fwd_inv_data.values()): - assert_allclose(i, j) + assert_allclose(i, j, type_test=False) if __name__ == "__main__": diff --git a/tests/test_utils_pytorch_numpy_unification.py b/tests/test_utils_pytorch_numpy_unification.py index f05235187c..c8e0a35c92 100644 --- a/tests/test_utils_pytorch_numpy_unification.py +++ b/tests/test_utils_pytorch_numpy_unification.py @@ -32,7 +32,7 @@ def test_percentile(self): # pre torch 1.7, no `quantile`. Our own method doesn't interpolate, # so we can only be accurate to 0.5 atol = 0.5 if not hasattr(torch, "quantile") else 1e-4 - assert_allclose(results[0], results[-1], atol=atol) + assert_allclose(results[0], results[-1], type_test=False, atol=atol) def test_fails(self): for p in TEST_NDARRAYS: diff --git a/tests/test_zoom.py b/tests/test_zoom.py index a99e110052..9411988a7e 100644 --- a/tests/test_zoom.py +++ b/tests/test_zoom.py @@ -37,7 +37,7 @@ def test_correct_results(self, zoom, mode): for channel in self.imt[0]: expected.append(zoom_scipy(channel, zoom=zoom, mode="nearest", order=_order, prefilter=False)) expected = np.stack(expected).astype(np.float32) - assert_allclose(zoomed, expected, atol=1.0) + assert_allclose(zoomed, p(expected), atol=1.0) def test_keep_size(self): for p in TEST_NDARRAYS: diff --git a/tests/test_zoomd.py b/tests/test_zoomd.py index 1ebd7d2d08..6231978ca7 100644 --- a/tests/test_zoomd.py +++ b/tests/test_zoomd.py @@ -27,22 +27,18 @@ class TestZoomd(NumpyImageTestCase2D): @parameterized.expand(VALID_CASES) def test_correct_results(self, zoom, mode, keep_size): key = "img" - zoom_fn = Zoomd( - key, - zoom=zoom, - mode=mode, - keep_size=keep_size, - ) + zoom_fn = Zoomd(key, zoom=zoom, mode=mode, keep_size=keep_size) for p in TEST_NDARRAYS: zoomed = zoom_fn({key: p(self.imt[0])}) _order = 0 if mode.endswith("linear"): _order = 1 - expected = [] - for channel in self.imt[0]: - expected.append(zoom_scipy(channel, zoom=zoom, mode="nearest", order=_order, prefilter=False)) + expected = [ + zoom_scipy(channel, zoom=zoom, mode="nearest", order=_order, prefilter=False) for channel in self.imt[0] + ] + expected = np.stack(expected).astype(np.float32) - assert_allclose(expected, zoomed[key], atol=1.0) + assert_allclose(zoomed[key], p(expected), atol=1.0) def test_keep_size(self): key = "img" diff --git a/tests/utils.py b/tests/utils.py index 94f7f55fe0..6b7f6c4c16 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -57,19 +57,38 @@ def clone(data: NdarrayTensor) -> NdarrayTensor: return copy.deepcopy(data) -def assert_allclose(a: NdarrayOrTensor, b: NdarrayOrTensor, *args, **kwargs): +def assert_allclose( + actual: NdarrayOrTensor, + desired: NdarrayOrTensor, + type_test: bool = True, + device_test: bool = False, + *args, + **kwargs, +): """ - Assert that all values of two data objects are close. + Assert that types and all values of two data objects are close. Args: - a (NdarrayOrTensor): Pytorch Tensor or numpy array for comparison - b (NdarrayOrTensor): Pytorch Tensor or numpy array to compare against - args: extra arguments to pass on to `np.testing.assert_allclose` - kwargs: extra arguments to pass on to `np.testing.assert_allclose` + actual: Pytorch Tensor or numpy array for comparison. + desired: Pytorch Tensor or numpy array to compare against. + type_test: whether to test that `actual` and `desired` are both numpy arrays or torch tensors. + device_test: whether to test the device property. + args: extra arguments to pass on to `np.testing.assert_allclose`. + kwargs: extra arguments to pass on to `np.testing.assert_allclose`. + + """ - a = a.cpu().numpy() if isinstance(a, torch.Tensor) else a - b = b.cpu().numpy() if isinstance(b, torch.Tensor) else b - np.testing.assert_allclose(a, b, *args, **kwargs) + if type_test: + # check both actual and desired are of the same type + np.testing.assert_equal(isinstance(actual, np.ndarray), isinstance(desired, np.ndarray), "numpy type") + np.testing.assert_equal(isinstance(actual, torch.Tensor), isinstance(desired, torch.Tensor), "torch type") + + if isinstance(desired, torch.Tensor) or isinstance(actual, torch.Tensor): + if device_test: + np.testing.assert_equal(str(actual.device), str(desired.device), "torch device check") # type: ignore + actual = actual.cpu().numpy() if isinstance(actual, torch.Tensor) else actual + desired = desired.cpu().numpy() if isinstance(desired, torch.Tensor) else desired + np.testing.assert_allclose(actual, desired, *args, **kwargs) def test_pretrained_networks(network, input_param, device): From fb2c2e95ae3d23f13cf561eda19654f4f4e11f9f Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Thu, 16 Sep 2021 11:55:44 +0800 Subject: [PATCH 24/89] [DLMED] fix float64 bug (#2961) Signed-off-by: Nic Ma --- monai/transforms/spatial/array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index c49f4e6479..cb80c2036b 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -526,7 +526,7 @@ def __call__( align_corners=self.align_corners if align_corners is None else align_corners, reverse_indexing=True, ) - output: torch.Tensor = xform(img_t.unsqueeze(0), transform_t, spatial_size=output_shape).squeeze(0) + output: torch.Tensor = xform(img_t.unsqueeze(0), transform_t, spatial_size=output_shape).float().squeeze(0) self._rotation_matrix = transform out: NdarrayOrTensor out, *_ = convert_to_dst_type(output, dst=img, dtype=output.dtype) From 3b6f4798909a6bfcb0d4e7dc5f2a93cdc229693c Mon Sep 17 00:00:00 2001 From: Ali Hatamizadeh Date: Thu, 16 Sep 2021 01:16:28 -0700 Subject: [PATCH 25/89] add multi-modal (vision + language) transformers (#2962) * add multimodal transformers Signed-off-by: ahatamizadeh --- docs/requirements.txt | 1 + docs/source/installation.md | 4 +- docs/source/networks.rst | 5 + monai/config/deviceconfig.py | 1 + monai/networks/nets/__init__.py | 9 + monai/networks/nets/autoencoder.py | 3 + monai/networks/nets/varautoencoder.py | 1 + monai/networks/nets/vit.py | 2 + monai/networks/nets/vltransformer.py | 397 ++++++++++++++++++++++++++ requirements-dev.txt | 1 + setup.cfg | 3 + tests/min_tests.py | 1 + tests/test_vltransformer.py | 80 ++++++ 13 files changed, 506 insertions(+), 2 deletions(-) create mode 100644 monai/networks/nets/vltransformer.py create mode 100644 tests/test_vltransformer.py diff --git a/docs/requirements.txt b/docs/requirements.txt index 00dd4d2c1e..47176c58a2 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -20,3 +20,4 @@ sphinxcontrib-serializinghtml sphinx-autodoc-typehints==1.11.1 pandas einops +transformers diff --git a/docs/source/installation.md b/docs/source/installation.md index 08ab109142..4bc4aa700a 100644 --- a/docs/source/installation.md +++ b/docs/source/installation.md @@ -174,9 +174,9 @@ Since MONAI v0.2.0, the extras syntax such as `pip install 'monai[nibabel]'` is - The options are ``` -[nibabel, skimage, pillow, tensorboard, gdown, ignite, torchvision, itk, tqdm, lmdb, psutil, cucim, openslide, pandas, einops] +[nibabel, skimage, pillow, tensorboard, gdown, ignite, torchvision, itk, tqdm, lmdb, psutil, cucim, openslide, pandas, einops, transformers] ``` which correspond to `nibabel`, `scikit-image`, `pillow`, `tensorboard`, -`gdown`, `pytorch-ignite`, `torchvision`, `itk`, `tqdm`, `lmdb`, `psutil`, `cucim`, `openslide-python`, `pandas` and `einops`, respectively. +`gdown`, `pytorch-ignite`, `torchvision`, `itk`, `tqdm`, `lmdb`, `psutil`, `cucim`, `openslide-python`, `pandas`, `einops` and `transformers`, respectively. - `pip install 'monai[all]'` installs all the optional dependencies. diff --git a/docs/source/networks.rst b/docs/source/networks.rst index 54c2756535..1020ff1026 100644 --- a/docs/source/networks.rst +++ b/docs/source/networks.rst @@ -500,6 +500,11 @@ Nets .. autoclass:: Critic :members: +`VLTransformers` +~~~~~~~~~~~~~~~~ +.. autoclass:: VLTransformers + :members: + `NetAdapter` ~~~~~~~~~~~~ .. autoclass:: NetAdapter diff --git a/monai/config/deviceconfig.py b/monai/config/deviceconfig.py index 273431fc72..ff45b29531 100644 --- a/monai/config/deviceconfig.py +++ b/monai/config/deviceconfig.py @@ -73,6 +73,7 @@ def get_optional_config_values(): output["psutil"] = psutil_version output["pandas"] = get_package_version("pandas") output["einops"] = get_package_version("einops") + output["transformers"] = get_package_version("transformers") return output diff --git a/monai/networks/nets/__init__.py b/monai/networks/nets/__init__.py index ad1ca2418b..0ddda1d6dd 100644 --- a/monai/networks/nets/__init__.py +++ b/monai/networks/nets/__init__.py @@ -84,4 +84,13 @@ from .unetr import UNETR from .varautoencoder import VarAutoEncoder from .vit import ViT +from .vltransformer import ( + BertAttention, + BertMixedLayer, + BertOutput, + BertPreTrainedModel, + MultiModal, + Pooler, + VLTransformers, +) from .vnet import VNet diff --git a/monai/networks/nets/autoencoder.py b/monai/networks/nets/autoencoder.py index ed5e351779..b7dc309b71 100644 --- a/monai/networks/nets/autoencoder.py +++ b/monai/networks/nets/autoencoder.py @@ -49,8 +49,11 @@ def __init__( dimensions: Optional[int] = None, ) -> None: """ + Initialize the AutoEncoder. + .. deprecated:: 0.6.0 ``dimensions`` is deprecated, use ``spatial_dims`` instead. + """ super().__init__() diff --git a/monai/networks/nets/varautoencoder.py b/monai/networks/nets/varautoencoder.py index 3baa59531a..a228efab07 100644 --- a/monai/networks/nets/varautoencoder.py +++ b/monai/networks/nets/varautoencoder.py @@ -47,6 +47,7 @@ class VarAutoEncoder(AutoEncoder): .. deprecated:: 0.6.0 ``dimensions`` is deprecated, use ``spatial_dims`` instead. + """ @deprecated_arg( diff --git a/monai/networks/nets/vit.py b/monai/networks/nets/vit.py index 3a5d94cc37..35e05727e2 100644 --- a/monai/networks/nets/vit.py +++ b/monai/networks/nets/vit.py @@ -18,6 +18,8 @@ from monai.networks.blocks.patchembedding import PatchEmbeddingBlock from monai.networks.blocks.transformerblock import TransformerBlock +__all__ = ["ViT"] + class ViT(nn.Module): """ diff --git a/monai/networks/nets/vltransformer.py b/monai/networks/nets/vltransformer.py new file mode 100644 index 0000000000..23a1a39ded --- /dev/null +++ b/monai/networks/nets/vltransformer.py @@ -0,0 +1,397 @@ +# Copyright 2020 - 2021 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 math +import os +import shutil +import tarfile +import tempfile +from typing import Sequence, Tuple, Union + +import torch +from torch import nn + +from monai.utils import optional_import + +transformers = optional_import("transformers") +load_tf_weights_in_bert = optional_import("transformers", name="load_tf_weights_in_bert") +cached_path = optional_import("transformers.file_utils", name="cached_path")[0] +BertEmbeddings = optional_import("transformers.models.bert.modeling_bert", name="BertEmbeddings")[0] +BertLayer = optional_import("transformers.models.bert.modeling_bert", name="BertLayer")[0] + +__all__ = [ + "BertPreTrainedModel", + "BertAttention", + "BertOutput", + "BertMixedLayer", + "Pooler", + "MultiModal", + "VLTransformers", +] + + +class BertPreTrainedModel(nn.Module): + """Module to load BERT pre-trained weights. + Based on: + LXMERT + https://github.com/airsplay/lxmert + BERT (pytorch-transformer) + https://github.com/huggingface/transformers + """ + + def __init__(self, *inputs, **kwargs) -> None: + super(BertPreTrainedModel, self).__init__() + + def init_bert_weights(self, module): + if isinstance(module, (nn.Linear, nn.Embedding)): + module.weight.data.normal_(mean=0.0, std=self.config.initializer_range) + elif isinstance(module, torch.nn.LayerNorm): + module.bias.data.zero_() + module.weight.data.fill_(1.0) + if isinstance(module, nn.Linear) and module.bias is not None: + module.bias.data.zero_() + + @classmethod + def from_pretrained( + cls, + num_language_layers, + num_vision_layers, + num_mixed_layers, + bert_config, + state_dict=None, + cache_dir=None, + from_tf=False, + *inputs, + **kwargs, + ): + archive_file = "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased.tar.gz" + resolved_archive_file = cached_path(archive_file, cache_dir=cache_dir) + tempdir = None + if os.path.isdir(resolved_archive_file) or from_tf: + serialization_dir = resolved_archive_file + else: + tempdir = tempfile.mkdtemp() + with tarfile.open(resolved_archive_file, "r:gz") as archive: + archive.extractall(tempdir) + serialization_dir = tempdir + model = cls(num_language_layers, num_vision_layers, num_mixed_layers, bert_config, *inputs, **kwargs) + if state_dict is None and not from_tf: + weights_path = os.path.join(serialization_dir, "pytorch_model.bin") + state_dict = torch.load(weights_path, map_location="cpu" if not torch.cuda.is_available() else None) + if tempdir: + shutil.rmtree(tempdir) + if from_tf: + weights_path = os.path.join(serialization_dir, "model.ckpt") + return load_tf_weights_in_bert(model, weights_path) + old_keys = [] + new_keys = [] + for key in state_dict.keys(): + new_key = None + if "gamma" in key: + new_key = key.replace("gamma", "weight") + if "beta" in key: + new_key = key.replace("beta", "bias") + if new_key: + old_keys.append(key) + new_keys.append(new_key) + for old_key, new_key in zip(old_keys, new_keys): + state_dict[new_key] = state_dict.pop(old_key) + missing_keys = [] + unexpected_keys = [] + error_msgs = [] + metadata = getattr(state_dict, "_metadata", None) + state_dict = state_dict.copy() + if metadata is not None: + state_dict._metadata = metadata + + def load(module, prefix=""): + local_metadata = {} if metadata is None else metadata.get(prefix[:-1], {}) + module._load_from_state_dict( + state_dict, prefix, local_metadata, True, missing_keys, unexpected_keys, error_msgs + ) + for name, child in module._modules.items(): + if child is not None: + load(child, prefix + name + ".") + + start_prefix = "" + if not hasattr(model, "bert") and any(s.startswith("bert.") for s in state_dict.keys()): + start_prefix = "bert." + load(model, prefix=start_prefix) + return model + + +class BertAttention(nn.Module): + """BERT attention layer. + Based on: BERT (pytorch-transformer) + https://github.com/huggingface/transformers + """ + + def __init__( + self, + config, + ) -> None: + super().__init__() + self.num_attention_heads = config.num_attention_heads + self.attention_head_size = int(config.hidden_size / config.num_attention_heads) + self.all_head_size = self.num_attention_heads * self.attention_head_size + self.query = nn.Linear(config.hidden_size, self.all_head_size) + self.key = nn.Linear(config.hidden_size, self.all_head_size) + self.value = nn.Linear(config.hidden_size, self.all_head_size) + self.dropout = nn.Dropout(config.attention_probs_dropout_prob) + + def transpose_for_scores(self, x): + new_x_shape = x.size()[:-1] + (self.num_attention_heads, self.attention_head_size) + x = x.view(*new_x_shape) + return x.permute(0, 2, 1, 3) + + def forward(self, hidden_states, context): + mixed_query_layer = self.query(hidden_states) + mixed_key_layer = self.key(context) + mixed_value_layer = self.value(context) + query_layer = self.transpose_for_scores(mixed_query_layer) + key_layer = self.transpose_for_scores(mixed_key_layer) + value_layer = self.transpose_for_scores(mixed_value_layer) + attention_scores = torch.matmul(query_layer, key_layer.transpose(-1, -2)) + attention_scores = attention_scores / math.sqrt(self.attention_head_size) + attention_probs = self.dropout(nn.Softmax(dim=-1)(attention_scores)) + context_layer = torch.matmul(attention_probs, value_layer) + context_layer = context_layer.permute(0, 2, 1, 3).contiguous() + new_context_layer_shape = context_layer.size()[:-2] + (self.all_head_size,) + context_layer = context_layer.view(*new_context_layer_shape) + return context_layer + + +class BertOutput(nn.Module): + """BERT output layer. + Based on: BERT (pytorch-transformer) + https://github.com/huggingface/transformers + """ + + def __init__(self, config) -> None: + super(BertOutput, self).__init__() + self.dense = nn.Linear(config.hidden_size, config.hidden_size) + self.LayerNorm = torch.nn.LayerNorm(config.hidden_size, eps=1e-12) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + + def forward(self, hidden_states, input_tensor): + hidden_states = self.dense(hidden_states) + hidden_states = self.dropout(hidden_states) + hidden_states = self.LayerNorm(hidden_states + input_tensor) + return hidden_states + + +class BertMixedLayer(nn.Module): + """BERT cross attention layer. + Based on: BERT (pytorch-transformer) + https://github.com/huggingface/transformers + """ + + def __init__( + self, + config, + ) -> None: + super().__init__() + self.att = BertAttention(config) + self.output = BertOutput(config) + + def forward(self, x, y): + output = self.att(x, y) + return self.output(output, x) + + +class Pooler(nn.Module): + """BERT pooler layer. + Based on: BERT (pytorch-transformer) + https://github.com/huggingface/transformers + """ + + def __init__( + self, + hidden_size, + ) -> None: + super(Pooler, self).__init__() + self.dense = nn.Linear(hidden_size, hidden_size) + self.activation = nn.Tanh() + + def forward(self, hidden_states): + first_token_tensor = hidden_states[:, 0] + pooled_output = self.dense(first_token_tensor) + pooled_output = self.activation(pooled_output) + return pooled_output + + +class MultiModal(BertPreTrainedModel): + """ + Multimodal Transformers From Pretrained BERT Weights" + """ + + def __init__( + self, + num_language_layers: int, + num_vision_layers: int, + num_mixed_layers: int, + bert_config: dict, # type: ignore + ) -> None: + """ + Args: + num_language_layers: number of language transformer layers. + num_vision_layers: number of vision transformer layers. + bert_config: configuration for bert language transformer encoder. + + """ + super().__init__() + self.config = type("obj", (object,), bert_config) + self.embeddings = BertEmbeddings(self.config) + self.language_encoder = nn.ModuleList([BertLayer(self.config) for _ in range(num_language_layers)]) + self.vision_encoder = nn.ModuleList([BertLayer(self.config) for _ in range(num_vision_layers)]) + self.mixed_encoder = nn.ModuleList([BertMixedLayer(self.config) for _ in range(num_mixed_layers)]) + self.apply(self.init_bert_weights) + + def forward(self, input_ids, token_type_ids=None, vision_feats=None, attention_mask=None): + language_features = self.embeddings(input_ids, token_type_ids) + for layer in self.vision_encoder: + hidden_state_vision = layer(vision_feats, None)[0] + for layer in self.language_encoder: + hidden_state_language = layer(language_features, attention_mask)[0] + for layer in self.mixed_encoder: + hidden_state_mixed = layer(hidden_state_language, hidden_state_vision) + return hidden_state_mixed + + +class VLTransformers(torch.nn.Module): + """ + Vision Language Multimodal Transformers + """ + + def __init__( + self, + in_channels: int, + img_size: Union[Sequence[int], int], # type: ignore + patch_size: Union[int, Tuple[int, int]], # type: ignore + num_classes: int, + num_language_layers: int, + num_vision_layers: int, + num_mixed_layers: int, + hidden_size: int = 768, + drop_out: float = 0.0, + attention_probs_dropout_prob: float = 0.1, + gradient_checkpointing: bool = False, + hidden_act: str = "gelu", + hidden_dropout_prob: float = 0.1, + initializer_range: float = 0.02, + intermediate_size: int = 3072, + layer_norm_eps: float = 1e-12, + max_position_embeddings: int = 512, + model_type: str = "bert", + num_attention_heads: int = 12, + num_hidden_layers: int = 12, + pad_token_id: int = 0, + position_embedding_type: str = "absolute", + transformers_version: str = "4.10.2", + type_vocab_size: int = 2, + use_cache: bool = True, + vocab_size: int = 30522, + chunk_size_feed_forward: int = 0, + is_decoder: bool = False, + add_cross_attention: bool = False, + ) -> None: + """ + Args: + in_channels: dimension of input channels. + img_size: dimension of input image. + patch_size: dimension of patch size. + num_classes: number of classes if classification is used. + num_language_layers: number of language transformer layers. + num_vision_layers: number of vision transformer layers. + num_mixed_layers: number of mixed transformer layers. + drop_out: faction of the input units to drop. + bert_config: configuration for bert language transformer encoder. + + Examples: + + .. code-block:: python + + # for 3-channel with image size of (224,224), patch size of (32,32), 3 classes, 2 language layers, + # 2 vision layers, 2 mixed modality layers and dropout of 0.2 in the classification head + net = VLTransformers(in_channels=3, + img_size=(224, 224), + num_classes=3, + num_language_layers=2, + num_vision_layers=2, + num_mixed_layers=2, + drop_out=0.2) + + """ + super(VLTransformers, self).__init__() + bert_config = { + "attention_probs_dropout_prob": attention_probs_dropout_prob, + "classifier_dropout": None, + "gradient_checkpointing": gradient_checkpointing, + "hidden_act": hidden_act, + "hidden_dropout_prob": hidden_dropout_prob, + "hidden_size": hidden_size, + "initializer_range": initializer_range, + "intermediate_size": intermediate_size, + "layer_norm_eps": layer_norm_eps, + "max_position_embeddings": max_position_embeddings, + "model_type": model_type, + "num_attention_heads": num_attention_heads, + "num_hidden_layers": num_hidden_layers, + "pad_token_id": pad_token_id, + "position_embedding_type": position_embedding_type, + "transformers_version": transformers_version, + "type_vocab_size": type_vocab_size, + "use_cache": use_cache, + "vocab_size": vocab_size, + "chunk_size_feed_forward": chunk_size_feed_forward, + "is_decoder": is_decoder, + "add_cross_attention": add_cross_attention, + } + if not (0 <= drop_out <= 1): + raise ValueError("dropout_rate should be between 0 and 1.") + + if (img_size[0] % patch_size[0] != 0) or (img_size[1] % patch_size[1] != 0): # type: ignore + raise ValueError("img_size should be divisible by patch_size.") + + self.multimodal = MultiModal.from_pretrained( + num_language_layers=num_language_layers, + num_vision_layers=num_vision_layers, + num_mixed_layers=num_mixed_layers, + bert_config=bert_config, + ) + + self.patch_size = patch_size + self.num_patches = (img_size[0] // self.patch_size[0]) * (img_size[1] // self.patch_size[1]) # type: ignore + self.vision_proj = nn.Conv2d( + in_channels=in_channels, + out_channels=hidden_size, + kernel_size=self.patch_size, # type: ignore + stride=self.patch_size, # type: ignore + ) + self.norm_vision_pos = nn.LayerNorm(hidden_size) + self.pos_embed_vis = nn.Parameter(torch.zeros(1, self.num_patches, hidden_size)) + self.pooler = Pooler(hidden_size=hidden_size) + self.drop = torch.nn.Dropout(drop_out) + self.cls_head = torch.nn.Linear(hidden_size, num_classes) + + def forward(self, input_ids, token_type_ids=None, vision_feats=None): + attention_mask = torch.ones_like(input_ids).unsqueeze(1).unsqueeze(2) + attention_mask = attention_mask.to(dtype=next(self.parameters()).dtype) + attention_mask = (1.0 - attention_mask) * -10000.0 + vision_feats = self.vision_proj(vision_feats).flatten(2).transpose(1, 2) + vision_feats = self.norm_vision_pos(vision_feats) + vision_feats = vision_feats + self.pos_embed_vis + hidden_state_mixed = self.multimodal( + input_ids=input_ids, token_type_ids=token_type_ids, vision_feats=vision_feats, attention_mask=attention_mask + ) + pooled_features = self.pooler(hidden_state_mixed) + logits = self.cls_head(self.drop(pooled_features)) + return logits diff --git a/requirements-dev.txt b/requirements-dev.txt index 785454ad5d..ed8739ded8 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -36,3 +36,4 @@ openslide-python==1.1.2 pandas requests einops +transformers diff --git a/setup.cfg b/setup.cfg index 6efe768a6f..f7ed90a14a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,6 +44,7 @@ all = openslide-python==1.1.2 pandas einops + transformers nibabel = nibabel skimage = @@ -74,6 +75,8 @@ pandas = pandas einops = einops +transformers = + transformers [flake8] select = B,C,E,F,N,P,T4,W,B9 max_line_length = 120 diff --git a/tests/min_tests.py b/tests/min_tests.py index 5b376d7b57..bac6521889 100644 --- a/tests/min_tests.py +++ b/tests/min_tests.py @@ -140,6 +140,7 @@ def run_testsuit(): "test_zoom", "test_zoom_affine", "test_zoomd", + "test_vltransformer", ] assert sorted(exclude_cases) == sorted(set(exclude_cases)), f"Duplicated items in {exclude_cases}" diff --git a/tests/test_vltransformer.py b/tests/test_vltransformer.py new file mode 100644 index 0000000000..a92a9bf79a --- /dev/null +++ b/tests/test_vltransformer.py @@ -0,0 +1,80 @@ +# Copyright 2020 - 2021 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 torch +from parameterized import parameterized + +from monai.networks import eval_mode +from monai.networks.nets.vltransformer import VLTransformers + +TEST_CASE_VLTransformers = [] +for drop_out in [0.4]: + for in_channels in [3]: + for img_size in [224]: + for patch_size in [16, 32]: + for num_language_layers in [2]: + for num_vision_layers in [4]: + for num_mixed_layers in [3]: + for num_classes in [8]: + test_case = [ + { + "in_channels": in_channels, + "img_size": (img_size,) * 2, + "patch_size": (patch_size,) * 2, + "num_vision_layers": num_vision_layers, + "num_mixed_layers": num_mixed_layers, + "num_language_layers": num_language_layers, + "num_classes": num_classes, + "drop_out": drop_out, + }, + (2, num_classes), # type: ignore + ] + TEST_CASE_VLTransformers.append(test_case) + + +class TestPatchEmbeddingBlock(unittest.TestCase): + @parameterized.expand(TEST_CASE_VLTransformers) + def test_shape(self, input_param, expected_shape): + net = VLTransformers(**input_param) + with eval_mode(net): + result = net(torch.randint(2, (2, 512)), torch.randint(2, (2, 512)), torch.randn((2, 3, 224, 224))) + self.assertEqual(result.shape, expected_shape) + + def test_ill_arg(self): + with self.assertRaises(ValueError): + VLTransformers( + in_channels=3, + img_size=(128, 128), + patch_size=(16, 16), + num_language_layers=2, + num_mixed_layers=4, + num_vision_layers=2, + num_classes=2, + drop_out=5.0, + ) + + with self.assertRaises(ValueError): + VLTransformers( + in_channels=1, + img_size=(97, 97), + patch_size=(16, 16), + num_language_layers=6, + num_mixed_layers=6, + num_vision_layers=8, + num_classes=8, + drop_out=0.4, + ) + + +if __name__ == "__main__": + unittest.main() From 71ebd912518582412772de8a9e96f69a406f1376 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Thu, 16 Sep 2021 14:03:43 +0100 Subject: [PATCH 26/89] Torch: `map_binary_to_indices`, `map_classes_to_indices`, `correct_crop_centers`, `generate_pos_neg_label_crop_centers`, `generate_label_classes_crop_centers` (#2958) torch map_binary_to_indices, map_classes_to_indices, correct_crop_centers, generate_pos_neg_label_crop_centers, generate_label_classes_crop_centers --- monai/transforms/__init__.py | 13 +- monai/transforms/croppad/array.py | 12 +- monai/transforms/croppad/dictionary.py | 10 +- monai/transforms/utility/array.py | 7 +- monai/transforms/utils.py | 74 ++++--- .../utils_pytorch_numpy_unification.py | 97 +++++++++ tests/test_correct_crop_centers.py | 39 ++++ ...est_generate_label_classes_crop_centers.py | 24 ++- ...est_generate_pos_neg_label_crop_centers.py | 57 ++++-- tests/test_map_binary_to_indices.py | 84 ++++---- tests/test_map_classes_to_indices.py | 189 ++++++++++++------ 11 files changed, 430 insertions(+), 176 deletions(-) create mode 100644 tests/test_correct_crop_centers.py diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index 8a32b9e0b8..8f76a4b7a6 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -524,4 +524,15 @@ weighted_patch_samples, zero_margins, ) -from .utils_pytorch_numpy_unification import clip, in1d, moveaxis, percentile, where +from .utils_pytorch_numpy_unification import ( + any_np_pt, + clip, + floor_divide, + in1d, + moveaxis, + nonzero, + percentile, + ravel, + unravel_index, + where, +) diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index d3cec35d93..fac14f4582 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -910,16 +910,18 @@ def randomize( image: Optional[np.ndarray] = None, ) -> None: self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) + fg_indices_: np.ndarray + bg_indices_: np.ndarray if fg_indices is None or bg_indices is None: if self.fg_indices is not None and self.bg_indices is not None: fg_indices_ = self.fg_indices bg_indices_ = self.bg_indices else: - fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) + fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) # type: ignore else: fg_indices_ = fg_indices bg_indices_ = bg_indices - self.centers = generate_pos_neg_label_crop_centers( + self.centers = generate_pos_neg_label_crop_centers( # type: ignore self.spatial_size, self.num_samples, self.pos_ratio, label.shape[1:], fg_indices_, bg_indices_, self.R ) @@ -1052,15 +1054,15 @@ def randomize( image: Optional[np.ndarray] = None, ) -> None: self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) - indices_: List[np.ndarray] + indices_: Sequence[np.ndarray] if indices is None: if self.indices is not None: indices_ = self.indices else: - indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) + indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) # type: ignore else: indices_ = indices - self.centers = generate_label_classes_crop_centers( + self.centers = generate_label_classes_crop_centers( # type: ignore self.spatial_size, self.num_samples, label.shape[1:], indices_, self.ratios, self.R ) diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py index 233f1b6edf..a504b23179 100644 --- a/monai/transforms/croppad/dictionary.py +++ b/monai/transforms/croppad/dictionary.py @@ -1100,13 +1100,15 @@ def randomize( bg_indices: Optional[np.ndarray] = None, image: Optional[np.ndarray] = None, ) -> None: + fg_indices_: np.ndarray + bg_indices_: np.ndarray self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) if fg_indices is None or bg_indices is None: - fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) + fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) # type: ignore else: fg_indices_ = fg_indices bg_indices_ = bg_indices - self.centers = generate_pos_neg_label_crop_centers( + self.centers = generate_pos_neg_label_crop_centers( # type: ignore self.spatial_size, self.num_samples, self.pos_ratio, label.shape[1:], fg_indices_, bg_indices_, self.R ) @@ -1283,10 +1285,10 @@ def randomize( self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) indices_: List[np.ndarray] if indices is None: - indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) + indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) # type: ignore else: indices_ = indices - self.centers = generate_label_classes_crop_centers( + self.centers = generate_label_classes_crop_centers( # type: ignore self.spatial_size, self.num_samples, label.shape[1:], indices_, self.ratios, self.R ) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 9109fb04c5..848a782533 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -810,12 +810,14 @@ def __call__( output_shape: expected shape of output indices. if None, use `self.output_shape` instead. """ + fg_indices: np.ndarray + bg_indices: np.ndarray label, *_ = convert_data_type(label, np.ndarray) # type: ignore if image is not None: image, *_ = convert_data_type(image, np.ndarray) # type: ignore if output_shape is None: output_shape = self.output_shape - fg_indices, bg_indices = map_binary_to_indices(label, image, self.image_threshold) + fg_indices, bg_indices = map_binary_to_indices(label, image, self.image_threshold) # type: ignore if output_shape is not None: fg_indices = np.stack([np.unravel_index(i, output_shape) for i in fg_indices]) bg_indices = np.stack([np.unravel_index(i, output_shape) for i in bg_indices]) @@ -868,7 +870,8 @@ def __call__( if output_shape is None: output_shape = self.output_shape - indices = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) + indices: List[np.ndarray] + indices = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) # type: ignore if output_shape is not None: indices = [np.stack([np.unravel_index(i, output_shape) for i in array]) for array in indices] diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index f0be87de0b..883d5e5faa 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -26,6 +26,7 @@ from monai.networks.layers import GaussianFilter from monai.transforms.compose import Compose, OneOf from monai.transforms.transform import MapTransform, Transform +from monai.transforms.utils_pytorch_numpy_unification import any_np_pt, nonzero, ravel, unravel_index from monai.utils import ( GridSampleMode, InterpolateMode, @@ -261,10 +262,10 @@ def resize_center(img: np.ndarray, *resize_dims: Optional[int], fill_value: floa def map_binary_to_indices( - label: np.ndarray, - image: Optional[np.ndarray] = None, + label: NdarrayOrTensor, + image: Optional[NdarrayOrTensor] = None, image_threshold: float = 0.0, -) -> Tuple[np.ndarray, np.ndarray]: +) -> Tuple[NdarrayOrTensor, NdarrayOrTensor]: """ Compute the foreground and background of input label data, return the indices after fattening. For example: @@ -277,28 +278,31 @@ def map_binary_to_indices( to define background. so the output items will not map to all the voxels in the label. image_threshold: if enabled `image`, use ``image > image_threshold`` to determine the valid image content area and select background only in this area. - """ + # Prepare fg/bg indices if label.shape[0] > 1: label = label[1:] # for One-Hot format data, remove the background channel - label_flat = np.any(label, axis=0).ravel() # in case label has multiple dimensions - fg_indices = np.nonzero(label_flat)[0] + label_flat = ravel(any_np_pt(label, 0)) # in case label has multiple dimensions + fg_indices = nonzero(label_flat) if image is not None: - img_flat = np.any(image > image_threshold, axis=0).ravel() - bg_indices = np.nonzero(np.logical_and(img_flat, ~label_flat))[0] + img_flat = ravel(any_np_pt(image > image_threshold, 0)) + img_flat, *_ = convert_data_type( + img_flat, type(label), device=label.device if isinstance(label, torch.Tensor) else None + ) + bg_indices = nonzero(img_flat & ~label_flat) else: - bg_indices = np.nonzero(~label_flat)[0] + bg_indices = nonzero(~label_flat) return fg_indices, bg_indices def map_classes_to_indices( - label: np.ndarray, + label: NdarrayOrTensor, num_classes: Optional[int] = None, - image: Optional[np.ndarray] = None, + image: Optional[NdarrayOrTensor] = None, image_threshold: float = 0.0, -) -> List[np.ndarray]: +) -> List[NdarrayOrTensor]: """ Filter out indices of every class of the input label data, return the indices after fattening. It can handle both One-Hot format label and Argmax format label, must provide `num_classes` for @@ -318,11 +322,11 @@ def map_classes_to_indices( determine the valid image content area and select class indices only in this area. """ - img_flat: Optional[np.ndarray] = None + img_flat: Optional[NdarrayOrTensor] = None if image is not None: - img_flat = np.any(image > image_threshold, axis=0).ravel() + img_flat = ravel((image > image_threshold).any(0)) - indices: List[np.ndarray] = [] + indices: List[NdarrayOrTensor] = [] # assuming the first dimension is channel channels = len(label) @@ -333,9 +337,9 @@ def map_classes_to_indices( num_classes_ = num_classes for c in range(num_classes_): - label_flat = np.any(label[c : c + 1] if channels > 1 else label == c, axis=0).ravel() - label_flat = np.logical_and(img_flat, label_flat) if img_flat is not None else label_flat - indices.append(np.nonzero(label_flat)[0]) + label_flat = ravel(any_np_pt(label[c : c + 1] if channels > 1 else label == c, 0)) + label_flat = img_flat & label_flat if img_flat is not None else label_flat + indices.append(nonzero(label_flat)) return indices @@ -385,8 +389,10 @@ def weighted_patch_samples( def correct_crop_centers( - centers: List[np.ndarray], spatial_size: Union[Sequence[int], int], label_spatial_shape: Sequence[int] -) -> List[np.ndarray]: + centers: List[Union[int, torch.Tensor]], + spatial_size: Union[Sequence[int], int], + label_spatial_shape: Sequence[int], +) -> List[int]: """ Utility to correct the crop center if the crop size is bigger than the image size. @@ -419,7 +425,9 @@ def correct_crop_centers( center_i = valid_end[i] - 1 centers[i] = center_i - return centers + corrected_centers: List[int] = [c.item() if isinstance(c, torch.Tensor) else c for c in centers] # type: ignore + + return corrected_centers def generate_pos_neg_label_crop_centers( @@ -427,10 +435,10 @@ def generate_pos_neg_label_crop_centers( num_samples: int, pos_ratio: float, label_spatial_shape: Sequence[int], - fg_indices: np.ndarray, - bg_indices: np.ndarray, + fg_indices: NdarrayOrTensor, + bg_indices: NdarrayOrTensor, rand_state: Optional[np.random.RandomState] = None, -) -> List[List[np.ndarray]]: +) -> List[List[int]]: """ Generate valid sample locations based on the label with option for specifying foreground ratio Valid: samples sitting entirely within image, expected input shape: [C, H, W, D] or [C, H, W] @@ -453,11 +461,12 @@ def generate_pos_neg_label_crop_centers( rand_state = np.random.random.__self__ # type: ignore centers = [] - fg_indices, bg_indices = np.asarray(fg_indices), np.asarray(bg_indices) - if fg_indices.size == 0 and bg_indices.size == 0: + fg_indices = np.asarray(fg_indices) if isinstance(fg_indices, Sequence) else fg_indices + bg_indices = np.asarray(bg_indices) if isinstance(bg_indices, Sequence) else bg_indices + if len(fg_indices) == 0 and len(bg_indices) == 0: raise ValueError("No sampling location available.") - if fg_indices.size == 0 or bg_indices.size == 0: + if len(fg_indices) == 0 or len(bg_indices) == 0: warnings.warn( f"N foreground {len(fg_indices)}, N background {len(bg_indices)}," "unable to generate class balanced samples." @@ -467,7 +476,8 @@ def generate_pos_neg_label_crop_centers( for _ in range(num_samples): indices_to_use = fg_indices if rand_state.rand() < pos_ratio else bg_indices random_int = rand_state.randint(len(indices_to_use)) - center = np.unravel_index(indices_to_use[random_int], label_spatial_shape) + idx = indices_to_use[random_int] + center = unravel_index(idx, label_spatial_shape) # shift center to range of valid centers center_ori = list(center) centers.append(correct_crop_centers(center_ori, spatial_size, label_spatial_shape)) @@ -479,10 +489,10 @@ def generate_label_classes_crop_centers( spatial_size: Union[Sequence[int], int], num_samples: int, label_spatial_shape: Sequence[int], - indices: List[np.ndarray], + indices: Sequence[NdarrayOrTensor], ratios: Optional[List[Union[float, int]]] = None, rand_state: Optional[np.random.RandomState] = None, -) -> List[List[np.ndarray]]: +) -> List[List[int]]: """ Generate valid sample locations based on the specified ratios of label classes. Valid: samples sitting entirely within image, expected input shape: [C, H, W, D] or [C, H, W] @@ -508,8 +518,6 @@ def generate_label_classes_crop_centers( if any(i < 0 for i in ratios_): raise ValueError("ratios should not contain negative number.") - # ensure indices are numpy array - indices = [np.asarray(i) for i in indices] for i, array in enumerate(indices): if len(array) == 0: warnings.warn(f"no available indices of class {i} to crop, set the crop ratio of this class to zero.") @@ -521,7 +529,7 @@ def generate_label_classes_crop_centers( # randomly select the indices of a class based on the ratios indices_to_use = indices[i] random_int = rand_state.randint(len(indices_to_use)) - center = np.unravel_index(indices_to_use[random_int], label_spatial_shape) + center = unravel_index(indices_to_use[random_int], label_spatial_shape) # shift center to range of valid centers center_ori = list(center) centers.append(correct_crop_centers(center_ori, spatial_size, label_spatial_shape)) diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 0fb8e34ef0..8808e25265 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -15,6 +15,7 @@ import torch from monai.config.type_definitions import NdarrayOrTensor +from monai.utils.misc import is_module_ver_at_least __all__ = [ "moveaxis", @@ -22,6 +23,11 @@ "clip", "percentile", "where", + "nonzero", + "floor_divide", + "unravel_index", + "ravel", + "any_np_pt", ] @@ -119,3 +125,94 @@ def where(condition: NdarrayOrTensor, x, y) -> NdarrayOrTensor: y = torch.as_tensor(y, device=condition.device, dtype=x.dtype) result = torch.where(condition, x, y) return result + + +def nonzero(x: NdarrayOrTensor): + """`np.nonzero` with equivalent implementation for torch. + + Args: + idx: array/tensor + + Returns: + Index unravelled for given shape + """ + if isinstance(x, np.ndarray): + return np.nonzero(x)[0] + return torch.nonzero(x).flatten() + + +def floor_divide(a: NdarrayOrTensor, b) -> NdarrayOrTensor: + """`np.floor_divide` with equivalent implementation for torch. + + As of pt1.8, use `torch.div(..., rounding_mode="floor")`, and + before that, use `torch.floor_divide`. + + Args: + a: first array/tensor + b: scalar to divide by + + Returns: + Element-wise floor division between two arrays/tensors. + """ + if isinstance(a, torch.Tensor): + if is_module_ver_at_least(torch, (1, 8, 0)): + return torch.div(a, b, rounding_mode="floor") + return torch.floor_divide(a, b) + else: + return np.floor_divide(a, b) + + +def unravel_index(idx, shape): + """`np.unravel_index` with equivalent implementation for torch. + + Args: + idx: index to unravel + b: shape of array/tensor + + Returns: + Index unravelled for given shape + """ + if isinstance(idx, torch.Tensor): + coord = [] + for dim in reversed(shape): + coord.insert(0, idx % dim) + idx = floor_divide(idx, dim) + return torch.stack(coord) + return np.unravel_index(np.asarray(idx, dtype=int), shape) + + +def ravel(x: NdarrayOrTensor): + """`np.ravel` with equivalent implementation for torch. + + Args: + x: array/tensor to ravel + + Returns: + Return a contiguous flattened array/tensor. + """ + if isinstance(x, torch.Tensor): + if hasattr(torch, "ravel"): + return x.ravel() + return x.flatten().contiguous() + return np.ravel(x) + + +def any_np_pt(x: NdarrayOrTensor, axis: int): + """`np.any` with equivalent implementation for torch. + + For pytorch, convert to boolean for compatibility with older versions. + + Args: + x: input array/tensor + axis: axis to perform `any` over + + Returns: + Return a contiguous flattened array/tensor. + """ + if isinstance(x, torch.Tensor): + try: + return torch.any(x, axis) + except RuntimeError: + # older versions of pytorch require the input to be cast to boolean + return torch.any(x.bool(), axis) + return np.any(x, axis) diff --git a/tests/test_correct_crop_centers.py b/tests/test_correct_crop_centers.py new file mode 100644 index 0000000000..853b3d41d3 --- /dev/null +++ b/tests/test_correct_crop_centers.py @@ -0,0 +1,39 @@ +# Copyright 2020 - 2021 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 torch +from parameterized import parameterized + +from monai.transforms.utils import correct_crop_centers +from tests.utils import assert_allclose + +TESTS = [ + [ + [1, 5, 0], + [2, 2, 2], + [10, 10, 10], + ], +] + + +class TestCorrectCropCenters(unittest.TestCase): + @parameterized.expand(TESTS) + def test_torch(self, spatial_size, centers, label_spatial_shape): + result1 = correct_crop_centers(centers, spatial_size, label_spatial_shape) + centers = [torch.tensor(i) for i in centers] + result2 = correct_crop_centers(centers, spatial_size, label_spatial_shape) + assert_allclose(result1, result2) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_generate_label_classes_crop_centers.py b/tests/test_generate_label_classes_crop_centers.py index 38f2a3e0d1..cc068504bf 100644 --- a/tests/test_generate_label_classes_crop_centers.py +++ b/tests/test_generate_label_classes_crop_centers.py @@ -10,11 +10,13 @@ # limitations under the License. import unittest +from copy import deepcopy -import numpy as np from parameterized import parameterized from monai.transforms import generate_label_classes_crop_centers +from monai.utils.misc import set_determinism +from tests.utils import TEST_NDARRAYS, assert_allclose TEST_CASE_1 = [ { @@ -23,7 +25,6 @@ "ratios": [1, 2], "label_spatial_shape": [3, 3, 3], "indices": [[3, 12, 21], [1, 9, 18]], - "rand_state": np.random.RandomState(), }, list, 2, @@ -37,7 +38,6 @@ "ratios": None, "label_spatial_shape": [3, 3, 3], "indices": [[3, 12, 21], [1, 9, 18]], - "rand_state": np.random.RandomState(), }, list, 1, @@ -48,10 +48,20 @@ class TestGenerateLabelClassesCropCenters(unittest.TestCase): @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) def test_type_shape(self, input_data, expected_type, expected_count, expected_shape): - result = generate_label_classes_crop_centers(**input_data) - self.assertIsInstance(result, expected_type) - self.assertEqual(len(result), expected_count) - self.assertEqual(len(result[0]), expected_shape) + results = [] + for p in TEST_NDARRAYS + (None,): + input_data = deepcopy(input_data) + if p is not None: + input_data["indices"] = p(input_data["indices"]) + set_determinism(0) + result = generate_label_classes_crop_centers(**input_data) + self.assertIsInstance(result, expected_type) + self.assertEqual(len(result), expected_count) + self.assertEqual(len(result[0]), expected_shape) + # check for consistency between numpy, torch and torch.cuda + results.append(result) + if len(results) > 1: + assert_allclose(results[0], results[-1]) if __name__ == "__main__": diff --git a/tests/test_generate_pos_neg_label_crop_centers.py b/tests/test_generate_pos_neg_label_crop_centers.py index 40181aa9ea..b263f10e55 100644 --- a/tests/test_generate_pos_neg_label_crop_centers.py +++ b/tests/test_generate_pos_neg_label_crop_centers.py @@ -10,35 +10,50 @@ # limitations under the License. import unittest +from copy import deepcopy -import numpy as np from parameterized import parameterized from monai.transforms import generate_pos_neg_label_crop_centers - -TEST_CASE_1 = [ - { - "spatial_size": [2, 2, 2], - "num_samples": 2, - "pos_ratio": 1.0, - "label_spatial_shape": [3, 3, 3], - "fg_indices": [1, 9, 18], - "bg_indices": [3, 12, 21], - "rand_state": np.random.RandomState(), - }, - list, - 2, - 3, -] +from monai.utils.misc import set_determinism +from tests.utils import TEST_NDARRAYS, assert_allclose + +TESTS = [] +TESTS.append( + [ + { + "spatial_size": [2, 2, 2], + "num_samples": 2, + "pos_ratio": 1.0, + "label_spatial_shape": [3, 3, 3], + "fg_indices": [1, 9, 18], + "bg_indices": [3, 12, 21], + }, + list, + 2, + 3, + ] +) class TestGeneratePosNegLabelCropCenters(unittest.TestCase): - @parameterized.expand([TEST_CASE_1]) + @parameterized.expand(TESTS) def test_type_shape(self, input_data, expected_type, expected_count, expected_shape): - result = generate_pos_neg_label_crop_centers(**input_data) - self.assertIsInstance(result, expected_type) - self.assertEqual(len(result), expected_count) - self.assertEqual(len(result[0]), expected_shape) + results = [] + for p in TEST_NDARRAYS + (None,): + input_data = deepcopy(input_data) + if p is not None: + for k in ["fg_indices", "bg_indices"]: + input_data[k] = p(input_data[k]) + set_determinism(0) + result = generate_pos_neg_label_crop_centers(**input_data) + self.assertIsInstance(result, expected_type) + self.assertEqual(len(result), expected_count) + self.assertEqual(len(result[0]), expected_shape) + # check for consistency between numpy, torch and torch.cuda + results.append(result) + if len(results) > 1: + assert_allclose(results[0], results[-1]) if __name__ == "__main__": diff --git a/tests/test_map_binary_to_indices.py b/tests/test_map_binary_to_indices.py index 1fafa6f446..2d29aa7c0d 100644 --- a/tests/test_map_binary_to_indices.py +++ b/tests/test_map_binary_to_indices.py @@ -15,50 +15,58 @@ from parameterized import parameterized from monai.transforms import map_binary_to_indices +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"label": np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), "image": None, "image_threshold": 0.0}, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 4, 8]), -] - -TEST_CASE_2 = [ - { - "label": np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), - "image": np.array([[[1, 1, 1], [1, 0, 1], [1, 1, 1]]]), - "image_threshold": 0.0, - }, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] - -TEST_CASE_3 = [ - { - "label": np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), - "image": np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), - "image_threshold": 1.0, - }, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] - -TEST_CASE_4 = [ - { - "label": np.array([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), - "image": np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), - "image_threshold": 1.0, - }, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + {"label": p(np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]])), "image": None, "image_threshold": 0.0}, + np.array([1, 2, 3, 5, 6, 7]), + np.array([0, 4, 8]), + ] + ) + TESTS.append( + [ + { + "label": p(np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]])), + "image": p(np.array([[[1, 1, 1], [1, 0, 1], [1, 1, 1]]])), + "image_threshold": 0.0, + }, + np.array([1, 2, 3, 5, 6, 7]), + np.array([0, 8]), + ] + ) + TESTS.append( + [ + { + "label": p(np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]])), + "image": p(np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])), + "image_threshold": 1.0, + }, + np.array([1, 2, 3, 5, 6, 7]), + np.array([0, 8]), + ] + ) + TESTS.append( + [ + { + "label": p(np.array([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]])), + "image": p(np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])), + "image_threshold": 1.0, + }, + np.array([1, 2, 3, 5, 6, 7]), + np.array([0, 8]), + ] + ) class TestMapBinaryToIndices(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4]) + @parameterized.expand(TESTS) def test_type_shape(self, input_data, expected_fg, expected_bg): fg_indices, bg_indices = map_binary_to_indices(**input_data) - np.testing.assert_allclose(fg_indices, expected_fg) - np.testing.assert_allclose(bg_indices, expected_bg) + assert_allclose(fg_indices, expected_fg, type_test=False) + assert_allclose(bg_indices, expected_bg, type_test=False) if __name__ == "__main__": diff --git a/tests/test_map_classes_to_indices.py b/tests/test_map_classes_to_indices.py index 2320954520..a585bd006b 100644 --- a/tests/test_map_classes_to_indices.py +++ b/tests/test_map_classes_to_indices.py @@ -15,86 +15,145 @@ from parameterized import parameterized from monai.transforms import map_classes_to_indices +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - # test Argmax data - {"label": np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), "num_classes": 3, "image": None, "image_threshold": 0.0}, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7])], -] +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + # test Argmax data + { + "label": p(np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])), + "num_classes": 3, + "image": None, + "image_threshold": 0.0, + }, + [ + np.array([0, 4, 8]), + np.array([1, 5, 6]), + np.array([2, 3, 7]), + ], + ] + ) -TEST_CASE_2 = [ - { - "label": np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), - "num_classes": 3, - "image": np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), - "image_threshold": 60, - }, - [np.array([0, 8]), np.array([1, 5, 6]), np.array([3])], -] + TESTS.append( + [ + { + "label": p(np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])), + "num_classes": 3, + "image": p(np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]])), + "image_threshold": 60, + }, + [ + np.array([0, 8]), + np.array([1, 5, 6]), + np.array([3]), + ], + ] + ) -TEST_CASE_3 = [ - # test One-Hot data - { - "label": np.array( + TESTS.append( + [ + # test One-Hot data + { + "label": p( + np.array( + [ + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + [[0, 1, 0], [0, 0, 1], [1, 0, 0]], + [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + ] + ) + ), + "image": None, + "image_threshold": 0.0, + }, [ - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 1, 0], [0, 0, 1], [1, 0, 0]], - [[0, 0, 1], [1, 0, 0], [0, 1, 0]], - ] - ), - "image": None, - "image_threshold": 0.0, - }, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7])], -] + np.array([0, 4, 8]), + np.array([1, 5, 6]), + np.array([2, 3, 7]), + ], + ] + ) -TEST_CASE_4 = [ - { - "label": np.array( + TESTS.append( + [ + { + "label": p( + np.array( + [ + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + [[0, 1, 0], [0, 0, 1], [1, 0, 0]], + [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + ] + ) + ), + "num_classes": None, + "image": p(np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]])), + "image_threshold": 60, + }, [ - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 1, 0], [0, 0, 1], [1, 0, 0]], - [[0, 0, 1], [1, 0, 0], [0, 1, 0]], - ] - ), - "num_classes": None, - "image": np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), - "image_threshold": 60, - }, - [np.array([0, 8]), np.array([1, 5, 6]), np.array([3])], -] + np.array([0, 8]), + np.array([1, 5, 6]), + np.array([3]), + ], + ] + ) -TEST_CASE_5 = [ - # test empty class - {"label": np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), "num_classes": 5, "image": None, "image_threshold": 0.0}, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7]), np.array([]), np.array([])], -] + TESTS.append( + [ + # test empty class + { + "label": p(np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])), + "num_classes": 5, + "image": None, + "image_threshold": 0.0, + }, + [ + np.array([0, 4, 8]), + np.array([1, 5, 6]), + np.array([2, 3, 7]), + np.array([]), + np.array([]), + ], + ] + ) -TEST_CASE_6 = [ - # test empty class - { - "label": np.array( + TESTS.append( + [ + # test empty class + { + "label": p( + np.array( + [ + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + [[0, 1, 0], [0, 0, 1], [1, 0, 0]], + [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + ] + ) + ), + "image": None, + "image_threshold": 0.0, + }, [ - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 1, 0], [0, 0, 1], [1, 0, 0]], - [[0, 0, 1], [1, 0, 0], [0, 1, 0]], - [[0, 0, 0], [0, 0, 0], [0, 0, 0]], - [[0, 0, 0], [0, 0, 0], [0, 0, 0]], - ] - ), - "image": None, - "image_threshold": 0.0, - }, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7]), np.array([]), np.array([])], -] + np.array([0, 4, 8]), + np.array([1, 5, 6]), + np.array([2, 3, 7]), + np.array([]), + np.array([]), + ], + ] + ) class TestMapClassesToIndices(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5, TEST_CASE_6]) + @parameterized.expand(TESTS) def test_value(self, input_data, expected_indices): indices = map_classes_to_indices(**input_data) for i, e in zip(indices, expected_indices): - np.testing.assert_allclose(i, e) + assert_allclose(i, e, type_test=False) if __name__ == "__main__": From 38403edfbda0d18817a20b93060ed2a978221dfa Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 10:37:56 -0400 Subject: [PATCH 27/89] cuCIM Transform (#2932) * Implement CuCIM wrapper transfrom Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- docs/source/transforms.rst | 23 +++ monai/transforms/__init__.py | 8 + monai/transforms/utility/array.py | 77 +++++++++- monai/transforms/utility/dictionary.py | 102 +++++++++++++ tests/test_cucim_dict_transform.py | 141 ++++++++++++++++++ tests/test_cucim_transform.py | 140 ++++++++++++++++++ tests/test_rand_cucim_dict_transform.py | 185 ++++++++++++++++++++++++ tests/test_rand_cucim_transform.py | 184 +++++++++++++++++++++++ 8 files changed, 859 insertions(+), 1 deletion(-) create mode 100644 tests/test_cucim_dict_transform.py create mode 100644 tests/test_cucim_transform.py create mode 100644 tests/test_rand_cucim_dict_transform.py create mode 100644 tests/test_rand_cucim_transform.py diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index add6b9b40c..0b0f9f0792 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -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 --------------------- @@ -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 ------------------ diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index 8f76a4b7a6..e693c06dc2 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -359,6 +359,7 @@ CastToType, ClassesToIndices, ConvertToMultiChannelBasedOnBratsClasses, + CuCIM, DataStats, EnsureChannelFirst, EnsureType, @@ -368,6 +369,7 @@ LabelToMask, Lambda, MapLabelValue, + RandCuCIM, RandLambda, RemoveRepeatedChannel, RepeatChannel, @@ -410,6 +412,9 @@ CopyItemsd, CopyItemsD, CopyItemsDict, + CuCIMd, + CuCIMD, + CuCIMDict, DataStatsd, DataStatsD, DataStatsDict, @@ -440,6 +445,9 @@ MapLabelValued, MapLabelValueD, MapLabelValueDict, + RandCuCIMd, + RandCuCIMD, + RandCuCIMDict, RandLambdad, RandLambdaD, RandLambdaDict, diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 848a782533..73fbd6666f 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -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", @@ -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) diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index a3c51fe3f2..695753a07d 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -36,6 +36,7 @@ CastToType, ClassesToIndices, ConvertToMultiChannelBasedOnBratsClasses, + CuCIM, DataStats, EnsureChannelFirst, EnsureType, @@ -87,6 +88,9 @@ "CopyItemsD", "CopyItemsDict", "CopyItemsd", + "CuCIMd", + "CuCIMD", + "CuCIMDict", "DataStatsD", "DataStatsDict", "DataStatsd", @@ -117,6 +121,9 @@ "MapLabelValueD", "MapLabelValueDict", "MapLabelValued", + "RandCuCIMd", + "RandCuCIMD", + "RandCuCIMDict", "RandLambdaD", "RandLambdaDict", "RandLambdad", @@ -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 @@ -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 diff --git a/tests/test_cucim_dict_transform.py b/tests/test_cucim_dict_transform.py new file mode 100644 index 0000000000..4936375142 --- /dev/null +++ b/tests/test_cucim_dict_transform.py @@ -0,0 +1,141 @@ +# Copyright 2020 - 2021 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 +from parameterized import parameterized + +from monai.transforms import CuCIMd +from monai.utils import optional_import, set_determinism +from tests.utils import skip_if_no_cuda + +_, has_cut = optional_import("cucim.core.operations.expose.transform") +cp, has_cp = optional_import("cupy") + +set_determinism(seed=0) + +TEST_CASE_COLOR_JITTER_1 = [ + {"name": "color_jitter", "brightness": 0.0, "contrast": 0.0, "saturation": 0.0, "hue": 0.0}, + np.array([[[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]]], dtype=np.float32), + np.array([[[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]]], dtype=np.float32), +] + +TEST_CASE_COLOR_JITTER_2 = [ + {"name": "color_jitter", "brightness": 0.0, "contrast": 0.0, "saturation": 0.0, "hue": 0.0}, + np.array([[[0, 1], [2, 3]], [[0, 1], [2, 3]], [[0, 1], [2, 3]]], dtype=np.uint8), + np.array([[[0, 1], [2, 3]], [[0, 1], [2, 3]], [[0, 1], [2, 3]]], dtype=np.uint8), +] + +TEST_CASE_FLIP_1 = [ + {"name": "image_flip", "spatial_axis": -1}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]]], dtype=np.float32), +] + + +TEST_CASE_ROTATE_1 = [ + {"name": "image_rotate_90", "k": 1, "spatial_axis": (-2, -1)}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]]], dtype=np.float32), +] + +TEST_CASE_SCALE_INTENSITY_1 = [ + {"name": "scale_intensity_range", "a_min": 0.0, "a_max": 4.0, "b_min": 0.0, "b_max": 1.0, "clip": False}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]]], dtype=np.float32), +] + +TEST_CASE_ZOOM_1 = [ + {"name": "zoom", "zoom_factor": (0.5, 0.5)}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.concatenate([np.ones((1, 3, 3), dtype=np.float32) * 1.0, np.ones((1, 3, 3), dtype=np.float32) * 2.0]), +] + + +@skip_if_no_cuda +@unittest.skipUnless(has_cp, "CuPy is required.") +@unittest.skipUnless(has_cut, "cuCIM transforms are required.") +class TestCuCIMDict(unittest.TestCase): + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_numpy_single(self, params, input, expected): + input = {"image": input} + output = CuCIMd(keys="image", **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_numpy_batch(self, params, input, expected): + input = {"image": input[cp.newaxis, ...]} + expected = expected[cp.newaxis, ...] + output = CuCIMd(keys="image", **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_cupy_single(self, params, input, expected): + input = {"image": cp.asarray(input)} + expected = cp.asarray(expected) + output = CuCIMd(keys="image", **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_cupy_batch(self, params, input, expected): + input = {"image": cp.asarray(input)[cp.newaxis, ...]} + expected = cp.asarray(expected)[cp.newaxis, ...] + output = CuCIMd(keys="image", **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_cucim_transform.py b/tests/test_cucim_transform.py new file mode 100644 index 0000000000..a6c0084c99 --- /dev/null +++ b/tests/test_cucim_transform.py @@ -0,0 +1,140 @@ +# Copyright 2020 - 2021 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 +from parameterized import parameterized + +from monai.transforms import CuCIM +from monai.utils import optional_import, set_determinism +from tests.utils import skip_if_no_cuda + +_, has_cut = optional_import("cucim.core.operations.expose.transform") +cp, has_cp = optional_import("cupy") + +set_determinism(seed=0) + +TEST_CASE_COLOR_JITTER_1 = [ + {"name": "color_jitter", "brightness": 0.0, "contrast": 0.0, "saturation": 0.0, "hue": 0.0}, + np.array([[[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]]], dtype=np.float32), + np.array([[[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]], [[0.0, 1.0], [1.0, 2.0]]], dtype=np.float32), +] + +TEST_CASE_COLOR_JITTER_2 = [ + {"name": "color_jitter", "brightness": 0.0, "contrast": 0.0, "saturation": 0.0, "hue": 0.0}, + np.array([[[0, 1], [2, 3]], [[0, 1], [2, 3]], [[0, 1], [2, 3]]], dtype=np.uint8), + np.array([[[0, 1], [2, 3]], [[0, 1], [2, 3]], [[0, 1], [2, 3]]], dtype=np.uint8), +] + +TEST_CASE_FLIP_1 = [ + {"name": "image_flip", "spatial_axis": -1}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]]], dtype=np.float32), +] + + +TEST_CASE_ROTATE_1 = [ + {"name": "image_rotate_90", "k": 1, "spatial_axis": (-2, -1)}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]]], dtype=np.float32), +] + +TEST_CASE_SCALE_INTENSITY_1 = [ + {"name": "scale_intensity_range", "a_min": 0.0, "a_max": 4.0, "b_min": 0.0, "b_max": 1.0, "clip": False}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]]], dtype=np.float32), +] + +TEST_CASE_ZOOM_1 = [ + {"name": "zoom", "zoom_factor": (0.5, 0.5)}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.concatenate([np.ones((1, 3, 3), dtype=np.float32) * 1.0, np.ones((1, 3, 3), dtype=np.float32) * 2.0]), +] + + +@skip_if_no_cuda +@unittest.skipUnless(has_cp, "CuPy is required.") +@unittest.skipUnless(has_cut, "cuCIM transforms are required.") +class TestCuCIM(unittest.TestCase): + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_numpy_single(self, params, input, expected): + output = CuCIM(**params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_numpy_batch(self, params, input, expected): + input = input[cp.newaxis, ...] + expected = expected[cp.newaxis, ...] + output = CuCIM(**params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_cupy_single(self, params, input, expected): + input = cp.asarray(input) + expected = cp.asarray(expected) + output = CuCIM(**params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_COLOR_JITTER_2, + TEST_CASE_FLIP_1, + TEST_CASE_ROTATE_1, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + ] + ) + def test_tramsforms_cupy_batch(self, params, input, expected): + input = cp.asarray(input)[cp.newaxis, ...] + expected = cp.asarray(expected)[cp.newaxis, ...] + output = CuCIM(**params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_rand_cucim_dict_transform.py b/tests/test_rand_cucim_dict_transform.py new file mode 100644 index 0000000000..c084331e0e --- /dev/null +++ b/tests/test_rand_cucim_dict_transform.py @@ -0,0 +1,185 @@ +# Copyright 2020 - 2021 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 +from parameterized import parameterized + +from monai.transforms import RandCuCIMd +from monai.utils import optional_import, set_determinism +from tests.utils import skip_if_no_cuda + +_, has_cut = optional_import("cucim.core.operations.expose.transform") +cp, has_cp = optional_import("cupy") + +set_determinism(seed=0) + +TEST_CASE_COLOR_JITTER_1 = [ + {"name": "color_jitter", "brightness": 0.0, "contrast": 0.0, "saturation": 0.0, "hue": 0.0}, + np.array([[[0, 1], [2, 3]], [[0, 10], [20, 30]], [[0, 50], [100, 150]]], dtype=np.uint8), + np.array([[[0, 1], [2, 3]], [[0, 10], [20, 30]], [[0, 50], [100, 150]]], dtype=np.uint8), +] + +TEST_CASE_FLIP_1 = [ + {"name": "image_flip", "spatial_axis": -1}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]]], dtype=np.float32), +] + +TEST_CASE_RAND_ROTATE_1 = [ + {"name": "rand_image_rotate_90", "prob": 1.0, "max_k": 1, "spatial_axis": (-2, -1)}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]]], dtype=np.float32), +] + + +TEST_CASE_RAND_ROTATE_2 = [ + {"name": "rand_image_rotate_90", "prob": 0.0, "max_k": 1, "spatial_axis": (-2, -1)}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), +] + +TEST_CASE_SCALE_INTENSITY_1 = [ + {"name": "scale_intensity_range", "a_min": 0.0, "a_max": 4.0, "b_min": 0.0, "b_max": 1.0, "clip": False}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]]], dtype=np.float32), +] + +TEST_CASE_ZOOM_1 = [ + {"name": "zoom", "zoom_factor": (0.5, 0.5)}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.concatenate([np.ones((1, 3, 3), dtype=np.float32) * 1.0, np.ones((1, 3, 3), dtype=np.float32) * 2.0]), +] + +TEST_CASE_RAND_ZOOM_1 = [ + {"name": "rand_zoom", "prob": 1.0, "min_zoom": 0.5, "max_zoom": 0.5}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.concatenate([np.ones((1, 3, 3), dtype=np.float32) * 1.0, np.ones((1, 3, 3), dtype=np.float32) * 2.0]), +] + +TEST_CASE_RAND_ZOOM_2 = [ + {"name": "rand_zoom", "prob": 0.0, "min_zoom": 0.5, "max_zoom": 0.5}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.mgrid[:3, 1:4].astype(dtype=np.float32), +] + + +@skip_if_no_cuda +@unittest.skipUnless(has_cp, "CuPy is required.") +@unittest.skipUnless(has_cut, "cuCIM transforms are required.") +class TestRandCuCIMDict(unittest.TestCase): + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_numpy_single(self, params, input, expected): + input = {"image": input} + # apply_prob=1.0 + output = RandCuCIMd(keys="image", apply_prob=1.0, **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIMd(keys="image", apply_prob=0.0, **params)(input)["image"] + self.assertTrue(output.dtype == input["image"].dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, input["image"]) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_numpy_batch(self, params, input, expected): + input = {"image": input[cp.newaxis, ...]} + expected = expected[cp.newaxis, ...] + # apply_prob=1.0 + output = RandCuCIMd(keys="image", apply_prob=1.0, **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIMd(keys="image", apply_prob=0.0, **params)(input)["image"] + self.assertTrue(output.dtype == input["image"].dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, input["image"]) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_cupy_single(self, params, input, expected): + input = {"image": cp.asarray(input)} + expected = cp.asarray(expected) + # apply_prob=1.0 + output = RandCuCIMd(keys="image", apply_prob=1.0, **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIMd(keys="image", apply_prob=0.0, **params)(input)["image"] + self.assertTrue(output.dtype == input["image"].dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, input["image"]) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_cupy_batch(self, params, input, expected): + input = {"image": cp.asarray(input)[cp.newaxis, ...]} + expected = cp.asarray(expected)[cp.newaxis, ...] + # apply_prob=1.0 + output = RandCuCIMd(keys="image", **params)(input)["image"] + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIMd(keys="image", apply_prob=0.0, **params)(input)["image"] + self.assertTrue(output.dtype == input["image"].dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, input["image"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_rand_cucim_transform.py b/tests/test_rand_cucim_transform.py new file mode 100644 index 0000000000..907bc35e01 --- /dev/null +++ b/tests/test_rand_cucim_transform.py @@ -0,0 +1,184 @@ +# Copyright 2020 - 2021 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 +from parameterized import parameterized + +from monai.transforms import RandCuCIM +from monai.utils import optional_import, set_determinism +from tests.utils import skip_if_no_cuda + +_, has_cut = optional_import("cucim.core.operations.expose.transform") +cp, has_cp = optional_import("cupy") + +set_determinism(seed=0) + +TEST_CASE_COLOR_JITTER_1 = [ + {"name": "color_jitter", "brightness": 0.0, "contrast": 0.0, "saturation": 0.0, "hue": 0.0}, + np.array([[[0, 1], [2, 3]], [[0, 10], [20, 30]], [[0, 50], [100, 150]]], dtype=np.uint8), + np.array([[[0, 1], [2, 3]], [[0, 10], [20, 30]], [[0, 50], [100, 150]]], dtype=np.uint8), +] + +TEST_CASE_FLIP_1 = [ + {"name": "image_flip", "spatial_axis": -1}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]], [[1.0, 0.0], [3.0, 2.0]]], dtype=np.float32), +] + +TEST_CASE_RAND_ROTATE_1 = [ + {"name": "rand_image_rotate_90", "prob": 1.0, "max_k": 1, "spatial_axis": (-2, -1)}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]], [[1.0, 3.0], [0.0, 2.0]]], dtype=np.float32), +] + + +TEST_CASE_RAND_ROTATE_2 = [ + {"name": "rand_image_rotate_90", "prob": 0.0, "max_k": 1, "spatial_axis": (-2, -1)}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), +] + +TEST_CASE_SCALE_INTENSITY_1 = [ + {"name": "scale_intensity_range", "a_min": 0.0, "a_max": 4.0, "b_min": 0.0, "b_max": 1.0, "clip": False}, + np.array([[[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]], [[0.0, 1.0], [2.0, 3.0]]], dtype=np.float32), + np.array([[[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]], [[0.0, 0.25], [0.5, 0.75]]], dtype=np.float32), +] + +TEST_CASE_ZOOM_1 = [ + {"name": "zoom", "zoom_factor": (0.5, 0.5)}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.concatenate([np.ones((1, 3, 3), dtype=np.float32) * 1.0, np.ones((1, 3, 3), dtype=np.float32) * 2.0]), +] + +TEST_CASE_RAND_ZOOM_1 = [ + {"name": "rand_zoom", "prob": 1.0, "min_zoom": 0.5, "max_zoom": 0.5}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.concatenate([np.ones((1, 3, 3), dtype=np.float32) * 1.0, np.ones((1, 3, 3), dtype=np.float32) * 2.0]), +] + +TEST_CASE_RAND_ZOOM_2 = [ + {"name": "rand_zoom", "prob": 0.0, "min_zoom": 0.5, "max_zoom": 0.5}, + np.mgrid[:3, 1:4].astype(dtype=np.float32), + np.mgrid[:3, 1:4].astype(dtype=np.float32), +] + + +@skip_if_no_cuda +@unittest.skipUnless(has_cp, "CuPy is required.") +@unittest.skipUnless(has_cut, "cuCIM transforms are required.") +class TestRandCuCIM(unittest.TestCase): + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_numpy_single(self, params, input, expected): + # apply_prob=1.0 + output = RandCuCIM(apply_prob=1.0, **params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIM(apply_prob=0.0, **params)(input) + self.assertTrue(output.dtype == input.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, input) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_numpy_batch(self, params, input, expected): + input = input[cp.newaxis, ...] + expected = expected[cp.newaxis, ...] + # apply_prob=1.0 + output = RandCuCIM(apply_prob=1.0, **params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIM(apply_prob=0.0, **params)(input) + self.assertTrue(output.dtype == input.dtype) + self.assertTrue(isinstance(output, np.ndarray)) + cp.testing.assert_allclose(output, input) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_cupy_single(self, params, input, expected): + input = cp.asarray(input) + expected = cp.asarray(expected) + # apply_prob=1.0 + output = RandCuCIM(apply_prob=1.0, **params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIM(apply_prob=0.0, **params)(input) + self.assertTrue(output.dtype == input.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, input) + + @parameterized.expand( + [ + TEST_CASE_COLOR_JITTER_1, + TEST_CASE_FLIP_1, + TEST_CASE_RAND_ROTATE_1, + TEST_CASE_RAND_ROTATE_2, + TEST_CASE_SCALE_INTENSITY_1, + TEST_CASE_ZOOM_1, + TEST_CASE_RAND_ZOOM_1, + TEST_CASE_RAND_ZOOM_2, + ] + ) + def test_tramsforms_cupy_batch(self, params, input, expected): + input = cp.asarray(input)[cp.newaxis, ...] + expected = cp.asarray(expected)[cp.newaxis, ...] + # apply_prob=1.0 + output = RandCuCIM(**params)(input) + self.assertTrue(output.dtype == expected.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, expected) + # apply_prob=0.0 + output = RandCuCIM(apply_prob=0.0, **params)(input) + self.assertTrue(output.dtype == input.dtype) + self.assertTrue(isinstance(output, cp.ndarray)) + cp.testing.assert_allclose(output, input) + + +if __name__ == "__main__": + unittest.main() From 0c39281e31f8464503d3405526e85080e28c913f Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:47:26 +0100 Subject: [PATCH 28/89] torch `SpatialCrop`, `SpatialCropd` (#2963) Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/__init__.py | 1 + monai/transforms/croppad/array.py | 78 +++++++++++-------- monai/transforms/croppad/dictionary.py | 47 ++++++----- monai/transforms/spatial/array.py | 2 +- monai/transforms/utils.py | 4 +- .../utils_pytorch_numpy_unification.py | 21 +++++ tests/test_spatial_crop.py | 28 ++++--- tests/test_spatial_cropd.py | 67 +++++++++------- 8 files changed, 152 insertions(+), 96 deletions(-) diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index e693c06dc2..826f66a34c 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -537,6 +537,7 @@ clip, floor_divide, in1d, + maximum, moveaxis, nonzero, percentile, diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index fac14f4582..0e6529703f 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -22,7 +22,7 @@ from torch.nn.functional import pad as pad_pt from monai.config import IndexSelection -from monai.config.type_definitions import NdarrayTensor +from monai.config.type_definitions import NdarrayOrTensor from monai.data.utils import get_random_patch, get_valid_patch_size from monai.transforms.transform import Randomizable, Transform from monai.transforms.utils import ( @@ -36,6 +36,7 @@ map_classes_to_indices, weighted_patch_samples, ) +from monai.transforms.utils_pytorch_numpy_unification import floor_divide, maximum from monai.utils import ( Method, NumpyPadMode, @@ -98,8 +99,7 @@ def __init__( @staticmethod def _np_pad(img: np.ndarray, all_pad_width, mode, **kwargs) -> np.ndarray: - img_np, *_ = convert_data_type(img, np.ndarray) - return np.pad(img_np, all_pad_width, mode=mode, **kwargs) # type: ignore + return np.pad(img, all_pad_width, mode=mode, **kwargs) # type: ignore @staticmethod def _pt_pad(img: torch.Tensor, all_pad_width, mode, **kwargs) -> torch.Tensor: @@ -109,9 +109,9 @@ def _pt_pad(img: torch.Tensor, all_pad_width, mode, **kwargs) -> torch.Tensor: def __call__( self, - img: NdarrayTensor, + img: NdarrayOrTensor, mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, - ) -> NdarrayTensor: + ) -> NdarrayOrTensor: """ Args: img: data to be transformed, assuming `img` is channel-first and @@ -132,7 +132,7 @@ def __call__( pad = self._pt_pad else: pad = self._np_pad # type: ignore - return pad(img, self.to_pad, mode, **self.kwargs) + return pad(img, self.to_pad, mode, **self.kwargs) # type: ignore class SpatialPad(Transform): @@ -190,9 +190,9 @@ def _determine_data_pad_width(self, data_shape: Sequence[int]) -> List[Tuple[int def __call__( self, - img: NdarrayTensor, + img: NdarrayOrTensor, mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, - ) -> NdarrayTensor: + ) -> NdarrayOrTensor: """ Args: img: data to be transformed, assuming `img` is channel-first and @@ -255,9 +255,9 @@ def __init__( def __call__( self, - img: NdarrayTensor, + img: NdarrayOrTensor, mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, - ) -> NdarrayTensor: + ) -> NdarrayOrTensor: """ Args: img: data to be transformed, assuming `img` is channel-first and @@ -337,9 +337,9 @@ def __init__( def __call__( self, - img: NdarrayTensor, + img: NdarrayOrTensor, mode: Optional[Union[NumpyPadMode, PytorchPadMode, str]] = None, - ) -> NdarrayTensor: + ) -> NdarrayOrTensor: """ Args: img: data to be transformed, assuming `img` is channel-first @@ -377,12 +377,14 @@ class SpatialCrop(Transform): - the start and end coordinates of the ROI """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__( self, - roi_center: Union[Sequence[int], np.ndarray, None] = None, - roi_size: Union[Sequence[int], np.ndarray, None] = None, - roi_start: Union[Sequence[int], np.ndarray, None] = None, - roi_end: Union[Sequence[int], np.ndarray, None] = None, + roi_center: Union[Sequence[int], NdarrayOrTensor, None] = None, + roi_size: Union[Sequence[int], NdarrayOrTensor, None] = None, + roi_start: Union[Sequence[int], NdarrayOrTensor, None] = None, + roi_end: Union[Sequence[int], NdarrayOrTensor, None] = None, roi_slices: Optional[Sequence[slice]] = None, ) -> None: """ @@ -395,33 +397,38 @@ def __init__( use the end coordinate of image. roi_slices: list of slices for each of the spatial dimensions. """ + roi_start_torch: torch.Tensor + if roi_slices: if not all(s.step is None or s.step == 1 for s in roi_slices): raise ValueError("Only slice steps of 1/None are currently supported") self.slices = list(roi_slices) else: if roi_center is not None and roi_size is not None: - roi_center = np.asarray(roi_center, dtype=np.int16) - roi_size = np.asarray(roi_size, dtype=np.int16) - roi_start_np = np.maximum(roi_center - np.floor_divide(roi_size, 2), 0) - roi_end_np = np.maximum(roi_start_np + roi_size, roi_start_np) + roi_center = torch.as_tensor(roi_center, dtype=torch.int16) + roi_size = torch.as_tensor(roi_size, dtype=torch.int16, device=roi_center.device) + roi_start_torch = maximum( # type: ignore + roi_center - floor_divide(roi_size, 2), + torch.zeros_like(roi_center), + ) + roi_end_torch = maximum(roi_start_torch + roi_size, roi_start_torch) else: if roi_start is None or roi_end is None: raise ValueError("Please specify either roi_center, roi_size or roi_start, roi_end.") - roi_start_np = np.maximum(np.asarray(roi_start, dtype=np.int16), 0) - roi_end_np = np.maximum(np.asarray(roi_end, dtype=np.int16), roi_start_np) - # Allow for 1D by converting back to np.array (since np.maximum will convert to int) - roi_start_np = roi_start_np if isinstance(roi_start_np, np.ndarray) else np.array([roi_start_np]) - roi_end_np = roi_end_np if isinstance(roi_end_np, np.ndarray) else np.array([roi_end_np]) - # convert to slices - self.slices = [slice(s, e) for s, e in zip(roi_start_np, roi_end_np)] - - def __call__(self, img: Union[np.ndarray, torch.Tensor]): + roi_start_torch = torch.as_tensor(roi_start, dtype=torch.int16) + roi_start_torch = maximum(roi_start_torch, torch.zeros_like(roi_start_torch)) # type: ignore + roi_end_torch = maximum(torch.as_tensor(roi_end, dtype=torch.int16), roi_start_torch) + # convert to slices (accounting for 1d) + if roi_start_torch.numel() == 1: + self.slices = [slice(int(roi_start_torch.item()), int(roi_end_torch.item()))] + else: + self.slices = [slice(int(s.item()), int(e.item())) for s, e in zip(roi_start_torch, roi_end_torch)] + + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ - img, *_ = convert_data_type(img, np.ndarray) sd = min(len(self.slices), len(img.shape[1:])) # spatial dims slices = [slice(None)] + self.slices[:sd] return img[tuple(slices)] @@ -822,7 +829,8 @@ def __call__(self, img: np.ndarray, weight_map: Optional[np.ndarray] = None) -> results = [] for center in self.centers: cropper = SpatialCrop(roi_center=center, roi_size=_spatial_size) - results.append(cropper(img)) + cropped: np.ndarray = cropper(img) # type: ignore + results.append(cropped) return results @@ -962,7 +970,8 @@ def __call__( if self.centers is not None: for center in self.centers: cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore - results.append(cropper(img)) + cropped: np.ndarray = cropper(img) # type: ignore + results.append(cropped) return results @@ -1098,7 +1107,8 @@ def __call__( if self.centers is not None: for center in self.centers: cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore - results.append(cropper(img)) + cropped: np.ndarray = cropper(img) # type: ignore + results.append(cropped) return results @@ -1146,7 +1156,7 @@ def __call__(self, img: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = N See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html """ img, *_ = convert_data_type(img, np.ndarray) # type: ignore - return self.padder(self.cropper(img), mode=mode) + return self.padder(self.cropper(img), mode=mode) # type: ignore class BoundingRect(Transform): diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py index a504b23179..2d50ba0b34 100644 --- a/monai/transforms/croppad/dictionary.py +++ b/monai/transforms/croppad/dictionary.py @@ -25,7 +25,7 @@ import numpy as np from monai.config import IndexSelection, KeysCollection -from monai.config.type_definitions import NdarrayTensor +from monai.config.type_definitions import NdarrayOrTensor from monai.data.utils import get_random_patch, get_valid_patch_size from monai.transforms.croppad.array import ( BorderPad, @@ -147,14 +147,14 @@ def __init__( self.mode = ensure_tuple_rep(mode, len(self.keys)) self.padder = SpatialPad(spatial_size, method, **kwargs) - def __call__(self, data: Mapping[Hashable, NdarrayTensor]) -> Dict[Hashable, NdarrayTensor]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, m in self.key_iterator(d, self.mode): self.push_transform(d, key, extra_info={"mode": m.value if isinstance(m, Enum) else m}) d[key] = self.padder(d[key], mode=m) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -222,14 +222,14 @@ def __init__( self.mode = ensure_tuple_rep(mode, len(self.keys)) self.padder = BorderPad(spatial_border=spatial_border, **kwargs) - def __call__(self, data: Mapping[Hashable, NdarrayTensor]) -> Dict[Hashable, NdarrayTensor]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, m in self.key_iterator(d, self.mode): self.push_transform(d, key, extra_info={"mode": m.value if isinstance(m, Enum) else m}) d[key] = self.padder(d[key], mode=m) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): @@ -298,14 +298,14 @@ def __init__( self.mode = ensure_tuple_rep(mode, len(self.keys)) self.padder = DivisiblePad(k=k, method=method, **kwargs) - def __call__(self, data: Mapping[Hashable, NdarrayTensor]) -> Dict[Hashable, NdarrayTensor]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, m in self.key_iterator(d, self.mode): self.push_transform(d, key, extra_info={"mode": m.value if isinstance(m, Enum) else m}) d[key] = self.padder(d[key], mode=m) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): @@ -339,6 +339,8 @@ class SpatialCropd(MapTransform, InvertibleTransform): - the start and end coordinates of the ROI """ + backend = SpatialCrop.backend + def __init__( self, keys: KeysCollection, @@ -365,14 +367,14 @@ def __init__( super().__init__(keys, allow_missing_keys) self.cropper = SpatialCrop(roi_center, roi_size, roi_start, roi_end, roi_slices) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): self.push_transform(d, key) d[key] = self.cropper(d[key]) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): @@ -426,7 +428,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda self.push_transform(d, key, orig_size=orig_size) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): @@ -481,7 +483,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): @@ -576,7 +578,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda d[key] = cropper(d[key]) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): @@ -772,7 +774,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n ret.append(cropped) return ret - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: d = deepcopy(dict(data)) # We changed the transform name from RandSpatialCropd to RandSpatialCropSamplesd # Need to revert that since we're calling RandSpatialCropd's inverse @@ -859,7 +861,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda d[key] = self.cropper.crop_pad(img=d[key], box_start=box_start, box_end=box_end, mode=m) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -964,7 +966,8 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n for i, center in enumerate(self.centers): cropper = SpatialCrop(roi_center=center, roi_size=_spatial_size) orig_size = img.shape[1:] - results[i][key] = cropper(img) + cropped: np.ndarray = cropper(img) # type: ignore + results[i][key] = cropped self.push_transform(results[i], key, extra_info={"center": center}, orig_size=orig_size) if self.center_coord_key: results[i][self.center_coord_key] = center @@ -979,7 +982,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n return results - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -1136,7 +1139,8 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n img = d[key] cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore orig_size = img.shape[1:] - results[i][key] = cropper(img) + cropped: np.ndarray = cropper(img) # type: ignore + results[i][key] = cropped self.push_transform(results[i], key, extra_info={"center": center}, orig_size=orig_size) # add `patch_index` to the meta data for key, meta_key, meta_key_postfix in self.key_iterator(d, self.meta_keys, self.meta_key_postfix): @@ -1147,7 +1151,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n return results - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -1315,7 +1319,8 @@ def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, np.ndarr img = d[key] cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore orig_size = img.shape[1:] - results[i][key] = cropper(img) + cropped: np.ndarray = cropper(img) # type: ignore + results[i][key] = cropped self.push_transform(results[i], key, extra_info={"center": center}, orig_size=orig_size) # add `patch_index` to the meta data for key, meta_key, meta_key_postfix in self.key_iterator(d, self.meta_keys, self.meta_key_postfix): @@ -1326,7 +1331,7 @@ def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, np.ndarr return results - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -1399,7 +1404,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda ) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index cb80c2036b..8b1fb854f2 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -618,7 +618,7 @@ def __call__( img_t, *_ = convert_data_type(img, torch.Tensor, dtype=torch.float32) # type: ignore _zoom = ensure_tuple_rep(self.zoom, img.ndim - 1) # match the spatial image dim - zoomed: torch.Tensor = torch.nn.functional.interpolate( # type: ignore + zoomed: NdarrayOrTensor = torch.nn.functional.interpolate( # type: ignore recompute_scale_factor=True, input=img_t.unsqueeze(0), scale_factor=list(_zoom), diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 883d5e5faa..05e45bf26f 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -22,7 +22,7 @@ import monai import monai.transforms.transform from monai.config import DtypeLike, IndexSelection -from monai.config.type_definitions import NdarrayOrTensor, NdarrayTensor +from monai.config.type_definitions import NdarrayOrTensor from monai.networks.layers import GaussianFilter from monai.transforms.compose import Compose, OneOf from monai.transforms.transform import MapTransform, Transform @@ -1271,7 +1271,7 @@ def print_table_column(name, torch, numpy, color=Colors.none): print_color(f"Number of uncategorised: {n_uncategorized}", Colors.red) -def convert_pad_mode(dst: NdarrayTensor, mode: Union[NumpyPadMode, PytorchPadMode, str]): +def convert_pad_mode(dst: NdarrayOrTensor, mode: Union[NumpyPadMode, PytorchPadMode, str]): """ Utility to convert padding mode between numpy array and PyTorch Tensor. diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 8808e25265..7b65f690c0 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -28,6 +28,7 @@ "unravel_index", "ravel", "any_np_pt", + "maximum", ] @@ -216,3 +217,23 @@ def any_np_pt(x: NdarrayOrTensor, axis: int): # older versions of pytorch require the input to be cast to boolean return torch.any(x.bool(), axis) return np.any(x, axis) + + +def maximum(a: NdarrayOrTensor, b: NdarrayOrTensor) -> NdarrayOrTensor: + """`np.maximum` with equivalent implementation for torch. + + `torch.maximum` only available from pt>1.6, else use `torch.stack` and `torch.max`. + + Args: + a: first array/tensor + b: second array/tensor + + Returns: + Element-wise maximum between two arrays/tensors. + """ + if isinstance(a, torch.Tensor) and isinstance(b, torch.Tensor): + # is torch and has torch.maximum (pt>1.6) + if hasattr(torch, "maximum"): + return torch.maximum(a, b) + return torch.stack((a, b)).max(dim=0)[0] + return np.maximum(a, b) diff --git a/tests/test_spatial_crop.py b/tests/test_spatial_crop.py index c76915f0a3..c18dd86e46 100644 --- a/tests/test_spatial_crop.py +++ b/tests/test_spatial_crop.py @@ -16,8 +16,9 @@ from parameterized import parameterized from monai.transforms import SpatialCrop +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASES = [ +TESTS = [ [ {"roi_center": [1, 1, 1], "roi_size": [2, 2, 2]}, (3, 3, 3, 3), @@ -53,17 +54,24 @@ class TestSpatialCrop(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_shape(self, input_param, input_shape, expected_shape): input_data = np.random.randint(0, 2, size=input_shape) - result = SpatialCrop(**input_param)(input_data) - self.assertTupleEqual(result.shape, expected_shape) - - @parameterized.expand(TEST_CASES) - def test_tensor_shape(self, input_param, input_shape, expected_shape): - input_data = torch.randint(0, 2, size=input_shape, device="cuda" if torch.cuda.is_available() else "cpu") - result = SpatialCrop(**input_param)(input_data) - self.assertTupleEqual(result.shape, expected_shape) + results = [] + for p in TEST_NDARRAYS: + for q in TEST_NDARRAYS + (None,): + input_param_mod = { + k: q(v) if k != "roi_slices" and q is not None else v for k, v in input_param.items() + } + im = p(input_data) + result = SpatialCrop(**input_param_mod)(im) + self.assertEqual(type(im), type(result)) + if isinstance(result, torch.Tensor): + self.assertEqual(result.device, im.device) + self.assertTupleEqual(result.shape, expected_shape) + results.append(result) + if len(results) > 1: + assert_allclose(results[0], results[-1], type_test=False) @parameterized.expand(TEST_ERRORS) def test_error(self, input_param): diff --git a/tests/test_spatial_cropd.py b/tests/test_spatial_cropd.py index 797c25d34b..17743124e0 100644 --- a/tests/test_spatial_cropd.py +++ b/tests/test_spatial_cropd.py @@ -15,38 +15,49 @@ from parameterized import parameterized from monai.transforms import SpatialCropd +from tests.utils import TEST_NDARRAYS -TEST_CASES = [ - [ - {"keys": ["img"], "roi_center": [1, 1, 1], "roi_size": [2, 2, 2]}, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - (3, 2, 2, 2), - ], - [ - {"keys": ["img"], "roi_start": [0, 0, 0], "roi_end": [2, 2, 2]}, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - (3, 2, 2, 2), - ], - [ - {"keys": ["img"], "roi_start": [0, 0], "roi_end": [2, 2]}, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - (3, 2, 2, 3), - ], - [ - {"keys": ["img"], "roi_start": [0, 0, 0, 0, 0], "roi_end": [2, 2, 2, 2, 2]}, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - (3, 2, 2, 2), - ], - [ - {"keys": ["img"], "roi_slices": [slice(s, e) for s, e in zip([-1, -2, 0], [None, None, 2])]}, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - (3, 1, 2, 2), - ], -] +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + {"keys": ["img"], "roi_center": [1, 1, 1], "roi_size": [2, 2, 2]}, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + (3, 2, 2, 2), + ] + ) + TESTS.append( + [ + {"keys": ["img"], "roi_start": [0, 0, 0], "roi_end": [2, 2, 2]}, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + (3, 2, 2, 2), + ] + ) + TESTS.append( + [ + {"keys": ["img"], "roi_start": [0, 0], "roi_end": [2, 2]}, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + (3, 2, 2, 3), + ] + ) + TESTS.append( + [ + {"keys": ["img"], "roi_start": [0, 0, 0, 0, 0], "roi_end": [2, 2, 2, 2, 2]}, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + (3, 2, 2, 2), + ] + ) + TESTS.append( + [ + {"keys": ["img"], "roi_slices": [slice(s, e) for s, e in zip([-1, -2, 0], [None, None, 2])]}, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + (3, 1, 2, 2), + ] + ) class TestSpatialCropd(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_shape(self, input_param, input_data, expected_shape): result = SpatialCropd(**input_param)(input_data) self.assertTupleEqual(result["img"].shape, expected_shape) From 43a43429ac7d4c5d374fab229ebe96f940fe0c6a Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Thu, 16 Sep 2021 17:33:36 -0400 Subject: [PATCH 29/89] Update with cupy.ndarray (#2965) * Update with cupy.ndarray Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Change to use has_cp Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Change the format Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> * Fix a bug Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/transforms/utility/array.py | 2 -- tests/test_cast_to_type.py | 22 +++++++++++++++++++++ tests/test_cast_to_typed.py | 33 +++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 73fbd6666f..57d43db5d0 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -330,8 +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)): - raise TypeError(f"img must be one of (numpy.ndarray, torch.Tensor) but is {type(img).__name__}.") img_out, *_ = convert_data_type(img, output_type=type(img), dtype=dtype or self.dtype) return img_out diff --git a/tests/test_cast_to_type.py b/tests/test_cast_to_type.py index 0ef25cbafa..d06efb17b5 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))) + @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) + + 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..342a677ce1 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]) + @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()} + + 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 46e594fc6038aaf4ee292629b05f062d0284a5ef Mon Sep 17 00:00:00 2001 From: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> Date: Fri, 17 Sep 2021 00:01:16 +0100 Subject: [PATCH 30/89] Fix for Jupyter plotting (#2964) * Fix for Jupyter plotting Signed-off-by: Eric Kerfoot * Fix for Jupyter plotting Signed-off-by: Eric Kerfoot * Fix for Jupyter plotting Signed-off-by: Eric Kerfoot --- monai/utils/jupyter_utils.py | 37 ++++++++++++++++++++++++----------- tests/test_threadcontainer.py | 2 +- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/monai/utils/jupyter_utils.py b/monai/utils/jupyter_utils.py index 26487083b1..ed109393f9 100644 --- a/monai/utils/jupyter_utils.py +++ b/monai/utils/jupyter_utils.py @@ -161,6 +161,7 @@ def plot_engine_status( window_fraction: int = 20, image_fn: Optional[Callable] = tensor_to_images, fig=None, + selected_inst: int = 0, ) -> Tuple: """ Plot the status of the given Engine with its logger. The plot will consist of a graph of loss values and metrics @@ -192,19 +193,33 @@ def plot_engine_status( imagemap = {} if image_fn is not None and engine.state is not None and engine.state.batch is not None: for src in (engine.state.batch, engine.state.output): + label = "Batch" if src is engine.state.batch else "Output" + batch_selected_inst = selected_inst # selected batch index, set to 0 when src is decollated + + # if the src object is a list of elements, ie. a decollated batch, select an element and keep it as + # a dictionary of tensors with a batch dimension added if isinstance(src, list): - for i, s in enumerate(src): - if isinstance(s, dict): - for k, v in s.items(): - if isinstance(v, torch.Tensor): - image = image_fn(k, v) - if image is not None: - imagemap[f"{k}_{i}"] = image - elif isinstance(s, torch.Tensor): - label = "Batch" if src is engine.state.batch else "Output" - image = image_fn(label, s) + selected_dict = src[selected_inst] # select this element + batch_selected_inst = 0 # set the selection to be the single index in the batch dimension + # store each tensor that is interpretable as an image with an added batch dimension + src = {k: v[None] for k, v in selected_dict.items() if isinstance(v, torch.Tensor) and v.ndim >= 3} + + # images will be generated from the batch item selected above only, or from the single item given as `src` + + if isinstance(src, dict): + for k, v in src.items(): + if isinstance(v, torch.Tensor) and v.ndim >= 4: + image = image_fn(k, v[batch_selected_inst]) + + # if we have images add each one separately to the map if image is not None: - imagemap[f"{label}_{i}"] = image + for i, im in enumerate(image): + imagemap[f"{k}_{i}"] = im + + elif isinstance(src, torch.Tensor): + image = image_fn(label, src) + if image is not None: + imagemap[f"{label}_{i}"] = image axes = plot_metric_images(fig, title, graphmap, imagemap, yscale, avg_keys, window_fraction) diff --git a/tests/test_threadcontainer.py b/tests/test_threadcontainer.py index 543dab4d0c..5613b1babd 100644 --- a/tests/test_threadcontainer.py +++ b/tests/test_threadcontainer.py @@ -79,7 +79,7 @@ def test_plot(self): # a third non-image key is added to test that this is correctly ignored when plotting data = {CommonKeys.IMAGE: img, CommonKeys.LABEL: img, "Not Image Data": ["This isn't an image"]} - loader = DataLoader([data] * 10) + loader = DataLoader([data] * 20, batch_size=2) trainer = SupervisedTrainer( device=torch.device("cpu"), From dc3e2638457d9759e91f14776b61a5e01d56f84f Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Fri, 17 Sep 2021 15:37:53 +0100 Subject: [PATCH 31/89] fixes tutorial issue 352 (#2968) * fixes tutorial issue 352 Signed-off-by: Wenqi Li * simplified Signed-off-by: Wenqi Li --- monai/transforms/spatial/array.py | 6 ++---- monai/transforms/spatial/dictionary.py | 6 ++---- tests/test_rand_affined.py | 5 +++++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 8b1fb854f2..df3d3eb093 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -1065,7 +1065,7 @@ def __call__( """ if grid is None: if spatial_size is not None: - grid = create_grid(spatial_size) + grid = create_grid(spatial_size, dtype=float) else: raise ValueError("Incompatible values: grid=None and spatial_size=None.") @@ -1084,9 +1084,7 @@ def __call__( else: affine = self.affine - if self.device not in (None, torch.device("cpu"), "cpu"): - grid, *_ = convert_data_type(grid, torch.Tensor, device=self.device) - grid, *_ = convert_data_type(grid, dtype=float) + grid, *_ = convert_data_type(grid, torch.Tensor, device=self.device, dtype=float) affine, *_ = convert_to_dst_type(affine, grid) grid = (affine @ grid.reshape((grid.shape[0], -1))).reshape([-1] + list(grid.shape[1:])) diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index d794e51e80..487225cb60 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -795,10 +795,8 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N sp_size = fall_back_tuple(self.rand_affine.spatial_size, data[self.keys[0]].shape[1:]) # change image size or do random transform do_resampling = self._do_transform or (sp_size != ensure_tuple(data[self.keys[0]].shape[1:])) - - affine: NdarrayOrTensor = np.eye(len(sp_size) + 1, dtype=np.float64) - if device not in (None, torch.device("cpu"), "cpu"): - affine, *_ = convert_data_type(affine, torch.Tensor, device=device) + affine: torch.Tensor = torch.eye(len(sp_size) + 1, dtype=torch.float64, device=device) + # converting affine to tensor because the resampler currently only support torch backend grid = None if do_resampling: # need to prepare grid grid = self.rand_affine.get_identity_grid(sp_size) diff --git a/tests/test_rand_affined.py b/tests/test_rand_affined.py index bec9602d62..0109175b16 100644 --- a/tests/test_rand_affined.py +++ b/tests/test_rand_affined.py @@ -211,6 +211,11 @@ def test_rand_affined(self, input_param, input_data, expected_val): expected = expected_val[key] if isinstance(expected_val, dict) else expected_val assert_allclose(result, expected, rtol=1e-4, atol=1e-4) + g.set_random_state(4) + res = g(input_data) + # affine should be tensor because the resampler only supports pytorch backend + self.assertTrue(isinstance(res["img_transforms"][0]["extra_info"]["affine"], torch.Tensor)) + def test_ill_cache(self): with self.assertWarns(UserWarning): # spatial size is None From ecbb03bedbf5839660d15ee61c18795e9cf0d6ab Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Sat, 18 Sep 2021 01:05:01 +0800 Subject: [PATCH 32/89] 2231 Enhance tensor transforms (#2966) * [DLMED] enhance tensor transforms Signed-off-by: Nic Ma * [DLMED] fix tests Signed-off-by: Nic Ma * [DLMED] fix mypy Signed-off-by: Nic Ma --- monai/transforms/intensity/array.py | 6 ++++-- monai/transforms/spatial/array.py | 2 +- tests/test_savitzky_golay_smooth.py | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index a1423c8ee5..a8babfc659 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -955,7 +955,7 @@ def __init__(self, window_length: int, order: int, axis: int = 1, mode: str = "z self.mode = mode self.img_t: torch.Tensor = torch.tensor(0.0) - def __call__(self, img: NdarrayOrTensor) -> torch.Tensor: + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Args: img: array containing input data. Must be real and in shape [channels, spatial1, spatial2, ...]. @@ -969,7 +969,9 @@ def __call__(self, img: NdarrayOrTensor) -> torch.Tensor: # add one to transform axis because a batch axis will be added at dimension 0 savgol_filter = SavitzkyGolayFilter(self.window_length, self.order, self.axis + 1, self.mode) # convert to Tensor and add Batch axis expected by HilbertTransform - out: torch.Tensor = savgol_filter(self.img_t.unsqueeze(0)).squeeze(0) + smoothed = savgol_filter(self.img_t.unsqueeze(0)).squeeze(0) + out, *_ = convert_to_dst_type(smoothed, dst=img) + return out diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index df3d3eb093..1b03d39a15 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -571,7 +571,7 @@ class Zoom(Transform): """ - backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + backend = [TransformBackends.TORCH] def __init__( self, diff --git a/tests/test_savitzky_golay_smooth.py b/tests/test_savitzky_golay_smooth.py index 45d0ea3e4d..71405466c4 100644 --- a/tests/test_savitzky_golay_smooth.py +++ b/tests/test_savitzky_golay_smooth.py @@ -62,7 +62,7 @@ class TestSavitzkyGolaySmooth(unittest.TestCase): @parameterized.expand([TEST_CASE_SINGLE_VALUE, TEST_CASE_2D_AXIS_2, TEST_CASE_SINE_SMOOTH]) def test_value(self, arguments, image, expected_data, atol): for p in TEST_NDARRAYS: - result = SavitzkyGolaySmooth(**arguments)(p(image)) + result = SavitzkyGolaySmooth(**arguments)(p(image.astype(np.float32))) torch.testing.assert_allclose(result, p(expected_data.astype(np.float32)), rtol=1e-7, atol=atol) @@ -70,7 +70,7 @@ class TestSavitzkyGolaySmoothREP(unittest.TestCase): @parameterized.expand([TEST_CASE_SINGLE_VALUE_REP]) def test_value(self, arguments, image, expected_data, atol): for p in TEST_NDARRAYS: - result = SavitzkyGolaySmooth(**arguments)(p(image)) + result = SavitzkyGolaySmooth(**arguments)(p(image.astype(np.float32))) torch.testing.assert_allclose(result, p(expected_data.astype(np.float32)), rtol=1e-7, atol=atol) From e2e2d08acf180145a3e51f569e74292a59d81597 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Sun, 19 Sep 2021 13:36:27 +0100 Subject: [PATCH 33/89] Torch `RandCropByPosNegLabel`, `RandCropByPosNegLabeld`, `RandCropByLabelClasses`, `RandCropByLabelClassesd` (#2967) Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/croppad/array.py | 90 ++++++------- monai/transforms/croppad/dictionary.py | 57 ++++---- tests/test_rand_crop_by_label_classes.py | 109 ++++++++------- tests/test_rand_crop_by_label_classesd.py | 89 ++++++------ tests/test_rand_crop_by_pos_neg_label.py | 129 +++++++++++------- tests/test_rand_crop_by_pos_neg_labeld.py | 157 ++++++++++++---------- 6 files changed, 339 insertions(+), 292 deletions(-) diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index 0e6529703f..e1c915cc93 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -884,17 +884,19 @@ class RandCropByPosNegLabel(Randomizable, Transform): """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__( self, spatial_size: Union[Sequence[int], int], - label: Optional[np.ndarray] = None, + label: Optional[NdarrayOrTensor] = None, pos: float = 1.0, neg: float = 1.0, num_samples: int = 1, - image: Optional[np.ndarray] = None, + image: Optional[NdarrayOrTensor] = None, image_threshold: float = 0.0, - fg_indices: Optional[np.ndarray] = None, - bg_indices: Optional[np.ndarray] = None, + fg_indices: Optional[NdarrayOrTensor] = None, + bg_indices: Optional[NdarrayOrTensor] = None, ) -> None: self.spatial_size = ensure_tuple(spatial_size) self.label = label @@ -906,41 +908,39 @@ def __init__( self.num_samples = num_samples self.image = image self.image_threshold = image_threshold - self.centers: Optional[List[List[np.ndarray]]] = None + self.centers: Optional[List[List[int]]] = None self.fg_indices = fg_indices self.bg_indices = bg_indices def randomize( self, - label: np.ndarray, - fg_indices: Optional[np.ndarray] = None, - bg_indices: Optional[np.ndarray] = None, - image: Optional[np.ndarray] = None, + label: NdarrayOrTensor, + fg_indices: Optional[NdarrayOrTensor] = None, + bg_indices: Optional[NdarrayOrTensor] = None, + image: Optional[NdarrayOrTensor] = None, ) -> None: self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) - fg_indices_: np.ndarray - bg_indices_: np.ndarray if fg_indices is None or bg_indices is None: if self.fg_indices is not None and self.bg_indices is not None: fg_indices_ = self.fg_indices bg_indices_ = self.bg_indices else: - fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) # type: ignore + fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) else: fg_indices_ = fg_indices bg_indices_ = bg_indices - self.centers = generate_pos_neg_label_crop_centers( # type: ignore + self.centers = generate_pos_neg_label_crop_centers( self.spatial_size, self.num_samples, self.pos_ratio, label.shape[1:], fg_indices_, bg_indices_, self.R ) def __call__( self, - img: np.ndarray, - label: Optional[np.ndarray] = None, - image: Optional[np.ndarray] = None, - fg_indices: Optional[np.ndarray] = None, - bg_indices: Optional[np.ndarray] = None, - ) -> List[np.ndarray]: + img: NdarrayOrTensor, + label: Optional[NdarrayOrTensor] = None, + image: Optional[NdarrayOrTensor] = None, + fg_indices: Optional[NdarrayOrTensor] = None, + bg_indices: Optional[NdarrayOrTensor] = None, + ) -> List[NdarrayOrTensor]: """ Args: img: input data to crop samples from based on the pos/neg ratio of `label` and `image`. @@ -962,16 +962,12 @@ def __call__( if image is None: image = self.image - image, *_ = convert_data_type(image, np.ndarray) # type: ignore - label, *_ = convert_data_type(label, np.ndarray) # type: ignore - self.randomize(label, fg_indices, bg_indices, image) - results: List[np.ndarray] = [] + results: List[NdarrayOrTensor] = [] if self.centers is not None: for center in self.centers: - cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore - cropped: np.ndarray = cropper(img) # type: ignore - results.append(cropped) + cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) + results.append(cropper(img)) return results @@ -1035,16 +1031,18 @@ class RandCropByLabelClasses(Randomizable, Transform): """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__( self, spatial_size: Union[Sequence[int], int], ratios: Optional[List[Union[float, int]]] = None, - label: Optional[np.ndarray] = None, + label: Optional[NdarrayOrTensor] = None, num_classes: Optional[int] = None, num_samples: int = 1, - image: Optional[np.ndarray] = None, + image: Optional[NdarrayOrTensor] = None, image_threshold: float = 0.0, - indices: Optional[List[np.ndarray]] = None, + indices: Optional[List[NdarrayOrTensor]] = None, ) -> None: self.spatial_size = ensure_tuple(spatial_size) self.ratios = ratios @@ -1053,35 +1051,35 @@ def __init__( self.num_samples = num_samples self.image = image self.image_threshold = image_threshold - self.centers: Optional[List[List[np.ndarray]]] = None + self.centers: Optional[List[List[int]]] = None self.indices = indices def randomize( self, - label: np.ndarray, - indices: Optional[List[np.ndarray]] = None, - image: Optional[np.ndarray] = None, + label: NdarrayOrTensor, + indices: Optional[List[NdarrayOrTensor]] = None, + image: Optional[NdarrayOrTensor] = None, ) -> None: self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) - indices_: Sequence[np.ndarray] + indices_: Sequence[NdarrayOrTensor] if indices is None: if self.indices is not None: indices_ = self.indices else: - indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) # type: ignore + indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) else: indices_ = indices - self.centers = generate_label_classes_crop_centers( # type: ignore + self.centers = generate_label_classes_crop_centers( self.spatial_size, self.num_samples, label.shape[1:], indices_, self.ratios, self.R ) def __call__( self, - img: np.ndarray, - label: Optional[np.ndarray] = None, - image: Optional[np.ndarray] = None, - indices: Optional[List[np.ndarray]] = None, - ) -> List[np.ndarray]: + img: NdarrayOrTensor, + label: Optional[NdarrayOrTensor] = None, + image: Optional[NdarrayOrTensor] = None, + indices: Optional[List[NdarrayOrTensor]] = None, + ) -> List[NdarrayOrTensor]: """ Args: img: input data to crop samples from based on the ratios of every class, assumes `img` is a @@ -1099,16 +1097,12 @@ def __call__( if image is None: image = self.image - image, *_ = convert_data_type(image, np.ndarray) # type: ignore - label, *_ = convert_data_type(label, np.ndarray) # type: ignore - self.randomize(label, indices, image) - results: List[np.ndarray] = [] + results: List[NdarrayOrTensor] = [] if self.centers is not None: for center in self.centers: - cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore - cropped: np.ndarray = cropper(img) # type: ignore - results.append(cropped) + cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) + results.append(cropper(img)) return results diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py index 2d50ba0b34..488b832450 100644 --- a/monai/transforms/croppad/dictionary.py +++ b/monai/transforms/croppad/dictionary.py @@ -33,6 +33,8 @@ CenterSpatialCrop, CropForeground, DivisiblePad, + RandCropByLabelClasses, + RandCropByPosNegLabel, ResizeWithPadOrCrop, SpatialCrop, SpatialPad, @@ -1061,6 +1063,8 @@ class RandCropByPosNegLabeld(Randomizable, MapTransform, InvertibleTransform): """ + backend = RandCropByPosNegLabel.backend + def __init__( self, keys: KeysCollection, @@ -1094,28 +1098,26 @@ def __init__( if len(self.keys) != len(self.meta_keys): raise ValueError("meta_keys should have the same length as keys.") self.meta_key_postfix = ensure_tuple_rep(meta_key_postfix, len(self.keys)) - self.centers: Optional[List[List[np.ndarray]]] = None + self.centers: Optional[List[List[int]]] = None def randomize( self, - label: np.ndarray, - fg_indices: Optional[np.ndarray] = None, - bg_indices: Optional[np.ndarray] = None, - image: Optional[np.ndarray] = None, + label: NdarrayOrTensor, + fg_indices: Optional[NdarrayOrTensor] = None, + bg_indices: Optional[NdarrayOrTensor] = None, + image: Optional[NdarrayOrTensor] = None, ) -> None: - fg_indices_: np.ndarray - bg_indices_: np.ndarray self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) if fg_indices is None or bg_indices is None: - fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) # type: ignore + fg_indices_, bg_indices_ = map_binary_to_indices(label, image, self.image_threshold) else: fg_indices_ = fg_indices bg_indices_ = bg_indices - self.centers = generate_pos_neg_label_crop_centers( # type: ignore + self.centers = generate_pos_neg_label_crop_centers( self.spatial_size, self.num_samples, self.pos_ratio, label.shape[1:], fg_indices_, bg_indices_, self.R ) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, np.ndarray]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> List[Dict[Hashable, NdarrayOrTensor]]: d = dict(data) label = d[self.label_key] image = d[self.image_key] if self.image_key else None @@ -1129,7 +1131,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n raise ValueError("no available ROI centers to crop.") # initialize returned list with shallow copy to preserve key ordering - results: List[Dict[Hashable, np.ndarray]] = [dict(d) for _ in range(self.num_samples)] + results: List[Dict[Hashable, NdarrayOrTensor]] = [dict(d) for _ in range(self.num_samples)] for i, center in enumerate(self.centers): # fill in the extra keys with unmodified data @@ -1137,17 +1139,16 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n results[i][key] = deepcopy(d[key]) for key in self.key_iterator(d): img = d[key] - cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore + cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) orig_size = img.shape[1:] - cropped: np.ndarray = cropper(img) # type: ignore - results[i][key] = cropped + results[i][key] = cropper(img) self.push_transform(results[i], key, extra_info={"center": center}, orig_size=orig_size) # add `patch_index` to the meta data for key, meta_key, meta_key_postfix in self.key_iterator(d, self.meta_keys, self.meta_key_postfix): meta_key = meta_key or f"{key}_{meta_key_postfix}" if meta_key not in results[i]: results[i][meta_key] = {} # type: ignore - results[i][meta_key][Key.PATCH_INDEX] = i + results[i][meta_key][Key.PATCH_INDEX] = i # type: ignore return results @@ -1250,6 +1251,8 @@ class RandCropByLabelClassesd(Randomizable, MapTransform, InvertibleTransform): """ + backend = RandCropByLabelClasses.backend + def __init__( self, keys: KeysCollection, @@ -1278,25 +1281,24 @@ def __init__( if len(self.keys) != len(self.meta_keys): raise ValueError("meta_keys should have the same length as keys.") self.meta_key_postfix = ensure_tuple_rep(meta_key_postfix, len(self.keys)) - self.centers: Optional[List[List[np.ndarray]]] = None + self.centers: Optional[List[List[int]]] = None def randomize( self, - label: np.ndarray, - indices: Optional[List[np.ndarray]] = None, - image: Optional[np.ndarray] = None, + label: NdarrayOrTensor, + indices: Optional[List[NdarrayOrTensor]] = None, + image: Optional[NdarrayOrTensor] = None, ) -> None: self.spatial_size = fall_back_tuple(self.spatial_size, default=label.shape[1:]) - indices_: List[np.ndarray] if indices is None: - indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) # type: ignore + indices_ = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) else: indices_ = indices - self.centers = generate_label_classes_crop_centers( # type: ignore + self.centers = generate_label_classes_crop_centers( self.spatial_size, self.num_samples, label.shape[1:], indices_, self.ratios, self.R ) - def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, np.ndarray]]: + def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, NdarrayOrTensor]]: d = dict(data) label = d[self.label_key] image = d[self.image_key] if self.image_key else None @@ -1309,7 +1311,7 @@ def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, np.ndarr raise ValueError("no available ROI centers to crop.") # initialize returned list with shallow copy to preserve key ordering - results: List[Dict[Hashable, np.ndarray]] = [dict(d) for _ in range(self.num_samples)] + results: List[Dict[Hashable, NdarrayOrTensor]] = [dict(d) for _ in range(self.num_samples)] for i, center in enumerate(self.centers): # fill in the extra keys with unmodified data @@ -1317,17 +1319,16 @@ def __call__(self, data: Mapping[Hashable, Any]) -> List[Dict[Hashable, np.ndarr results[i][key] = deepcopy(d[key]) for key in self.key_iterator(d): img = d[key] - cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) # type: ignore + cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) orig_size = img.shape[1:] - cropped: np.ndarray = cropper(img) # type: ignore - results[i][key] = cropped + results[i][key] = cropper(img) self.push_transform(results[i], key, extra_info={"center": center}, orig_size=orig_size) # add `patch_index` to the meta data for key, meta_key, meta_key_postfix in self.key_iterator(d, self.meta_keys, self.meta_key_postfix): meta_key = meta_key or f"{key}_{meta_key_postfix}" if meta_key not in results[i]: results[i][meta_key] = {} # type: ignore - results[i][meta_key][Key.PATCH_INDEX] = i + results[i][meta_key][Key.PATCH_INDEX] = i # type: ignore return results diff --git a/tests/test_rand_crop_by_label_classes.py b/tests/test_rand_crop_by_label_classes.py index b21f971042..d562a44a6d 100644 --- a/tests/test_rand_crop_by_label_classes.py +++ b/tests/test_rand_crop_by_label_classes.py @@ -15,68 +15,77 @@ from parameterized import parameterized from monai.transforms import ClassesToIndices, RandCropByLabelClasses +from tests.utils import TEST_NDARRAYS -TEST_CASE_0 = [ +TESTS_INDICES, TESTS_SHAPE = [], [] +for p in TEST_NDARRAYS: # One-Hot label - { - "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "num_classes": None, - "spatial_size": [2, 2, -1], - "ratios": [1, 1, 1], - "num_samples": 2, - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image_threshold": 0, - }, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - list, - (3, 2, 2, 3), -] + TESTS_INDICES.append( + [ + { + "label": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "num_classes": None, + "spatial_size": [2, 2, -1], + "ratios": [1, 1, 1], + "num_samples": 2, + "image": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "image_threshold": 0, + }, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + list, + (3, 2, 2, 3), + ] + ) -TEST_CASE_1 = [ - # Argmax label - { - "label": np.random.randint(0, 2, size=[1, 3, 3, 3]), - "num_classes": 2, - "spatial_size": [2, 2, 2], - "ratios": [1, 1], - "num_samples": 2, - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image_threshold": 0, - }, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - list, - (3, 2, 2, 2), -] + TESTS_INDICES.append( + [ + # Argmax label + { + "label": p(np.random.randint(0, 2, size=[1, 3, 3, 3])), + "num_classes": 2, + "spatial_size": [2, 2, 2], + "ratios": [1, 1], + "num_samples": 2, + "image": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "image_threshold": 0, + }, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + list, + (3, 2, 2, 2), + ] + ) -TEST_CASE_2 = [ - # provide label at runtime - { - "label": None, - "num_classes": 2, - "spatial_size": [2, 2, 2], - "ratios": [1, 1], - "num_samples": 2, - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image_threshold": 0, - }, - { - "img": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "label": np.random.randint(0, 2, size=[1, 3, 3, 3]), - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - }, - list, - (3, 2, 2, 2), -] + TESTS_SHAPE.append( + [ + # provide label at runtime + { + "label": None, + "num_classes": 2, + "spatial_size": [2, 2, 2], + "ratios": [1, 1], + "num_samples": 2, + "image": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "image_threshold": 0, + }, + { + "img": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "label": p(np.random.randint(0, 2, size=[1, 3, 3, 3])), + "image": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + }, + list, + (3, 2, 2, 2), + ] + ) class TestRandCropByLabelClasses(unittest.TestCase): - @parameterized.expand([TEST_CASE_0, TEST_CASE_1, TEST_CASE_2]) + @parameterized.expand(TESTS_INDICES + TESTS_SHAPE) def test_type_shape(self, input_param, input_data, expected_type, expected_shape): result = RandCropByLabelClasses(**input_param)(**input_data) self.assertIsInstance(result, expected_type) self.assertTupleEqual(result[0].shape, expected_shape) - @parameterized.expand([TEST_CASE_0, TEST_CASE_1]) + @parameterized.expand(TESTS_INDICES) def test_indices(self, input_param, input_data, expected_type, expected_shape): input_param["indices"] = ClassesToIndices(num_classes=input_param["num_classes"])(input_param["label"]) result = RandCropByLabelClasses(**input_param)(**input_data) diff --git a/tests/test_rand_crop_by_label_classesd.py b/tests/test_rand_crop_by_label_classesd.py index 829096953b..27fe3425dd 100644 --- a/tests/test_rand_crop_by_label_classesd.py +++ b/tests/test_rand_crop_by_label_classesd.py @@ -15,52 +15,59 @@ from parameterized import parameterized from monai.transforms import ClassesToIndicesd, RandCropByLabelClassesd +from tests.utils import TEST_NDARRAYS -TEST_CASE_0 = [ - # One-Hot label - { - "keys": "img", - "label_key": "label", - "num_classes": None, - "spatial_size": [2, 2, -1], - "ratios": [1, 1, 1], - "num_samples": 2, - "image_key": "image", - "image_threshold": 0, - }, - { - "img": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), - }, - list, - (3, 2, 2, 3), -] +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + # One-Hot label + { + "keys": "img", + "label_key": "label", + "num_classes": None, + "spatial_size": [2, 2, -1], + "ratios": [1, 1, 1], + "num_samples": 2, + "image_key": "image", + "image_threshold": 0, + }, + { + "img": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "image": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "label": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + }, + list, + (3, 2, 2, 3), + ] + ) -TEST_CASE_1 = [ - # Argmax label - { - "keys": "img", - "label_key": "label", - "num_classes": 2, - "spatial_size": [2, 2, 2], - "ratios": [1, 1], - "num_samples": 2, - "image_key": "image", - "image_threshold": 0, - }, - { - "img": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "label": np.random.randint(0, 2, size=[1, 3, 3, 3]), - }, - list, - (3, 2, 2, 2), -] + TESTS.append( + [ + # Argmax label + { + "keys": "img", + "label_key": "label", + "num_classes": 2, + "spatial_size": [2, 2, 2], + "ratios": [1, 1], + "num_samples": 2, + "image_key": "image", + "image_threshold": 0, + }, + { + "img": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "image": p(np.random.randint(0, 2, size=[3, 3, 3, 3])), + "label": p(np.random.randint(0, 2, size=[1, 3, 3, 3])), + }, + list, + (3, 2, 2, 2), + ] + ) class TestRandCropByLabelClassesd(unittest.TestCase): - @parameterized.expand([TEST_CASE_0, TEST_CASE_1]) + @parameterized.expand(TESTS) def test_type_shape(self, input_param, input_data, expected_type, expected_shape): result = RandCropByLabelClassesd(**input_param)(input_data) self.assertIsInstance(result, expected_type) diff --git a/tests/test_rand_crop_by_pos_neg_label.py b/tests/test_rand_crop_by_pos_neg_label.py index e0f669ab3f..a81976dea1 100644 --- a/tests/test_rand_crop_by_pos_neg_label.py +++ b/tests/test_rand_crop_by_pos_neg_label.py @@ -10,68 +10,93 @@ # limitations under the License. import unittest +from copy import deepcopy import numpy as np from parameterized import parameterized from monai.transforms import RandCropByPosNegLabel +from tests.utils import TEST_NDARRAYS -TEST_CASE_0 = [ - { - "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "spatial_size": [2, 2, -1], - "pos": 1, - "neg": 1, - "num_samples": 2, - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image_threshold": 0, - }, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - list, - (3, 2, 2, 3), -] +TESTS = [] +TESTS.append( + [ + { + "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "spatial_size": [2, 2, -1], + "pos": 1, + "neg": 1, + "num_samples": 2, + "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "image_threshold": 0, + }, + {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, + (3, 2, 2, 3), + ] +) +TESTS.append( + [ + { + "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "spatial_size": [2, 2, 2], + "pos": 1, + "neg": 1, + "num_samples": 2, + "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "image_threshold": 0, + }, + {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, + (3, 2, 2, 2), + ] +) +TESTS.append( + [ + { + "label": None, + "spatial_size": [2, 2, 2], + "pos": 1, + "neg": 1, + "num_samples": 2, + "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "image_threshold": 0, + }, + { + "img": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), + }, + (3, 2, 2, 2), + ] +) -TEST_CASE_1 = [ - { - "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "spatial_size": [2, 2, 2], - "pos": 1, - "neg": 1, - "num_samples": 2, - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image_threshold": 0, - }, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - list, - (3, 2, 2, 2), -] -TEST_CASE_2 = [ - { - "label": None, - "spatial_size": [2, 2, 2], - "pos": 1, - "neg": 1, - "num_samples": 2, - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image_threshold": 0, - }, - { - "img": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - }, - list, - (3, 2, 2, 2), -] +class TestRandCropByPosNegLabel(unittest.TestCase): + @staticmethod + def convert_data_type(im_type, d, keys=("img", "image", "label")): + out = deepcopy(d) + for k, v in out.items(): + if k in keys and isinstance(v, np.ndarray): + out[k] = im_type(v) + return out + @parameterized.expand(TESTS) + def test_type_shape(self, input_param, input_data, expected_shape): + results = [] + for p in TEST_NDARRAYS: + input_param_mod = self.convert_data_type(p, input_param) + input_data_mod = self.convert_data_type(p, input_data) + cropper = RandCropByPosNegLabel(**input_param_mod) + cropper.set_random_state(0) + result = cropper(**input_data_mod) -class TestRandCropByPosNegLabel(unittest.TestCase): - @parameterized.expand([TEST_CASE_0, TEST_CASE_1, TEST_CASE_2]) - def test_type_shape(self, input_param, input_data, expected_type, expected_shape): - result = RandCropByPosNegLabel(**input_param)(**input_data) - self.assertIsInstance(result, expected_type) - self.assertTupleEqual(result[0].shape, expected_shape) + self.assertIsInstance(result, list) + self.assertTupleEqual(result[0].shape, expected_shape) + + # check for same results across numpy, torch.Tensor and torch.cuda.Tensor + result = np.asarray([i if isinstance(i, np.ndarray) else i.cpu().numpy() for i in result]) + results.append(np.asarray(result)) + if len(results) > 1: + np.testing.assert_allclose(results[0], results[-1]) if __name__ == "__main__": diff --git a/tests/test_rand_crop_by_pos_neg_labeld.py b/tests/test_rand_crop_by_pos_neg_labeld.py index 17a3e117bb..6d2f39cc54 100644 --- a/tests/test_rand_crop_by_pos_neg_labeld.py +++ b/tests/test_rand_crop_by_pos_neg_labeld.py @@ -10,90 +10,101 @@ # limitations under the License. import unittest +from copy import deepcopy import numpy as np from parameterized import parameterized from monai.transforms import RandCropByPosNegLabeld +from tests.utils import TEST_NDARRAYS -TEST_CASE_0 = [ - { - "keys": ["image", "extra", "label"], - "label_key": "label", - "spatial_size": [-1, 2, 2], - "pos": 1, - "neg": 1, - "num_samples": 2, - "image_key": None, - "image_threshold": 0, - }, - { - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "extra": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "image_meta_dict": {"affine": np.eye(3), "shape": "CHWD"}, - }, - list, - (3, 3, 2, 2), +TESTS = [ + [ + { + "keys": ["image", "extra", "label"], + "label_key": "label", + "spatial_size": [-1, 2, 2], + "pos": 1, + "neg": 1, + "num_samples": 2, + "image_key": None, + "image_threshold": 0, + }, + { + "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "extra": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "image_meta_dict": {"affine": np.eye(3), "shape": "CHWD"}, + }, + (3, 3, 2, 2), + ], + [ + { + "keys": ["image", "extra", "label"], + "label_key": "label", + "spatial_size": [2, 2, 2], + "pos": 1, + "neg": 1, + "num_samples": 2, + "image_key": None, + "image_threshold": 0, + }, + { + "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "extra": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), + "label_meta_dict": {"affine": np.eye(3), "shape": "CHWD"}, + }, + (3, 2, 2, 2), + ], + [ + { + "keys": ["image", "extra", "label"], + "label_key": "label", + "spatial_size": [2, 2, 2], + "pos": 1, + "neg": 1, + "num_samples": 2, + "image_key": None, + "image_threshold": 0, + }, + { + "image": np.zeros([3, 3, 3, 3]) - 1, + "extra": np.zeros([3, 3, 3, 3]), + "label": np.ones([3, 3, 3, 3]), + "extra_meta_dict": {"affine": np.eye(3), "shape": "CHWD"}, + }, + (3, 2, 2, 2), + ], ] -TEST_CASE_1 = [ - { - "keys": ["image", "extra", "label"], - "label_key": "label", - "spatial_size": [2, 2, 2], - "pos": 1, - "neg": 1, - "num_samples": 2, - "image_key": None, - "image_threshold": 0, - }, - { - "image": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "extra": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "label": np.random.randint(0, 2, size=[3, 3, 3, 3]), - "label_meta_dict": {"affine": np.eye(3), "shape": "CHWD"}, - }, - list, - (3, 2, 2, 2), -] -TEST_CASE_2 = [ - { - "keys": ["image", "extra", "label"], - "label_key": "label", - "spatial_size": [2, 2, 2], - "pos": 1, - "neg": 1, - "num_samples": 2, - "image_key": None, - "image_threshold": 0, - }, - { - "image": np.zeros([3, 3, 3, 3]) - 1, - "extra": np.zeros([3, 3, 3, 3]), - "label": np.ones([3, 3, 3, 3]), - "extra_meta_dict": {"affine": np.eye(3), "shape": "CHWD"}, - }, - list, - (3, 2, 2, 2), -] +class TestRandCropByPosNegLabeld(unittest.TestCase): + @staticmethod + def convert_data_type(im_type, d, keys=("img", "image", "label")): + out = deepcopy(d) + for k, v in out.items(): + if k in keys and isinstance(v, np.ndarray): + out[k] = im_type(v) + return out + @parameterized.expand(TESTS) + def test_type_shape(self, input_param, input_data, expected_shape): + for p in TEST_NDARRAYS: + input_param_mod = self.convert_data_type(p, input_param) + input_data_mod = self.convert_data_type(p, input_data) + cropper = RandCropByPosNegLabeld(**input_param_mod) + cropper.set_random_state(0) + result = cropper(input_data_mod) -class TestRandCropByPosNegLabeld(unittest.TestCase): - @parameterized.expand([TEST_CASE_0, TEST_CASE_1, TEST_CASE_2]) - def test_type_shape(self, input_param, input_data, expected_type, expected_shape): - result = RandCropByPosNegLabeld(**input_param)(input_data) - self.assertIsInstance(result, expected_type) - self.assertTupleEqual(result[0]["image"].shape, expected_shape) - self.assertTupleEqual(result[0]["extra"].shape, expected_shape) - self.assertTupleEqual(result[0]["label"].shape, expected_shape) - _len = len(tuple(input_data.keys())) - self.assertTupleEqual(tuple(result[0].keys())[:_len], tuple(input_data.keys())) - for i, item in enumerate(result): - self.assertEqual(item["image_meta_dict"]["patch_index"], i) - self.assertEqual(item["label_meta_dict"]["patch_index"], i) - self.assertEqual(item["extra_meta_dict"]["patch_index"], i) + self.assertIsInstance(result, list) + + _len = len(tuple(input_data.keys())) + self.assertTupleEqual(tuple(result[0].keys())[:_len], tuple(input_data.keys())) + for k in ("image", "extra", "label"): + self.assertTupleEqual(result[0][k].shape, expected_shape) + for i, item in enumerate(result): + self.assertEqual(item[k + "_meta_dict"]["patch_index"], i) if __name__ == "__main__": From ee202faa5ff6dd84b63f4c876159c54a8e13bd6a Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Mon, 20 Sep 2021 09:09:26 +0100 Subject: [PATCH 34/89] enhance affinegrid to use torch backend (#2969) * enhance affinegrid to use torch backend Signed-off-by: Wenqi Li * style fixes Signed-off-by: Wenqi Li * codeformat fixes Signed-off-by: Wenqi Li * backend affien grid Signed-off-by: Wenqi Li * device support Signed-off-by: Wenqi Li * less lookup Signed-off-by: Wenqi Li * create grid with torch backend Signed-off-by: Wenqi Li * fixes tests Signed-off-by: Wenqi Li * default to torch create grid Signed-off-by: Wenqi Li * fixes unit test Signed-off-by: Wenqi Li * randaffine with create grid Signed-off-by: Wenqi Li * create_grid backend change for spatial transforms Signed-off-by: Wenqi Li * create control grid tensor Signed-off-by: Wenqi Li * enhance spatial, and crop xforms - Update test_rand_deform_grid.py - center_scale_crop - center_spatial_crop - rand_scale_crop - rand_spatial_crop - rand_spatial_crop_samples Signed-off-by: Wenqi Li * fixes invert Signed-off-by: Wenqi Li * tensor resize, unit test fixes Signed-off-by: Wenqi Li --- monai/data/png_writer.py | 6 +- monai/transforms/croppad/array.py | 35 ++-- monai/transforms/croppad/dictionary.py | 32 +++- monai/transforms/spatial/array.py | 92 +++++---- monai/transforms/spatial/dictionary.py | 19 +- monai/transforms/utils.py | 228 +++++++++++++++++++---- monai/utils/type_conversion.py | 32 ++-- tests/test_center_scale_crop.py | 2 + tests/test_center_spatial_crop.py | 2 + tests/test_center_spatial_cropd.py | 51 +++-- tests/test_create_grid_and_affine.py | 186 +++++++++--------- tests/test_get_equivalent_dtype.py | 8 + tests/test_rand_deform_grid.py | 8 +- tests/test_rand_scale_crop.py | 24 ++- tests/test_rand_scale_cropd.py | 13 +- tests/test_rand_spatial_crop.py | 10 +- tests/test_rand_spatial_crop_samples.py | 16 +- tests/test_rand_spatial_crop_samplesd.py | 64 ++++--- tests/test_rand_spatial_cropd.py | 11 +- tests/test_resize.py | 24 ++- tests/test_resize_with_pad_or_crop.py | 17 +- tests/test_resize_with_pad_or_cropd.py | 14 +- tests/test_resized.py | 24 ++- 23 files changed, 606 insertions(+), 312 deletions(-) diff --git a/monai/data/png_writer.py b/monai/data/png_writer.py index 2baec3b872..52163e40ac 100644 --- a/monai/data/png_writer.py +++ b/monai/data/png_writer.py @@ -48,7 +48,7 @@ def write_png( """ if not isinstance(data, np.ndarray): - raise AssertionError("input data must be numpy array.") + raise ValueError("input data must be numpy array.") if len(data.shape) == 3 and data.shape[2] == 1: # PIL Image can't save image with 1 channel data = data.squeeze(2) if output_spatial_shape is not None: @@ -59,11 +59,11 @@ def write_png( _min, _max = np.min(data), np.max(data) if len(data.shape) == 3: data = np.moveaxis(data, -1, 0) # to channel first - data = xform(data) + data = xform(data) # type: ignore data = np.moveaxis(data, 0, -1) else: # (H, W) data = np.expand_dims(data, 0) # make a channel - data = xform(data)[0] # first channel + data = xform(data)[0] # type: ignore if mode != InterpolateMode.NEAREST: data = np.clip(data, _min, _max) # type: ignore diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index e1c915cc93..276ba6104d 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -128,10 +128,7 @@ def __call__( # all zeros, skip padding return img mode = convert_pad_mode(dst=img, mode=mode or self.mode).value - if isinstance(img, torch.Tensor): - pad = self._pt_pad - else: - pad = self._np_pad # type: ignore + pad = self._pt_pad if isinstance(img, torch.Tensor) else self._np_pad return pad(img, self.to_pad, mode, **self.kwargs) # type: ignore @@ -449,15 +446,16 @@ class CenterSpatialCrop(Transform): the spatial size of output data will be [32, 40, 40]. """ + backend = SpatialCrop.backend + def __init__(self, roi_size: Union[Sequence[int], int]) -> None: self.roi_size = roi_size - def __call__(self, img: np.ndarray): + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore roi_size = fall_back_tuple(self.roi_size, img.shape[1:]) center = [i // 2 for i in img.shape[1:]] cropper = SpatialCrop(roi_center=center, roi_size=roi_size) @@ -474,11 +472,12 @@ class CenterScaleCrop(Transform): """ + backend = CenterSpatialCrop.backend + def __init__(self, roi_scale: Union[Sequence[float], float]): self.roi_scale = roi_scale - def __call__(self, img: np.ndarray): - img, *_ = convert_data_type(img, np.ndarray) # type: ignore + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: img_size = img.shape[1:] ndim = len(img_size) roi_size = [ceil(r * s) for r, s in zip(ensure_tuple_rep(self.roi_scale, ndim), img_size)] @@ -510,6 +509,8 @@ class RandSpatialCrop(Randomizable, Transform): if True, the actual size is sampled from `randint(roi_size, max_roi_size + 1)`. """ + backend = CenterSpatialCrop.backend + def __init__( self, roi_size: Union[Sequence[int], int], @@ -535,15 +536,14 @@ def randomize(self, img_size: Sequence[int]) -> None: valid_size = get_valid_patch_size(img_size, self._size) self._slices = (slice(None),) + get_random_patch(img_size, valid_size, self.R) - def __call__(self, img: np.ndarray): + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize(img.shape[1:]) if self._size is None: - raise AssertionError + raise RuntimeError("self._size not specified.") if self.random_center: return img[self._slices] cropper = CenterSpatialCrop(self._size) @@ -582,12 +582,11 @@ def __init__( self.roi_scale = roi_scale self.max_roi_scale = max_roi_scale - def __call__(self, img: np.ndarray): + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't apply to the channel dim. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore img_size = img.shape[1:] ndim = len(img_size) self.roi_size = [ceil(r * s) for r, s in zip(ensure_tuple_rep(self.roi_scale, ndim), img_size)] @@ -629,6 +628,8 @@ class RandSpatialCropSamples(Randomizable, Transform): """ + backend = RandScaleCrop.backend + def __init__( self, roi_size: Union[Sequence[int], int], @@ -652,12 +653,11 @@ def set_random_state( def randomize(self, data: Optional[Any] = None) -> None: pass - def __call__(self, img: np.ndarray) -> List[np.ndarray]: + def __call__(self, img: NdarrayOrTensor) -> List[NdarrayOrTensor]: """ Apply the transform to `img`, assuming `img` is channel-first and cropping doesn't change the channel dim. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore return [self.cropper(img) for _ in range(self.num_samples)] @@ -1128,6 +1128,8 @@ class ResizeWithPadOrCrop(Transform): """ + backend = list(set(SpatialPad.backend) & set(CenterSpatialCrop.backend)) + def __init__( self, spatial_size: Union[Sequence[int], int], @@ -1138,7 +1140,7 @@ def __init__( self.padder = SpatialPad(spatial_size=spatial_size, method=method, mode=mode, **np_kwargs) self.cropper = CenterSpatialCrop(roi_size=spatial_size) - def __call__(self, img: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = None) -> np.ndarray: + def __call__(self, img: NdarrayOrTensor, mode: Optional[Union[NumpyPadMode, str]] = None) -> NdarrayOrTensor: """ Args: img: data to pad or crop, assuming `img` is channel-first and @@ -1149,7 +1151,6 @@ def __call__(self, img: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = N If None, defaults to the ``mode`` in construction. See also: https://numpy.org/doc/1.18/reference/generated/numpy.pad.html """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore return self.padder(self.cropper(img), mode=mode) # type: ignore diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py index 488b832450..2590bf2e77 100644 --- a/monai/transforms/croppad/dictionary.py +++ b/monai/transforms/croppad/dictionary.py @@ -416,13 +416,15 @@ class CenterSpatialCropd(MapTransform, InvertibleTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = CenterSpatialCrop.backend + def __init__( self, keys: KeysCollection, roi_size: Union[Sequence[int], int], allow_missing_keys: bool = False ) -> None: super().__init__(keys, allow_missing_keys) self.cropper = CenterSpatialCrop(roi_size) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): orig_size = d[key].shape[1:] @@ -466,13 +468,15 @@ class CenterScaleCropd(MapTransform, InvertibleTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = CenterSpatialCrop.backend + def __init__( self, keys: KeysCollection, roi_scale: Union[Sequence[float], float], allow_missing_keys: bool = False ) -> None: super().__init__(keys, allow_missing_keys=allow_missing_keys) self.roi_scale = roi_scale - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) # use the spatial size of first image to scale, expect all images have the same spatial size img_size = data[self.keys[0]].shape[1:] @@ -537,6 +541,8 @@ class RandSpatialCropd(Randomizable, MapTransform, InvertibleTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = CenterSpatialCrop.backend + def __init__( self, keys: KeysCollection, @@ -565,11 +571,11 @@ def randomize(self, img_size: Sequence[int]) -> None: valid_size = get_valid_patch_size(img_size, self._size) self._slices = (slice(None),) + get_random_patch(img_size, valid_size, self.R) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) self.randomize(d[self.keys[0]].shape[1:]) # image shape from the first data key if self._size is None: - raise AssertionError + raise RuntimeError("self._size not specified.") for key in self.key_iterator(d): if self.random_center: self.push_transform(d, key, {"slices": [(i.start, i.stop) for i in self._slices[1:]]}) # type: ignore @@ -638,6 +644,8 @@ class RandScaleCropd(RandSpatialCropd): allow_missing_keys: don't raise exception if key is missing. """ + backend = RandSpatialCropd.backend + def __init__( self, keys: KeysCollection, @@ -659,7 +667,7 @@ def __init__( self.roi_scale = roi_scale self.max_roi_scale = max_roi_scale - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: img_size = data[self.keys[0]].shape[1:] ndim = len(img_size) self.roi_size = [ceil(r * s) for r, s in zip(ensure_tuple_rep(self.roi_scale, ndim), img_size)] @@ -723,6 +731,8 @@ class RandSpatialCropSamplesd(Randomizable, MapTransform, InvertibleTransform): """ + backend = RandSpatialCropd.backend + def __init__( self, keys: KeysCollection, @@ -755,7 +765,7 @@ def set_random_state( def randomize(self, data: Optional[Any] = None) -> None: pass - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, np.ndarray]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> List[Dict[Hashable, NdarrayOrTensor]]: ret = [] for i in range(self.num_samples): d = dict(data) @@ -765,14 +775,14 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> List[Dict[Hashable, n cropped = self.cropper(d) # self.cropper will have added RandSpatialCropd to the list. Change to RandSpatialCropSamplesd for key in self.key_iterator(cropped): - cropped[str(key) + InverseKeys.KEY_SUFFIX][-1][InverseKeys.CLASS_NAME] = self.__class__.__name__ - cropped[str(key) + InverseKeys.KEY_SUFFIX][-1][InverseKeys.ID] = id(self) + cropped[str(key) + InverseKeys.KEY_SUFFIX][-1][InverseKeys.CLASS_NAME] = self.__class__.__name__ # type: ignore + cropped[str(key) + InverseKeys.KEY_SUFFIX][-1][InverseKeys.ID] = id(self) # type: ignore # add `patch_index` to the meta data for key, meta_key, meta_key_postfix in self.key_iterator(d, self.meta_keys, self.meta_key_postfix): meta_key = meta_key or f"{key}_{meta_key_postfix}" if meta_key not in cropped: cropped[meta_key] = {} # type: ignore - cropped[meta_key][Key.PATCH_INDEX] = i + cropped[meta_key][Key.PATCH_INDEX] = i # type: ignore ret.append(cropped) return ret @@ -1377,6 +1387,8 @@ class ResizeWithPadOrCropd(MapTransform, InvertibleTransform): """ + backend = ResizeWithPadOrCrop.backend + def __init__( self, keys: KeysCollection, @@ -1390,7 +1402,7 @@ def __init__( self.mode = ensure_tuple_rep(mode, len(self.keys)) self.padcropper = ResizeWithPadOrCrop(spatial_size=spatial_size, method=method, **np_kwargs) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, m in self.key_iterator(d, self.mode): orig_size = d[key].shape[1:] diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 1b03d39a15..6f662f2dce 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -362,6 +362,8 @@ class Resize(Transform): See also: https://pytorch.org/docs/stable/nn.functional.html#interpolate """ + backend = [TransformBackends.TORCH] + def __init__( self, spatial_size: Union[Sequence[int], int], @@ -376,10 +378,10 @@ def __init__( def __call__( self, - img: np.ndarray, + img: NdarrayOrTensor, mode: Optional[Union[InterpolateMode, str]] = None, align_corners: Optional[bool] = None, - ) -> np.ndarray: + ) -> NdarrayOrTensor: """ Args: img: channel first array, must have shape: (num_channels, H[, W, ..., ]). @@ -394,33 +396,33 @@ def __call__( ValueError: When ``self.spatial_size`` length is less than ``img`` spatial dimensions. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore + img_, *_ = convert_data_type(img, torch.Tensor, dtype=torch.float) # type: ignore if self.size_mode == "all": - input_ndim = img.ndim - 1 # spatial ndim + input_ndim = img_.ndim - 1 # spatial ndim output_ndim = len(ensure_tuple(self.spatial_size)) if output_ndim > input_ndim: - input_shape = ensure_tuple_size(img.shape, output_ndim + 1, 1) - img = img.reshape(input_shape) + input_shape = ensure_tuple_size(img_.shape, output_ndim + 1, 1) + img_ = img_.reshape(input_shape) elif output_ndim < input_ndim: raise ValueError( "len(spatial_size) must be greater or equal to img spatial dimensions, " f"got spatial_size={output_ndim} img={input_ndim}." ) - spatial_size_ = fall_back_tuple(self.spatial_size, img.shape[1:]) + spatial_size_ = fall_back_tuple(self.spatial_size, img_.shape[1:]) else: # for the "longest" mode - img_size = img.shape[1:] + img_size = img_.shape[1:] if not isinstance(self.spatial_size, int): raise ValueError("spatial_size must be an int number if size_mode is 'longest'.") scale = self.spatial_size / max(img_size) spatial_size_ = tuple(int(round(s * scale)) for s in img_size) resized = torch.nn.functional.interpolate( # type: ignore - input=torch.as_tensor(np.ascontiguousarray(img), dtype=torch.float).unsqueeze(0), + input=img_.unsqueeze(0), # type: ignore size=spatial_size_, mode=look_up_option(self.mode if mode is None else mode, InterpolateMode).value, align_corners=self.align_corners if align_corners is None else align_corners, ) - resized = resized.squeeze(0).detach().cpu().numpy() - return np.asarray(resized) + out, *_ = convert_to_dst_type(resized.squeeze(0), img) + return out class Rotate(Transform, ThreadUnsafe): @@ -462,7 +464,7 @@ def __init__( self.padding_mode: GridSamplePadMode = look_up_option(padding_mode, GridSamplePadMode) self.align_corners = align_corners self.dtype = dtype - self._rotation_matrix: Optional[np.ndarray] = None + self._rotation_matrix: Optional[NdarrayOrTensor] = None def __call__( self, @@ -511,7 +513,7 @@ def __call__( corners = np.asarray(np.meshgrid(*[(0, dim) for dim in im_shape], indexing="ij")).reshape( (len(im_shape), -1) ) - corners = transform[:-1, :-1] @ corners + corners = transform[:-1, :-1] @ corners # type: ignore output_shape = np.asarray(corners.ptp(axis=1) + 0.5, dtype=int) shift_1 = create_translate(input_ndim, (-(output_shape - 1) / 2).tolist()) transform = shift @ transform @ shift_1 @@ -532,7 +534,7 @@ def __call__( out, *_ = convert_to_dst_type(output, dst=img, dtype=output.dtype) return out - def get_rotation_matrix(self) -> Optional[np.ndarray]: + def get_rotation_matrix(self) -> Optional[NdarrayOrTensor]: """ Get the most recently applied rotation matrix This is not thread-safe. @@ -1055,6 +1057,10 @@ def __call__( grid: Optional[NdarrayOrTensor] = None, ) -> Tuple[NdarrayOrTensor, NdarrayOrTensor]: """ + The grid can be initialized with a `spatial_size` parameter, or provided directly as `grid`. + Therefore, either `spatial_size` or `grid` must be provided. + When initialising from `spatial_size`, the backend "torch" will be used. + Args: spatial_size: output grid size. grid: grid to be transformed. Shape must be (3, H, W) for 2D or (4, H, W, D) for 3D. @@ -1065,26 +1071,32 @@ def __call__( """ if grid is None: if spatial_size is not None: - grid = create_grid(spatial_size, dtype=float) + grid = create_grid(spatial_size, device=self.device, backend="torch") else: raise ValueError("Incompatible values: grid=None and spatial_size=None.") + _b = TransformBackends.TORCH if isinstance(grid, torch.Tensor) else TransformBackends.NUMPY + _device = grid.device if isinstance(grid, torch.Tensor) else self.device affine: NdarrayOrTensor if self.affine is None: spatial_dims = len(grid.shape) - 1 - affine = np.eye(spatial_dims + 1) + affine = ( + torch.eye(spatial_dims + 1, device=_device) + if _b == TransformBackends.TORCH + else np.eye(spatial_dims + 1) + ) if self.rotate_params: - affine = affine @ create_rotate(spatial_dims, self.rotate_params) + affine = affine @ create_rotate(spatial_dims, self.rotate_params, device=_device, backend=_b) if self.shear_params: - affine = affine @ create_shear(spatial_dims, self.shear_params) + affine = affine @ create_shear(spatial_dims, self.shear_params, device=_device, backend=_b) if self.translate_params: - affine = affine @ create_translate(spatial_dims, self.translate_params) + affine = affine @ create_translate(spatial_dims, self.translate_params, device=_device, backend=_b) if self.scale_params: - affine = affine @ create_scale(spatial_dims, self.scale_params) + affine = affine @ create_scale(spatial_dims, self.scale_params, device=_device, backend=_b) else: affine = self.affine - grid, *_ = convert_data_type(grid, torch.Tensor, device=self.device, dtype=float) + grid, *_ = convert_data_type(grid, torch.Tensor, device=_device, dtype=float) affine, *_ = convert_to_dst_type(affine, grid) grid = (affine @ grid.reshape((grid.shape[0], -1))).reshape([-1] + list(grid.shape[1:])) @@ -1206,6 +1218,8 @@ class RandDeformGrid(Randomizable, Transform): Generate random deformation grid. """ + backend = [TransformBackends.TORCH] + def __init__( self, spacing: Union[Sequence[float], float], @@ -1243,11 +1257,12 @@ def __call__(self, spatial_size: Sequence[int]): spatial_size: spatial size of the grid. """ self.spacing = fall_back_tuple(self.spacing, (1.0,) * len(spatial_size)) - control_grid = create_control_grid(spatial_size, self.spacing) + control_grid = create_control_grid(spatial_size, self.spacing, device=self.device, backend="torch") self.randomize(control_grid.shape[1:]) - control_grid[: len(spatial_size)] += self.rand_mag * self.random_offset - if self.as_tensor_output: - control_grid = torch.as_tensor(np.ascontiguousarray(control_grid), device=self.device) + _offset, *_ = convert_to_dst_type(self.rand_mag * self.random_offset, control_grid) + control_grid[: len(spatial_size)] += _offset + if not self.as_tensor_output: + control_grid, *_ = convert_data_type(control_grid, output_type=np.ndarray, dtype=np.float32) return control_grid @@ -1300,8 +1315,9 @@ def __call__( """ if grid is None: raise ValueError("Unknown grid.") + _device = img.device if isinstance(img, torch.Tensor) else self.device img_t: torch.Tensor - img_t, *_ = convert_data_type(img, torch.Tensor, device=self.device, dtype=torch.float32) # type: ignore + img_t, *_ = convert_data_type(img, torch.Tensor, device=_device, dtype=torch.float32) # type: ignore grid, *_ = convert_to_dst_type(grid, img_t) if USE_COMPILED: @@ -1553,7 +1569,7 @@ def _init_identity_cache(self): f"'spatial_size={self.spatial_size}', please specify 'spatial_size'." ) return None - return torch.tensor(create_grid(spatial_size=_sp_size)).to(self.rand_affine_grid.device) + return create_grid(spatial_size=_sp_size, device=self.rand_affine_grid.device, backend="torch") def get_identity_grid(self, spatial_size: Sequence[int]): """ @@ -1567,7 +1583,11 @@ def get_identity_grid(self, spatial_size: Sequence[int]): spatial_size, [2] * ndim ): raise RuntimeError(f"spatial_size should not be dynamic, got {spatial_size}.") - return create_grid(spatial_size=spatial_size) if self._cached_grid is None else self._cached_grid + return ( + create_grid(spatial_size=spatial_size, device=self.rand_affine_grid.device, backend="torch") + if self._cached_grid is None + else self._cached_grid + ) def set_random_state( self, seed: Optional[int] = None, state: Optional[np.random.RandomState] = None @@ -1701,6 +1721,7 @@ def __init__( ) self.resampler = Resample(device=device) + self.device = device self.spatial_size = spatial_size self.mode: GridSampleMode = look_up_option(mode, GridSampleMode) self.padding_mode: GridSamplePadMode = look_up_option(padding_mode, GridSamplePadMode) @@ -1745,14 +1766,15 @@ def __call__( grid = self.rand_affine_grid(grid=grid) grid = torch.nn.functional.interpolate( # type: ignore recompute_scale_factor=True, - input=torch.as_tensor(grid).unsqueeze(0), + input=grid.unsqueeze(0), scale_factor=list(ensure_tuple(self.deform_grid.spacing)), mode=InterpolateMode.BICUBIC.value, align_corners=False, ) grid = CenterSpatialCrop(roi_size=sp_size)(grid[0]) else: - grid = create_grid(spatial_size=sp_size) + _device = img.device if isinstance(img, torch.Tensor) else self.device + grid = create_grid(spatial_size=sp_size, device=_device, backend="torch") out: NdarrayOrTensor = self.resampler( img, grid, mode=mode or self.mode, padding_mode=padding_mode or self.padding_mode ) @@ -1890,13 +1912,13 @@ def __call__( """ sp_size = fall_back_tuple(spatial_size or self.spatial_size, img.shape[1:]) self.randomize(grid_size=sp_size) - grid = create_grid(spatial_size=sp_size) + _device = img.device if isinstance(img, torch.Tensor) else self.device + grid = create_grid(spatial_size=sp_size, device=_device, backend="torch") if self._do_transform: if self.rand_offset is None: - raise AssertionError - grid = torch.as_tensor(np.ascontiguousarray(grid), device=self.device) - gaussian = GaussianFilter(3, self.sigma, 3.0).to(device=self.device) - offset = torch.as_tensor(self.rand_offset, device=self.device).unsqueeze(0) + raise RuntimeError("rand_offset is not initialized.") + gaussian = GaussianFilter(3, self.sigma, 3.0).to(device=_device) + offset = torch.as_tensor(self.rand_offset, device=_device).unsqueeze(0) grid[:3] += gaussian(offset)[0] * self.magnitude grid = self.rand_affine_grid(grid=grid) out: NdarrayOrTensor = self.resampler( diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index 487225cb60..f36300dea6 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -521,6 +521,8 @@ class Resized(MapTransform, InvertibleTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = Resize.backend + def __init__( self, keys: KeysCollection, @@ -535,7 +537,7 @@ def __init__( self.align_corners = ensure_tuple_rep(align_corners, len(self.keys)) self.resizer = Resize(spatial_size=spatial_size, size_mode=size_mode) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key, mode, align_corners in self.key_iterator(d, self.mode, self.align_corners): self.push_transform( @@ -549,7 +551,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda d[key] = self.resizer(d[key], mode=mode, align_corners=align_corners) return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) @@ -826,9 +828,7 @@ def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, Nd for key in self.key_iterator(d): transform = self.get_most_recent_transform(d, key) # if transform was not performed and spatial size is None, nothing to do. - if not transform[InverseKeys.DO_TRANSFORM] and self.rand_affine.spatial_size is None: - out: NdarrayOrTensor = d[key] - else: + if transform[InverseKeys.DO_TRANSFORM] or self.rand_affine.spatial_size is not None: orig_size = transform[InverseKeys.ORIG_SIZE] # Create inverse transform fwd_affine = transform[InverseKeys.EXTRA_INFO]["affine"] @@ -968,7 +968,8 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N ) grid = CenterSpatialCrop(roi_size=sp_size)(grid[0]) else: - grid = create_grid(spatial_size=sp_size) + _device = self.rand_2d_elastic.deform_grid.device + grid = create_grid(spatial_size=sp_size, device=_device, backend="torch") for key, mode, padding_mode in self.key_iterator(d, self.mode, self.padding_mode): d[key] = self.rand_2d_elastic.resampler(d[key], grid, mode=mode, padding_mode=padding_mode) @@ -1084,12 +1085,12 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N sp_size = fall_back_tuple(self.rand_3d_elastic.spatial_size, data[self.keys[0]].shape[1:]) self.randomize(grid_size=sp_size) - grid = create_grid(spatial_size=sp_size) + _device = self.rand_3d_elastic.device + grid = create_grid(spatial_size=sp_size, device=_device, backend="torch") if self._do_transform: device = self.rand_3d_elastic.device - grid = torch.tensor(grid).to(device) gaussian = GaussianFilter(spatial_dims=3, sigma=self.rand_3d_elastic.sigma, truncated=3.0).to(device) - offset = torch.tensor(self.rand_3d_elastic.rand_offset, device=device).unsqueeze(0) + offset = torch.as_tensor(self.rand_3d_elastic.rand_offset, device=device).unsqueeze(0) grid[:3] += gaussian(offset)[0] * self.rand_3d_elastic.magnitude grid = self.rand_3d_elastic.rand_affine_grid(grid=grid) diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 05e45bf26f..a627a7544a 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -541,7 +541,9 @@ def create_grid( spatial_size: Sequence[int], spacing: Optional[Sequence[float]] = None, homogeneous: bool = True, - dtype: DtypeLike = float, + dtype=float, + device: Optional[torch.device] = None, + backend=TransformBackends.NUMPY, ): """ compute a `spatial_size` mesh. @@ -551,6 +553,26 @@ def create_grid( spacing: same len as ``spatial_size``, defaults to 1.0 (dense grid). homogeneous: whether to make homogeneous coordinates. dtype: output grid data type. + device: device to compute and store the output (when the backend is "torch"). + backend: APIs to use, ``numpy`` or ``torch``. + + """ + _backend = look_up_option(backend, TransformBackends) + if _backend == TransformBackends.NUMPY: + return _create_grid_numpy(spatial_size, spacing, homogeneous, dtype) + if _backend == TransformBackends.TORCH: + return _create_grid_torch(spatial_size, spacing, homogeneous, dtype, device) + raise ValueError("backend {} is not supported".format(backend)) + + +def _create_grid_numpy( + spatial_size: Sequence[int], + spacing: Optional[Sequence[float]] = None, + homogeneous: bool = True, + dtype: DtypeLike = float, +): + """ + compute a `spatial_size` mesh with the numpy API. """ spacing = spacing or tuple(1.0 for _ in spatial_size) ranges = [np.linspace(-(d - 1.0) / 2.0 * s, (d - 1.0) / 2.0 * s, int(d)) for d, s in zip(spatial_size, spacing)] @@ -560,23 +582,58 @@ def create_grid( return np.concatenate([coords, np.ones_like(coords[:1])]) +def _create_grid_torch( + spatial_size: Sequence[int], + spacing: Optional[Sequence[float]] = None, + homogeneous: bool = True, + dtype=torch.float32, + device: Optional[torch.device] = None, +): + """ + compute a `spatial_size` mesh with the torch API. + """ + spacing = spacing or tuple(1.0 for _ in spatial_size) + ranges = [ + torch.linspace(-(d - 1.0) / 2.0 * s, (d - 1.0) / 2.0 * s, int(d), device=device, dtype=dtype) + for d, s in zip(spatial_size, spacing) + ] + coords = torch.meshgrid(*ranges) + if not homogeneous: + return torch.stack(coords) + return torch.stack([*coords, torch.ones_like(coords[0])]) + + def create_control_grid( - spatial_shape: Sequence[int], spacing: Sequence[float], homogeneous: bool = True, dtype: DtypeLike = float + spatial_shape: Sequence[int], + spacing: Sequence[float], + homogeneous: bool = True, + dtype: DtypeLike = float, + device: Optional[torch.device] = None, + backend=TransformBackends.NUMPY, ): """ control grid with two additional point in each direction """ + torch_backend = look_up_option(backend, TransformBackends) == TransformBackends.TORCH + ceil_func: Callable = torch.ceil if torch_backend else np.ceil # type: ignore grid_shape = [] for d, s in zip(spatial_shape, spacing): - d = int(d) + d = torch.as_tensor(d, device=device) if torch_backend else int(d) # type: ignore if d % 2 == 0: - grid_shape.append(np.ceil((d - 1.0) / (2.0 * s) + 0.5) * 2.0 + 2.0) + grid_shape.append(ceil_func((d - 1.0) / (2.0 * s) + 0.5) * 2.0 + 2.0) else: - grid_shape.append(np.ceil((d - 1.0) / (2.0 * s)) * 2.0 + 3.0) - return create_grid(grid_shape, spacing, homogeneous, dtype) + grid_shape.append(ceil_func((d - 1.0) / (2.0 * s)) * 2.0 + 3.0) + return create_grid( + spatial_size=grid_shape, spacing=spacing, homogeneous=homogeneous, dtype=dtype, device=device, backend=backend + ) -def create_rotate(spatial_dims: int, radians: Union[Sequence[float], float]) -> np.ndarray: +def create_rotate( + spatial_dims: int, + radians: Union[Sequence[float], float], + device: Optional[torch.device] = None, + backend=TransformBackends.NUMPY, +) -> NdarrayOrTensor: """ create a 2D or 3D rotation matrix @@ -585,48 +642,83 @@ def create_rotate(spatial_dims: int, radians: Union[Sequence[float], float]) -> radians: rotation radians when spatial_dims == 3, the `radians` sequence corresponds to rotation in the 1st, 2nd, and 3rd dim respectively. + device: device to compute and store the output (when the backend is "torch"). + backend: APIs to use, ``numpy`` or ``torch``. Raises: ValueError: When ``radians`` is empty. ValueError: When ``spatial_dims`` is not one of [2, 3]. """ + _backend = look_up_option(backend, TransformBackends) + if _backend == TransformBackends.NUMPY: + return _create_rotate( + spatial_dims=spatial_dims, radians=radians, sin_func=np.sin, cos_func=np.cos, eye_func=np.eye + ) + if _backend == TransformBackends.TORCH: + return _create_rotate( + spatial_dims=spatial_dims, + radians=radians, + sin_func=lambda th: torch.sin(torch.as_tensor(th, dtype=torch.float32, device=device)), + cos_func=lambda th: torch.cos(torch.as_tensor(th, dtype=torch.float32, device=device)), + eye_func=lambda rank: torch.eye(rank, device=device), + ) + raise ValueError("backend {} is not supported".format(backend)) + + +def _create_rotate( + spatial_dims: int, + radians: Union[Sequence[float], float], + sin_func: Callable = np.sin, + cos_func: Callable = np.cos, + eye_func: Callable = np.eye, +) -> NdarrayOrTensor: radians = ensure_tuple(radians) if spatial_dims == 2: if len(radians) >= 1: - sin_, cos_ = np.sin(radians[0]), np.cos(radians[0]) - return np.array([[cos_, -sin_, 0.0], [sin_, cos_, 0.0], [0.0, 0.0, 1.0]]) + sin_, cos_ = sin_func(radians[0]), cos_func(radians[0]) + out = eye_func(3) + out[0, 0], out[0, 1] = cos_, -sin_ + out[1, 0], out[1, 1] = sin_, cos_ + return out # type: ignore raise ValueError("radians must be non empty.") if spatial_dims == 3: affine = None if len(radians) >= 1: - sin_, cos_ = np.sin(radians[0]), np.cos(radians[0]) - affine = np.array( - [[1.0, 0.0, 0.0, 0.0], [0.0, cos_, -sin_, 0.0], [0.0, sin_, cos_, 0.0], [0.0, 0.0, 0.0, 1.0]] - ) + sin_, cos_ = sin_func(radians[0]), cos_func(radians[0]) + affine = eye_func(4) + affine[1, 1], affine[1, 2] = cos_, -sin_ + affine[2, 1], affine[2, 2] = sin_, cos_ if len(radians) >= 2: - sin_, cos_ = np.sin(radians[1]), np.cos(radians[1]) + sin_, cos_ = sin_func(radians[1]), cos_func(radians[1]) if affine is None: raise ValueError("Affine should be a matrix.") - affine = affine @ np.array( - [[cos_, 0.0, sin_, 0.0], [0.0, 1.0, 0.0, 0.0], [-sin_, 0.0, cos_, 0.0], [0.0, 0.0, 0.0, 1.0]] - ) + _affine = eye_func(4) + _affine[0, 0], _affine[0, 2] = cos_, sin_ + _affine[2, 0], _affine[2, 2] = -sin_, cos_ + affine = affine @ _affine if len(radians) >= 3: - sin_, cos_ = np.sin(radians[2]), np.cos(radians[2]) + sin_, cos_ = sin_func(radians[2]), cos_func(radians[2]) if affine is None: raise ValueError("Affine should be a matrix.") - affine = affine @ np.array( - [[cos_, -sin_, 0.0, 0.0], [sin_, cos_, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] - ) + _affine = eye_func(4) + _affine[0, 0], _affine[0, 1] = cos_, -sin_ + _affine[1, 0], _affine[1, 1] = sin_, cos_ + affine = affine @ _affine if affine is None: raise ValueError("radians must be non empty.") - return affine + return affine # type: ignore raise ValueError(f"Unsupported spatial_dims: {spatial_dims}, available options are [2, 3].") -def create_shear(spatial_dims: int, coefs: Union[Sequence[float], float]) -> np.ndarray: +def create_shear( + spatial_dims: int, + coefs: Union[Sequence[float], float], + device: Optional[torch.device] = None, + backend=TransformBackends.NUMPY, +) -> NdarrayOrTensor: """ create a shearing matrix @@ -642,51 +734,109 @@ def create_shear(spatial_dims: int, coefs: Union[Sequence[float], float]) -> np. [0.0, 0.0, 0.0, 1.0], ] + device: device to compute and store the output (when the backend is "torch"). + backend: APIs to use, ``numpy`` or ``torch``. + Raises: NotImplementedError: When ``spatial_dims`` is not one of [2, 3]. """ + _backend = look_up_option(backend, TransformBackends) + if _backend == TransformBackends.NUMPY: + return _create_shear(spatial_dims=spatial_dims, coefs=coefs, eye_func=np.eye) + if _backend == TransformBackends.TORCH: + return _create_shear( + spatial_dims=spatial_dims, coefs=coefs, eye_func=lambda rank: torch.eye(rank, device=device) + ) + raise ValueError("backend {} is not supported".format(backend)) + + +def _create_shear(spatial_dims: int, coefs: Union[Sequence[float], float], eye_func=np.eye) -> NdarrayOrTensor: if spatial_dims == 2: coefs = ensure_tuple_size(coefs, dim=2, pad_val=0.0) - return np.array([[1, coefs[0], 0.0], [coefs[1], 1.0, 0.0], [0.0, 0.0, 1.0]]) + out = eye_func(3) + out[0, 1], out[1, 0] = coefs[0], coefs[1] + return out # type: ignore if spatial_dims == 3: coefs = ensure_tuple_size(coefs, dim=6, pad_val=0.0) - return np.array( - [ - [1.0, coefs[0], coefs[1], 0.0], - [coefs[2], 1.0, coefs[3], 0.0], - [coefs[4], coefs[5], 1.0, 0.0], - [0.0, 0.0, 0.0, 1.0], - ] - ) + out = eye_func(4) + out[0, 1], out[0, 2] = coefs[0], coefs[1] + out[1, 0], out[1, 2] = coefs[2], coefs[3] + out[2, 0], out[2, 1] = coefs[4], coefs[5] + return out # type: ignore raise NotImplementedError("Currently only spatial_dims in [2, 3] are supported.") -def create_scale(spatial_dims: int, scaling_factor: Union[Sequence[float], float]): +def create_scale( + spatial_dims: int, + scaling_factor: Union[Sequence[float], float], + device: Optional[torch.device] = None, + backend=TransformBackends.NUMPY, +) -> NdarrayOrTensor: """ create a scaling matrix Args: spatial_dims: spatial rank scaling_factor: scaling factors for every spatial dim, defaults to 1. - """ + device: device to compute and store the output (when the backend is "torch"). + backend: APIs to use, ``numpy`` or ``torch``. + """ + _backend = look_up_option(backend, TransformBackends) + if _backend == TransformBackends.NUMPY: + return _create_scale(spatial_dims=spatial_dims, scaling_factor=scaling_factor, array_func=np.diag) + if _backend == TransformBackends.TORCH: + return _create_scale( + spatial_dims=spatial_dims, + scaling_factor=scaling_factor, + array_func=lambda x: torch.diag(torch.as_tensor(x, device=device)), + ) + raise ValueError("backend {} is not supported".format(backend)) + + +def _create_scale( + spatial_dims: int, scaling_factor: Union[Sequence[float], float], array_func=np.diag +) -> NdarrayOrTensor: scaling_factor = ensure_tuple_size(scaling_factor, dim=spatial_dims, pad_val=1.0) - return np.diag(scaling_factor[:spatial_dims] + (1.0,)) + return array_func(scaling_factor[:spatial_dims] + (1.0,)) # type: ignore -def create_translate(spatial_dims: int, shift: Union[Sequence[float], float]) -> np.ndarray: +def create_translate( + spatial_dims: int, + shift: Union[Sequence[float], float], + device: Optional[torch.device] = None, + backend=TransformBackends.NUMPY, +) -> NdarrayOrTensor: """ create a translation matrix Args: spatial_dims: spatial rank shift: translate pixel/voxel for every spatial dim, defaults to 0. - """ + device: device to compute and store the output (when the backend is "torch"). + backend: APIs to use, ``numpy`` or ``torch``. + """ + _backend = look_up_option(backend, TransformBackends) + if _backend == TransformBackends.NUMPY: + return _create_translate(spatial_dims=spatial_dims, shift=shift, eye_func=np.eye, array_func=np.asarray) + if _backend == TransformBackends.TORCH: + return _create_translate( + spatial_dims=spatial_dims, + shift=shift, + eye_func=lambda x: torch.eye(torch.as_tensor(x), device=device), # type: ignore + array_func=lambda x: torch.as_tensor(x, device=device), # type: ignore + ) + raise ValueError("backend {} is not supported".format(backend)) + + +def _create_translate( + spatial_dims: int, shift: Union[Sequence[float], float], eye_func=np.eye, array_func=np.asarray +) -> NdarrayOrTensor: shift = ensure_tuple(shift) - affine = np.eye(spatial_dims + 1) + affine = eye_func(spatial_dims + 1) for i, a in enumerate(shift[:spatial_dims]): affine[i, spatial_dims] = a - return np.asarray(affine) + return array_func(affine) # type: ignore def generate_spatial_bounding_box( diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index 3636dbc6c0..87095fef99 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -6,6 +6,7 @@ from monai.config.type_definitions import DtypeLike, NdarrayOrTensor from monai.utils import optional_import +from monai.utils.module import look_up_option cp, has_cp = optional_import("cupy") cp_ndarray, _ = optional_import("cupy", name="ndarray") @@ -41,33 +42,34 @@ def dtype_torch_to_numpy(dtype): """Convert a torch dtype to its numpy equivalent.""" - if dtype not in _torch_to_np_dtype: - raise ValueError(f"Unsupported torch to numpy dtype '{dtype}'.") - return _torch_to_np_dtype[dtype] + return look_up_option(dtype, _torch_to_np_dtype) def dtype_numpy_to_torch(dtype): """Convert a numpy dtype to its torch equivalent.""" # np dtypes can be given as np.float32 and np.dtype(np.float32) so unify them dtype = np.dtype(dtype) if type(dtype) is type else dtype - if dtype not in _np_to_torch_dtype: - raise ValueError(f"Unsupported numpy to torch dtype '{dtype}'.") - return _np_to_torch_dtype[dtype] + return look_up_option(dtype, _np_to_torch_dtype) def get_equivalent_dtype(dtype, data_type): """Convert to the `dtype` that corresponds to `data_type`. - Example: + + Example:: + im = torch.tensor(1) dtype = get_equivalent_dtype(np.float32, type(im)) + """ if dtype is None: return None if data_type is torch.Tensor: if type(dtype) is torch.dtype: + # already a torch dtype and target `data_type` is torch.Tensor return dtype return dtype_numpy_to_torch(dtype) if type(dtype) is not torch.dtype: + # assuming the dtype is ok if it is not a torch dtype and target `data_type` is not torch.Tensor return dtype return dtype_torch_to_numpy(dtype) @@ -193,12 +195,11 @@ def convert_to_cupy(data, dtype, wrap_sequence: bool = True): elif isinstance(data, dict): return {k: convert_to_cupy(v, dtype) for k, v in data.items()} # make it contiguous - if isinstance(data, cp.ndarray): - if data.ndim > 0: - data = cp.ascontiguousarray(data) - else: + if not isinstance(data, cp.ndarray): raise ValueError(f"The input data type [{type(data)}] cannot be converted into cupy arrays!") + if data.ndim > 0: + data = cp.ascontiguousarray(data) return data @@ -220,6 +221,15 @@ def convert_data_type( If left blank, it remains unchanged. Returns: modified data, orig_type, orig_device + + Note: + When both `output_type` and `dtype` are specified with different backend + (e.g., `torch.Tensor` and `np.float32`), the `output_type` will be used as the primary type, + for example:: + + >>> convert_data_type(1, torch.Tensor, dtype=np.float32) + (1.0, , None) + """ orig_type: Any if isinstance(data, torch.Tensor): diff --git a/tests/test_center_scale_crop.py b/tests/test_center_scale_crop.py index e28849ce90..4c5bfc4fac 100644 --- a/tests/test_center_scale_crop.py +++ b/tests/test_center_scale_crop.py @@ -38,11 +38,13 @@ class TestCenterScaleCrop(unittest.TestCase): @parameterized.expand([TEST_CASE_0, TEST_CASE_1, TEST_CASE_3]) def test_shape(self, input_param, input_data, expected_shape): result = CenterScaleCrop(**input_param)(input_data) + self.assertEqual(isinstance(result, torch.Tensor), isinstance(input_data, torch.Tensor)) np.testing.assert_allclose(result.shape, expected_shape) @parameterized.expand([TEST_CASE_2]) def test_value(self, input_param, input_data, expected_value): result = CenterScaleCrop(**input_param)(input_data) + self.assertEqual(isinstance(result, torch.Tensor), isinstance(input_data, torch.Tensor)) np.testing.assert_allclose(result, expected_value) diff --git a/tests/test_center_spatial_crop.py b/tests/test_center_spatial_crop.py index 3e828176a5..d6a7edb305 100644 --- a/tests/test_center_spatial_crop.py +++ b/tests/test_center_spatial_crop.py @@ -38,11 +38,13 @@ class TestCenterSpatialCrop(unittest.TestCase): @parameterized.expand([TEST_CASE_0, TEST_CASE_1, TEST_CASE_3]) def test_shape(self, input_param, input_data, expected_shape): result = CenterSpatialCrop(**input_param)(input_data) + self.assertEqual(isinstance(result, torch.Tensor), isinstance(input_data, torch.Tensor)) np.testing.assert_allclose(result.shape, expected_shape) @parameterized.expand([TEST_CASE_2]) def test_value(self, input_param, input_data, expected_value): result = CenterSpatialCrop(**input_param)(input_data) + self.assertEqual(isinstance(result, torch.Tensor), isinstance(input_data, torch.Tensor)) np.testing.assert_allclose(result, expected_value) diff --git a/tests/test_center_spatial_cropd.py b/tests/test_center_spatial_cropd.py index 349253ab56..8ffcdf4387 100644 --- a/tests/test_center_spatial_cropd.py +++ b/tests/test_center_spatial_cropd.py @@ -15,36 +15,51 @@ from parameterized import parameterized from monai.transforms import CenterSpatialCropd +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_0 = [ - {"keys": "img", "roi_size": [2, -1, -1]}, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - (3, 2, 3, 3), -] +TEST_SHAPES = [] +for p in TEST_NDARRAYS: + TEST_SHAPES.append( + [ + {"keys": "img", "roi_size": [2, -1, -1]}, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + (3, 2, 3, 3), + ] + ) -TEST_CASE_1 = [ - {"keys": "img", "roi_size": [2, 2, 2]}, - {"img": np.random.randint(0, 2, size=[3, 3, 3, 3])}, - (3, 2, 2, 2), -] + TEST_SHAPES.append( + [ + {"keys": "img", "roi_size": [2, 2, 2]}, + {"img": p(np.random.randint(0, 2, size=[3, 3, 3, 3]))}, + (3, 2, 2, 2), + ] + ) -TEST_CASE_2 = [ - {"keys": "img", "roi_size": [2, 2]}, - {"img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]])}, - np.array([[[1, 2], [2, 3]]]), -] +TEST_CASES = [] +for p in TEST_NDARRAYS: + TEST_CASES.append( + [ + {"keys": "img", "roi_size": [2, 2]}, + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]) + ) + }, + p(np.array([[[1, 2], [2, 3]]])), + ] + ) class TestCenterSpatialCropd(unittest.TestCase): - @parameterized.expand([TEST_CASE_0, TEST_CASE_1]) + @parameterized.expand(TEST_SHAPES) def test_shape(self, input_param, input_data, expected_shape): result = CenterSpatialCropd(**input_param)(input_data) self.assertTupleEqual(result["img"].shape, expected_shape) - @parameterized.expand([TEST_CASE_2]) + @parameterized.expand(TEST_CASES) def test_value(self, input_param, input_data, expected_value): result = CenterSpatialCropd(**input_param)(input_data) - np.testing.assert_allclose(result["img"], expected_value) + assert_allclose(result["img"], expected_value, type_test=False) if __name__ == "__main__": diff --git a/tests/test_create_grid_and_affine.py b/tests/test_create_grid_and_affine.py index 0c0e52e04a..b53eaa5b9d 100644 --- a/tests/test_create_grid_and_affine.py +++ b/tests/test_create_grid_and_affine.py @@ -12,6 +12,7 @@ import unittest import numpy as np +import torch from monai.transforms import ( create_control_grid, @@ -21,6 +22,7 @@ create_shear, create_translate, ) +from tests.utils import assert_allclose class TestCreateGrid(unittest.TestCase): @@ -32,50 +34,47 @@ def test_create_grid(self): with self.assertRaisesRegex(TypeError, ""): create_grid((1, 1), spacing=2.0) - g = create_grid((1, 1)) - expected = np.array([[[0.0]], [[0.0]], [[1.0]]]) - np.testing.assert_allclose(g, expected) + test_assert(create_grid, ((1, 1),), np.array([[[0.0]], [[0.0]], [[1.0]]])) - g = create_grid((1, 1), homogeneous=False) - expected = np.array([[[0.0]], [[0.0]]]) - np.testing.assert_allclose(g, expected) + test_assert(create_grid, ((1, 1), None, False), np.array([[[0.0]], [[0.0]]])) - g = create_grid((1, 1), spacing=(1.2, 1.3)) - expected = np.array([[[0.0]], [[0.0]], [[1.0]]]) - np.testing.assert_allclose(g, expected) + test_assert(create_grid, ((1, 1), (1.2, 1.3)), np.array([[[0.0]], [[0.0]], [[1.0]]])) - g = create_grid((1, 1, 1), spacing=(1.2, 1.3, 1.0)) - expected = np.array([[[[0.0]]], [[[0.0]]], [[[0.0]]], [[[1.0]]]]) - np.testing.assert_allclose(g, expected) + test_assert(create_grid, ((1, 1, 1), (1.2, 1.3, 1.0)), np.array([[[[0.0]]], [[[0.0]]], [[[0.0]]], [[[1.0]]]])) - g = create_grid((1, 1, 1), spacing=(1.2, 1.3, 1.0), homogeneous=False) - expected = np.array([[[[0.0]]], [[[0.0]]], [[[0.0]]]]) - np.testing.assert_allclose(g, expected) + test_assert(create_grid, ((1, 1, 1), (1.2, 1.3, 1.0), False), np.array([[[[0.0]]], [[[0.0]]], [[[0.0]]]])) g = create_grid((1, 1, 1), spacing=(1.2, 1.3, 1.0), dtype=np.int32) np.testing.assert_equal(g.dtype, np.int32) - g = create_grid((2, 2, 2)) - expected = np.array( - [ - [[[-0.5, -0.5], [-0.5, -0.5]], [[0.5, 0.5], [0.5, 0.5]]], - [[[-0.5, -0.5], [0.5, 0.5]], [[-0.5, -0.5], [0.5, 0.5]]], - [[[-0.5, 0.5], [-0.5, 0.5]], [[-0.5, 0.5], [-0.5, 0.5]]], - [[[1.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 1.0]]], - ] + g = create_grid((1, 1, 1), spacing=(1.2, 1.3, 1.0), dtype=torch.float64, backend="torch") + np.testing.assert_equal(g.dtype, torch.float64) + + test_assert( + create_grid, + ((2, 2, 2),), + np.array( + [ + [[[-0.5, -0.5], [-0.5, -0.5]], [[0.5, 0.5], [0.5, 0.5]]], + [[[-0.5, -0.5], [0.5, 0.5]], [[-0.5, -0.5], [0.5, 0.5]]], + [[[-0.5, 0.5], [-0.5, 0.5]], [[-0.5, 0.5], [-0.5, 0.5]]], + [[[1.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 1.0]]], + ] + ), ) - np.testing.assert_allclose(g, expected) - g = create_grid((2, 2, 2), spacing=(1.2, 1.3, 1.0)) - expected = np.array( - [ - [[[-0.6, -0.6], [-0.6, -0.6]], [[0.6, 0.6], [0.6, 0.6]]], - [[[-0.65, -0.65], [0.65, 0.65]], [[-0.65, -0.65], [0.65, 0.65]]], - [[[-0.5, 0.5], [-0.5, 0.5]], [[-0.5, 0.5], [-0.5, 0.5]]], - [[[1.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 1.0]]], - ] + test_assert( + create_grid, + ((2, 2, 2), (1.2, 1.3, 1.0)), + np.array( + [ + [[[-0.6, -0.6], [-0.6, -0.6]], [[0.6, 0.6], [0.6, 0.6]]], + [[[-0.65, -0.65], [0.65, 0.65]], [[-0.65, -0.65], [0.65, 0.65]]], + [[[-0.5, 0.5], [-0.5, 0.5]], [[-0.5, 0.5], [-0.5, 0.5]]], + [[[1.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [1.0, 1.0]]], + ] + ), ) - np.testing.assert_allclose(g, expected) def test_create_control_grid(self): with self.assertRaisesRegex(TypeError, ""): @@ -83,72 +82,87 @@ def test_create_control_grid(self): with self.assertRaisesRegex(TypeError, ""): create_control_grid((1, 1), 2.0) - g = create_control_grid((1.0, 1.0), (1.0, 1.0)) - expected = np.array( - [ - [[-1.0, -1.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, 0.0, 1.0]], - [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], - ] + test_assert( + create_control_grid, + ((1.0, 1.0), (1.0, 1.0)), + np.array( + [ + [[-1.0, -1.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, 0.0, 1.0]], + [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], + ] + ), ) - np.testing.assert_allclose(g, expected) - g = create_control_grid((1.0, 1.0), (2.0, 2.0)) - expected = np.array( - [ - [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], - [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], - [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], - ] + test_assert( + create_control_grid, + ((1.0, 1.0), (2.0, 2.0)), + np.array( + [ + [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], + [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], + [[1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0]], + ] + ), ) - np.testing.assert_allclose(g, expected) - g = create_control_grid((2.0, 2.0), (1.0, 1.0)) - expected = np.array( - [ - [[-1.5, -1.5, -1.5, -1.5], [-0.5, -0.5, -0.5, -0.5], [0.5, 0.5, 0.5, 0.5], [1.5, 1.5, 1.5, 1.5]], - [[-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5]], - [[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]], - ] + test_assert( + create_control_grid, + ((2.0, 2.0), (1.0, 1.0)), + np.array( + [ + [[-1.5, -1.5, -1.5, -1.5], [-0.5, -0.5, -0.5, -0.5], [0.5, 0.5, 0.5, 0.5], [1.5, 1.5, 1.5, 1.5]], + [[-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5], [-1.5, -0.5, 0.5, 1.5]], + [[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]], + ] + ), ) - np.testing.assert_allclose(g, expected) - g = create_control_grid((2.0, 2.0), (2.0, 2.0)) - expected = np.array( - [ - [[-3.0, -3.0, -3.0, -3.0], [-1.0, -1.0, -1.0, -1.0], [1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0]], - [[-3.0, -1.0, 1.0, 3.0], [-3.0, -1.0, 1.0, 3.0], [-3.0, -1.0, 1.0, 3.0], [-3.0, -1.0, 1.0, 3.0]], - [[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]], - ] + test_assert( + create_control_grid, + ((2.0, 2.0), (2.0, 2.0)), + np.array( + [ + [[-3.0, -3.0, -3.0, -3.0], [-1.0, -1.0, -1.0, -1.0], [1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0]], + [[-3.0, -1.0, 1.0, 3.0], [-3.0, -1.0, 1.0, 3.0], [-3.0, -1.0, 1.0, 3.0], [-3.0, -1.0, 1.0, 3.0]], + [[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]], + ] + ), ) - np.testing.assert_allclose(g, expected) - g = create_control_grid((1.0, 1.0, 1.0), (2.0, 2.0, 2.0), homogeneous=False) - expected = np.array( - [ - [ - [[-2.0, -2.0, -2.0], [-2.0, -2.0, -2.0], [-2.0, -2.0, -2.0]], - [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - [[2.0, 2.0, 2.0], [2.0, 2.0, 2.0], [2.0, 2.0, 2.0]], - ], - [ - [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], - [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], - [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], - ], + test_assert( + create_control_grid, + ((1.0, 1.0, 1.0), (2.0, 2.0, 2.0), False), + np.array( [ - [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], - [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], - [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], - ], - ] + [ + [[-2.0, -2.0, -2.0], [-2.0, -2.0, -2.0], [-2.0, -2.0, -2.0]], + [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], + [[2.0, 2.0, 2.0], [2.0, 2.0, 2.0], [2.0, 2.0, 2.0]], + ], + [ + [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], + [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], + [[-2.0, -2.0, -2.0], [0.0, 0.0, 0.0], [2.0, 2.0, 2.0]], + ], + [ + [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], + [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], + [[-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0], [-2.0, 0.0, 2.0]], + ], + ] + ), ) - np.testing.assert_allclose(g, expected) def test_assert(func, params, expected): - m = func(*params) - np.testing.assert_allclose(m, expected, atol=1e-7) + gpu_test = ("torch_gpu",) if torch.cuda.is_available() else () + for b in ("torch", "numpy") + gpu_test: + if b == "torch_gpu": + m = func(*params, device="cuda:0", backend="torch") + else: + m = func(*params, backend=b) + assert_allclose(m, expected, type_test=False, atol=1e-7) class TestCreateAffine(unittest.TestCase): diff --git a/tests/test_get_equivalent_dtype.py b/tests/test_get_equivalent_dtype.py index 04ba5ae5fb..de2379b15b 100644 --- a/tests/test_get_equivalent_dtype.py +++ b/tests/test_get_equivalent_dtype.py @@ -32,6 +32,14 @@ def test_get_equivalent_dtype(self, im, input_dtype): out_dtype = get_equivalent_dtype(input_dtype, type(im)) self.assertEqual(out_dtype, im.dtype) + def test_native_type(self): + """the get_equivalent_dtype currently doesn't change the build-in type""" + n_type = [float, int, bool] + for n in n_type: + for im_dtype in DTYPES: + out_dtype = get_equivalent_dtype(n, type(im_dtype)) + self.assertEqual(out_dtype, n) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_rand_deform_grid.py b/tests/test_rand_deform_grid.py index 7c12c263d2..4725e28339 100644 --- a/tests/test_rand_deform_grid.py +++ b/tests/test_rand_deform_grid.py @@ -12,10 +12,10 @@ import unittest import numpy as np -import torch from parameterized import parameterized from monai.transforms import RandDeformGrid +from tests.utils import assert_allclose TEST_CASES = [ [ @@ -129,11 +129,7 @@ def test_rand_deform_grid(self, input_param, input_data, expected_val): g = RandDeformGrid(**input_param) g.set_random_state(123) result = g(**input_data) - self.assertEqual(isinstance(result, torch.Tensor), isinstance(expected_val, torch.Tensor)) - if isinstance(result, torch.Tensor): - np.testing.assert_allclose(result.cpu().numpy(), expected_val.cpu().numpy(), rtol=1e-4, atol=1e-4) - else: - np.testing.assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, type_test=False, rtol=1e-3, atol=1e-3) if __name__ == "__main__": diff --git a/tests/test_rand_scale_crop.py b/tests/test_rand_scale_crop.py index db5487ebff..a0c5471ffb 100644 --- a/tests/test_rand_scale_crop.py +++ b/tests/test_rand_scale_crop.py @@ -15,6 +15,7 @@ from parameterized import parameterized from monai.transforms import RandScaleCrop +from tests.utils import TEST_NDARRAYS, assert_allclose TEST_CASE_1 = [ {"roi_scale": [1.0, 1.0, -1.0], "random_center": True}, @@ -55,22 +56,25 @@ class TestRandScaleCrop(unittest.TestCase): @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) def test_shape(self, input_param, input_data, expected_shape): - result = RandScaleCrop(**input_param)(input_data) - self.assertTupleEqual(result.shape, expected_shape) + for p in TEST_NDARRAYS: + result = RandScaleCrop(**input_param)(p(input_data)) + self.assertTupleEqual(result.shape, expected_shape) @parameterized.expand([TEST_CASE_3]) def test_value(self, input_param, input_data): - cropper = RandScaleCrop(**input_param) - result = cropper(input_data) - roi = [(2 - i // 2, 2 + i - i // 2) for i in cropper._size] - np.testing.assert_allclose(result, input_data[:, roi[0][0] : roi[0][1], roi[1][0] : roi[1][1]]) + for p in TEST_NDARRAYS: + cropper = RandScaleCrop(**input_param) + result = cropper(p(input_data)) + roi = [(2 - i // 2, 2 + i - i // 2) for i in cropper._size] + assert_allclose(result, input_data[:, roi[0][0] : roi[0][1], roi[1][0] : roi[1][1]], type_test=False) @parameterized.expand([TEST_CASE_4, TEST_CASE_5, TEST_CASE_6]) def test_random_shape(self, input_param, input_data, expected_shape): - cropper = RandScaleCrop(**input_param) - cropper.set_random_state(seed=123) - result = cropper(input_data) - self.assertTupleEqual(result.shape, expected_shape) + for p in TEST_NDARRAYS: + cropper = RandScaleCrop(**input_param) + cropper.set_random_state(seed=123) + result = cropper(p(input_data)) + self.assertTupleEqual(result.shape, expected_shape) if __name__ == "__main__": diff --git a/tests/test_rand_scale_cropd.py b/tests/test_rand_scale_cropd.py index 265c6c467d..f78a81d339 100644 --- a/tests/test_rand_scale_cropd.py +++ b/tests/test_rand_scale_cropd.py @@ -15,6 +15,7 @@ from parameterized import parameterized from monai.transforms import RandScaleCropd +from tests.utils import TEST_NDARRAYS, assert_allclose TEST_CASE_1 = [ {"keys": "img", "roi_scale": [1.0, 1.0, -1.0], "random_center": True}, @@ -66,10 +67,14 @@ def test_shape(self, input_param, input_data, expected_shape): @parameterized.expand([TEST_CASE_3]) def test_value(self, input_param, input_data): - cropper = RandScaleCropd(**input_param) - result = cropper(input_data) - roi = [(2 - i // 2, 2 + i - i // 2) for i in cropper._size] - np.testing.assert_allclose(result["img"], input_data["img"][:, roi[0][0] : roi[0][1], roi[1][0] : roi[1][1]]) + for p in TEST_NDARRAYS: + cropper = RandScaleCropd(**input_param) + input_data["img"] = p(input_data["img"]) + result = cropper(input_data) + roi = [(2 - i // 2, 2 + i - i // 2) for i in cropper._size] + assert_allclose( + result["img"], input_data["img"][:, roi[0][0] : roi[0][1], roi[1][0] : roi[1][1]], type_test=False + ) @parameterized.expand([TEST_CASE_4, TEST_CASE_5, TEST_CASE_6]) def test_random_shape(self, input_param, input_data, expected_shape): diff --git a/tests/test_rand_spatial_crop.py b/tests/test_rand_spatial_crop.py index 01e057e589..19b1841c6d 100644 --- a/tests/test_rand_spatial_crop.py +++ b/tests/test_rand_spatial_crop.py @@ -15,6 +15,7 @@ from parameterized import parameterized from monai.transforms import RandSpatialCrop +from tests.utils import TEST_NDARRAYS, assert_allclose TEST_CASE_0 = [ {"roi_size": [3, 3, -1], "random_center": True}, @@ -56,10 +57,11 @@ def test_shape(self, input_param, input_data, expected_shape): @parameterized.expand([TEST_CASE_3]) def test_value(self, input_param, input_data): - cropper = RandSpatialCrop(**input_param) - result = cropper(input_data) - roi = [(2 - i // 2, 2 + i - i // 2) for i in cropper._size] - np.testing.assert_allclose(result, input_data[:, roi[0][0] : roi[0][1], roi[1][0] : roi[1][1]]) + for p in TEST_NDARRAYS: + cropper = RandSpatialCrop(**input_param) + result = cropper(p(input_data)) + roi = [(2 - i // 2, 2 + i - i // 2) for i in cropper._size] + assert_allclose(result, input_data[:, roi[0][0] : roi[0][1], roi[1][0] : roi[1][1]], type_test=False) @parameterized.expand([TEST_CASE_4, TEST_CASE_5]) def test_random_shape(self, input_param, input_data, expected_shape): diff --git a/tests/test_rand_spatial_crop_samples.py b/tests/test_rand_spatial_crop_samples.py index 0ade9bbbba..eefe7d0e0a 100644 --- a/tests/test_rand_spatial_crop_samples.py +++ b/tests/test_rand_spatial_crop_samples.py @@ -15,6 +15,7 @@ from parameterized import parameterized from monai.transforms import RandSpatialCropSamples +from tests.utils import TEST_NDARRAYS, assert_allclose TEST_CASE_1 = [ {"roi_size": [3, 3, 3], "num_samples": 4, "random_center": True, "random_size": False}, @@ -70,14 +71,15 @@ class TestRandSpatialCropSamples(unittest.TestCase): @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) def test_shape(self, input_param, input_data, expected_shape, expected_last_item): - xform = RandSpatialCropSamples(**input_param) - xform.set_random_state(1234) - result = xform(input_data) + for p in TEST_NDARRAYS: + xform = RandSpatialCropSamples(**input_param) + xform.set_random_state(1234) + result = xform(p(input_data)) - np.testing.assert_equal(len(result), input_param["num_samples"]) - for item, expected in zip(result, expected_shape): - self.assertTupleEqual(item.shape, expected) - np.testing.assert_allclose(result[-1], expected_last_item) + np.testing.assert_equal(len(result), input_param["num_samples"]) + for item, expected in zip(result, expected_shape): + self.assertTupleEqual(item.shape, expected) + assert_allclose(result[-1], expected_last_item, type_test=False) if __name__ == "__main__": diff --git a/tests/test_rand_spatial_crop_samplesd.py b/tests/test_rand_spatial_crop_samplesd.py index 3f5eee7b27..4b41ce3344 100644 --- a/tests/test_rand_spatial_crop_samplesd.py +++ b/tests/test_rand_spatial_crop_samplesd.py @@ -15,6 +15,7 @@ from parameterized import parameterized from monai.transforms import Compose, RandSpatialCropSamplesd, ToTensord +from tests.utils import TEST_NDARRAYS, assert_allclose TEST_CASE_1 = [ {"keys": ["img", "seg"], "num_samples": 4, "roi_size": [2, 2, 2], "random_center": True}, @@ -38,31 +39,48 @@ }, ] -TEST_CASE_2 = [ - {"keys": ["img", "seg"], "num_samples": 8, "roi_size": [2, 2, 3], "random_center": False}, - {"img": np.arange(81).reshape(3, 3, 3, 3), "seg": np.arange(81, 0, -1).reshape(3, 3, 3, 3)}, - [(3, 3, 3, 3), (3, 2, 3, 3), (3, 2, 2, 3), (3, 2, 3, 3), (3, 3, 3, 3), (3, 3, 3, 3), (3, 2, 2, 3), (3, 3, 2, 3)], - { - "img": np.array( +TEST_CASE_2 = [] +for p in TEST_NDARRAYS: + TEST_CASE_2.append( + [ + {"keys": ["img", "seg"], "num_samples": 8, "roi_size": [2, 2, 3], "random_center": False}, + {"img": p(np.arange(81).reshape(3, 3, 3, 3)), "seg": p(np.arange(81, 0, -1).reshape(3, 3, 3, 3))}, [ - [[[0, 1, 2], [3, 4, 5]], [[9, 10, 11], [12, 13, 14]], [[18, 19, 20], [21, 22, 23]]], - [[[27, 28, 29], [30, 31, 32]], [[36, 37, 38], [39, 40, 41]], [[45, 46, 47], [48, 49, 50]]], - [[[54, 55, 56], [57, 58, 59]], [[63, 64, 65], [66, 67, 68]], [[72, 73, 74], [75, 76, 77]]], - ] - ), - "seg": np.array( - [ - [[[81, 80, 79], [78, 77, 76]], [[72, 71, 70], [69, 68, 67]], [[63, 62, 61], [60, 59, 58]]], - [[[54, 53, 52], [51, 50, 49]], [[45, 44, 43], [42, 41, 40]], [[36, 35, 34], [33, 32, 31]]], - [[[27, 26, 25], [24, 23, 22]], [[18, 17, 16], [15, 14, 13]], [[9, 8, 7], [6, 5, 4]]], - ] - ), - }, -] + (3, 3, 3, 3), + (3, 2, 3, 3), + (3, 2, 2, 3), + (3, 2, 3, 3), + (3, 3, 3, 3), + (3, 3, 3, 3), + (3, 2, 2, 3), + (3, 3, 2, 3), + ], + { + "img": p( + np.array( + [ + [[[0, 1, 2], [3, 4, 5]], [[9, 10, 11], [12, 13, 14]], [[18, 19, 20], [21, 22, 23]]], + [[[27, 28, 29], [30, 31, 32]], [[36, 37, 38], [39, 40, 41]], [[45, 46, 47], [48, 49, 50]]], + [[[54, 55, 56], [57, 58, 59]], [[63, 64, 65], [66, 67, 68]], [[72, 73, 74], [75, 76, 77]]], + ] + ) + ), + "seg": p( + np.array( + [ + [[[81, 80, 79], [78, 77, 76]], [[72, 71, 70], [69, 68, 67]], [[63, 62, 61], [60, 59, 58]]], + [[[54, 53, 52], [51, 50, 49]], [[45, 44, 43], [42, 41, 40]], [[36, 35, 34], [33, 32, 31]]], + [[[27, 26, 25], [24, 23, 22]], [[18, 17, 16], [15, 14, 13]], [[9, 8, 7], [6, 5, 4]]], + ] + ) + ), + }, + ] + ) class TestRandSpatialCropSamplesd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) + @parameterized.expand([TEST_CASE_1, *TEST_CASE_2]) def test_shape(self, input_param, input_data, expected_shape, expected_last): xform = RandSpatialCropSamplesd(**input_param) xform.set_random_state(1234) @@ -73,8 +91,8 @@ def test_shape(self, input_param, input_data, expected_shape, expected_last): for i, item in enumerate(result): self.assertEqual(item["img_meta_dict"]["patch_index"], i) self.assertEqual(item["seg_meta_dict"]["patch_index"], i) - np.testing.assert_allclose(item["img"], expected_last["img"]) - np.testing.assert_allclose(item["seg"], expected_last["seg"]) + assert_allclose(item["img"], expected_last["img"], type_test=True) + assert_allclose(item["seg"], expected_last["seg"], type_test=True) def test_deep_copy(self): data = {"img": np.ones((1, 10, 11, 12))} diff --git a/tests/test_rand_spatial_cropd.py b/tests/test_rand_spatial_cropd.py index 610c1974aa..edcb61dc99 100644 --- a/tests/test_rand_spatial_cropd.py +++ b/tests/test_rand_spatial_cropd.py @@ -15,6 +15,7 @@ from parameterized import parameterized from monai.transforms import RandSpatialCropd +from tests.utils import TEST_NDARRAYS TEST_CASE_0 = [ {"keys": "img", "roi_size": [3, 3, -1], "random_center": True}, @@ -67,10 +68,12 @@ def test_value(self, input_param, input_data): @parameterized.expand([TEST_CASE_4, TEST_CASE_5]) def test_random_shape(self, input_param, input_data, expected_shape): - cropper = RandSpatialCropd(**input_param) - cropper.set_random_state(seed=123) - result = cropper(input_data) - self.assertTupleEqual(result["img"].shape, expected_shape) + for p in TEST_NDARRAYS: + cropper = RandSpatialCropd(**input_param) + cropper.set_random_state(seed=123) + input_data["img"] = p(input_data["img"]) + result = cropper(input_data) + self.assertTupleEqual(result["img"].shape, expected_shape) if __name__ == "__main__": diff --git a/tests/test_resize.py b/tests/test_resize.py index e5ec5dd1a9..f6c4a8b14b 100644 --- a/tests/test_resize.py +++ b/tests/test_resize.py @@ -16,7 +16,7 @@ from parameterized import parameterized from monai.transforms import Resize -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose TEST_CASE_0 = [{"spatial_size": 15}, (6, 10, 15)] @@ -45,16 +45,22 @@ def test_correct_results(self, spatial_size, mode): _order = 1 if spatial_size == (32, -1): spatial_size = (32, 64) - expected = [] - for channel in self.imt[0]: - expected.append( - skimage.transform.resize( - channel, spatial_size, order=_order, clip=False, preserve_range=False, anti_aliasing=False - ) + expected = [ + skimage.transform.resize( + channel, + spatial_size, + order=_order, + clip=False, + preserve_range=False, + anti_aliasing=False, ) + for channel in self.imt[0] + ] + expected = np.stack(expected).astype(np.float32) - out = resize(self.imt[0]) - np.testing.assert_allclose(out, expected, atol=0.9) + for p in TEST_NDARRAYS: + out = resize(p(self.imt[0])) + assert_allclose(out, expected, type_test=False, atol=0.9) @parameterized.expand([TEST_CASE_0, TEST_CASE_1, TEST_CASE_2]) def test_longest_shape(self, input_param, expected_shape): diff --git a/tests/test_resize_with_pad_or_crop.py b/tests/test_resize_with_pad_or_crop.py index 46f1fc86cc..2162a0bb1b 100644 --- a/tests/test_resize_with_pad_or_crop.py +++ b/tests/test_resize_with_pad_or_crop.py @@ -12,9 +12,11 @@ import unittest import numpy as np +import torch from parameterized import parameterized from monai.transforms import ResizeWithPadOrCrop +from tests.utils import TEST_NDARRAYS TEST_CASES = [ [ @@ -48,11 +50,16 @@ class TestResizeWithPadOrCrop(unittest.TestCase): @parameterized.expand(TEST_CASES) def test_pad_shape(self, input_param, input_shape, expected_shape): - paddcroper = ResizeWithPadOrCrop(**input_param) - result = paddcroper(np.zeros(input_shape)) - np.testing.assert_allclose(result.shape, expected_shape) - result = paddcroper(np.zeros(input_shape), mode="constant") - np.testing.assert_allclose(result.shape, expected_shape) + for p in TEST_NDARRAYS: + if isinstance(p(0), torch.Tensor) and ( + "constant_values" in input_param or input_param["mode"] == "reflect" + ): + continue + paddcroper = ResizeWithPadOrCrop(**input_param) + result = paddcroper(p(np.zeros(input_shape))) + np.testing.assert_allclose(result.shape, expected_shape) + result = paddcroper(p(np.zeros(input_shape)), mode="constant") + np.testing.assert_allclose(result.shape, expected_shape) if __name__ == "__main__": diff --git a/tests/test_resize_with_pad_or_cropd.py b/tests/test_resize_with_pad_or_cropd.py index 32a62a9e16..58f6c92a8f 100644 --- a/tests/test_resize_with_pad_or_cropd.py +++ b/tests/test_resize_with_pad_or_cropd.py @@ -12,9 +12,11 @@ import unittest import numpy as np +import torch from parameterized import parameterized from monai.transforms import ResizeWithPadOrCropd +from tests.utils import TEST_NDARRAYS TEST_CASES = [ [ @@ -48,9 +50,15 @@ class TestResizeWithPadOrCropd(unittest.TestCase): @parameterized.expand(TEST_CASES) def test_pad_shape(self, input_param, input_data, expected_val): - paddcroper = ResizeWithPadOrCropd(**input_param) - result = paddcroper(input_data) - np.testing.assert_allclose(result["img"].shape, expected_val) + for p in TEST_NDARRAYS: + if isinstance(p(0), torch.Tensor) and ( + "constant_values" in input_param or input_param["mode"] == "reflect" + ): + continue + paddcroper = ResizeWithPadOrCropd(**input_param) + input_data["img"] = p(input_data["img"]) + result = paddcroper(input_data) + np.testing.assert_allclose(result["img"].shape, expected_val) if __name__ == "__main__": diff --git a/tests/test_resized.py b/tests/test_resized.py index 930faf00eb..47b8e8a704 100644 --- a/tests/test_resized.py +++ b/tests/test_resized.py @@ -16,7 +16,7 @@ from parameterized import parameterized from monai.transforms import Resized -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose TEST_CASE_0 = [{"keys": "img", "spatial_size": 15}, (6, 10, 15)] @@ -48,16 +48,22 @@ def test_correct_results(self, spatial_size, mode): _order = 1 if spatial_size == (32, -1): spatial_size = (32, 64) - expected = [] - for channel in self.imt[0]: - expected.append( - skimage.transform.resize( - channel, spatial_size, order=_order, clip=False, preserve_range=False, anti_aliasing=False - ) + expected = [ + skimage.transform.resize( + channel, + spatial_size, + order=_order, + clip=False, + preserve_range=False, + anti_aliasing=False, ) + for channel in self.imt[0] + ] + expected = np.stack(expected).astype(np.float32) - out = resize({"img": self.imt[0]})["img"] - np.testing.assert_allclose(out, expected, atol=0.9) + for p in TEST_NDARRAYS: + out = resize({"img": p(self.imt[0])})["img"] + assert_allclose(out, expected, type_test=False, atol=0.9) @parameterized.expand([TEST_CASE_0, TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) def test_longest_shape(self, input_param, expected_shape): From e2e5e31e3c20bec10e39bcba8071ca661650040f Mon Sep 17 00:00:00 2001 From: Behrooz <3968947+drbeh@users.noreply.github.com> Date: Mon, 20 Sep 2021 11:35:59 -0400 Subject: [PATCH 35/89] Add make the name of wsi reader lowercase (#2973) Signed-off-by: Behrooz <3968947+drbeh@users.noreply.github.com> --- monai/apps/pathology/data/datasets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monai/apps/pathology/data/datasets.py b/monai/apps/pathology/data/datasets.py index 3694ca4144..d86781f4c5 100644 --- a/monai/apps/pathology/data/datasets.py +++ b/monai/apps/pathology/data/datasets.py @@ -64,7 +64,7 @@ def __init__( self.patch_size = ensure_tuple_rep(patch_size, 2) self.image_path_list = list({x["image"] for x in self.data}) - self.image_reader_name = image_reader_name + self.image_reader_name = image_reader_name.lower() self.image_reader = WSIReader(image_reader_name) self.wsi_object_dict = None if self.image_reader_name != "openslide": @@ -190,7 +190,7 @@ def __init__( self.patch_size = ensure_tuple_rep(patch_size, 2) # set up whole slide image reader - self.image_reader_name = image_reader_name + self.image_reader_name = image_reader_name.lower() self.image_reader = WSIReader(image_reader_name) # process data and create a list of dictionaries containing all required data and metadata From 731bad89cfd8fa1bbd702c0d1e079f14037745a5 Mon Sep 17 00:00:00 2001 From: Ali Hatamizadeh Date: Mon, 20 Sep 2021 10:20:56 -0700 Subject: [PATCH 36/89] update multimodal doc and model names (Transchex) (#2979) * update multimodal doc and model names (Transchex) Signed-off-by: ahatamizadeh --- docs/source/networks.rst | 4 ++-- monai/networks/nets/__init__.py | 10 +--------- .../nets/{vltransformer.py => transchex.py} | 11 ++++++----- tests/min_tests.py | 2 +- tests/{test_vltransformer.py => test_transchex.py} | 14 +++++++------- 5 files changed, 17 insertions(+), 24 deletions(-) rename monai/networks/nets/{vltransformer.py => transchex.py} (98%) rename tests/{test_vltransformer.py => test_transchex.py} (90%) diff --git a/docs/source/networks.rst b/docs/source/networks.rst index 1020ff1026..36d62752d4 100644 --- a/docs/source/networks.rst +++ b/docs/source/networks.rst @@ -500,9 +500,9 @@ Nets .. autoclass:: Critic :members: -`VLTransformers` +`Transchex` ~~~~~~~~~~~~~~~~ -.. autoclass:: VLTransformers +.. autoclass:: Transchex :members: `NetAdapter` diff --git a/monai/networks/nets/__init__.py b/monai/networks/nets/__init__.py index 0ddda1d6dd..6076fcbe3d 100644 --- a/monai/networks/nets/__init__.py +++ b/monai/networks/nets/__init__.py @@ -80,17 +80,9 @@ seresnext101, ) from .torchvision_fc import TorchVisionFCModel, TorchVisionFullyConvModel +from .transchex import BertAttention, BertMixedLayer, BertOutput, BertPreTrainedModel, MultiModal, Pooler, Transchex from .unet import UNet, Unet, unet from .unetr import UNETR from .varautoencoder import VarAutoEncoder from .vit import ViT -from .vltransformer import ( - BertAttention, - BertMixedLayer, - BertOutput, - BertPreTrainedModel, - MultiModal, - Pooler, - VLTransformers, -) from .vnet import VNet diff --git a/monai/networks/nets/vltransformer.py b/monai/networks/nets/transchex.py similarity index 98% rename from monai/networks/nets/vltransformer.py rename to monai/networks/nets/transchex.py index 23a1a39ded..1ec5039e6a 100644 --- a/monai/networks/nets/vltransformer.py +++ b/monai/networks/nets/transchex.py @@ -34,7 +34,7 @@ "BertMixedLayer", "Pooler", "MultiModal", - "VLTransformers", + "Transchex", ] @@ -266,9 +266,10 @@ def forward(self, input_ids, token_type_ids=None, vision_feats=None, attention_m return hidden_state_mixed -class VLTransformers(torch.nn.Module): +class Transchex(torch.nn.Module): """ - Vision Language Multimodal Transformers + TransChex based on: "Hatamizadeh et al.,TransCheX: Self-Supervised Pretraining of Vision-Language + Transformers for Chest X-ray Analysis" """ def __init__( @@ -321,7 +322,7 @@ def __init__( # for 3-channel with image size of (224,224), patch size of (32,32), 3 classes, 2 language layers, # 2 vision layers, 2 mixed modality layers and dropout of 0.2 in the classification head - net = VLTransformers(in_channels=3, + net = Transchex(in_channels=3, img_size=(224, 224), num_classes=3, num_language_layers=2, @@ -330,7 +331,7 @@ def __init__( drop_out=0.2) """ - super(VLTransformers, self).__init__() + super(Transchex, self).__init__() bert_config = { "attention_probs_dropout_prob": attention_probs_dropout_prob, "classifier_dropout": None, diff --git a/tests/min_tests.py b/tests/min_tests.py index bac6521889..f47a06b3bb 100644 --- a/tests/min_tests.py +++ b/tests/min_tests.py @@ -140,7 +140,7 @@ def run_testsuit(): "test_zoom", "test_zoom_affine", "test_zoomd", - "test_vltransformer", + "test_transchex", ] assert sorted(exclude_cases) == sorted(set(exclude_cases)), f"Duplicated items in {exclude_cases}" diff --git a/tests/test_vltransformer.py b/tests/test_transchex.py similarity index 90% rename from tests/test_vltransformer.py rename to tests/test_transchex.py index a92a9bf79a..716d3cc52e 100644 --- a/tests/test_vltransformer.py +++ b/tests/test_transchex.py @@ -15,9 +15,9 @@ from parameterized import parameterized from monai.networks import eval_mode -from monai.networks.nets.vltransformer import VLTransformers +from monai.networks.nets.transchex import Transchex -TEST_CASE_VLTransformers = [] +TEST_CASE_TRANSCHEX = [] for drop_out in [0.4]: for in_channels in [3]: for img_size in [224]: @@ -39,20 +39,20 @@ }, (2, num_classes), # type: ignore ] - TEST_CASE_VLTransformers.append(test_case) + TEST_CASE_TRANSCHEX.append(test_case) class TestPatchEmbeddingBlock(unittest.TestCase): - @parameterized.expand(TEST_CASE_VLTransformers) + @parameterized.expand(TEST_CASE_TRANSCHEX) def test_shape(self, input_param, expected_shape): - net = VLTransformers(**input_param) + net = Transchex(**input_param) with eval_mode(net): result = net(torch.randint(2, (2, 512)), torch.randint(2, (2, 512)), torch.randn((2, 3, 224, 224))) self.assertEqual(result.shape, expected_shape) def test_ill_arg(self): with self.assertRaises(ValueError): - VLTransformers( + Transchex( in_channels=3, img_size=(128, 128), patch_size=(16, 16), @@ -64,7 +64,7 @@ def test_ill_arg(self): ) with self.assertRaises(ValueError): - VLTransformers( + Transchex( in_channels=1, img_size=(97, 97), patch_size=(16, 16), From f786957caff0bad25a167fad200f57eefdd37cf2 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Mon, 20 Sep 2021 21:50:51 +0100 Subject: [PATCH 37/89] 2914 remove the deprecated API for v0.7 (#2981) * remove deprecated Signed-off-by: Wenqi Li * min-test list Signed-off-by: Wenqi Li * preserves tests from tests/test_handler_transform_inverter.py Signed-off-by: Wenqi Li --- docs/source/handlers.rst | 5 - monai/handlers/__init__.py | 10 +- monai/handlers/segmentation_saver.py | 2 +- monai/handlers/transform_inverter.py | 144 --------------------- monai/handlers/utils.py | 78 +----------- monai/networks/nets/netadapter.py | 3 + monai/networks/nets/resnet.py | 4 + monai/transforms/post/array.py | 6 + monai/transforms/post/dictionary.py | 3 + monai/transforms/spatial/array.py | 27 ++++ monai/transforms/spatial/dictionary.py | 16 +++ tests/min_tests.py | 1 - tests/test_handler_transform_inverter.py | 152 ----------------------- tests/test_invertd.py | 72 ++++++++++- 14 files changed, 129 insertions(+), 394 deletions(-) delete mode 100644 monai/handlers/transform_inverter.py delete mode 100644 tests/test_handler_transform_inverter.py diff --git a/docs/source/handlers.rst b/docs/source/handlers.rst index 5caccc6b4b..cb4333d1da 100644 --- a/docs/source/handlers.rst +++ b/docs/source/handlers.rst @@ -150,11 +150,6 @@ GarbageCollector handler .. autoclass:: GarbageCollector :members: -Transform inverter ------------------- -.. autoclass:: TransformInverter - :members: - Post processing --------------- .. autoclass:: PostProcessing diff --git a/monai/handlers/__init__.py b/monai/handlers/__init__.py index c9eecc6d46..bf1a9d3f89 100644 --- a/monai/handlers/__init__.py +++ b/monai/handlers/__init__.py @@ -32,13 +32,5 @@ from .stats_handler import StatsHandler from .surface_distance import SurfaceDistance from .tensorboard_handlers import TensorBoardHandler, TensorBoardImageHandler, TensorBoardStatsHandler -from .transform_inverter import TransformInverter -from .utils import ( - evenly_divisible_all_gather, - from_engine, - stopping_fn_from_loss, - stopping_fn_from_metric, - string_list_all_gather, - write_metrics_reports, -) +from .utils import from_engine, stopping_fn_from_loss, stopping_fn_from_metric, write_metrics_reports from .validation_handler import ValidationHandler diff --git a/monai/handlers/segmentation_saver.py b/monai/handlers/segmentation_saver.py index 535f58945b..27b2cbc039 100644 --- a/monai/handlers/segmentation_saver.py +++ b/monai/handlers/segmentation_saver.py @@ -26,7 +26,7 @@ Engine, _ = optional_import("ignite.engine", IgniteInfo.OPT_IMPORT_VERSION, min_version, "Engine") -@deprecated(since="0.6.0", removed="0.7.0", msg_suffix="Please consider using `SaveImage[d]` transform instead.") +@deprecated(since="0.6.0", removed="0.8.0", msg_suffix="Please consider using `SaveImage[d]` transform instead.") class SegmentationSaver: """ Event handler triggered on completing every iteration to save the segmentation predictions into files. diff --git a/monai/handlers/transform_inverter.py b/monai/handlers/transform_inverter.py deleted file mode 100644 index 83b5f56396..0000000000 --- a/monai/handlers/transform_inverter.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2020 - 2021 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 warnings -from typing import TYPE_CHECKING, Callable, Optional, Sequence, Union - -import torch - -from monai.config import IgniteInfo, KeysCollection -from monai.engines.utils import CommonKeys, IterationEvents -from monai.transforms import Invertd, InvertibleTransform -from monai.utils import deprecated, ensure_tuple, ensure_tuple_rep, min_version, optional_import - -Events, _ = optional_import("ignite.engine", IgniteInfo.OPT_IMPORT_VERSION, min_version, "Events") -if TYPE_CHECKING: - from ignite.engine import Engine -else: - Engine, _ = optional_import("ignite.engine", IgniteInfo.OPT_IMPORT_VERSION, min_version, "Engine") - - -@deprecated(since="0.6.0", removed="0.7.0", msg_suffix="Please consider using `Invertd` transform instead.") -class TransformInverter: - """ - Ignite handler to automatically invert `transforms`. - It takes `engine.state.output` as the input data and uses the transforms information from `engine.state.batch`. - Expect both `engine.state.output` and `engine.state.batch` to be list of dictionaries data. - The inverted data is in-place saved back to `engine.state.output` with key: "{output_key}". - And the inverted meta dict will be stored in `engine.state.batch` - with key: "{meta_keys}" or "{key}_{meta_key_postfix}". - - .. deprecated:: 0.6.0 - Use :class:`monai.transforms.Invertd` instead. - - """ - - def __init__( - self, - transform: InvertibleTransform, - output_keys: KeysCollection = CommonKeys.PRED, - batch_keys: KeysCollection = CommonKeys.IMAGE, - meta_keys: Optional[KeysCollection] = None, - batch_meta_keys: Optional[KeysCollection] = None, - meta_key_postfix: str = "meta_dict", - nearest_interp: Union[bool, Sequence[bool]] = True, - to_tensor: Union[bool, Sequence[bool]] = True, - device: Union[Union[str, torch.device], Sequence[Union[str, torch.device]]] = "cpu", - post_func: Union[Callable, Sequence[Callable]] = lambda x: x, - num_workers: Optional[int] = 0, - ) -> None: - """ - Args: - transform: a callable data transform on input data. - output_keys: the key of expected data in `ignite.engine.output`, invert transforms on it. - it also can be a list of keys, will invert transform for each of them. - Default to "pred". it's in-place operation. - batch_keys: the key of input data in `ignite.engine.batch`. will get the applied transforms - for this input data, then invert them for the expected data with `output_keys`. - It can also be a list of keys, each matches to the `output_keys` data. default to "image". - meta_keys: explicitly indicate the key for the inverted meta data dictionary. - the meta data is a dictionary object which contains: filename, original_shape, etc. - it can be a sequence of string, map to the `keys`. - if None, will try to construct meta_keys by `{key}_{meta_key_postfix}`. - batch_meta_keys: the key of the meta data of input data in `ignite.engine.batch`, - will get the `affine`, `data_shape`, etc. - the meta data is a dictionary object which contains: filename, original_shape, etc. - it can be a sequence of string, map to the `keys`. - if None, will try to construct meta_keys by `{orig_key}_{meta_key_postfix}`. - meta data will also be inverted and stored in `meta_keys`. - meta_key_postfix: if `orig_meta_keys` is None, use `{orig_key}_{meta_key_postfix}` to to fetch the - meta data from dict, if `meta_keys` is None, use `{key}_{meta_key_postfix}`. - default is `meta_dict`, the meta data is a dictionary object. - For example, to handle orig_key `image`, read/write `affine` matrices from the - metadata `image_meta_dict` dictionary's `affine` field. - the inverted meta dict will be stored with key: "{key}_{meta_key_postfix}". - nearest_interp: whether to use `nearest` interpolation mode when inverting the spatial transforms, - default to `True`. If `False`, use the same interpolation mode as the original transform. - it also can be a list of bool, each matches to the `output_keys` data. - to_tensor: whether to convert the inverted data into PyTorch Tensor first, default to `True`. - it also can be a list of bool, each matches to the `output_keys` data. - device: if converted to Tensor, move the inverted results to target device before `post_func`, - default to "cpu", it also can be a list of string or `torch.device`, - each matches to the `output_keys` data. - post_func: post processing for the inverted data, should be a callable function. - it also can be a list of callable, each matches to the `output_keys` data. - - """ - self.inverter = Invertd( - keys=output_keys, - transform=transform, - orig_keys=batch_keys, - meta_keys=meta_keys, - orig_meta_keys=batch_meta_keys, - meta_key_postfix=meta_key_postfix, - nearest_interp=nearest_interp, - to_tensor=to_tensor, - device=device, - post_func=post_func, - ) - self.output_keys = ensure_tuple(output_keys) - self.meta_keys = ensure_tuple_rep(None, len(self.output_keys)) if meta_keys is None else ensure_tuple(meta_keys) - if len(self.output_keys) != len(self.meta_keys): - raise ValueError("meta_keys should have the same length as output_keys.") - self.meta_key_postfix = ensure_tuple_rep(meta_key_postfix, len(self.output_keys)) - - def attach(self, engine: Engine) -> None: - """ - Args: - engine: Ignite Engine, it can be a trainer, validator or evaluator. - """ - engine.add_event_handler(IterationEvents.MODEL_COMPLETED, self) - - def __call__(self, engine: Engine) -> None: - """ - Args: - engine: Ignite Engine, it can be a trainer, validator or evaluator. - """ - if not isinstance(engine.state.batch, list) or not isinstance(engine.state.output, list): - warnings.warn("inverter requires `engine.state.batch` and `engine.state.output` to be lists.") - else: - for i, (b, o) in enumerate(zip(engine.state.batch, engine.state.output)): - # combine `batch` and `output` to temporarily act as 1 dict for postprocessing - data = dict(b) - data.update(o) - ret = self.inverter(data) - - for output_key, meta_key, meta_key_postfix in zip( - self.output_keys, self.meta_keys, self.meta_key_postfix - ): - # save the inverted data into state.output - engine.state.output[i][output_key] = ret.get(output_key) - # save the inverted meta dict into state.batch - meta_key = meta_key or f"{output_key}_{meta_key_postfix}" - if meta_key in ret: - # FIXME: we save inverted meta dict into `batch` to be compatible with `SegmentationSaver` - # will deprecate both handlers soon - engine.state.batch[i][meta_key] = ret.get(meta_key) diff --git a/monai/handlers/utils.py b/monai/handlers/utils.py index 13f23c582a..15d2c59682 100644 --- a/monai/handlers/utils.py +++ b/monai/handlers/utils.py @@ -11,13 +11,13 @@ import os from collections import OrderedDict -from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Union +from typing import TYPE_CHECKING, Dict, Optional, Sequence, Union import numpy as np import torch from monai.config import IgniteInfo, KeysCollection -from monai.utils import deprecated, ensure_tuple, get_torch_version_tuple, look_up_option, min_version, optional_import +from monai.utils import ensure_tuple, look_up_option, min_version, optional_import idist, _ = optional_import("ignite", IgniteInfo.OPT_IMPORT_VERSION, min_version, "distributed") if TYPE_CHECKING: @@ -28,8 +28,6 @@ __all__ = [ "stopping_fn_from_metric", "stopping_fn_from_loss", - "evenly_divisible_all_gather", - "string_list_all_gather", "write_metrics_reports", "from_engine", ] @@ -57,78 +55,6 @@ def stopping_fn(engine: Engine): return stopping_fn -@deprecated(since="0.6.0", removed="0.7.0", msg_suffix="The API had been moved to monai.utils module.") -def evenly_divisible_all_gather(data: torch.Tensor) -> torch.Tensor: - """ - Utility function for distributed data parallel to pad at first dim to make it evenly divisible and all_gather. - - Args: - data: source tensor to pad and execute all_gather in distributed data parallel. - - Note: - The input data on different ranks must have exactly same `dtype`. - - .. versionchanged:: 0.6.0 - The API had been moved to `monai.utils`. - - """ - if not isinstance(data, torch.Tensor): - raise ValueError("input data must be PyTorch Tensor.") - - if idist.get_world_size() <= 1: - return data - - # make sure the data is evenly-divisible on multi-GPUs - length = data.shape[0] - all_lens = idist.all_gather(length) - max_len = max(all_lens) - if length < max_len: - size = [max_len - length] + list(data.shape[1:]) - data = torch.cat([data, data.new_full(size, 0)], dim=0) - # all gather across all processes - data = idist.all_gather(data) - # delete the padding NaN items - return torch.cat([data[i * max_len : i * max_len + l, ...] for i, l in enumerate(all_lens)], dim=0) - - -@deprecated(since="0.6.0", removed="0.7.0", msg_suffix="The API had been moved to monai.utils module.") -def string_list_all_gather(strings: List[str]) -> List[str]: - """ - Utility function for distributed data parallel to all gather a list of strings. - Note that if the item in `strings` is longer than 1024 chars, it will be truncated to 1024: - https://pytorch.org/ignite/v0.4.5/distributed.html#ignite.distributed.utils.all_gather. - - Args: - strings: a list of strings to all gather. - - .. versionchanged:: 0.6.0 - The API had been moved to `monai.utils`. - - """ - world_size = idist.get_world_size() - if world_size <= 1: - return strings - - result: List[List[str]] = [[] for _ in range(world_size)] - # get length of strings - length = len(strings) - all_lens = idist.all_gather(length) - max_len = max(all_lens) - # pad the item to make sure the same length - if length < max_len: - strings += ["" for _ in range(max_len - length)] - - if get_torch_version_tuple() <= (1, 6): - raise RuntimeError("string all_gather can not be supported in PyTorch < 1.7.0.") - - for s in strings: - gathered = idist.all_gather(s) - for i, g in enumerate(gathered): - if len(g) > 0: - result[i].append(g) - return [i for k in result for i in k] - - def write_metrics_reports( save_dir: str, images: Optional[Sequence[str]], diff --git a/monai/networks/nets/netadapter.py b/monai/networks/nets/netadapter.py index 80288f7945..13da7698d3 100644 --- a/monai/networks/nets/netadapter.py +++ b/monai/networks/nets/netadapter.py @@ -37,6 +37,9 @@ class NetAdapter(torch.nn.Module): bias: the bias value when replacing the last layer. if False, the layer will not learn an additive bias, default to True. + .. deprecated:: 0.6.0 + ``n_classes`` is deprecated, use ``num_classes`` instead. + """ @deprecated_arg("n_classes", since="0.6") diff --git a/monai/networks/nets/resnet.py b/monai/networks/nets/resnet.py index 3b86dc3d62..49d4f3d2fa 100644 --- a/monai/networks/nets/resnet.py +++ b/monai/networks/nets/resnet.py @@ -168,6 +168,10 @@ class ResNet(nn.Module): - 'B': kernel_size 1 conv + norm. widen_factor: widen output for each layer. num_classes: number of output (classifications) + + .. deprecated:: 0.6.0 + ``n_classes`` is deprecated, use ``num_classes`` instead. + """ @deprecated_arg("n_classes", since="0.6") diff --git a/monai/transforms/post/array.py b/monai/transforms/post/array.py index 631947025c..a7280cfe98 100644 --- a/monai/transforms/post/array.py +++ b/monai/transforms/post/array.py @@ -129,6 +129,9 @@ class AsDiscrete(Transform): rounding: if not None, round the data according to the specified option, available options: ["torchrounding"]. + .. deprecated:: 0.6.0 + ``n_classes`` is deprecated, use ``num_classes`` instead. + """ @deprecated_arg("n_classes", since="0.6") @@ -181,6 +184,9 @@ def __call__( rounding: if not None, round the data according to the specified option, available options: ["torchrounding"]. + .. deprecated:: 0.6.0 + ``n_classes`` is deprecated, use ``num_classes`` instead. + """ # in case the new num_classes is default but you still call deprecated n_classes if n_classes is not None and num_classes is None: diff --git a/monai/transforms/post/dictionary.py b/monai/transforms/post/dictionary.py index 2fc3993e3e..97ae4ec5a9 100644 --- a/monai/transforms/post/dictionary.py +++ b/monai/transforms/post/dictionary.py @@ -158,6 +158,9 @@ def __init__( each element corresponds to a key in ``keys``. allow_missing_keys: don't raise exception if key is missing. + .. deprecated:: 0.6.0 + ``n_classes`` is deprecated, use ``num_classes`` instead. + """ # in case the new num_classes is default but you still call deprecated n_classes if n_classes is not None and num_classes is None: diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 6f662f2dce..01bd0cec6d 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -1029,6 +1029,9 @@ class AffineGrid(Transform): supplied matrix. Should be square with each side = num of image spatial dimensions + 1. + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ backend = [TransformBackends.TORCH, TransformBackends.NUMPY] @@ -1152,6 +1155,10 @@ def __init__( - :py:meth:`monai.transforms.utils.create_shear` - :py:meth:`monai.transforms.utils.create_translate` - :py:meth:`monai.transforms.utils.create_scale` + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ self.rotate_range = ensure_tuple(rotate_range) self.shear_range = ensure_tuple(shear_range) @@ -1290,6 +1297,10 @@ def __init__( Padding mode for outside grid values. Defaults to ``"border"``. See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample device: device on which the tensor will be allocated. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ self.mode: GridSampleMode = look_up_option(mode, GridSampleMode) self.padding_mode: GridSamplePadMode = look_up_option(padding_mode, GridSamplePadMode) @@ -1418,6 +1429,10 @@ def __init__( See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample device: device on which the tensor will be allocated. image_only: if True return only the image volume, otherwise return (image, affine). + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ self.affine_grid = AffineGrid( rotate_params=rotate_params, @@ -1531,6 +1546,10 @@ def __init__( See also: - :py:class:`RandAffineGrid` for the random affine parameters configurations. - :py:class:`Affine` for the affine transformation parameters configurations. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ RandomizableTransform.__init__(self, prob) @@ -1707,6 +1726,10 @@ def __init__( See also: - :py:class:`RandAffineGrid` for the random affine parameters configurations. - :py:class:`Affine` for the affine transformation parameters configurations. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ RandomizableTransform.__init__(self, prob) self.deform_grid = RandDeformGrid( @@ -1853,6 +1876,10 @@ def __init__( See also: - :py:class:`RandAffineGrid` for the random affine parameters configurations. - :py:class:`Affine` for the affine transformation parameters configurations. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ RandomizableTransform.__init__(self, prob) self.rand_affine_grid = RandAffineGrid( diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index f36300dea6..0b6473a22c 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -633,6 +633,10 @@ def __init__( See also: - :py:class:`monai.transforms.compose.MapTransform` - :py:class:`RandAffineGrid` for the random affine parameters configurations. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ MapTransform.__init__(self, keys, allow_missing_keys) self.affine = Affine( @@ -761,6 +765,10 @@ def __init__( See also: - :py:class:`monai.transforms.compose.MapTransform` - :py:class:`RandAffineGrid` for the random affine parameters configurations. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ MapTransform.__init__(self, keys, allow_missing_keys) RandomizableTransform.__init__(self, prob) @@ -922,6 +930,10 @@ def __init__( See also: - :py:class:`RandAffineGrid` for the random affine parameters configurations. - :py:class:`Affine` for the affine transformation parameters configurations. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ MapTransform.__init__(self, keys, allow_missing_keys) RandomizableTransform.__init__(self, prob) @@ -1052,6 +1064,10 @@ def __init__( See also: - :py:class:`RandAffineGrid` for the random affine parameters configurations. - :py:class:`Affine` for the affine transformation parameters configurations. + + .. deprecated:: 0.6.0 + ``as_tensor_output`` is deprecated. + """ MapTransform.__init__(self, keys, allow_missing_keys) RandomizableTransform.__init__(self, prob) diff --git a/tests/min_tests.py b/tests/min_tests.py index f47a06b3bb..5e188a828e 100644 --- a/tests/min_tests.py +++ b/tests/min_tests.py @@ -75,7 +75,6 @@ def run_testsuit(): "test_handler_surface_distance", "test_handler_tb_image", "test_handler_tb_stats", - "test_handler_transform_inverter", "test_handler_validation", "test_hausdorff_distance", "test_header_correct", diff --git a/tests/test_handler_transform_inverter.py b/tests/test_handler_transform_inverter.py deleted file mode 100644 index 385311eba7..0000000000 --- a/tests/test_handler_transform_inverter.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2020 - 2021 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 sys -import unittest - -import numpy as np -import torch -from ignite.engine import Engine - -from monai.data import CacheDataset, DataLoader, create_test_image_3d, decollate_batch -from monai.engines.utils import IterationEvents -from monai.handlers import TransformInverter -from monai.transforms import ( - AddChanneld, - CastToTyped, - Compose, - CopyItemsd, - LoadImaged, - Orientationd, - RandAffined, - RandAxisFlipd, - RandFlipd, - RandRotate90d, - RandRotated, - RandZoomd, - ResizeWithPadOrCropd, - ScaleIntensityd, - Spacingd, - ToTensord, -) -from monai.utils.misc import set_determinism -from tests.utils import make_nifti_image - -KEYS = ["image", "label"] - - -class TestTransformInverter(unittest.TestCase): - def test_invert(self): - set_determinism(seed=0) - im_fname, seg_fname = [make_nifti_image(i) for i in create_test_image_3d(101, 100, 107, noise_max=100)] - transform = Compose( - [ - LoadImaged(KEYS), - AddChanneld(KEYS), - Orientationd(KEYS, "RPS"), - Spacingd(KEYS, pixdim=(1.2, 1.01, 0.9), mode=["bilinear", "nearest"], dtype=np.float32), - ScaleIntensityd("image", minv=1, maxv=10), - RandFlipd(KEYS, prob=0.5, spatial_axis=[1, 2]), - RandAxisFlipd(KEYS, prob=0.5), - RandRotate90d(KEYS, spatial_axes=(1, 2)), - RandZoomd(KEYS, prob=0.5, min_zoom=0.5, max_zoom=1.1, keep_size=True), - RandRotated(KEYS, prob=0.5, range_x=np.pi, mode="bilinear", align_corners=True), - RandAffined(KEYS, prob=0.5, rotate_range=np.pi, mode="nearest"), - ResizeWithPadOrCropd(KEYS, 100), - ToTensord("image"), # test to support both Tensor and Numpy array when inverting - CastToTyped(KEYS, dtype=[torch.uint8, np.uint8]), - CopyItemsd("label", times=2, names=["label_inverted1", "label_inverted2"]), - CopyItemsd("image", times=2, names=["image_inverted1", "image_inverted2"]), - ] - ) - data = [{"image": im_fname, "label": seg_fname} for _ in range(12)] - - # num workers = 0 for mac or gpu transforms - num_workers = 0 if sys.platform == "darwin" or torch.cuda.is_available() else 2 - - dataset = CacheDataset(data, transform=transform, progress=False) - loader = DataLoader(dataset, num_workers=num_workers, batch_size=5) - - # set up engine - def _train_func(engine, batch): - self.assertTupleEqual(batch["image"].shape[1:], (1, 100, 100, 100)) - engine.state.output = engine.state.batch = decollate_batch(batch) - engine.fire_event(IterationEvents.MODEL_COMPLETED) - return engine.state.output - - engine = Engine(_train_func) - engine.register_events(*IterationEvents) - - # set up testing handler - TransformInverter( - transform=transform, - output_keys=["image_inverted1", "label_inverted1"], - batch_keys="label", - meta_keys=["image_inverted1_meta_dict", "label_inverted1_meta_dict"], - batch_meta_keys="label_meta_dict", - nearest_interp=True, - to_tensor=[True, False], - device="cpu", - ).attach(engine) - - # test different nearest interpolation values - TransformInverter( - transform=transform, - output_keys=["image_inverted2", "label_inverted2"], - batch_keys="image", - meta_keys=None, - batch_meta_keys="image_meta_dict", - meta_key_postfix="meta_dict", - nearest_interp=[True, False], - post_func=[lambda x: x + 10, lambda x: x], - ).attach(engine) - - engine.run(loader, max_epochs=1) - set_determinism(seed=None) - - for output in engine.state.output: - self.assertTupleEqual(output["image"].shape, (1, 100, 100, 100)) - self.assertTupleEqual(output["label"].shape, (1, 100, 100, 100)) - # check the nearest inerpolation mode - i = output["image_inverted1"] - torch.testing.assert_allclose(i.to(torch.uint8).to(torch.float), i.to(torch.float)) - self.assertTupleEqual(i.shape, (1, 100, 101, 107)) - i = output["label_inverted1"] - np.testing.assert_allclose(i.astype(np.uint8).astype(np.float32), i.astype(np.float32)) - self.assertTupleEqual(i.shape, (1, 100, 101, 107)) - - # check the case that different items use different interpolation mode to invert transforms - d = output["image_inverted2"] - # if the interpolation mode is nearest, accumulated diff should be smaller than 1 - self.assertLess(torch.sum(d.to(torch.float) - d.to(torch.uint8).to(torch.float)).item(), 1.0) - self.assertTupleEqual(d.shape, (1, 100, 101, 107)) - - d = output["label_inverted2"] - # if the interpolation mode is not nearest, accumulated diff should be greater than 10000 - self.assertGreater(torch.sum(d.to(torch.float) - d.to(torch.uint8).to(torch.float)).item(), 10000.0) - self.assertTupleEqual(d.shape, (1, 100, 101, 107)) - - # check labels match - reverted = engine.state.output[-1]["label_inverted1"].astype(np.int32) - original = LoadImaged(KEYS)(data[-1])["label"] - n_good = np.sum(np.isclose(reverted, original, atol=1e-3)) - reverted_name = engine.state.batch[-1]["label_inverted1_meta_dict"]["filename_or_obj"] - original_name = data[-1]["label"] - self.assertEqual(reverted_name, original_name) - print("invert diff", reverted.size - n_good) - # 25300: 2 workers (cpu, non-macos) - # 1812: 0 workers (gpu or macos) - # 1824: torch 1.5.1 - self.assertTrue((reverted.size - n_good) in (25300, 1812, 1824), "diff. in 3 possible values") - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test_invertd.py b/tests/test_invertd.py index 5b98653f0a..eda900bf2d 100644 --- a/tests/test_invertd.py +++ b/tests/test_invertd.py @@ -34,6 +34,7 @@ ResizeWithPadOrCropd, ScaleIntensityd, Spacingd, + ToTensord, ) from monai.utils.misc import set_determinism from tests.utils import make_nifti_image @@ -63,8 +64,10 @@ def test_invert(self): CopyItemsd("image_meta_dict", times=1, names="test_dict"), # test to support Tensor, Numpy array and dictionary when inverting EnsureTyped(keys=["image", "test_dict"]), + ToTensord("image"), CastToTyped(KEYS, dtype=[torch.uint8, np.uint8]), - CopyItemsd("label", times=1, names="label_inverted"), + CopyItemsd("label", times=2, names=["label_inverted", "label_inverted1"]), + CopyItemsd("image", times=2, names=["image_inverted", "image_inverted1"]), ] ) data = [{"image": im_fname, "label": seg_fname} for _ in range(12)] @@ -76,25 +79,58 @@ def test_invert(self): loader = DataLoader(dataset, num_workers=num_workers, batch_size=5) inverter = Invertd( # `image` was not copied, invert the original value directly - keys=["image", "label_inverted", "test_dict"], + keys=["image_inverted", "label_inverted", "test_dict"], transform=transform, orig_keys=["label", "label", "test_dict"], - meta_keys=["image_meta_dict", "label_inverted_meta_dict", None], + meta_keys=["image_inverted_meta_dict", "label_inverted_meta_dict", None], orig_meta_keys=["label_meta_dict", "label_meta_dict", None], nearest_interp=True, to_tensor=[True, False, False], device="cpu", ) + inverter_1 = Invertd( + # `image` was not copied, invert the original value directly + keys=["image_inverted1", "label_inverted1"], + transform=transform, + orig_keys=["image", "image"], + meta_keys=["image_inverted1_meta_dict", "label_inverted1_meta_dict"], + orig_meta_keys=["image_meta_dict", "image_meta_dict"], + nearest_interp=[True, False], + to_tensor=[True, True], + device="cpu", + ) + + expected_keys = [ + "image", + "image_inverted", + "image_inverted1", + "image_inverted1_meta_dict", + "image_inverted_meta_dict", + "image_meta_dict", + "image_transforms", + "label", + "label_inverted", + "label_inverted1", + "label_inverted1_meta_dict", + "label_inverted_meta_dict", + "label_meta_dict", + "label_transforms", + "test_dict", + "test_dict_transforms", + ] # execute 1 epoch for d in loader: d = decollate_batch(d) for item in d: item = inverter(item) - # this unit test only covers basic function, test_handler_transform_inverter covers more + item = inverter_1(item) + + self.assertListEqual(sorted(item), expected_keys) + self.assertTupleEqual(item["image"].shape[1:], (100, 100, 100)) self.assertTupleEqual(item["label"].shape[1:], (100, 100, 100)) - # check the nearest inerpolation mode - i = item["image"] + # check the nearest interpolation mode + i = item["image_inverted"] torch.testing.assert_allclose(i.to(torch.uint8).to(torch.float), i.to(torch.float)) self.assertTupleEqual(i.shape[1:], (100, 101, 107)) i = item["label_inverted"] @@ -104,6 +140,30 @@ def test_invert(self): self.assertTrue(isinstance(item["test_dict"]["affine"], np.ndarray)) self.assertTrue(isinstance(item["test_dict"]["filename_or_obj"], str)) + # check the case that different items use different interpolation mode to invert transforms + d = item["image_inverted1"] + # if the interpolation mode is nearest, accumulated diff should be smaller than 1 + self.assertLess(torch.sum(d.to(torch.float) - d.to(torch.uint8).to(torch.float)).item(), 1.0) + self.assertTupleEqual(d.shape, (1, 100, 101, 107)) + + d = item["label_inverted1"] + # if the interpolation mode is not nearest, accumulated diff should be greater than 10000 + self.assertGreater(torch.sum(d.to(torch.float) - d.to(torch.uint8).to(torch.float)).item(), 10000.0) + self.assertTupleEqual(d.shape, (1, 100, 101, 107)) + + # check labels match + reverted = item["label_inverted"].astype(np.int32) + original = LoadImaged(KEYS)(data[-1])["label"] + n_good = np.sum(np.isclose(reverted, original, atol=1e-3)) + reverted_name = item["label_inverted_meta_dict"]["filename_or_obj"] + original_name = data[-1]["label"] + self.assertEqual(reverted_name, original_name) + print("invert diff", reverted.size - n_good) + # 25300: 2 workers (cpu, non-macos) + # 1812: 0 workers (gpu or macos) + # 1824: torch 1.5.1 + self.assertTrue((reverted.size - n_good) in (25300, 1812, 1824), "diff. in 3 possible values") + set_determinism(seed=None) From b791ed2437b93d8f85b6c3a71b4a6d407fa92cbc Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Tue, 21 Sep 2021 17:51:04 +0100 Subject: [PATCH 38/89] 2985 - enhance nightly test (#2986) * enhance nightly test Signed-off-by: Wenqi Li * print after the test for information Signed-off-by: Wenqi Li --- .github/workflows/cron.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index a36cfbcdb9..77d43d35bd 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -215,7 +215,7 @@ jobs: which python python -m pip install --upgrade pip wheel python -m pip install -r requirements-dev.txt - BUILD_MONAI=0 python setup.py develop # install monai + BUILD_MONAI=1 python setup.py develop # install monai nvidia-smi export CUDA_VISIBLE_DEVICES=$(python -m tests.utils) echo $CUDA_VISIBLE_DEVICES @@ -234,5 +234,7 @@ jobs: trap 'if pgrep python; then pkill python; fi;' ERR python -c $'import torch\na,b=torch.zeros(1,device="cuda:0"),torch.zeros(1,device="cuda:1");\nwhile True:print(a,b)' > /dev/null & cd /opt/tutorials + python -c 'import monai; monai.config.print_debug_info()' $(pwd)/runner.sh + python -c 'import monai; monai.config.print_debug_info()' if pgrep python; then pkill python; fi From f31b55fc47f7baf7b9fab433f13a8b5a32d8c45f Mon Sep 17 00:00:00 2001 From: neuronflow <7048826+neuronflow@users.noreply.github.com> Date: Tue, 21 Sep 2021 19:42:32 +0200 Subject: [PATCH 39/89] dimension check for pretrained model weights (#2984) * dimension check for pretrained model weights This PR implements a dimension check, before trying to load pre-trained model weights. Signed-off-by: neuronflow * [MONAI] python code formatting Signed-off-by: monai-bot Signed-off-by: neuronflow * multi line split error Signed-off-by: neuronflow Co-authored-by: monai-bot --- monai/networks/nets/densenet.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/monai/networks/nets/densenet.py b/monai/networks/nets/densenet.py index e9f3b6d33e..dc2c07bb12 100644 --- a/monai/networks/nets/densenet.py +++ b/monai/networks/nets/densenet.py @@ -306,7 +306,11 @@ def __init__( **kwargs, ) if pretrained: - # it only worked when `spatial_dims` is 2 + if kwargs["spatial_dims"] > 2: + raise NotImplementedError( + "Parameter `spatial_dims` is > 2 ; currently PyTorch Hub does not" + "provide pretrained models for more than two spatial dimensions." + ) _load_state_dict(self, "densenet121", progress) @@ -329,7 +333,11 @@ def __init__( **kwargs, ) if pretrained: - # it only worked when `spatial_dims` is 2 + if kwargs["spatial_dims"] > 2: + raise NotImplementedError( + "Parameter `spatial_dims` is > 2 ; currently PyTorch Hub does not" + "provide pretrained models for more than two spatial dimensions." + ) _load_state_dict(self, "densenet169", progress) @@ -352,7 +360,11 @@ def __init__( **kwargs, ) if pretrained: - # it only worked when `spatial_dims` is 2 + if kwargs["spatial_dims"] > 2: + raise NotImplementedError( + "Parameter `spatial_dims` is > 2 ; currently PyTorch Hub does not" + "provide pretrained models for more than two spatial dimensions." + ) _load_state_dict(self, "densenet201", progress) From 790fc8f572322c6a4c1ab527acfb27447be4bb66 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Wed, 22 Sep 2021 01:52:48 +0000 Subject: [PATCH 40/89] Refactor unnecessary `else` / `elif` when `if` block has a `return` statement (#2996) * Refactor unnecessary `else` / `elif` when `if` block has a `return` statement * Remove unnecessary lambda expression (#2997) Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com> * type fixes Signed-off-by: Wenqi Li * remove repeated init Signed-off-by: Wenqi Li * fixes import, unused vars Signed-off-by: Wenqi Li Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com> Co-authored-by: Wenqi Li --- monai/handlers/utils.py | 12 +++---- monai/transforms/compose.py | 34 +++++++++---------- monai/transforms/croppad/dictionary.py | 1 - monai/transforms/intensity/array.py | 2 +- monai/transforms/post/array.py | 2 +- monai/transforms/spatial/array.py | 3 +- monai/transforms/utility/array.py | 17 +++++----- monai/transforms/utility/dictionary.py | 3 +- monai/transforms/utils.py | 7 ++-- .../utils_pytorch_numpy_unification.py | 3 +- tests/test_intensity_stats.py | 2 +- tests/test_intensity_statsd.py | 2 +- 12 files changed, 39 insertions(+), 49 deletions(-) diff --git a/monai/handlers/utils.py b/monai/handlers/utils.py index 15d2c59682..60f95d458e 100644 --- a/monai/handlers/utils.py +++ b/monai/handlers/utils.py @@ -130,12 +130,12 @@ class mean median max 5percentile 95percentile notnans if summary_ops is not None: supported_ops = OrderedDict( { - "mean": lambda x: np.nanmean(x), - "median": lambda x: np.nanmedian(x), - "max": lambda x: np.nanmax(x), - "min": lambda x: np.nanmin(x), + "mean": np.nanmean, + "median": np.nanmedian, + "max": np.nanmax, + "min": np.nanmin, "90percentile": lambda x: np.nanpercentile(x[0], x[1]), - "std": lambda x: np.nanstd(x), + "std": np.nanstd, "notnans": lambda x: (~np.isnan(x)).sum(), } ) @@ -149,7 +149,7 @@ def _compute_op(op: str, d: np.ndarray): return c_op(d) threshold = int(op.split("percentile")[0]) - return supported_ops["90percentile"]((d, threshold)) + return supported_ops["90percentile"]((d, threshold)) # type: ignore with open(os.path.join(save_dir, f"{k}_summary.csv"), "w") as f: f.write(f"class{deli}{deli.join(ops)}\n") diff --git a/monai/transforms/compose.py b/monai/transforms/compose.py index 4bf175769b..38aa2199c6 100644 --- a/monai/transforms/compose.py +++ b/monai/transforms/compose.py @@ -204,14 +204,13 @@ def __init__( def _normalize_probabilities(self, weights): if len(weights) == 0: return weights - else: - weights = np.array(weights) - if np.any(weights < 0): - raise AssertionError("Probabilities must be greater than or equal to zero.") - if np.all(weights == 0): - raise AssertionError("At least one probability must be greater than zero.") - weights = weights / weights.sum() - return list(weights) + weights = np.array(weights) + if np.any(weights < 0): + raise AssertionError("Probabilities must be greater than or equal to zero.") + if np.all(weights == 0): + raise AssertionError("At least one probability must be greater than zero.") + weights = weights / weights.sum() + return list(weights) def flatten(self): transforms = [] @@ -232,16 +231,15 @@ def flatten(self): def __call__(self, data): if len(self.transforms) == 0: return data - else: - index = self.R.multinomial(1, self.weights).argmax() - _transform = self.transforms[index] - data = apply_transform(_transform, data, self.map_items, self.unpack_items) - # if the data is a mapping (dictionary), append the OneOf transform to the end - if isinstance(data, Mapping): - for key in data.keys(): - if key + InverseKeys.KEY_SUFFIX in data: - self.push_transform(data, key, extra_info={"index": index}) - return data + index = self.R.multinomial(1, self.weights).argmax() + _transform = self.transforms[index] + data = apply_transform(_transform, data, self.map_items, self.unpack_items) + # if the data is a mapping (dictionary), append the OneOf transform to the end + if isinstance(data, Mapping): + for key in data.keys(): + if key + InverseKeys.KEY_SUFFIX in data: + self.push_transform(data, key, extra_info={"index": index}) + return data def inverse(self, data): if len(self.transforms) == 0: diff --git a/monai/transforms/croppad/dictionary.py b/monai/transforms/croppad/dictionary.py index 2590bf2e77..222d6ae17c 100644 --- a/monai/transforms/croppad/dictionary.py +++ b/monai/transforms/croppad/dictionary.py @@ -663,7 +663,6 @@ def __init__( random_size=random_size, allow_missing_keys=allow_missing_keys, ) - MapTransform.__init__(self, keys, allow_missing_keys) self.roi_scale = roi_scale self.max_roi_scale = max_roi_scale diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index a8babfc659..3be205996e 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1457,7 +1457,7 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, raise RuntimeError("Image needs a channel direction.") if isinstance(self.loc[0], int) and len(img.shape) == 4 and len(self.loc) == 2: raise RuntimeError("Input images of dimension 4 need location tuple to be length 3 or 4") - if isinstance(self.loc[0], Sequence) and len(img.shape) == 4 and min(map(lambda x: len(x), self.loc)) == 2: + if isinstance(self.loc[0], Sequence) and len(img.shape) == 4 and min(map(len, self.loc)) == 2: raise RuntimeError("Input images of dimension 4 need location tuple to be length 3 or 4") n_dims = len(img.shape[1:]) diff --git a/monai/transforms/post/array.py b/monai/transforms/post/array.py index a7280cfe98..d20f368109 100644 --- a/monai/transforms/post/array.py +++ b/monai/transforms/post/array.py @@ -205,7 +205,7 @@ def __call__( rounding = self.rounding if rounding is None else rounding if rounding is not None: - rounding = look_up_option(rounding, ["torchrounding"]) + look_up_option(rounding, ["torchrounding"]) img = torch.round(img) return img.float() diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 01bd0cec6d..cb4e69a509 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -335,8 +335,7 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ if isinstance(img, np.ndarray): return np.ascontiguousarray(np.flip(img, map_spatial_axes(img.ndim, self.spatial_axis))) - else: - return torch.flip(img, map_spatial_axes(img.ndim, self.spatial_axis)) + return torch.flip(img, map_spatial_axes(img.ndim, self.spatial_axis)) class Resize(Transform): diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 57d43db5d0..3df53f8850 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -391,9 +391,8 @@ def __call__(self, data: NdarrayOrTensor): if self.data_type == "tensor": dtype_ = get_equivalent_dtype(self.dtype, torch.Tensor) return convert_to_tensor(data, dtype=dtype_, device=self.device) - else: - dtype_ = get_equivalent_dtype(self.dtype, np.ndarray) - return convert_to_numpy(data, dtype=dtype_) + dtype_ = get_equivalent_dtype(self.dtype, np.ndarray) + return convert_to_numpy(data, dtype=dtype_) class ToNumpy(Transform): @@ -1091,11 +1090,11 @@ def __call__( img_ = img[mask] supported_ops = { - "mean": lambda x: np.nanmean(x), - "median": lambda x: np.nanmedian(x), - "max": lambda x: np.nanmax(x), - "min": lambda x: np.nanmin(x), - "std": lambda x: np.nanstd(x), + "mean": np.nanmean, + "median": np.nanmedian, + "max": np.nanmax, + "min": np.nanmin, + "std": np.nanstd, } def _compute(op: Callable, data: np.ndarray): @@ -1107,7 +1106,7 @@ def _compute(op: Callable, data: np.ndarray): for o in self.ops: if isinstance(o, str): o = look_up_option(o, supported_ops.keys()) - meta_data[self.key_prefix + "_" + o] = _compute(supported_ops[o], img_) + meta_data[self.key_prefix + "_" + o] = _compute(supported_ops[o], img_) # type: ignore elif callable(o): meta_data[self.key_prefix + "_custom_" + str(custom_index)] = _compute(o, img_) custom_index += 1 diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 695753a07d..4fb07644a9 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -15,7 +15,6 @@ Class names are ended with 'd' to denote dictionary-based transforms. """ -import copy import logging import re from copy import deepcopy @@ -886,7 +885,7 @@ def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, N if isinstance(val, torch.Tensor): d[new_key] = val.detach().clone() else: - d[new_key] = copy.deepcopy(val) + d[new_key] = deepcopy(val) return d diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index a627a7544a..fbd4a6b12b 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -20,12 +20,11 @@ import torch import monai -import monai.transforms.transform from monai.config import DtypeLike, IndexSelection from monai.config.type_definitions import NdarrayOrTensor from monai.networks.layers import GaussianFilter from monai.transforms.compose import Compose, OneOf -from monai.transforms.transform import MapTransform, Transform +from monai.transforms.transform import MapTransform, Transform, apply_transform from monai.transforms.utils_pytorch_numpy_unification import any_np_pt, nonzero, ravel, unravel_index from monai.utils import ( GridSampleMode, @@ -1330,9 +1329,7 @@ def _get_data(obj, key): prev_data = _get_data(test_data, key) prev_type = type(prev_data) prev_device = prev_data.device if isinstance(prev_data, torch.Tensor) else None - test_data = monai.transforms.transform.apply_transform( - _transform, test_data, transform.map_items, transform.unpack_items - ) + test_data = apply_transform(_transform, test_data, transform.map_items, transform.unpack_items) # every time the type or device changes, increment the counter curr_data = _get_data(test_data, key) curr_device = curr_data.device if isinstance(curr_data, torch.Tensor) else None diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 7b65f690c0..4283c4a81f 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -159,8 +159,7 @@ def floor_divide(a: NdarrayOrTensor, b) -> NdarrayOrTensor: if is_module_ver_at_least(torch, (1, 8, 0)): return torch.div(a, b, rounding_mode="floor") return torch.floor_divide(a, b) - else: - return np.floor_divide(a, b) + return np.floor_divide(a, b) def unravel_index(idx, shape): diff --git a/tests/test_intensity_stats.py b/tests/test_intensity_stats.py index 059271e442..92a2c04585 100644 --- a/tests/test_intensity_stats.py +++ b/tests/test_intensity_stats.py @@ -31,7 +31,7 @@ ] TEST_CASE_3 = [ - {"ops": [lambda x: np.mean(x), "max", lambda x: np.min(x)], "key_prefix": "orig"}, + {"ops": [np.mean, "max", np.min], "key_prefix": "orig"}, np.array([[[0.0, 1.0], [2.0, 3.0]]]), None, {"orig_custom_0": 1.5, "orig_max": 3.0, "orig_custom_1": 0.0}, diff --git a/tests/test_intensity_statsd.py b/tests/test_intensity_statsd.py index 8c8bc8795a..596c80deb5 100644 --- a/tests/test_intensity_statsd.py +++ b/tests/test_intensity_statsd.py @@ -34,7 +34,7 @@ ] TEST_CASE_3 = [ - {"keys": "img", "ops": [lambda x: np.mean(x), "max", lambda x: np.min(x)], "key_prefix": "orig"}, + {"keys": "img", "ops": [np.mean, "max", np.min], "key_prefix": "orig"}, {"img": np.array([[[0.0, 1.0], [2.0, 3.0]]])}, "img_meta_dict", {"orig_custom_0": 1.5, "orig_max": 3.0, "orig_custom_1": 0.0}, From d3d17432acdb2d269e0af9eb26677eba4f91e6cd Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Wed, 22 Sep 2021 21:03:09 +0800 Subject: [PATCH 41/89] 3000 Support not copy in CacheDataset (#3001) * [DLMED] add copy option Signed-off-by: Nic Ma * [DLMED] enhance test Signed-off-by: Nic Ma * [MONAI] python code formatting Signed-off-by: monai-bot Co-authored-by: monai-bot --- monai/data/dataset.py | 16 ++++++++++++++-- tests/test_cachedataset.py | 17 +++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/monai/data/dataset.py b/monai/data/dataset.py index c970e83d0d..2549041fbd 100644 --- a/monai/data/dataset.py +++ b/monai/data/dataset.py @@ -575,6 +575,7 @@ def __init__( cache_rate: float = 1.0, num_workers: Optional[int] = None, progress: bool = True, + copy_cache: bool = True, ) -> None: """ Args: @@ -587,11 +588,16 @@ def __init__( num_workers: the number of worker processes to use. If num_workers is None then the number returned by os.cpu_count() is used. progress: whether to display a progress bar. + copy_cache: whether to `deepcopy` the cache content before applying the random transforms, + default to `True`. if the random transforms don't modify the cache content + or every cache item is only used once in a `multi-processing` environment, + may set `copy=False` for better performance. """ if not isinstance(transform, Compose): transform = Compose(transform) super().__init__(data=data, transform=transform) self.progress = progress + self.copy_cache = copy_cache self.cache_num = min(int(cache_num), int(len(data) * cache_rate), len(data)) self.num_workers = num_workers if self.num_workers is not None: @@ -656,7 +662,8 @@ def _transform(self, index: int): # only need to deep copy data on first non-deterministic transform if not start_run: start_run = True - data = deepcopy(data) + if self.copy_cache: + data = deepcopy(data) data = apply_transform(_transform, data) return data @@ -722,6 +729,10 @@ class SmartCacheDataset(Randomizable, CacheDataset): shuffle: whether to shuffle the whole data list before preparing the cache content for first epoch. it will not modify the original input data sequence in-place. seed: random seed if shuffle is `True`, default to `0`. + copy_cache: whether to `deepcopy` the cache content before applying the random transforms, + default to `True`. if the random transforms don't modify the cache content + or every cache item is only used once in a `multi-processing` environment, + may set `copy=False` for better performance. """ def __init__( @@ -736,6 +747,7 @@ def __init__( progress: bool = True, shuffle: bool = True, seed: int = 0, + copy_cache: bool = True, ) -> None: if shuffle: self.set_random_state(seed=seed) @@ -743,7 +755,7 @@ def __init__( self.randomize(data) self.shuffle = shuffle - super().__init__(data, transform, cache_num, cache_rate, num_init_workers, progress) + super().__init__(data, transform, cache_num, cache_rate, num_init_workers, progress, copy_cache) if self._cache is None: self._cache = self._fill_cache() if self.cache_num >= len(data): diff --git a/tests/test_cachedataset.py b/tests/test_cachedataset.py index bbb8143631..e5bb1b9a90 100644 --- a/tests/test_cachedataset.py +++ b/tests/test_cachedataset.py @@ -19,7 +19,7 @@ from parameterized import parameterized from monai.data import CacheDataset, DataLoader, PersistentDataset, SmartCacheDataset -from monai.transforms import Compose, Lambda, LoadImaged, ThreadUnsafe, Transform +from monai.transforms import Compose, Lambda, LoadImaged, RandLambda, ThreadUnsafe, Transform from monai.utils import get_torch_version_tuple TEST_CASE_1 = [Compose([LoadImaged(keys=["image", "label", "extra"])]), (128, 128, 128)] @@ -84,7 +84,12 @@ def test_shape(self, transform, expected_shape): def test_set_data(self): data_list1 = list(range(10)) - transform = Lambda(func=lambda x: np.array([x * 10])) + transform = Compose( + [ + Lambda(func=lambda x: np.array([x * 10])), + RandLambda(func=lambda x: x + 1), + ] + ) dataset = CacheDataset( data=data_list1, @@ -92,19 +97,23 @@ def test_set_data(self): cache_rate=1.0, num_workers=4, progress=True, + copy_cache=False if sys.platform == "linux" else True, ) num_workers = 2 if sys.platform == "linux" else 0 dataloader = DataLoader(dataset=dataset, num_workers=num_workers, batch_size=1) for i, d in enumerate(dataloader): - np.testing.assert_allclose([[data_list1[i] * 10]], d) + np.testing.assert_allclose([[data_list1[i] * 10 + 1]], d) + # simulate another epoch, the cache content should not be modified + for i, d in enumerate(dataloader): + np.testing.assert_allclose([[data_list1[i] * 10 + 1]], d) # update the datalist and fill the cache content data_list2 = list(range(-10, 0)) dataset.set_data(data=data_list2) # rerun with updated cache content for i, d in enumerate(dataloader): - np.testing.assert_allclose([[data_list2[i] * 10]], d) + np.testing.assert_allclose([[data_list2[i] * 10 + 1]], d) class _StatefulTransform(Transform, ThreadUnsafe): From ed2d12c8a49dd823ce60240fff957669bc182f6a Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Wed, 22 Sep 2021 16:35:04 +0100 Subject: [PATCH 42/89] 3002 - compatibility with torch 1.9.1 (#3003) * test 1.9.1 Signed-off-by: Wenqi Li * temp tests Signed-off-by: Wenqi Li * Revert "temp tests" This reverts commit 1f27a6321761d0080a12e5f3c9fcd406907b29ae. Signed-off-by: Wenqi Li --- .github/workflows/integration.yml | 2 +- .github/workflows/pythonapp-gpu.yml | 2 +- .github/workflows/pythonapp.yml | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ed025e98fe..3a70983137 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -34,7 +34,7 @@ jobs: which python python -m pip install --upgrade pip wheel python -m pip uninstall -y torch torchvision - python -m pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 -f https://download.pytorch.org/whl/torch_stable.html + python -m pip install torch==1.9.1+cu111 torchvision==0.10.1+cu111 -f https://download.pytorch.org/whl/torch_stable.html python -m pip install -r requirements-dev.txt - name: Run integration tests run: | diff --git a/.github/workflows/pythonapp-gpu.yml b/.github/workflows/pythonapp-gpu.yml index 999567ae16..32d51e30e4 100644 --- a/.github/workflows/pythonapp-gpu.yml +++ b/.github/workflows/pythonapp-gpu.yml @@ -47,7 +47,7 @@ jobs: pytorch: "-h" base: "nvcr.io/nvidia/pytorch:21.08-py3" - environment: PT19+CUDA102 - pytorch: "torch==1.9.0 torchvision==0.10.0" + pytorch: "torch==1.9.1 torchvision==0.10.1" base: "nvcr.io/nvidia/cuda:10.2-devel-ubuntu18.04" container: image: ${{ matrix.base }} diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml index 73197915cf..28a9f34839 100644 --- a/.github/workflows/pythonapp.yml +++ b/.github/workflows/pythonapp.yml @@ -87,10 +87,10 @@ jobs: - if: runner.os == 'windows' name: Install torch cpu from pytorch.org (Windows only) run: | - python -m pip install torch==1.9.0+cpu torchvision==0.10.0+cpu -f https://download.pytorch.org/whl/torch_stable.html + python -m pip install torch==1.9.1+cpu torchvision==0.10.1+cpu -f https://download.pytorch.org/whl/torch_stable.html - name: Install the dependencies run: | - python -m pip install torch==1.9.0 torchvision==0.10.0 + python -m pip install torch==1.9.1 torchvision==0.10.1 cat "requirements-dev.txt" python -m pip install -r requirements-dev.txt python -m pip list @@ -138,11 +138,11 @@ jobs: - if: runner.os == 'windows' name: Install torch cpu from pytorch.org (Windows only) run: | - python -m pip install torch==1.9.0+cpu -f https://download.pytorch.org/whl/torch_stable.html + python -m pip install torch==1.9.1+cpu -f https://download.pytorch.org/whl/torch_stable.html - name: Install the dependencies run: | # min. requirements - python -m pip install torch==1.9.0 + python -m pip install torch==1.9.1 python -m pip install -r requirements-min.txt python -m pip list BUILD_MONAI=0 python setup.py develop # no compile of extensions @@ -188,7 +188,7 @@ jobs: - name: Install the dependencies run: | # min. requirements - python -m pip install torch==1.9.0 + python -m pip install torch==1.9.1 python -m pip install -r requirements-min.txt python -m pip list BUILD_MONAI=0 python setup.py develop # no compile of extensions From dfe8528dd718589ef4335438e31fd54e00d012d2 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Wed, 22 Sep 2021 21:43:55 +0100 Subject: [PATCH 43/89] Fix cucim dep compatibility (#3006) * fixes cucim compatibility Signed-off-by: Wenqi Li * simplified import Signed-off-by: Wenqi Li --- monai/data/image_reader.py | 17 +++-------------- requirements-dev.txt | 4 +++- setup.cfg | 4 ++-- tests/test_cuimage_reader.py | 8 +++++--- tests/test_lesion_froc.py | 11 ++++++----- tests/test_masked_inference_wsi_dataset.py | 2 +- tests/test_openslide_reader.py | 2 +- tests/test_patch_wsi_dataset.py | 5 +++-- tests/test_smartcache_patch_wsi_dataset.py | 5 +++-- 9 files changed, 27 insertions(+), 31 deletions(-) diff --git a/monai/data/image_reader.py b/monai/data/image_reader.py index cd1486d6d3..a2ddb74334 100644 --- a/monai/data/image_reader.py +++ b/monai/data/image_reader.py @@ -25,21 +25,17 @@ from .utils import is_supported_format if TYPE_CHECKING: - import cucim import itk # type: ignore import nibabel as nib - import openslide from nibabel.nifti1 import Nifti1Image from PIL import Image as PILImage - has_itk = has_nib = has_pil = has_cim = has_osl = True + has_itk = has_nib = has_pil = True else: itk, has_itk = optional_import("itk", allow_namespace_pkg=True) nib, has_nib = optional_import("nibabel") Nifti1Image, _ = optional_import("nibabel.nifti1", name="Nifti1Image") PILImage, has_pil = optional_import("PIL.Image") - cucim, has_cim = optional_import("cucim") - openslide, has_osl = optional_import("openslide") __all__ = ["ImageReader", "ITKReader", "NibabelReader", "NumpyReader", "PILReader", "WSIReader"] @@ -670,11 +666,9 @@ def __init__(self, reader_lib: str = "OpenSlide"): super().__init__() self.reader_lib = reader_lib.lower() if self.reader_lib == "openslide": - if has_osl: - self.wsi_reader = openslide.OpenSlide + self.wsi_reader, *_ = optional_import("openslide", name="OpenSlide") elif self.reader_lib == "cucim": - if has_cim: - self.wsi_reader = cucim.CuImage + self.wsi_reader, *_ = optional_import("cucim", name="CuImage") else: raise ValueError('`reader_lib` should be either "cuCIM" or "OpenSlide"') @@ -697,11 +691,6 @@ def read(self, data: Union[Sequence[str], str, np.ndarray], **kwargs): data: file name or a list of file names to read. """ - if (self.reader_lib == "openslide") and (not has_osl): - raise ImportError("No module named 'openslide'") - if (self.reader_lib == "cucim") and (not has_cim): - raise ImportError("No module named 'cucim'") - img_: List = [] filenames: Sequence[str] = ensure_tuple(data) diff --git a/requirements-dev.txt b/requirements-dev.txt index ed8739ded8..e28f85b244 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -31,8 +31,10 @@ Sphinx==3.5.3 recommonmark==0.6.0 sphinx-autodoc-typehints==1.11.1 sphinx-rtd-theme==0.5.2 -cucim~=0.19.0; platform_system == "Linux" +cucim>=21.8.2; platform_system == "Linux" openslide-python==1.1.2 +imagecodecs; platform_system == "Linux" +tifffile; platform_system == "Linux" pandas requests einops diff --git a/setup.cfg b/setup.cfg index f7ed90a14a..eddb898b0d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,7 +40,7 @@ all = tqdm>=4.47.0 lmdb psutil - cucim~=0.19.0 + cucim>=21.8.2 openslide-python==1.1.2 pandas einops @@ -68,7 +68,7 @@ lmdb = psutil = psutil cucim = - cucim~=0.19.0 + cucim>=21.8.2 openslide = openslide-python==1.1.2 pandas = diff --git a/tests/test_cuimage_reader.py b/tests/test_cuimage_reader.py index 2cbfaec113..34df4b5fe4 100644 --- a/tests/test_cuimage_reader.py +++ b/tests/test_cuimage_reader.py @@ -21,10 +21,11 @@ from monai.data.image_reader import WSIReader from monai.utils import optional_import -_, has_cim = optional_import("cucim") +cucim, has_cucim = optional_import("cucim") +has_cucim = has_cucim and hasattr(cucim, "CuImage") PILImage, has_pil = optional_import("PIL.Image") -FILE_URL = "http://openslide.cs.cmu.edu/download/openslide-testdata/Generic-TIFF/CMU-1.tiff" +FILE_URL = "https://drive.google.com/uc?id=1sGTKZlJBIz53pfqTxoTqiIQzIoEzHLAe" FILE_PATH = os.path.join(os.path.dirname(__file__), "testing_data", "temp_" + os.path.basename(FILE_URL)) HEIGHT = 32914 @@ -83,7 +84,7 @@ class TestCuCIMReader(unittest.TestCase): - @skipUnless(has_cim, "Requires CuCIM") + @skipUnless(has_cucim, "Requires CuCIM") def setUp(self): download_url(FILE_URL, FILE_PATH, "5a3cfd4fd725c50578ddb80b517b759f") @@ -112,6 +113,7 @@ def test_read_patches(self, file_path, patch_info, expected_img): @parameterized.expand([TEST_CASE_RGB_0, TEST_CASE_RGB_1]) @skipUnless(has_pil, "Requires PIL") + @skipUnless(has_cucim and cucim.__version__ == "0.19.0", "Skipped for cicum>0.19.0") def test_read_rgba(self, img_expected): image = {} reader = WSIReader("cuCIM") diff --git a/tests/test_lesion_froc.py b/tests/test_lesion_froc.py index 2454de88fa..4a67c8d0b3 100644 --- a/tests/test_lesion_froc.py +++ b/tests/test_lesion_froc.py @@ -19,18 +19,19 @@ from monai.apps.pathology.metrics import LesionFROC from monai.utils import optional_import -_, has_cucim = optional_import("cucim") +_cucim, has_cucim = optional_import("cucim") +has_cucim = has_cucim and hasattr(_cucim, "CuImage") _, has_skimage = optional_import("skimage.measure") _, has_sp = optional_import("scipy.ndimage") -PILImage, has_pil = optional_import("PIL.Image") +imwrite, has_tif = optional_import("tifffile", name="imwrite") def save_as_tif(filename, array): array = array[::-1, ...] # Upside-down - img = PILImage.fromarray(array) if not filename.endswith(".tif"): filename += ".tif" - img.save(os.path.join("tests", "testing_data", filename)) + file_path = os.path.join("tests", "testing_data", filename) + imwrite(file_path, array, compress="jpeg", tile=(16, 16)) def around(val, interval=3): @@ -301,7 +302,7 @@ class TestEvaluateTumorFROC(unittest.TestCase): @skipUnless(has_cucim, "Requires cucim") @skipUnless(has_skimage, "Requires skimage") @skipUnless(has_sp, "Requires scipy") - @skipUnless(has_pil, "Requires PIL") + @skipUnless(has_tif, "Requires tifffile") def setUp(self): prepare_test_data() diff --git a/tests/test_masked_inference_wsi_dataset.py b/tests/test_masked_inference_wsi_dataset.py index 361c17e106..7dc322cefa 100644 --- a/tests/test_masked_inference_wsi_dataset.py +++ b/tests/test_masked_inference_wsi_dataset.py @@ -25,7 +25,7 @@ _, has_cim = optional_import("cucim") _, has_osl = optional_import("openslide") -FILE_URL = "http://openslide.cs.cmu.edu/download/openslide-testdata/Generic-TIFF/CMU-1.tiff" +FILE_URL = "https://drive.google.com/uc?id=1sGTKZlJBIz53pfqTxoTqiIQzIoEzHLAe" base_name, extension = os.path.splitext(os.path.basename(FILE_URL)) FILE_NAME = "temp_" + base_name FILE_PATH = os.path.join(os.path.dirname(__file__), "testing_data", FILE_NAME + extension) diff --git a/tests/test_openslide_reader.py b/tests/test_openslide_reader.py index c0b395fd02..efbd611579 100644 --- a/tests/test_openslide_reader.py +++ b/tests/test_openslide_reader.py @@ -24,7 +24,7 @@ _, has_osl = optional_import("openslide") -FILE_URL = "http://openslide.cs.cmu.edu/download/openslide-testdata/Generic-TIFF/CMU-1.tiff" +FILE_URL = "https://drive.google.com/uc?id=1sGTKZlJBIz53pfqTxoTqiIQzIoEzHLAe" FILE_PATH = os.path.join(os.path.dirname(__file__), "testing_data", "temp_" + os.path.basename(FILE_URL)) HEIGHT = 32914 diff --git a/tests/test_patch_wsi_dataset.py b/tests/test_patch_wsi_dataset.py index f775f28376..50b0e13859 100644 --- a/tests/test_patch_wsi_dataset.py +++ b/tests/test_patch_wsi_dataset.py @@ -21,10 +21,11 @@ from monai.apps.utils import download_url from monai.utils import optional_import -_, has_cim = optional_import("cucim") +_cucim, has_cim = optional_import("cucim") +has_cim = has_cim and hasattr(_cucim, "CuImage") _, has_osl = optional_import("openslide") -FILE_URL = "http://openslide.cs.cmu.edu/download/openslide-testdata/Generic-TIFF/CMU-1.tiff" +FILE_URL = "https://drive.google.com/uc?id=1sGTKZlJBIz53pfqTxoTqiIQzIoEzHLAe" FILE_PATH = os.path.join(os.path.dirname(__file__), "testing_data", "temp_" + os.path.basename(FILE_URL)) TEST_CASE_0 = [ diff --git a/tests/test_smartcache_patch_wsi_dataset.py b/tests/test_smartcache_patch_wsi_dataset.py index c484e5fc69..a2605ec525 100644 --- a/tests/test_smartcache_patch_wsi_dataset.py +++ b/tests/test_smartcache_patch_wsi_dataset.py @@ -21,9 +21,10 @@ from monai.apps.utils import download_url from monai.utils import optional_import -_, has_cim = optional_import("cucim") +_cucim, has_cim = optional_import("cucim") +has_cim = has_cim and hasattr(_cucim, "CuImage") -FILE_URL = "http://openslide.cs.cmu.edu/download/openslide-testdata/Generic-TIFF/CMU-1.tiff" +FILE_URL = "https://drive.google.com/uc?id=1sGTKZlJBIz53pfqTxoTqiIQzIoEzHLAe" FILE_PATH = os.path.join(os.path.dirname(__file__), "testing_data", "temp_" + os.path.basename(FILE_URL)) TEST_CASE_0 = [ From b3406ae35d2a11e00608507c8b01cb108702e82b Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Thu, 23 Sep 2021 01:19:09 +0100 Subject: [PATCH 44/89] update cucim dep (#3007) Signed-off-by: Wenqi Li --- tests/test_masked_inference_wsi_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_masked_inference_wsi_dataset.py b/tests/test_masked_inference_wsi_dataset.py index 7dc322cefa..927ba9de5f 100644 --- a/tests/test_masked_inference_wsi_dataset.py +++ b/tests/test_masked_inference_wsi_dataset.py @@ -22,7 +22,7 @@ from monai.utils import optional_import from tests.utils import skip_if_quick -_, has_cim = optional_import("cucim") +_, has_cim = optional_import("cucim", name="CuImage") _, has_osl = optional_import("openslide") FILE_URL = "https://drive.google.com/uc?id=1sGTKZlJBIz53pfqTxoTqiIQzIoEzHLAe" From eed14dfba311ce532b6fa9d88bfc044628fca8a0 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Thu, 23 Sep 2021 14:09:23 +0800 Subject: [PATCH 45/89] [DLMED] fix CI test (#3008) Signed-off-by: Nic Ma --- tests/test_scale_intensity_range_percentiles.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_scale_intensity_range_percentiles.py b/tests/test_scale_intensity_range_percentiles.py index 5ba3a1e1ee..0024cb349d 100644 --- a/tests/test_scale_intensity_range_percentiles.py +++ b/tests/test_scale_intensity_range_percentiles.py @@ -32,7 +32,7 @@ def test_scaling(self): scaler = ScaleIntensityRangePercentiles(lower=lower, upper=upper, b_min=b_min, b_max=b_max) for p in TEST_NDARRAYS: result = scaler(p(img)) - assert_allclose(result, p(expected)) + assert_allclose(result, p(expected), rtol=1e-4) def test_relative_scaling(self): img = self.imt @@ -51,7 +51,7 @@ def test_relative_scaling(self): for p in TEST_NDARRAYS: result = scaler(p(img)) - assert_allclose(result, p(expected_img)) + assert_allclose(result, p(expected_img), rtol=1e-4) def test_invalid_instantiation(self): self.assertRaises(ValueError, ScaleIntensityRangePercentiles, lower=-10, upper=99, b_min=0, b_max=255) From 46bf30db247339355d3ac586cabaa8833bb051bd Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Thu, 23 Sep 2021 23:30:15 +0800 Subject: [PATCH 46/89] 3009 Update highlights web page (#3013) * [DLMED] update highlights Signed-off-by: Nic Ma --- docs/images/fast_training.png | Bin 708448 -> 1035766 bytes docs/images/threaddataloader.png | Bin 0 -> 411731 bytes docs/source/highlights.md | 96 +++++++++++++++++++++++-------- 3 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 docs/images/threaddataloader.png diff --git a/docs/images/fast_training.png b/docs/images/fast_training.png index d0584b9dac37f6658f38c418d2d9e0c11e7da811..34e47bcb21b6f6b253c2e838b34e815f8e1b8ec0 100644 GIT binary patch literal 1035766 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

x}97 z-1HY2v*xt?AB z8R3o@`TZ2DjW|aXpV=FJrNhN{mdI7zpK$WpAS5!DZX!vBtRI{Po6g!)`0_E*IcdEs zhtW8sI+v5-6pv7 zZLf`cPMLVv&N91b=I@_Y$6ye%7*jRjb)HHQe*{KpZ+9Hf`srTgNXKinqA;DLcR`Sgk!(g%(Cp}!XbGXCW zi2ocODWS-q)O&FFV%apB&5}u=I|7KZsYN-1@t7z3<-uT_X8IApB-fg#H z-ucwK{{5U&jXQDFWO|I?O#zZ2=X16RNz+n(;m@Ec%98u|FJ`8CT8^#%)#@K{0i9j^ajOarW5t>ydo_ zb+PGGpB7Om`v_U->H8hiPw^pNHwUhJp;5i%1r^qDWpR+Ow}q^&USkU*VlpWy9ayV=8+3Yk z?;+K>C2AZKZy@%%9)hl9_1fPX1z!yXd^H|Y-Az9aF#Y{^;2@YeK*u`4ZC|v~C)%Po z#vK@`_W7Skx*V%Y0=JnglDzoS7d9|qFd$!Egu7`mSr9#L_RQ!WYRjLBm7SU6#xmkc z>6RJ3%t2W<>Tfx3sGjyfli%$-0vAm4TIBvu& ztJGWFnkex@!BviqvwxeDR3bG1JP&(2dc+IICv%2N9%a5-On1Ozy;<|(|J#CN*24hj zND3{sOhB~0iYr$g_M+Z?x6O`x6#?AA?ggU0WGwBwTb3a;6kW~z8`2ZQI^bpPf0$ZLA(wyBF-h%yfDNt{^ zRcqy62%&)Yy})y1^mJSz68hu>s~l3odj{Mr>sMzZ#dxFO<~<*?ya= zPIHCFyrbsGRb#Y>{;qoApw8yZXe>!p7{*c}A$&Rt&oPDt9+Fm_aOVv5qRy9a`ne1! zv;C{sN6!?Ue+!5zK6@cBMW{>dvsWoE-liJh207aK2%w+)SGj5nG`ad#Ia&(L z^9N@ul2ewDcZ@YtA1GROLbQ-CWzyT0Gsq7v#D1!7dy&=@brf7shb14k7d*58OH!sV zE{CmGNk=J$$2wP%#ZVz{u~rw(>5DCX(ezF^UoQ8Vz@>%s>f}>&xc-%?1Gdp<4 zZr}eLnQ}W2USIsASc-uw)vw|+%Hsbymq+e0@6mG`Q~h{ z5sXWv0tGwYpQS%Z1->9A5;$n{L*A3}DxJw`cTNtvLV`cnx&18y_JJ7Q068Cj(<4|b z9<{^;;Il92%==RFBNsRQ3(!|06C_T_5pg;zM_JSqrMt8eeV>Kb}vZAQCrg?Has;UPZ_5VNvr zHBaWYA>a!8gYY`I?THR>#I?Gyz8NahV&hO<8~9tu+IEAKJrv{KpCz^C7H28=hWlFW z$T7|!{H8Ioz?Oz1><@9A`RvvGz*;btTL)=MbMv>Td_nbhmp!JD9bq$@EXctv#IS;e z75CtUZoIu=^o)mbfJq>rcn+nYPd@q$3VLsu84shmPM_S5qc;U*b_0L!6C$oo2KKeI z=B#U*_b1lH8{f%~i(8UqlFZfVoJ8MzdoXj?pXQU(4~hK5tw8jSu%x8x;{ATR==DsA zZ`-tx3*1+uo=N6gA_=W=PSGx@n`GnfuUx&2cgIT<(lO1P-KxYF) zsoB%+Y5Ipgc9**tPmP-xFsR;ZF|6ZtXXR>aQ_m`B#oq5vq1v!wrwyvK{cKXza_jND zte&g}_Rl?>79@Ik*B77W8Lgw9Mm*}`6M&tJIu>EuU7l*)^R3%*^f>yHG^nn&0ha&F z%BM>IZWRo2G^CuBZ8&Q8_lbUS?9hZ1@YJ8P80rDjL(mtp>jyU^Y% zA0EpZx4IDb_ZVj~p%ndPl`nasc5MU2;wZ5nIa~OmZ_;(@a8mbAycIj$#|l)tG~d!& z{pT@KI^g6W#l?$gmXC@v1f@qB z(Mt`FW)y@#Q};CoC%Im`H1`w{>};!FYY{&4m!5neb$ooq_%%9igK$~iv(JRo3mdCs z$01Tb=t5r5BBuJoW6zmQu62p_+6_c;#DSysGX7CaUOe}B%#_$8;t$89v5NL+o+1Sx zEDQcE(@y$7bf--!&{OlNB(0xynnE5XMMb#YAjZIAo}uUPongk@-8MHo_%SaIp(UTx zyyr$<^rZ8*Ez2kso{Pf9{ggx#N*J)_rvWeaN^9@;O^W^PZyIzpoN9WVZ8|)Sm}B7( zeGlGIcJBa2|Cif&&d{kdUjGmF*C`GeRDOp)pkBz4j(!y=P{to+R=^Wd$|#<^sn^bf zgm{<$U~#zY^!tJaP%*_bnTZtHEy!&)tdVarW*C$os0`!-(_ZP<+30zm_A%}(HgE&m zAo37gcxbaSCxC8p;$EA7zX>!s=pl?YRs7`9LSQzUfZ`DzH%?{?lcZExj*~$;t4vNYwiCkWB<_BSa=z2UmFmmkV86PFmgJd3FrM8L85d1-$8mA$y*vKa z`Qr_c0nuoh6(hH^A5+>O25vz^62d9lWS0*$R0h%rhYSa#5u5q1R%b6H$;}gb+h3y3 z1BjB{L7!7c+^swFh2m>W%3m4?0JiemwJ-f>!gQw6O4Oay9`Xi+Oh8UdSU)ns->i?a zWb?D$3=WPyJfll-t)rMzVyvXX{dwr}6NjQ>cNat4<2O8p5kuVjCp@7HLUJhxr(WObnQle9B+-NuAVLJV^CUl9U$~ zTq2`6`=c41qTLB)YU&0-CLod+K0MZpOIbqEHYSEMTw1bnFhg9*fz}~vLnOl8;6(&!X-WyZ4K%>?BNj6P*6LQ&Bin z)v8_QWtoq0RXgNc-PiW3Y#CKv4v?M`3#*;M z(GUp447<;}VTpRvBBG6Fulm1rJ9a>wmkiJ>r_$tNeSZggk^wTnaaVOz!Y)ip_=wLx5>$`j{Ln`XA&+t`8|GawH&6 zJIh1p!6P(JtI-cTi2mZG{zbNoq*IS6<&l}GWqZ{VBH8(Gyna6Hh}&J*M7GVFx&ynZ z997k0Z~k6Phfrb7)tdFrLWv;+0fuD{`W;(E&Lx|+pKWP2$wf~fL;>qynl@qkHy=TG z{%8ib^4RDCKBjns4<*wTZ+%BZQZMICuM-9XswCBCSz4oGZ&HruB(WnJE+4t^awr66 z)-PagPgDZJbrObiNIz}$6%ZtOnu#U{*~K2imt%@c2gKVJQCpdGK3 zLq2>#flM-c#UiTy=Mp-ft*6G2d*E^5+J{ovG>LFH=v4-gRVveR3{=*z0RgYBNMvU8 z`AsC(4O;2az7sGgTn6M(9SWNb$@$m73}$F4QX9$HwtSPIf8=9*?~(cYXpE=Vn9`;JCT5T%`&+ z65Evm?F;>+yTDW<_2mmWux2ki%&R++Ci0miS9iD~ogKolNulx5~3&MtXe z5k(#EjAdT~!iokIn6v{?SY&~o=)7x%?6Md}Wflo)oYI%>(k$8X^rP(PTXKG5zAjMh z>h_;$ofT{6uPIwI{aivQSx+*k8WK;)fT}zIfxWBLk(aFvgjL4#? zw#oc-G~lPE5E&RB#l13w_WGLOVYWoYPN3O_I*<76r%;5WiaxE}A3$y(E- zyOSn*1#YnXdm>-EUDNslGitpnKay}AeffhKO0CsL-{mE~Vrj!A7L@6C!9JUKa1I0P zr*Tv`#|`yk*V&2z55*%YtXG8!8CjBb)*;`$JGvoEd zPnEoD7p&(`MFzKx)nQRWg*wKdYzJvy+m|y153Ez#mK)z6uu*iF>(j_gfEnu9OW4Dz zg-|798ovvj)mUM8r0~oN^8`Q@ECs->L5{LC^)g<#S2<&U6e__fEP3E62P+MwYfN85aOA9O9S+=>~Z?B zCQ7_`z$R2iRDS^YiuMc{{f7z`GG_#l7IjGQin5l?o*p0ed>N@rrPA=6m4N5eq~6DP znd2&gG&x%e^m%w3jL*u=iI{ zA_k(o<$^$VUfS2kpv{Xufk@x`j!QIcdlSWmAWb{}ZZs`bKmEi)NX0}SJ}J?}^}0Z9 z`BPHaWOPW&r~Q(34jy0_5Lf1vp4flAT{NgSYz$rQb~gbAhE%e@eVFJQUx}~!Q#-+j z#KVcMr&7SRek%3kQ6q?Nv5@2E5_qAKWu}Jy3HbAd6i!du%`b8fFJ~}H%;bH40dG0t zr>Qr6e&%=j-Mg&bl%v2oc59@DRp7RbD(h4g#qh zYStkGQou$1c9fkFeNJ#r))i3e_&jUu@yEY={tV(?1|7#)zqjAUC>DW|_SjN(BX4^F zP5lasK56e8C`Zw-`Zis&euU;BWLRBjx(Lv6Rg=@0zg0ro?72Cq^pofFKj7kyCd7Vy za6%gk!F_tTgD*8>KGj%a=(qd~!}6iKz7yQcWV5>`MMB5xXf@;aT&QcWb0=)xpJ{LU zf!eH)&{hTaaN8R8_t@g8Z%x9!%CWZ#r@)*k;8-E&BP|`d>*OsbNquN+pDQ9vU0P_L ztEmwhnwhI0OQlL~n`6g`s108+pTLipzF0N?j2H3B+0a&>;xdod$W{&cvRc{5_8v1V zhz4L=ab%#8hLaBnGHF*vlchhvSw){wWpIM7V)KQvr-M27Gy+sxg~Eb(6*Kez=KKq9 z5Y(D`R=Cz5YUwfS;p}H@Xe$te>wi{cWT%*hG2-6(R+KxF~JH8 z-^YM81i~LY^0Zse&3avCqYv%3kq>qh6YrJaj*4PII@_6iNb)NppAamf>0sRF=p`te z0+?@1ZRN>+tY5w16hYL~F=aZ762k6g+-I@vFEBYdG~HWmi4#f&YW7%^ZT{;msfwTy zX7MHWvldy|8BP;M-Qx2z2e5Wmv-=rQRKzVF(h7rOat`iqfN-xnWdOA;0s3==`Pl2+ zo*SSF;sc%&%2o6hz}HWGP!!Sqy;<0~+O7zEnYh{Yn+uvJ#;~ZMdjvZ&w?I*%dLu2; z{Z3qj&}(o-cCd*5L4hT`TjZ`N_*|ut54@P&BeqwmYg6|(1znq<4J1l&Az$*f4h^sI zTS@^evoxINCdF3*JO?z6PZt-SD|V2y!pgAUuRY+lLBlT1wP$+^3np;75af{$^|uOD zzyn`qn4vSWsi{1p?DoxGaZCfAagpVVUl}|MZdl-7fxkj!W^9d2ZA~rv(i1PSY?+~l zlyvtaCf-(ak#)bO4z5G1%rjcbY2Y+iG~g$@z<^WDS{(3F6gYU|M%-WD=|AXk`JFxk z7p|+R=i5ES@iBK9Uoaw0wZ{}l;{JBz|8DR{=6Pd0oXyVXVb2U4un z3lZo0R@Otw5nX4>40>9;?qb^slpl{~%4p`REdqjYD6;gSU>2SqlNcxwIFte^WcQ=U z%RtOIHkgn6%#Kd}@_Y2f_-t^#=R`pWnu5q-Dr1~>$roM@jWT^bGOaOgn(#Qc@f)D5 zH42zUXO8~N9#r`7aAwg>=PD!+jr5|EYmZ^kB8C7nXeUsSR*di)7$A}SyhR#3d!y(w zf`yR?E!^UIS=Goi8~t3AE9wwNkB|XfYhy(g!P*^ShfF?rk&}z_>SfywO3cQYVjm}| zMo`gh;Olm5Wd!$VI`Q${gpQY7I=&7KzWn%M(vsdtu#a>bCMHY>lppK_{SX{>h{M~r zB_n1+Da+6WsrelivDr83Q+w@&qSx(cdyGI4Y3&lV?S_)IY*ajA{S5eFt8?lm;_hMa zPW0YJP^9w=!TlXl^Y(Cu<0(pWPehyR4#K?$=HG=E$6Mj>QazlJ(_HvFeT1v#IlGZm z+?h!^J4I6D?VVLSPeGK3_6MV57~v&E&+vF2_Y#-Q$aV=u<_wLKd?pBh8neI^T(Wgn zu33itwdO^+*ZGs-9lW*N3!Z)tU-dD(+i5M=yrbDUUA(@2YQO%usz*A-+IC(2I*dHd zaMGjzJ6nsGv<4QSn*SGRacuhY~k+@!o>rja@Mn7CxfBRVBnw1by5NH%o=SUkgj?qhtu5*04;g8t&k~- zYT_S4Kgv8bB$yc17W3k%t;*Fv(%#g7VM)L0<)XnQsC$^L*ZWprS@Ofgz@~(sGs{eN z+H^pdkJ}p>^DAXuZ5jaGeZ8>@Y|ow0HDKpR`>r8bF8_tJe0`S|M8iTX!6wGF-S(ToYypynWwb3M=<~S^2u>AV*joo2eE#~! zI*d4_i$^49IocX`#TL>11>@M&9$VhOq1$y|MCJ+1XK)E!BmVVIC{%-liwqTZZ9fkd zTx05pC3ETuq*K2V4cO&u)25^c%uPVI%|qHu>oD=r?-Y`plM_q>2TG5w_B< zU#pr>3WkMAqDR>q()i!G(ARq~`U}_5)vueO)II!MnO4Mj7FpTEU)Q@+AyH`2m)oG; z7bSEwSs^ZBZMX5-qUl!Uw?8atxV5BVUrnCaDc`>+t>|1O=OrpNN^ie$2Z;X*EeT#w z*|43HEuP0VU%9IlqDNC6Lq>@y{VZm=U`cB%WB{gpxhTpe8H3KF<;_H#6Jtw+1^w=_4X55n>F_-6(WqedD@ ze{YvE*d5)H7j_0f@qa3ZOdnYAG zh=DRC0!;X?KWpv1#OmkFP}XC2e#z4EL5plWG5FXnH34kO@bfu}z za;$2ubggtvfWx+@vrt-pTaf-ThIh7DKrqS0(bCsl0}Q+8zBQzFf?gRa;tTdkWYulS zNGBk2uVE+v4l!OnZhfK#CTVp;5o-3Xwt!?(6$me*y8vSVpukp`{r@;ab4yc>UwrA&Lh00h!)z+iG((h; z*5)$2bQiabG_#sdjNt&BQzQhY7Och(TDbr?%I(}v0;aG;4xz27&HtTT(;t$+c|-@# z#4R(S`msk$+ZGY>;h&acU}}1U%~JJZza`01Z!{vmUg+VxmAkWlpkWB%hmzgQA|B2 z0lv%BP1=qE2he!tQOGq9=c+(yHcIr2L<`gx8?0GTH)(rhEXl-k3M|Yi*3g6$29p;!Or(AUFW zc7IeWuPm!Hl6(6PW{zk&9KV~dtwb_L4B>^O9SyX?NC&A(KX*4T$0VOgk`Q>Oql~O%+!3cxWKU+ilz)XwPJ+ z+1?vBhVTH7d#3sx>|l>cmHJ>Gw5tT<73z7Cqju=(V=<#HO3B4>mXeVDAY=WaKioqPQ(Z3>b)mIYA1T<%~S%w z8Kch3tgk@C$c{cwtlT^byOE3pxZb?J*5U{_?wNu=0ixuB&quo}7n1{6_~@z^29@y7 zQ4SEkkUddmOb>z31=h!WW!m$7W)p~L_@HC!>$59Z)XnyBugDWR7e^{+3q}&sN*5_-@nw!;?kPTHuROleE;C!%9%b5NG|CT zGIRGwji@cxU=PHbNC#E&PjS8bdTMN$-N!kHHulUKYsny9m8MorLRGe_J+5p}^(h4G zGRC1!$IDdMlbz=WbLzXk&%Kgs7)tb{k-?m*29g}kB<#8>8T9~p%;JS3x^hg6t{eO+6WOq+&C{P!4g({+z z>j9w5tyo0)!>~aMx&!RsYCj+f672eRIOSUgRlBpUtDsKFP1WzRRn-*APn}OWN6$aQ4CpWR7h;4S zE52(|$EsH7dOmj)CV%}#={|*qIqDdktV^)?xiH^!XZyLFP>4vY0Kjk7$HMBP(f2t1 zg*-K&3~z-HSq*8E^j}nLkR)Z;J%`1gVS&7pPBc+%IqGG>s2C#+TEbu&og*w%g%6@BQ_9WIt&k5T@&A3PqDc>0GL}M+Sr`^#>La zlp)gTJ~6^s&^n_(E(zP093?i}v8+I@$t=Gq;07`!w-IDipx$Q@W?HupXY>lug{Sv5 z2O(4z1h6y|0QD+}pRuH#fLToeedcJqf68!+OQgpga$3wV6$_mqdp8vNxm0wUT7)DB z7LrtrzmDFv4enK8MS!Hc<`zmNA9*`3R7m? z3f?0&l*|8@xAVCef@EZ|T+bF|Lh*5G3G~c&`n64SP9}@jmtr z^7Nqf{0bwBNLO?F?B~+ANR#kUD|U{-UNQFSO@GueLZ4d?a}_pgAPxtUBD^WcQng#k$A+d*Z z^@~d zKE83`WdKXU0V0A4&-cSo+DoSj*fX~4E&M0Z)Njj-yapT;nr>9maUOF3i>omD<`*sN zKG6*0=lpYhdVe`U3g*ht+pLQ*J}C2Zu_t}o6%*yGwOh{eSweokrVz_z>XgpSr zJF(i4{}Z`&&^1ZTuU^GMn8(nC01uWLL(cLQgWnMFAdGkVEjwufI2#S8@|0H<+DB}(Igel1YB3_{>P@Now~sn#5B0EFEXgMEh}-I05ba;JM~+^ zF9NzM$Ka-l`R1ysY<@n1g9^SLbbFM8k@MyDCaK;J_x?j zh#g8Xfnj&Gl)mmt{fb~3JKV`0X%SF?0)SgeVGK0k-RCSNjQr@A3$oeh5Q*WK(Vj?} zGNo7Bn49MkS3nstD=_285)hG;j2vLyv^$Z%8Y_YUNvLNWhq|~fw@1kENkv9o#6HcM z9#1F8uQ`w4)xd;K!V_8ge>{E5%?RUeJk6~OQ->Hqi;Us+^TqEf(W9mO=K4nrL;dNjdhPQplpBX+tUUD< zLI2HrZ8@!2zF? z<&hoK@a54*f#6ZVDV-)7Fj|&RAmliHp5byz`mvQ#8W1ukI_Jj%FsSAt!z4YTD{L9L zTpq)o0hiSm^rzc6c*!l|axT`Y9uEn`oqP51h@w7U(cj}#puRiY-|{@c4wnMEXZs;; zo8N!x03dL7rg2@sL6$Hinf*M@FFZkG#fV|mjhy6!hT4R+Xz3kVtwL7)1G=T?jcDm@ z<~md|*?R!h$S~{DG&P9$|NJ zj6LIPV~4Ycc(tN$hqsG-HR_!=BLW_wxDi}5@WLFakA{CDM;?jAgnxP>ha^p`CY@1< zoNaeBnb0*4`1smh$X{a=EHo250=}_UOGc!-tJiiLQKvg3B91S}w!J004YmogW*R7F zqUGj9Jb%6Oe}$?4rXU)jcMv~{iVuq3vXjUhuvyRGaMV{7YniPz9Lx4WEy$DRPl8j4 zA?x#y1HiDvYGk8+>U??I(9H+`v&a$k{e1i)N0x{j(ciMgkHs!v3o?YvlhvNQyd6m<)7f zcSO-i5-HZEXS4&oJ{_A5h4$87Gi!IGqT?0eBKY#R3T4jcTOegGY_GdZ%|qRCLqs4S zmg{6cDJe)9@pEsjJ^{FJJ7kok{npHx=<*rIQ_?QYNjypux`+Ur6*2h-v)beGXun@p zb&FN>;LT!D1aJnJ()P`l06Mm*>t8>Y^PgQe3K_Vfi*FYLih*CcNNlPlT=0?dz_4l} z*buFh$wrT!qW;ueJ-DtMEF$@tV&S*Avms&wsuJP@wBp)cLNozjgGLzB)~8nge*ucRArb`B00nH|LUe%rq>;=e&uU#wHNi=*XpeMA?P`f&{k)H*o?K+A#D4qxvDkLb&DUal#YGOPq>oCg}dBm z&@ODj17tNiguO{cj9Y!p&hhI(-e_0lh<12~STig7FRHf=V8p{MX{!fwh!IEDt2^`Z zeoFwo+_9YZ{-A`sZ8?kj0AO^?)hJ}Xu#o~RkGY1r-(Hx^y#a;Hx)8%`sf8Em5Jj8$ z9EQw359wiY`_AagOLl9+<7LE4{WPQF8Jx=xP(zw=l1rn26-rT}QhWLphzQz|Ekhgk zI#4+GDcJSV6$qMO!75SVWncW;0H>anZupAwKEb_v01__RGno~^hH(Utx<`k-vsHv- z0NJ(PCT2n@Mo4wr4@*lkVbkn@)R=Kh1J{agn51rlF*wzOkpU9 zphlnp7`BOgjD>N6+J)#tha?1HFmVn)F?FMaimCsVFf&(m}y?Blsd2X}bbPw`UV7yX+-MjTzSDaaH<*LUf1VUyo$cEc^I9 z;GdZE88^9eS0Vo3;vf(+N(8Ylt_nZka8^FxxX{e0GU`OLTC7(cTdFY5-`fV1n^^r% z2!X41YqVAe{>WionuHr-0HO(nvQb z-Cav9ozKPl^Zm^{f9mYq?CjjvbC0MqD4267qQ?1aVDMMlRb$1%>_f4uK5r#8(;aBx*>5l^1=pi|W75OeKi4 z1VWb=3Qz%GGi22+SLK}eO})yap#iKa-SO%12U|3LPLoAo7Gip?#wk}+o!r^&!xuVI za7YoWo<3{!(brnvGp#Xc;@k>gP$M0D^I2xdSi5(Td(AJclpYs+fr9H(os)VtJI3Mv zWHe2|YfKw4EB^^*%nUZX?e0$`zfVs&{KG4r8*(e%dfEV3jn6V>8ZF*-KdXjc(Q@3^ zR0H>D_wC(G_LWvy&#n*^yH_w3$JIEa!Z5`9V%`l7N><5* z^ew)eOY^;{J?uI`4eG|qAkhAvwX}NtY-gv}kcN7M{PsBh1vz9H3KeqO5@~1{w&zr% znwHMW?nI<DJ-WNA$?V*5NubdY-Me;R0fM<&Q0q8kpf7|BUU9?(Kw01~nKzouGRg&>-0+Uow9C znx=o^jy6jP_v8{@=`7qr?YkOkW^IWts1;2BL#-95-!T89F{Q_9}y~BxQH9K6b6}xs8o?L#sk?rz6P50Vg6rOp?#>N^%wc+C4u@kw-4CC~nz(1QiHId?3iO;lYLZHyl9OhhZm!a@Je0C5yT&N_b_{*5 zZ_Re8$Uu4dEb*D@MIVr%d$TB42~zfZ**4DbjR33{^gfa4G~2!aX;#Dy1EhN}jmR_pqozS%BBP23-6 z`iV0|Mt_;NBt@Ey2DtcY9FKpAA18ggM`T$* z#UdD*b%+R3gu*<}4=G+P%0$q?t*|nOr}Z*StG(Zyik7+!JgE+&D|SQm0TTR zbiw++T>^sS$G+hx0Ko5U?$^6Wetc&6bow^156ga~i_EN^-0C13-4k;wlj6+H(f?gI zvk@CqA!TeLR*Hp?6}>)I(dT}u_2yAZTs ztmrDNpqDDrc@v}T=7u1__Zr>@PUgmru4Iowiorw@29RR zE@(rUcHPStZfwQ%M%mk*x^pL+$hV3)a?%?T`Y)F^mYi;9)Hl=2PPJ`J(8^7J;MWlb zQ<@~ua$FQegHxljS=o< z`P9fx=Rx>~%0&w`s_?ku1&dj2vnpb4*3X0gJT%ar`YXOZu64rJy^p(z;J>b3p2kZ;Ses^r_BP3v(rm13XC! zGo=)}0JE3yz=DtFMjTvjITL;`QISSe7pL|fboeXY7cp_^*Yq=cjmRGkf}kj;CRdrz>6bO7YQ9_#8*{ZJ0bJ za*5wMGit$uE4Xy?oHq6aA47t8y8g{#?qOJP`fu~S#<&SPD7eH%OmecZjzm&3#oor77kgPVh4KmBJ{OlS$Pdfk^MRfA5S$Ml00v17bfGmzu)9(9TVD)kj z7X#e=XiI)*5g`2daDqS_LyLRg|ML|EjpwQ|VebMS(Rtvzfb4LFrj$p$3A3NwYESG$ zsR{0ez}{4))z&8`e{#Xi^GEQzNv8q>`3&371rzjn*BX_bOkL;6-);G zgw}HHNtUiznKDf}QH2dp6J{-OfMG}#$rvGDooVs~__p6ai|6@#8+^Xcmx_CvDYnm- zjD33r_~C2H#>x3+36zyvuCkvwppn_bf;?yJYnm=FipT;MFC3YZWiMLA@~G&qL5qC0|@SkwEnkyO8vstW$M9=Uj7+8Yr0jqa9VQjBTjXgMSvX~%@K1XAi zFL}1+O)!78w_qrWd-Dirg~b6+aoE0Je1(4VuXoX~dSsgIEEcp=`-9DJd1 z7H>piHc}RkQ7UAi+mKY$`~KW$?t-Kfe$l*7;OSKwo?c_X4i%yW4?1#w0zmU)s zg~>}*ni0VN{wMf(cOnP3b+BCe-?@H5tYC7-5-$-!^NuJP-+DYiaNWG|{`ck3p*RVvcn==TY@Cl)92mEBV z1YicU6zlB)>=`DKwKns%sfYecg$+PHTRk{;?cS9A56Mslz$r%38~h4S{msDW|KN=~ z$~Xi=SO@NRQS_7K%U8b3H}@(88%!Qu-WBq8SFF`H(dSP**tfnNd-boYLVbSRx9Hpx z+oB_B>elcfKyU$Olj6SDe-yIG1i7LtDCu!8IRB@oH!q)zajlAElg|W5IkN&_YJoa3 zANw-_0j|YLyQo^YL6eU@IUD3n2h5|@PW^QkeltZ%28vxap4utj_^G!{MsqzR{YrYmAEOd1^ zE#lkZ7fMD+uP*?#S97P!wg&r96|v90VKH}P5%E0>uo>tXc*dEG?vX!zzWyO}$_N8V zJ9tHUt>N4p12Z&6POgf&Z&NeY3JvYPI7=>oyh_#9#!qgqT~mx&?=U^ydzU8<2Ic6e zjKN$Aw3ifK;hXT#?cHxdJAlV7iy$LxT|aK#c46B%X5}K4c4h(CJP5^qc z1&xl?Uf^53n-=E|AP@qj~NXm5^*;cP`uj z@gVh`1(sHdwy3zX4d#tM10Wmo8*4WoEwsI!ANz&6*tcs;iyV3OgTz=QyR!Qe#-_>Q z@S$46NcS68Qv*>%fg!t<`o3256f^`*W~S z31+wxusU3w3A6&^1M0v8i&4^V{RUREHy?c4ZSr};cxcuCP;vtW=gSdm@xxGMC09?y zXGtZ<+L?_Kk8w70zcgih)w2FLRtQS*bx_+omWcR^e;BhwPlRhDfdx$*(RpcX422mx zEdsji=zv~Ic@f_A8m4VK%_X!74W!d=*3uN%a=HcJl;jN;!a zaB6{i{Qjk6<3Z%*tHSDVKHoqcz_bb_y1hQPnJGNvn<>7kvV4AE>p!kbRPkV#(fS9ZUgHOCBS1=#O%<^xBzJ-4<(?;TsC^Zow88*rsiXWlj*-U;xR zj#c!SD5M(>b!+1PXUsA486j3D4vw_zz4&dKtepl)XCQHfoHm@s4s05_X>IagCo69> zf}vvx>X#Y4+!#NvQgCT-6K>{7pAr(z6OQ>9duo-D*u-bqUE<~4bWl_yaFDsVsE13g zGkBCq&)ul^5wON*cL+s0Nr>nQDeTP?fRhe|eUAF?o&gDQAmNk{EZBgrcpPoO|K)3P zsXEN;A7ILHJ1y*3qaGooe*=`~iL^EVJrDkA8a^Jh4~o{#McL4R2?Ri};XwMA=kap=g@0wk*x~TfKkAST zwqE{JuK~i~h)9Y*Z1O_s`tnM%f*n{>v(S*>flEBIK>UNgDV&=)E=Xhc?GNZ)q}i(| zO6{QA)g`-u6fLjPxL8QN?lRlvi=5aMU+$^Wr9$Udo)fqrwkvpfWRIkI`M_^^`r?qf zP+#59H1Ut3e&pt(b3P$f)GIHcssBAGO2}%y&@$4iH0Px@7c5728T{km(e-VnbCe{U zS%^4`kmf9TQ7`P>>9;Y8e7ypXf&=w9S1YKmZn2i-eLhG<-11&cSA@-?VB9w6xx61y zz#%sk1lDV2$}B=REHwF&q)v-0Ho7z1OpB0ZQdLM)Q!H?yMqYfrfd+>fs^rD( zR%Hu!T}A+;;@)7{qkZlx#@*Wa$I>ZQ0L$p~#a_=dw)YaC4j;T|nJdNx1XSC`hz5Kj zRKqf-v!0Tp@gbIi~b$BL{ z{slI?lcly9HTq1SZS=D$Us)%e+D#zHh#>9bXbP|ckiW6`T7{u=Fc zD|X-djBM^sebhj3Ba6Erg_+lB5;(To*`8!AFg_bG z`SD_8*|(Mzgm;|Y8MV!|d*sQNl7nMdr0liLEPiOdZHQt&e;LqJNOdbu_n?n$b%jw| zWyw9hm-ZCeWD*5&v$`U+y=rIR6`lt3)L`gqJM{>vby{BnKD}Q&>KgM;aSgDE?R}lL$9SA4C`sZ! z&eW8OTYvMYea=`#K{B^ilZ?k8MYxweY%g>rn!zl>C9Q&veDa-9+ybp#TJ}94n}grJ zQ4O%dK0U+OTA!^OSMVn2l_vmVm&#gqvPBv~Z%1xAU?ZREQ-Jw~%zxMykZU6Cuhk zf1@eY-g3moU_J(j&;+mNYH;j)YjnuhV+Ei}dBi}?7e82c;y4>y8NU~M0TGjCh(EE& zl@C~xmc#|!io2hSWAk(1!UWT))awUl->iTYV&rlTOF+C`TEc0*w=Lx+F#A9Cp$z6v zW^Esk1WI~0945KlC_Ww<0K=cr{l4emKB)4qS#JImI`3=BF3V)6)4e^Y9P8QhYPCAR698GpLNa7rNXlxpy__ z!w)hO#e%+fT!pTu2vIZP;gELWF_RuHXDl0#BU~^lbc2@1NtSIdY|bzm>+7W`^6sC3vMhmWud^!|$DjEgDjvj^yO`L*jd&ERP5?N9uP#SUok!6Q4bpPDIuI54C8D`v#r+kK8m?P4Sags=Aw1U=}hrY@+BJ&&JBX{ zq5ffna6nA_&4KU3!Abcz6Q8Qs%{~r@X<{W)_B(RJhsqZm$dZ$kqeli)oZerQmT#91 zOA3yLb&CH8h6!aJ2b|ZEWq_-FG0{DcPd&(W@Ynm7d#y_jshtc4ScMUFHIRfwL1%TP90L;&FaN07E7K4RR(##}lAtNF<7m4;zm6$+(3x1neC>#`2L0ZZ=$ByuD<-isx(d zy{5$gSi>^F4gvbmRl>INiFM_GIhy%bD52@9r1|?W;|`~Kg@s!X;CYbjX|Dp<{>cPFY{pA56D3JC0TL=y7$^ zhqY6UsV3G(OIo&nWLkd2Q)YK41yMD<{f@w=*^RAbbhI(OE{KPNMOW`G1|+u08Y6PD zOQD-uW?e!!YtbIrOnr7XS(VrK`MkfmRIeFpk09ixb@+NqU?4!Tl4<96=nK%hh)^09 z9I;+Yr_om3r(IP7bifB*S0#B{n~mCc=ZxjN6MB=jh`GaIkD2FOOcvT_IH7?fUQL1G&%k`JBF^g*>_s4A#x4qv>aw1dzwo7ck zrw^#mpQ1|WxE*VT#IUTVp&=)PGahKqf$vn7LfA)DSQvS2)M(*t?#Z?(pmM=tSsxwr z2PG2lr`-GgL*?BUtDtRacoy$%B)%EU>;R!lTZgdfP! zrqpuORk1sNdq7Xw z2|M-5&5Z;AapBEn*dYGmB)M;7Qn3eqRXP55aI>axo39CJE;|PgB-V`;={>z0GVb$#$&AkS`8rQg zyZ-NTZUgEuIRP+wb<`bXY2ecL=ZRfPv7=ii;3byEzO@6^Li3DnP%3i&Kd|yW=Bk+D z>UKh(U0K=OM+OH;HlS-wqjI=@kvlKRK!6t^b z6XbO1$A3?hQlVml%M2~90HbU}PP-ne7<#25>hxCj<{EO{RMS^ND7g4-ri4}#5Juwn zj$U^?=*WNj(;q+|nLyP#QR9$>v7r`3=p|+z(cgGwo=D9M33mn|zF`V~B0f7{t?my% zX532nu6Vk9bG~MOiI_r z%|tzpnQbM3E2}d>GroeY%sbKsu|tOvL}1;RGgd{rcIaA``x5rWCs;M}@G0!DVUA|+ zDVg}3M7oZ!seT{u3e7Doj^!&rSZa8Ln$Z0Gc24tF!ZA$lWzub-cZ^SW%4VdyLNwex zdoR2H_P>hSDSQCdbzZR8^y3A-ou?lNoS zSBa*}T_rKU!LG3cjgKgP0omJ`A&YpP=PM=3&i+ zDr1Z@)3?UO^riaO)YbT6n`!y89Lp3LDhO%*TPx_Wye9%Rl*sN?I-s^GvA09DDNtgt z7JtwxG@|ZpdON8aE*4MVlSI@AqH5yBZjsaYC96$GBK7OHpVzC)_mjo%4VGrvGeOZ# z=VtBqW{6J*br~dp6C`r{10;2*Q{PCct`?k}B^Sd_tJCnrgsYrXEwpoY6 z_8DPc7QUL`r9z4K4%qDJCDASy1MF`d32zKl*#gpQ=LcK7Pc%gbl7p6aibHN&xZ=qG z+ymd%T&(rLF5-$`to0$fk#HqX=Uu)-cwqi}!?JEnQvSD-f>;bLpJ!~bO9&i`1nrgV zz1E9Z#vJ-eTMt^A=f@6u=OH5B2hKZ7*`30SG$j?q)~GwerfJNPNh>TwI4{lJ*G%ZAdnGQV z{V2`4Tm<;GO~p}VFjiShE^xx?qlqs&KgChelu2?Kf{ybU;Iy_5S)#AVee;xUCOe2zIbYd*CqiTocbL#%1GTx4ISb^>t{p5*-_qRCt zGucEvE<880q?d*kDA$LBCSfl+1WSAlv%8Kv)e%F{by`f*y~0}4GIRVSqXmawcj#_) z-J9nl-3wMgRB_>?qcXI!NI9yGt4lwTyc>}>V|_ePcM zN^jLq7p*nUQEFOa$hR`*1l0}Ayl*5`T8&=bQG)wBDL z4M!?^ny2JD%DqQKEIGCxc`rskMZ}nEXY`AX^-Al6ntK*_o73LvUbZy8gk^VnR06}I zoWiY7tXQ)cm`&R0U|$#c_j=rFTDRTQ518;vWYJVJRaHzIP7-4mZpx$}F19VV=6kT2 zY|g6FgZbOT>lshw)2)VAly4udbJIM;i^{?aVdad9#tXUsFu;_oTicN|g77y1cT$e0 z<5Yt7+&oIduC$@NTybJEb@s=F`_|^}uc9~a*8gt)DiXI#^G`0Is-4!EaVA2VR4PY4?mYj=b7&f^oTjrXQP`Wh|=}(*BbCG z%)h;ls~Rv>T;zMjGQ;r-eTdf#Wq@5#UTE&*{dHUE^moxBdt`%Zs_F- z#GbyDmdN*r);2_;{)tCZc>Sk1@`Qq?y%2e&@CJGC(6o110lUJpFJ#5QB9Xn>2+N0z zTMpquK*^0J^S;_{o-%dt;m|YMpTirWbAK5@6ws%gAvjz{-9yX`Uq9xMUbzTfJwCkUq|v=#vk)hKeN_6;>-Wc3lfJX3FMov*2Z;#72`CNYnS-8a6=)z%Wid=$fFpDc!RL*cX7*>rzA^|mk`ovv!zI^CU zgb{;)5_0C>;|88Ycku!8Ox_Q-QdQ94-JH=KA#2P;6!#LBoJMNYXy1=eN7fr9&f8Hl zzj^6C=)xa?6L$YG#|e#PvjV34$)gSleU+L9Tekqlneows=|Dq)MS-Cr#-M^HSW_uF zL9*i~i(_qcL;4;90k7L$mvw3B(;6gh+uG6$eYa*B zbyGbT;AdJshj1`WxX_M`=Ea*SH13ND+WUX{&T(JB??GQDDW_06N0Wjo?Y$(k=K8gZ zXkpCdjq?^fIb9mQ>8?*BG3PXcCoiYCqv3-BsYsK=0&+5EVuhaJKt+DZR zQ;kG>`ww=+KbkVIAXIF=*K4Ysz08Lt(0xIN*bN^I zCUjhsczXp6mKS}XDPzd)6i$Rc=xeLbZV_5DNx(5AZ1b2a=RWis6bNh4lahR3=qhPN ztfYEGxXpzsw}}#Ve%lj|gp9`?8|x>G=j9JqgP7ruiM)pp<(>%3uNT7Grn`LpgAPG6 zWk@9x2KNusT6Q=FbjaxI@d(2!!GrT_$$68;DBgyU1DXy`Jzh6`UaU!~NuMpEWoL$> zdZ?Q-5lbAk^UA+sV)^TjL#A#`v=zBTM89OYC_hSD zX%XlwPuUCo=)4Gv*@``9+|cp97`5 z-jfbEn@GFrNmSRoYaoJ){oQg3KXC^1@KbW2@TZZNqIWTs7>QM9jiBQVgt?Q-s{T_Uj_q$IXmU%|+9)wXB&{&p1bgqtsO=FEE+*L%z$0OIb5vu9GU6K({Ub(YL1S3w1<@tZ?vs?OD3AC9O^N~TWoR;g~~)$S@qAICedPFg4)*wH)r_{c_tdz}i9SeDvYvyE!8n;92z zjZP4El!t*sKFJFTU&WJ*C4=Y0uT{y1cDv~SyFGgn8= zJuH_Dl$Mb74SV{&cFpvBFok@Gx0@mFljFxZU2(gp*eLaM{U;ruNGocLzf=fb=4n#< zC;sNyNsI)f5;N4vlcC%Lk=MwyR6w1qd2m0Js998Ct2 zYrjLx@HYbOc4ul?Z-8pARWwtpqm_AWwWTXb|Z z8{wIjy#G61!$xlCEC?o`0~x`j=}?bG3E!LgJhn78WG>8tv&#c=3#NQ9rMCnEU9%XF z0bYv^1u(#Nhm-VE#GUzpQzlwoqOCc(BVZ)GbiJUGDmKXy$Mk13md53N5^C?}L+#gFe2xk)^S+G5^ zLGSxkjN5zvm}@aCC-3HkO_sy2Vac`Sw0ov>+I*56w;IhS2dNc-GUgd-BGWRA`|ifn ziOs)bttAGt`Ocqt^tGJ`N^N$b`&oLW!p9vU=0&)u2*zdVrEP%ANI9*-j4}EhVV*Vj zB51K7J|@XpD(x}8-0uVtwHvpo52@vn*0^cL43ly><@Aqb4HRj5T)v;Pj`l%Kblp^S z`r7Is;qaquLbo+oZ@dln$9QX#NWK0+{^C9+Roxh?L((>vDBk7e)!xHN+n(3sU@v9? zVub(|(?L}gc9fUZ*XF2271u5_>5|he3<*2t{g_+p-BGC&Jy<#$)nPLAm+pk?FwV;q zhWEOspMtsOwE-h5F)pjSJKhILKMo|Xo`_wu6AA~T+K$cZl=xY-ZL8}le)9UDjFb~? zs*^ccy&L1=w{i>2zmu5l(-G+v?r95{Wc7S^K3^i{7iP;J z_yp-sFHSbzD^j*v)H@~6%a3cR^tz`f#RI9Ytw)%zhjpPx6UpE@14!+rozKnbkbCM`upZdL3^ep{mP~#rSVbJ#R_B zd_$@l$t|4IW=4CGE$q`FNqdrQ+`%u11)8U%slx#aG!j^;4s9SpEWUekK|? zOjZfpa#VuMJKiojtGdnWR-o-NQMELDx(99I4mL+Var4n9*&FNMzp0u<`-hyy9Lxyt z@4OMrB|F>3xbig&+5^5(yE#8TWYIo%e6i&hHz?i%rRVl&Ve9v*Ae)?*pa069h@DXU z%-WINX(Ftr6gNE6d^e}a@Po1IMmI5>)_a0lHq15uz-JY80CI!2n!e7r9L{z+zD%-N zfc8HQy(UVJDtIv6F1$}O^5If6jz8`1@L3hA_PMxWVtB~un^M;j@IIV@m&o?OsA9g4 zX)F*v*nRq7v>&<-n{JV=`%xL--UoRITU$&pi{R)}q%><6dke=qG%Oo-AN!L-ZiDOEIo4^za+AKR5;dmttEj%g{d%V_&z;TamexttgMJ*_j2K@&f>j~l&ZhL! z1HxrC*^j0NL~*L%gRg26rrD=C*VUq=vNsQ?7gz@D2roL$`k~-V@y1Y~%D}-I)eetg zDejHRP%;s-4%nHl=inJJt5q^#hJkGe=5ut;z9%}I|B zG>x0h8i8djI7TvEBDTaW!UD=wDadFWQ*Jgn#bDx`O-w+jrZXewUKQ zY}L8~KFsa?Y#08Nqlw1npbAe&;z-8l6+E98?bG}#H`$o$iz^8F_;PF9-Z(F_%kPwY zvSV+0UgsPr>4e53`A=V)x?dPH@>;a*Zec85Huyxzo zw#Bz>d>sELO|@_i6jce&3bmqj2ku3!Ho@c12U`k^xI36r*J)_2A4Zc>hQ{MttT5>> zt?TT3NT8cKchj(D>hqUAhH8eZSFbm>qiasAH-XNMj5-M{7|v*dPA|!5pd(WY1EA}p zj`gv1TuqCq(aAk=UoanIOm(NJn>JC1oHUvt5s!sHq5Mn0{q-A@XYGfqjyYBhCw)aw zjL$NP$Z_x5g!z;g+e$g^c2DW*w>Z;Nc<_I%H3*l80p3(>ufO1?Z2!*ylZsZYO2Omw z6rz+K&S(9eh33w$;4bg`U;0!}Rd!}Ur?mg&_bu}<)aE(otT>4~OaCTE9&o1XA4;e_ zCSUHn;6R>QZ@OlErdJ1b)fWP6sF^-`h>u`O8dOq5a!TYul55Vjn7NOlWi1ebEt zeD1@g#r^9VuMQOt2-B`tqE)4f-Hx7An{*PRf5?I-zQe_Zj-{kd4y3}kdal4S9<1h2 zgK4}}HZ&dyiQifj--8L_nyych(C`M5#onM107(kBv?DGtJ*mM)Uc^^o;sWmIE7oGX z5;~|`$-*RnzrO*yddLN7dTaZ8-iQ(Y2!s8x0&TWb;Nt?haq^P)SH4F&sQMk8?Tj)O z;D+sOzKdv2>a5_mLs4-n}3*ECZMXYM5K(5&j?#n<|lv7OztPO(*}bvNbp*dOaC5Y zPoF)SjV?La;S+VagCEAzEzann|04Kc${Z6H#E1a!xce?}NP_ zGnk=DOR^4PLcP!L%@~FTdM;Ura)kOx+HxKV1f(Nq@x1@Y4+S3wNS?`BV0yL=H__31 zi?dN`y}nM%@K0<2QnM86o2*n?eyP_WiWooiUa4HEh41Ud%iHU71%W6W zOMLm?Yakfso_wc97xFKy7?^2Y#!tGo|Iz3)F%C)HkPc*AFVc(Q6{!ZbJT)c%0B?bC5H(0tS3WBI37(t4z+^$2olpB&yJX`Rzwc6JlP%(L}y z*|fI)!)5kO*{oURY%)74f^ykC&N;%yG+9k!=Ip_^p*fq%|G*AS4ES(E9f|!__Aw*8tl~3H6PZ@%_-ZE3=w8(S`-8-F37`PQ}JGFi#eo zfr)QgPqRv9i*wbe>t{?=Jf!+bk9nW`55h-?pX2qyr~T%Ud?+#t*$5)%$c4va+9T%T zz1+${p?nD%&g-N>USX&A&i_a=Qgr_$KbQ1)==Q|DyL?3e^-3~nRrlev=y^v&*7sm( zo&jYd8d{^5BQf3qg9=mJ2)Jcv))nX_r_GN>IePgU?Rs6lUt%pkglXfdA+Suawz*oD zg~a5!Cw-ilM5@)Q#MI~#*tg$|d1-{lS{r6IrhGAvN>u`fzW(f@TRd^K*GoMJM{DGg znw|qCn1&a4^)*+S)=Q%*a=c6uQpkN?b_?Lm(W19`>%YWt^Q7=CPEE5o1oMJ|?qhA4 zj=5o{N~@-FmqIk8~tBoWg%xC}F)+!I^NV{@l3d0-L$2ASrj zwQQD=|97%)tJu#Wju!UMlVKM=OQu&&SQ=WfBA}x7qyt^-bWJbrqQ?$4U>Vy;Y4WDl zPW@g*@2?X+DCsiNs>TrY4!tgG_rh8`1Q-l2I?S57})~|{%FaL{tNDP+! zbvA|GzCknH8~0M~ix;!2^4bA&=0oS?vhF{KhQEg44Oc~PgImxC6v>BFj&a)ItpDM- zy~K|QoSm?qB(|zyz{aj^Pz{Ak#$K? z?!_2WFS~Vp*61~h#D2OLKivV=)}jeUguY4fp@q4!JjNdn{wC#B@dwVDg@TXbXF=Je zKptG_76=~XhG^VID7#lE+TK16qh0U$`%Y}`7c4a@SzY>f6!hgQLLxLUhy{bxbNpia za`QnPSStup#RuWp&p^~a7N_+}S0th#dl;n;5LS?di3@`DsX?$U<=p;;n(g*jVJlu3 z8vjk<+^>LFvRO`XPGB>{&Rl~$+NxGH2!OpeXp1%KAP_Xz6VT!Adwm>l!6gF+;!X-< zkn5pU_vvvsBP^t#pg>(j>u25ym8CDLUj(B@j+w5QiqC+1sg`-m#gmav1wsP10cn~Y zKwdOdY9c>0Is=$tEYV$%?vaiQeR4C(xJF`4dqXy~VlRrt;7?#y<93j_pDiy9;<&lf zq!sQ-KTIjZ*pBAZAA6HC?59r4n>cFfwN!!e+(hj&n=#hmH3IGeBtt=1Q$+gz=mbx^ z0*}`aWyR)b)N!?e*wT(yfwR6IkcsQSRWd{oPVrHgZ3f z!qC+T)@P~eWMgZ1g<7k~wZujB)(xe9se5ViVTuXwj7 zYBHI9`{8Df5RGA6a?h)8xt*Rb1=VPmO^q1bx-Lfse!xstRFdbDDGiz8WN8lD(jcFx zdS3gy=GR|)Idg(RK1AIh9fSd0f?StR`4%4f9VKgsj)+i?l16@-ef3wYQR?K`@@F5%^lKf7KC|vRXm4%7)tZoYTCNT5 z_I`o8DV>?*B(W3BG#T0pJ(L_y7*wEn6+t=pGbW=pO!edZXjN%NReapMUQw-NHX8}e zZG~gJS+`f2N>pmSNSYa=lU}A(?N6D>1MeO|Dt+p-jq@`|zcVDa`z+Tci(7GRxdCdL zcz%^Fgew19lope=*=JrvvbRc>7RPyGIc=b!{dJ3Xn`IQQE^F?9;T6qcN{?%P3dFPt zj2x2$f6rg6qdBXBLBaayArYrr4jDF4Dqe|VF-m;I>Q>%w*Kz(L_lF!kz~2y6lu(bi zqAJ*bsLfJQ({BQ(vdAU=r^QG8d*>x{8yl6NB#H&i5kk_8+FPnkfGG@)IcUEvq6%ysFWL$M(Fl6Z7R zu^wOCiQB>8ugmrS0^kljp$Sh7D{q2Tda`Cw&N1eFk51h%;F&N+%iH77>|Z;};Af1q z5K|yce^El!kUz{et!d~T$O!Ym z7F7<*#XxIcu|Fq=u+6slC-Y-b&cfD~7q||?05u0UIMo^iF>Yo?kYAFR_Z8G8f+@#&d>y{~{lMcZ}1roGA~&Qzb}(Aq$d z)xk5jxErj!EyIQB8seM6q{UlrTnx`!>HQ&eECiG6#*yV`J_G5SdCdslZFbg8%P*3B zZ#$T2%R?yb- z{_8|@-O}}4oH1Mt9>|fOe!Tr{{{UbZPu?^6j*0)Q?I?HLIZv&ovXD2q)eLOG3S);@ z{r7=X)&GyGzmAGRjrPZ3VvwOhN*X~yxSLU&I|kVC49E_zeLxm-P!B55Dc+8TAtZ_cO&iOWzF4r3x ze!~%BK~d$ku%tfkyAAFI(_-BZgG1SP_0Imes49|i_|kmJ<6Lo zH55+^Y9Y5Tx_WI~p=E9TVsY`$8hV;Bg%vS;IM7vcZ+LkwB)}UZ1WXpnt{~F?;0+!G_+x%=GlH~eKbjh+Y4Am14&6SErt-pg_`V!{@r?F%M zOFkwcADBqIcjR5qjUe?GadVZM6lU!=LPdEfOd1(OspZ(Kw$va&77-n9BcT@!SfM=! zkQu65rn$F)0)|>9U5X9qRp*OZ+B~Dy+(}#m>FoC@!D97=59?KJSs1Cv5r~`!uw#I>jRA zlz&-TFEQ50L)Q0@i|0pzaOz_ITkHK3NBlw`x{}7POlI1z=&0w#nf*z(N(w4i~faPj%G-vddQ1yn{KeQyZ%qpe7K z+P|p<3?qdvl8bJ%1WU8kB_zC>7lF?Z^5(TXgy2Jg>wu;}id z>+e{%^a>HKWUsnIrSE+QwhxR&r@jz^Alhhpd?L1*nO9;BK5jrT1P+0zVhsU4lfci9 z{h<>O=&+He_BPB0Uo!#QAC1M_D`ZRT)|L~tL(R`;`1mqmBhZazaKEs45!_7u)8O`O z{yB)4Rr$nJMk}+mClNM@iTVU-SOvg-d`r*@Yh^H-XHu~W#Mh!BsFd0Ph8qV81#Dpp z4Qq`cRk)KZY@0(XD~5oQ16t{ISfM7*a{4HQOcLkL5(cZ@kAa3--kO|xip-4N0(~bHTZeoZ)x*%VQ=Y>Xs)~8 z()CA*v9;UN3CHfd7d|B#f&3CWuU=soxW+ddIkv!L|9eBh@vLs%GYPr67Fl7B^p>m~JM@S30MV4T78&f%Kv?e#`sP z=$VGNwcn00$d;tFa)zk)?NjyS%^nQZwNf#KGb+3?nm)J*$e;3uS2D^wvubw^usf}8{ON8S!uTlheZW`|p*`mzx_n`gPr=KGUMFS`3>|N0V;|+)k69Kr z7Ycrr{=)^COnY$rxq*`rU@#F~G zDq|GuX)(s$cGA~682`G`N>e2hDc_v>%OCtyn0Mo|srP7$m{9T$hD>gdQZ4#y>evVT zpR@#iDZBW=T*Ko zT9AQme=))B0wxz~4IC|4J;K7mt^gTgl<}hi$D4XVSg!JTjU5@3qdDO88`c*JgI?)j zN3&WuYfA(bU(CIGPPDYr7$ZhSp{p65FH6|9sfDf4>#<*2&LZUY|&AV5KZJ2Qox)Xax09x{pJC z*h@}IMCOqkrT}B0lX-i3>9cf@9}>b{iI2xDMmWt6%}e_ki&K<@W3CpuA|DFF4qLJD zZH!r7&SMqB$CH>)xh+M6XZrD8e?Z9iC9(3z4y*ejJ)7~B;?=1LG#B9D^Wo5)w7e$E z`KRqS+R}c`U!JP@&<5fUwV1k6>Y$I_<0PzHyuP1R5Us!>Nq*MR20uTJ7^@LEtk}-? zbiyll7O@8h{{C#qh|`Zo7AQE2Zx}}}&eYEpqbk|Tsk^YgTeDY@8^TzNPo&F zm-TtAmL!wsqxqu6*yYwF_K6OPj%GxDi<9uozoE!O=e6G(iY^vpe(~Pdupmrm4Z0d_K6g<}n*|w7yahpw&x4yrMCi{$#36IPT;@NDG32Na&7b-bwD1^r zG{52t08x|LE*}2g?BEWfB4-kNzz%WOdx6{6y`D?6t?~Wg_%SOhghL^CsUHvTpc7cd z3Zpp!zkYuIC@Rgs^@{_8@cj<279+LgMXY6`$Fw|_loluS?^E)JdmbS;|EpNTb;*zt z*T@AdM0u)ObGNG2bPE?Bls!)DI@B!lft4v47{;|d^<=ar5W|1dz$aX5jmPttr9W^4 zY=$_K6I1nZfwNy-!as}170OFdR?U#=G~aTehV!on7T*tB*-J-kJQT*)Bd&d?+Go>t z@#V-0zyTWW*S__NpNP@3)PM^gpWR9N(mv-;guB&*2v1Hh9=r<6V zPqVhXjX6sHdMyRz>J7$iM%jQ{fQ#(53^u zj#j#v$nibTG`f>rw|SYSwPq+Q@}ohMKzqsq~Hbs zUaAo3Fk)YA9dj+MBzxM{K?*80*V~ElTG^6`K%zT0<-FKnuBjPd z&gmB2L@mF!jB{UCNgks7+$UU!FVAyA-G0kZH`J>wfMxi5^SIY58Ch!iWa-AWB7z?Oa z^&~?tE@Up`enq>?JDsd(MthHe6xDOWoJ!6vk(bibxyg~|BX59xk`NIS>PotfzuJLx zJ>Dg~gz>}uy~2>?GKYiC`JN6W}=Of+UT;{E zo7B^XS|Zr1JSoGZ>TWkUa)$Y%S$$Agic8zMeH0w+L%B*T*>HnRLx({2zTVFWg+2gxSg~Trt z26IJqk{*%qyg?C`(hDe^E|Q2=ewF@aAY3N>jl29ytgSs7tz!5zfjbewZQ(ZeQamrj zE0!ed$7IC(3Q6nubHiW)0Fx=aNHk6{-?qf*&^Kz^|H1`Wsl&B>xp($ipK^*%ZBBh1 zzgW@22L-*}o}F*xk1oq<86+!Lo5?Zh2y^h|aQaqkZ92?d6Y#B0d^R6k!s`nA1TJ^ia&E;0db*5GWf1r8r$X7~yC*95k|EeJm&%!JWvQQfB>u(hn6 z^P@Rg-zcax9|xm~5Jz%nJ}PZ+glmGiz{HNbtq)d>IN^Fa(CBF@dBXb=Oe)U7!un## z^=9mKQ(paM@8f*TN1ZaA@F(5!2bbLm1R1g24&^x$gBo@E8ft4_V`s59Y=NM!2KQw` zezS%UaK9XC#f0rm44Dv03aRBWzM>fd1ds2{)Rlu%-aWX{lT}*=lUdN%tvkc;P8Q+? zAmbI@yGTsXAP6u5jFDdm8UzNyz`!pAGO~Hi8pzMlyR=6^s5xw)uZU-o3W5OzBp%-v zfHXeB+Hv>r!0S)?p}rfaRYd8%GfjcKGU1^0gU+#UC(E8aOdY9rkvrU;qP;v1zOy0n zYFZrRngK+t*$9<_r7*lm)IrFe0Oor_l3I^cKoD6f<;@^)?7bx~wQYIw%wKZr++J8# zPMyunE&<*pb1Uj6d;^cX{Jql^qS*J`b*>t!+?9xrU0snP$X|Qp_nP*g~HYXVI zLu%}##GC6wYaDsR!7;2FeUCM!3`G|N)GzY}{7EZWc~3JuqaC;0RK{L&Q^8U1Rz@39 z`Gh|_13{a!RXYaxD=O0A%~Bhxs_hL~2^^>PyUuY9n#Lc@$DN}Wy@d%>K1*O;;pn*h z{T}t}gg&QnWZqmHzm26m++_kh2v4Fq&J3YW7Rhr-zoD1axbuO{DZ#D+`^n78SGj5_ z!3+2HwV9Q!zRFQZ1me5_nHm!Q^luLAC>mW!-?a0yx}ORtSD2|TZBQ#$SgIVZcq+Th zD1!$N%tLG$Ii%R13yPYe$tZpfswRNjym5a$VIEAOZ)F7t*L(%3gj>c{*rMtcH-8vDzuv|-KNCQveIle$zc$wMklhA*xL3OUD_ zJt|Xjy1UVGQ}i>!7nkn4C9Rbdj(5)UcPpm3V2EB_pC8KUlh(q3hzGkbJ;n*Zp{s@P zjHos}JC?rzqwZB;x{z_!zBlXf*SI3_tLNta-ky3R1}dnABqr{TUWpCQ2H^ro5>O(% zVt#udh&JB+Pi zrnhMh%>IpE7LQK5+o;=lMy*}tv9}Ghbr|mrhWbo#fXSrs#*q*5>E>)Q;v+L);tvVW z!P%Gt>7o#?p7RnzZ!m{Y+iAYmhtyKaGaa;`x5cb}Vn&q5UG+P9gZ?a2_JFIt`%8-s zu2m-CmRw}NwM<4`KD!8b9t}yoe9gjdeKm2-H)eoo_~bxz3hk4sCgmt)aNF}B$En0A z+Ucde1mRbQI?X!pbs^R8+OjfU5SOnX((CiPLFXQ?^aRBnP|On8pV>d`fHNOd^Cx?Y z;$B-Hpx~etUU-XLMu1ir>fs`={dUzbCDLz8ikr5A$o<)9|5=r(6oa zxWRVc9xi`D;RNpReUR|r2m*u!Hpk~^$uN?M9AF?K5b(i7V|>xftO82uJ>pQG>6m4O z9QWHFm@lBx7ho8P=xa)rySfDel~qByzfOBlAO$k`I}Yn=i&I}0ARVMnpE@-sfb!8Rc7w6cam zs~E98l5v8h_eD-n{hZ;n$pIG9`@%k`{>5JQdWPgINkYJC`hSSESEUC4CF}Jr4~_|~ zq$dslCCR7T@k3{W!-J<@oIEHC|EELZ5A_CE{mM|N-PrwxBCRO@;Z;}76G%lh`y8Xt zt+Tl+K*uUuR1Ws950gqTJz=YK))!xssZa^D{|!jr6K8u8M+HY6T(CLhjRq4<`n%BJ zA>Y%S1bl+$N!CV*=82ZzmAf(Fx*`^2?8|`!7vPY6M*kp6u&uPohwA)K8wM7d02UH?lijGXJdg#HPiozRC`HpN_Q z8dEg-KlQ;%Shg*YAAwYMqCGmuAh=kwm$&H@<%7q{ic-U=^W zq*@ewjlSPv2puPJldbff3_GLH*b z|0fC*94f3Sb6I5N?JplS;2(t@4>F{$Ct>v(i6n3oS9))>amh;^K79GLI=B@v&pgi5 zDf*NA=fj%luL4$F?iK?_Y23}P%(0g;00)_v1x+cu`qF-BiJkg=dJPbjPV1hGE~94& zJ!O~(vl}`WTs<>Q*Obp(RJX5LOM5l?{ed=PDP@rd5q+v08~K8YN4tcHGXn0 z`d2O&4`-PZ*_2}C>#6!(a^yyDGK&D#D@fy?scC>R2!TL#UW*o!kToccE%SaT^TyTH zxeK^3kB+B@ZS zW zpKgon|IH9%)*jVA+D<}d|NcsGX#sDZiSK&r z3Dogsxk+J;zjVaa0*F^rf?P@0NbK5o;QroVH=(Sp*q&SaOX$0u$zG)SY^l~MW;z{2 z6z>ID7n3DoHLUE?t)}lPI2y9hw~qYLFpuVdONoYS?RuI&g-x{bWr0N1|H#M((nyju zY(yS7I&(_CV;wlp{D&n+7k7^CQb_t4J^=4^e0q~ZR%`yC9$!Fm)EDPJ3R57zf|C`C z3_h#iE<~r34=o>g&Pf13R)d$_PY@MR*9a1*(@a9gAQN=w6t@%ioI=v?Rz77gTfi}K z7p(wP=Tiz^>u(vbF#-ii1}+{%=;l^GT3W$v8PZ}};`E%HGd1Z(6=S8ist}w!v`L-G zP;Ggx;~5=|pOU_C8Kb)h;%(;bn*mxfONxm&Eg2F9dzE0x!TMxtvbUU895tM$_9Mk^ ziP@ScR8?8Y1PR{^TRkaVE*iID-&n3=2N77ZudvTecIF$h+_kP#{%mD#$N>_z=O zSWdh3ui2t+!||5y7VyRt6#dGm472bQcHl|&8saaH%VZC-P%j9s$OeeU(hpwXp`yRH zzq`=uQz|`q*ZAAlLJovoaXnaJ*i1i@+jB}!j`|p0eCR@PoM#*%Z8uwP81E)Q`JX0? zXJ^s~8NNyLH=Lfz+i?$!d?xU3zzDg>b0*w20=A(rqw*&hTkb;Nc&)i^^g>5`@Ba=R zq&+N>e|$c$dIF{P%77_&fOOS@Cvc(vs|AqQP4j=^;4%T$C~|wdU;dWZ!MqApW%GXq zZD7FwuF0cJyJPB(ER~jczod8iOb-k)ZGG&077Q%|4-Dj+_t6>MRG(#XfN|^CC-&4J z2NPNnx4YNEf9&sGVk(UU*r#vPPyJOxe`)O(hJfb$MhysFMZah4ACjyD{VWUYntuIy zyw=3u^1a-&MimPV?dI0T__3;kF8$2f0!(=`WKC-ae8X^A@#Vs{*CvwU-$H6J&Sk8P zwU0^GfD9dP_O3*kc>_T7b75huG^60@n@5#ikU^nDD{;SUcA2oP1}I}9jpfB%7Y`4Q z$Rc^1i~eUgM_yawp+I^kOA6Vpmi_h^e3!h#k>%6^Z2>nMoS%xMli~OdWHQlYgx2F& zv*%0vrYlD{^Y%A#z8H?8k$c?gt08-PCafWlX~w)D0|HmF#A*V)Phwm+TP+sYW$`O3 zY-fU$ZxV==ccvAt!0E_#ce+!|=h=AePU}x51+ZK}&^xM_RmICm$?7KuKE; zEW~e0H44!%Mw0j40ZUCIDysioz9+l*nr=m)$GoA|=Jbsxh-0|lYvB&x%O;pa9&J|m zd6z^0mRUh`$I&{pL5>Ai4BOpOJHmU?*2hjW(gjI;(w55}5^@EiKP*ovaX^SwgEh5c zCgOIjC$8dDu!?=(3&8KGoS>bdyOW`)oowjtOe6|ul3AvsQ9zT-A`>ClI-D(?1UOxC z`JRK-lxu{FGQZ`6js&ra+wMT=0Z^lioL5*ZA|e#*RY}a)q9hP?y&N1XH382d~e#r}vb{eSDE_UGi@cG3ZIHEirsPkF_fNqrhC9os*zMk^84QHC!v9el%e(J!e}SIUMunQL;&Z-5U6V_+~WAhsFWkfW6&4e!e2t zeQ~lk{&Xg)8bdj(8K_cBkIY?Bt^Oc3v>6hQonFjR27RhuN2O#KqiX_yHD(H zM!}3Q%Ghkav%-I_4i%8Q1V)0+U84$G52hc(qMV?}^Y!Ue?wvDlngZRFxdVo$7%Z`P z&g`=6UGl9@gTEduN}%cw+^c0wHTs?c$n_OIcVx!oB3Go)m$m=t`|+>uN8Da>0)C4R zq9DUyOf`j0!3GlYI~RON@JW@yA@`ruYof0JnJDhLLA6FYQ2~?2x+%E2=K~2z3VFca z-=C6}c30j5a%-RNfMxHcpt1#pPTzf;c_@-yMxyu|<3XoF`pbZ%oqGg_?Aiq5&rF4@ zm>;uiUtD!On^ThhzaDOzH)Gz%=Oj^2x;RFrxH;kZ$7@H575-|c?dy1eo6MkX7I?O7 zUlYc^tkTvODAtzdEKku4$lFw11@iJC)r4kR-Hg6B8u(>MPJsaFdiN)w*YU$P!qiCF8-gpb{+`x5 zhq^5KofuU{c%SO|1e-yIx=vBQJ`$i0UFLFx33dcz!yPY78hVpLJi1xM@zK#99nr4G z+oX1tWOG|c=E1@8d~YWUXq+Ro_4hgaX)Au~Xfyn2+p`FoU3nLaA?WXoIFg{&^(lDf zSSa!{X>ITKd{LX?=Mhn&`2+9}L_#HQxw<)686s78JwcMOBS*^=g-H>5gSgd_OdS6> z(qm0tT#Y2sar$0^EDJt*Db_VuiY{jYoYH+o+9Jmr;XQHl#Hc(Z81@8G_eyaN4Vv^+ zBK%D_G+R6h)i~1M{+i+qSOr==h^qb9V?dW4hdrjUl~Y#Gq9JtumY9+m9wr@SMkT(l zGv}HY!o2pH1g|Lxr-<~&myYe57VCu4%(&942lH=cqt&q6Q*JA~O};mzC_$vdbdGmU zaGt!S@3!k3Z`domuSff?BszW6h(fCyn@j0bR`W0+u5_F+=DqcBZ+G0x7Pp}kC}ROF zE~TVshsR}E`>7Zu!p!b4;1LZa{6kATRpzmdbU<0qOSmn5sqIK)xIwS!Dw5vmfJ->0 zg1x;pLN5XEgD6kwdP;la$CjlN1(i?!|K|IoH*w!gioR5Qaj-aLi(yTZZ=M#rwg%Pf z#0V&g!May`eNPM9X{x0$G++WIT0~ckTRq)~+F=VsM9>w4c)g|EC=<7G{onc&quYGU z^-o~r>;NoRG&Pd{M<6bc8fFE6{E`o&L9gA~?ridd|61Rf<7&n`z>k$xyh}-9bV+OD zu+?s42jL|CWt9(h1_0@4yd!&13;DcLBD&DcSo+_x4}}1VkQpQYxvP;r2X1P1gUeNs zMGwN-L8*p=d`cVevassxn8HBZ$ZZ%Hjw28)AfpnR_r%7n#H3lA{68unrwZTu;Fa~y ziSNLc)O@SDPGDsR;G)fE8p1!`gwtI=y4PwiwDXaSpzIxTiH!o6m6{jQb{cTw z#ehvy(uWmt`393$q(BE8^IV3igAaSIDVVGpbjXnra?R%WwVA0HWLqSlqW>|{iHQW5#cJoz3>L(g!cPL_D~sX9MsMpNHnowkXBr=m=K(Z^NUBLu9MSz#5#7-XLuC=d{nB zqG$dm(P^s2YNj|`vDYI@>UDwrDJEqkafB)8WMTD=3S+&-NUY14?}u$aX~S>z3|w=j zmv=#s4<0AZZ;ew8YW<$O$iu?~RZWzOn$1jgjMgxjwNAoDo7v4+yl&>~nz0;(0HuI9 z{!yrGtz7LqZhj&&;p)jB*I)_koXYkHyE8G=uN>^%utpTW1$1{v1LzVN|7opjv9GqD zlAk;)!eYEZ#-g~^o!ixHc`|I--|j{IW~!c|@qMVh5seMxSL4hLXi|t6ftUZv;3wg3 z57w7{x3o=Wrh2jODovR?wJH+d1|FJ!aS&;wAn8y#MI(7Dch~N(lGTuT`wF5+Y?b?4g zH=}*e+k4XE8C;EgYipX%r9FHZ`|W+yTm@tl_L<0ImAhvNb7McCo*1)+7$>iJR=^9) zeyJzBlPcHLPz0i|{`}9>`8%_}-H-b8{k7srmv6*Sj_S!@f`}v*m9_rc5u{s6t^%QM zQWO`?QejhdtPQ^GVGM}dRj;UVN{v~o+_`Xg(pjrs3*pEGCU+#y-bTR!AT+-tg8`pL z`zs_EdH=*N7d02Oq8w?$tz+xes^PD-%7q{? zw>bQ|B-WG~qK={+m->JJ76)C#o*)@0LCQS##xq+8uT4UKK35L+YS)e(1(SxP2Sj%a z&9YZH3E}(ZMVqehh@7DfR>Mh0S zX}>LaQ$1IcS^9_u47*ZL+4C0SQ>}k67msGt&{3dn(hKA7J;m--iq8!h$vx;m>AYMr zpkWQUp)(y2XtGE>U3o;${MV1fbkvfj_xc}x1xC!|u9C(mnSeSXd$qvA&Tb5MW?neB zpON|PF;AsMdb%ZOcI#??5ueMRPU+7)din^6${1Zl9NXf~zh5Qdi(0A}9lbAO!SuBB zwnvwVme2HOkJVoU#)Wv{@S?`RB>LgNc0*wGH)Ap%6HvSSm(8(K{eH95t8zWnq9*Rm zCm@s~mMDH=!1(`ws-$Eaa^EKjG5QiDV-t+LOdVT)ccaNmLo%1V=n zlT4T(eW+t>6hn;_kb~8%1I3dSu+d`rlf|gaJgv60W4<)okc3*+z-TTp4oi^cHy0WR z1?O=tr0P2BeZhr?F{rj9vQT60a^BykEt5yO+V@K!E;>~pGWr2JqS`fB7^gxPT!?yr zh2fLw;gl6YGjkUxTycNTkQy~WL4E&6K{eNg9E7h#MT`5zZNhK)ovXs99z-Bl0%4hE zrRcnRAKE7e-g#oBMA^)%8GnUZhD1M!HDyFHuRAC?cAqrCGum*=eSxWn9>B!iSYv_k z8&B#<;r^ac$a<+mY?dyGC3bN&;xLabS8&%aa`PvFYp@K#4&7{rh&M;e>`=J(0NaVt z1@U!;B{^$~>l6nhcs3Lc?%XiR#-L)K^~-txKn;5@3&6r>6HB9v+n<6`^2E&tk%z7B z1ZO=5u2-HEZH~qi99BC(*-y4}JN>i+MfGsb%YQ! zY=UGZd(8?D&b_Bdq3>lEO`tK>e|WjmCHTERx!%>-GE%RRR{9fxVGuA-YMAF{a)bV{3HO0fj4r_s>V8qA=Qm zxbXl$MSVwBS5zFA+hQq3=->v+^I4mj@!|hv#akZ_x)mm-XP}?JjxjZRyuTWYCPZXy zO<{U#*}D26UjEiz*+Ti}Ot5f*-MG6gsk-mLa*xvBCk9~FibD?9OfLEg`~Od6e|yhj zyPq6v2CwCI9e(&smGt4(_{Kv%d<`y!p7zM9}tJWR15Z&Z`m=6`{yzV`FAGU%biFOtM;bO;lG*ftq&jo%Uuv3*ZqgzMG z{ZhUoK#P|FgCC~P@eP|1tZW5)Q?B=m@zgFiTwBg*7JBvBVZ2{tHf_zmVy)X zvI|z4vtzKI-D$$XSKD)2N7x{46()gF5|0joAc}9hCNkimS97~AM`^+39h{-Ebrd+0 zIkd1lZ+=GEQW_NM0+T$cf2BHy&W3JH#m~KgL9?ZAhs2y3^AjZpQ~0I%pXm5Ncu_v6 zdsh2*?EH)~IqyL1xl+>kp1l97C=NKX=tb#ewG^3334EPJcRf>QE}_8!@uIiFsaPy` zl{6-D3>NgF%pMjp-<*R440%9Ro%9-h4Z^Yh12;Czxf({}gs>!_&82 zQ{!hP_-Wos>DajM9ay~o$+yx0zW;;e5CbT-?2|@)re;iy?f9Pmc(+eozw9n|HUGfV zlxbjI9+T;jyeemt_~HDUnFlETrGC*-gJ1sAX3ri)ZtIlzqCW5cU$3Pvc$pCelp>2j zJ(?bwkU$JFui~&DI_t@Pefl()8Fbe_AzsyrdD%Qm!XaLEM(I;;OWkx^E(!4n3rvmq`Td}Q3QU7UAy#;`CN3{ef0qlGqGMz8ZKQ2(#^N? zv$?L^m+njI@^zKVI!AYDXnWwJ*-*D- zQ7}Zi?~++yZ%_*)Mvvb{1xPaH z00{Sd*~F*)j0#!F*&*i17BIrmDfUbl0KZW##|9@WTH(Q0k5Ae&aj!r5qOKdruX1T& z?H8PY6av>b9zh}o8PB|t?KFZ^5 zwb>(EgnU16Su~>OjoZVlT7|oM!KZuz2z5Zv;yG!9t{E~O4Tftl?^dEzO@G_CeDkyj zFZEV~yysKh8q_4ZRr2sHu0#9Yz-7q6P2l?&2+-4R5&wUkv$y3v(#rC?H?kBwDEB^P zpeH+4Qn9zMSlriQFZWu|vo^?|xmqSoD!_k$7PBH5lEwCNMn}=-F@TB+M?p0TXd@QH<&TC{#(T zW9A-%=@$sS-L}Tves%%fw=0N=#ok!#jh58=8Tvm)3uPQvJoAP$f85N$vR=;38=sDV zcS~y5Ji%;=<$&yQU!4Ynn-=&BY7?R8rXXF^?MTL{f9fL_|HAIJ`z|v^$q5`;5dxMs zbB00C0o&`XVl02W<1JOIRnmFG-_6!c(}37GJxF%FLdi_e3WTgSH=+i!33f3uWl6xF zT6P>P`}oMR5P`jJo>__tvp+IRVC`66&M{Bo?{v1#GykOo$rJNu#SCVceDGD=>eJM$%&&JLZgo}yq6c}vXFdVCY0*-<2oBHuSRJw_`n~P=<#@S{ zwjo=SVq#c6*;9&}NbDz-gYa{&XxTh5KyP$PTs&*&C608wxYxj$6z&f+V!`Ls(luYY zq=GpD;#WG+BWx#NiM-CBhLQ_5c(R89j<(j0vkTvg{kk7}iA65qg0e3K;8XkBm$CgH zDPyuEV*49MVzT7I`y)MK%%qe13*%$V+9LXAjmaC2#r}C#4{m${UM#;=(oZjexXt#K zeA6%dm=`is^8F?j6)8_2BXsB7Ly?ze)f# zWtST>_@OhX>FZMTpK0@LTZyyEB33)ke}ajNUdIcW#0!EtcC3)l-fm!_fWoe$M(0m$ zp4O#xfPi?+~#dBsLFn(@4m{7p$(6(>?*U_gtlo3VQ$R;N!vW_Slm1>)>DPrLxIGyN+CW4Mg{#hS=293J_%l zU6h*w4W5CHJl=C%$b_w~+q1M*);Pj@teNs$eC9Qx>hJi~<=PRA>&~3-Y9qaNvOgaF z+7zw4^KNNyDa+q|D9ay-zVkC)q1o0K#giT)Q6H<&{Pz}B&%3vm7MgAxH@0i(>?PZc zR|8_|SR4?sPB`1c=dIZhGNlQW9x76SOo^8kN8jp*YBjnONQ5|@J*0^zzit=~TfEeY z-Z4Ct9raV6!kbk0AC>KcvH3od0lV?& z;3F)~l#(x!*v1sL)T9MTA*DKk)%wqCtW<0&p?UmsYS}~KJ}(JuAg^?Lnre!41H(F+ zW+^V0?UawV6_y9Lp)Oa<^O}~oYlHa0N{v`gCT>CqiqGc)AuBB;*T2?Lnt@Dh2#!vv zbzdLLTSU7x+Ayh&0Z7O3IIGXsl4+&OIl6I%oGWh*)&^NIn1{Bv&(6+`A#+pIwC_9X zB7|w|;-SSbl5dac%mS7}GBh)Rntn&3y~~U`Tqn?;wLl#V zE+F}_x^qsweI8ec{LJ)?uc=b5igcz(d|M289T>m|z1q07eajlI z

uogASbH!+I|vnvDZg(-W5qyZPkera55kL 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%0D!-igr0 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�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%0AjkK=HX|P_TE2bbOJIRNTObLAdX4G0gD8M=EK5B- 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 rau4E-bgCDdM=tdSF;&qs>j^W&MALn}fnSG;6^Q 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%0ApW*n$a>kh+DXxb}G)^P3Q9^qUf)`_m4M zkO1}9S=IpeJj#-P+zq5R2~T&{1|uJ(1yn-j1xSpg^82DopVKO42453~@<4*<%dpA$ z6ltEB|AGVMehJqm5cKsSL-1O0bEDSrtNj2<@!%fn#~*C@L!cvFVX*_Dj*ygm^YdpI zMYjyGfV2D(j>e+@fIx}g-7!s(a?QJ2&$yzROv+vfb&o6P0!; zHG1X`dCDkSE{Tsl0bySL!5isV!Ika2z$|H>pntq5gDp#Q~NHq^fNEwd&c4q**e zyBke~;Rs(dP%Zci?>z8wJ{yFe@5~kuWj_-{PrrP8j(XSL+*D2FXUlu*q@F=}$ANV{ zYnNdVmmqQ$m}+7+X;OZ+bsAUca`flvm(5OZ+W}V(sxD1~>Bgg^+e7l}uE8>&ig|hU zhcs5}I|;t!+bm{7#YW^E1p%(1B`7x(d{Tw)fIpARX-)AV zo2<%wSI?s#cOM@!6w51~0)l!Xk&1ZZQ`_)hAliN2J=c@TvJMROD>j66oNi86Rh4?S z-XPO~3(}mYmSY_r=}vKLYcGCVh?CP6Ig2$M@=g3)qs%s_$*M%MDskpo_MxRbN@Yu;L)!PRtdJTtvA)U@Z=?1G zKZ<&18*59|fKiAF>(y8}@46uy%T*RV8c z*q#1dnNL|di%=QuOqS`k?X_V%{^P`m8GK9^9gK==-cjcRa+W-?{r%KCviiv6s6ro_ zD`t{S14c~dT*?uE`IxGo`NEDVt{=4XBo|Mja?vby+> z`p4@>V4~V;jz;3Pc8Z{1+hu+_j1`J7oFKb{={j^PsFVMH77f2oY9Gm0? zX3{#w+CeD41oP1nEGtqkb#7xe2f9dFOfT}#*6fF z&W-&~0e+|Na|#0Da$MsF*FF9hjbpV`>_(k{r2R&CHcd^dx@s`qPH+lr(O5cjyEneT zEx4sc*Syvfodru+0Pgb~`&Jj_Y;4B+#o}9w zN4f4YEEC+pfrssyz(EH@bkTJ6<_D3Eute;8M!$U^M*U&4$Av?vVw3!w_tJWo)90l~ zWb5~yJ%=jq)@T?^QLTGj&TVttdIR@(5(%x3mM!)*ZJP9aTrI0Vg~Lp2DK!f4# z?EPe`ov8hT1Vz4JpOL{tPBWfjUcgj50?_Wbwm^%+dAOJL7DkZ90usX3{u;*q9se%S|RBZMWiszW1d0Psf@ z^CMwj2b+W3|B;Iy*9}(%@4gP6?MyM{T*fz5Mo_yg7tPgM_6oaIrNyxKQFp);i@(bo z#z|FRMG|NIbn!o0fW#)xTPD7({8uAdUF#!m=#9tk))Cv$uTSXob0Oe8y=ppt#ftEY z2nD%f$JYgLp${=9;|y66=s1bVLnygEExp<1qr7@D6ZI`@f~LAh0x!t6+B^akO5!Qy zM~_P>YArNCvD+E(wapm403^ZuI3Ig~GLhtJ_=b|B zczO-#O`=6`YG1tM!3c;JdH$NATPiSKm@$GS{=q|=(JBQl(y>2bVWxIb3yXxmWO=?n zC&QdbA?ki8T&ztZzic##ZXA01zOjeMqjp6Twk$jtxeSq~6LdLTVqlhu8O>Xh zPCo?Z(QnQn-cxUYvYc6*(AlDtS@GL|XAj`Wu#qBIII!2!Z@M?PSof6(!RkZx>G_8sjM<`ht3P=^~1PIS&H z)J6Vuw5wkdvfE;uzY(-M4ZyzxqQWW9jeaxosq`GbCF z4H8(#1BOhphop^gWYas08Ci{=2LsKRw4~aVdWZgI5Pg`%2!BSpWU%Rtki;!0k;$VL zC5}lt2%xvPBCl3w1O1A^ttmxC+X&*T5sz$~^WV{A=kpzR-1npt)P~IR+GPA-RBugw z8m!plsL3I7rjzfp73f1eCvYT_q{0t!q8CFT?5-$Q54!(`5S!WXn6(GK;bo~y=+}4? zctb&KMG^$t?p>StSk4I~>Rt0|f7B*L?}=~2D#KhgjFd!1iG(v^L}H)LdhIt^m(UM( zGjcH3XjxYHb1RyDXzA2CqUdp=9D<2V6Q~)FP?!oT#<#zCQu+IZRAJ?p+2wYGSoTaQ zJh0dM6Y*q>1TsN@EBjR9-Qmy1t}VY!{!za*eoGtQ7I5T!acZ^6d~_L8Xr(*p)h?87 zSonffd_ZRZ1K+l^O_pQZ#3#~Hh4=mBSoe;Ha^9W_*_Io%_;LZ8Q|djNvz`5uI>Kv4 zO=*#u@?c-ya{^QEjy1^pgG+x`gzZ`6^p6^hX<^RaZ%srXM^Wd~I*k*f+xBQqVVplHc{I@0Qi-TiHJtZE=2 zNNbYjLbzI~!9ZEnh>_c_3G}DAch$>1U05|J^PTqF>ma4-f6;6pr9#N39-EmuQH6^Q z$s_O-L9>xI8si5AL?_~&Z?}E~Qk9eLS3;CrR$p*+9;Jk-P!FYW=X=P6;SM9-PhRJH zqx2sX$&Cv=z6l?P*V$)E#fU@c&NW6CleqHtm{uMVTgj9o)tf7QbyuBr$_<@%c|GMC&X+C&HPapL`j(jd|MYfrV^8*MY5#FETz|^NeDVe0@>*1`emPK{2 z@otzbM5$}6cROFt%BHTY5uHHqZsR=kJ2M))thZ_R8oWt3{z(a26)?EoyNSZ-?z${1 zx=ua!cB{ViB$}D=71(q4aJL9o)E2Z{`K(x`1T$TAzet|v*VV-`Syg~}anE!4z7!o(MlWgWR@miyM-MNhgzDThQ z0-EQ7%~nJx2IR`Axz8$)%ORM^zA>Lvo{P!JAyWMq8KX;8UP6rJB9fd0jYvwAqiHekf48G8u3ZW{8evRw~vzh0r$ld8W@m9jqYQR4D?98lv-!^@48OmpK`b) zQ8b)^{?Suu3C$heEq?bs^qT%LcU>D$0QFyypST?Ko*-=mLD9uhe(1!Y$fY1GIe>SR z&b^1(AwyXH&qfo`arfJftgrs&jdewR*Osvl&)^j**Lk?bXj#BRiBP$^gQ`$at;kr>3Ta zhS6Ga;aT>|*^g~So9*qbL*=ODp%Hy$60X}Y-UP7RJ$XXzjIdhdHy?RCL~%smC zHU^NSs#)-PxxWvaCJYaoCMn}e6ASNowYMzUlu1fFW~@RAq!jh6oN<{j2uxq|ZT0b& zKbZ7^-`%d>UGHmMqyPM(Q9EyNDml@?Mhmd`ubJNqIZm7CsYd?TQw zG@5`yP&Z%?Bz$X-Bfr3S??fa6_>XmgZGH* z1yfNgoDlE0>y}wqubSqa++JK-cvB0S3M{b5@lOrd7q;~ntE z%~qOr6J`JRRg&pPzI{$;Y0XFujf0mA^?DBqax z8E2$My8R?#T3InFSnavcve@^ZD`(+<0WH>u?+OmZBVxkMMo8YCRNuFns4h*5I+%A+ zyl;T?CI}sviwZWFW-mUamy~g)*``u3@^y{!fL~l2oN42Z3yU<4I|XkYtu4zU`G1{Q zZFS@k9qlji9_=+wm_w7BvTqM|pgX)J&lDt6*{w_1h->>f25>8xfn|Sj%EmT4C;Cd) zHXbBmA=32jclv^q4~gB2Y4)t-0yed=!P6YXti>+WVv=FtTwe0ZD+1s#+*UFN$*8Xq zC=|I^kk-tJp4xm39NjTDcug3ThTWGTl>kY76Ji~r7K*wAXao>;bB{%-TotMs=t-7i9{gtDbgiMVFH-!6I-$)6}=WYg3Dq4ev8`#x`$B>aRnIJV4M z*Yq<#Z9cQM`%w*d9;fMjuC8LP>65?u>e7Dkml5w}X^JXr;*agN!5fqwE6KQlS_ia2}vOrixbOLrw~311@=`nY6=>i_f(7$cu%b zQt%G(VdGlkH2H;ERRlb*@__vslcvPKukQrhy>A(;^4Adozp+Q%5tIeQeR<{>jZ(aJ z`R_+--k9ERZ358XLm z^_7f?9||?M&y{mk38>Ry?!dAN;XrMaGcQq(^Il7`tXvY-SZIpf1Sr0E$*l{0Q}xNmd`c}-4aQj~A)#%{W_f&wZZZ~gjGe7~kjTGN zfz`{^rtVEXch8U@7Sl4y-DL>x$xn+-Jc6@*Pk=1&7P2B&En-eOFTC|YuARG+Z241gg*-^KO9O*S(5tsNusBUW>RgqDl!fvDn!HWX zd_SZMRml%XggH`k5@mGEF|s44Qu-FCiLp>^~3^*3*pwi}d0PtfD_JQE*Nc7XKm=9uFicQDHM zmq*7R!U6LIoZ37d2Weh=(Lk@S8XE?XeqkltVocw;0^xJ9M_&%SLmy89IUJ++VYs5B zvrB9#E|tiS13FBTf%w6`!X5Qj5_gEvE9S4Rc_Chs5?#M$_0Q;|u1EfC)*33Vm4%f5 zq$~__9dgiPpg^NOh?{j`EA{1Ub!liBWXCzw0~t$P*%GLBK{jgdFab*K#|`GjF)?`y zD6-HxC(As&nqnX^$dj(Y1=5s0n%=iI?@$aphTJC0-CDr!5RU^P72&>%; z(BkS^urM*n?56kWN(h0wyeJ>6ZV4}t^f6e;k850l&TB-ERu_6?Rxf6z96d{r^h1mB zIjn#HUbx5#qg5(cF25N$4W&=OtMd(#4`BYui)cgbJBLPaiNsXnaJ^RQl2*JRX&|NV z9yMFF%BkA~)ov-<*ggniAVHfsJg=sY0@)Chca<~e$&oACNPLx^VhEglc5pUoYuJU~guk@t82^eo{QS z_uz9RnsIm9CJM;H+Qq6LWpot;P~>U$WJS%F3OVv*w1Z?`oA^dhzlAkvdR=)tX%^WF z-mUrPAGf;P2dhh-_;LeOHE&vM^sgHWd|Se$-lpVf#49rsSpRplwtpvSSL8nibYpMD zGrw1YWC-;Q2-f@Qi(A;wjQA7ZvWi9lr?0HK@Cph+-?Z}tI^^A@>!wK#D67M=1VW+u zH@~SvI!_ieSL&BI%lD%`jQFmh=U#m{ zVWseSR?S02WPoMqAcMg8qucZOeo$|a%Y6`QI|oUf1Y~zwmcm&6wvkM~YfzFs zu$Tt8-n}?i|Ly~#@p-Xp4O0;Cw`$h%4K*eja!vv0l^bJKTk7hF2Ox}q*UBmc$r!vV z>dMWA4ApCqGLg#ZHXl!>qAruatCcL+(+5w@RswJ*4v~rY5%qV>tM*1P>mcw=$Vt>e zB)qFdt%(UZ?ARNj%rJ%=%IH#{>c#Ntly0vC&}~c;?F%5h_4REA@Y~oo_sCo1es-f~ z{n(?t{AJDjbqEq<7lI0TXbbu!7X#=0;081)pzlu-ftaGX$}a2!9zwYs(jgU$7zW2R z09bprU1eY^@BraOh$9Imsca{4-5yt3Bu%p^6J<;Xe|~S5vw9HhQss2Rd>4nQTD z@U1DVX~?8%QH-_Dh1~)bHONQ3mnmvEYsqN1_$cMfR*pL0o@7IxH^+QKhjfdPg0+AZ z$#zTHpI$PzoyokhEl^{qkvbFF%nsQG{&trb8s^u<`gQUJl1t*tOg#*Y!StEyZ#k`ZU*wOEWcZzI4fvD@3V-xpQgd> z0AA)qRd2c}e*7~EDo_N$rpl`y)L@<0xgZkS81Q1BC?a$EQ!e19<5V6W4ieE=k;owq z#d}+~jbQ5>_3RGUG2eh4-2eb9ooe-3?>tCIlXY*2X2u`JeBX@7I}^T?UumrF(*z!JQ*+s1zb8CsgaI6w=nqR~V0Q4w1&M+|H^rQtkSF`{oTo zu9V)Lam4z|QM+SCt;i6H#f>0D%5@+SoVXOFxM8Qfe`Q30BM!{I49dYU64(y!A3Xz3lX9EmsE{X$ebLG`Qi8GX)%%ZNGbUXK4`J0R+ZPR~F=!#~0kyG*js--qenowuFfhTLSb4qvAQV46P82T%5|!YA*sKL2BOM{A&Vg z?CH++J+N%FX}n+4GK3a`-~;5^LGFWJ!S{)0zU#)JObp#vUNSLTAq_6(Fe!ceF}9F* zHt59j3?E7b!P_;Sf9H+m9}IUi0z=_szdC7-J{eMz0tytjVU~c9UT;)V*qgrf67&$c z1m3#=49~{#ocHl>p;sLM0WYjR1t9R-#}hWf7iwaoAzkTQ!>H7hQL`XfKI_(MC$`$k z4FvdXSt9LRMAj7L7h5s5CyM(upB0pOU9DGM0&h=0pdg69=8RCeriUVeE^>K=*Qgo( zG1UEs1o|aMrKz1$UHKGJc}$N>qE9+`2RIwo1qWS{5)JJTG5bUW^^06VX}=`C-`|!h z^j)HS2S~^|d`E1YfZ(v1f95Z;YH#W5(`DFilKTFpD8Q9q%0?R@vKX{Mymf@RV_|^Xj|q%-(3qz6-60u6Oll-TTJRkNn+0}j%t4DNlV0^2UliC6WnUF|ep6kXptjF+1uI?J zZ%3u$8O2Oa%o`)$%j_$|e0O{)N});#Nx?ZhG9FnIVc)`Ssg z4msULSX`?G-!Dk?{{9^Y5`X~8CVKkSj`*P!i9%wl;dWlpyI#AD{W23@1#=r;Z%YvV ztZuN&p9d^9c=&XXYKH@y+bz(vx`Fjx!Y_JDv^@kb0cfB|L8?ko2VXc~CZs>>j>Xv( znccbSZC_mpTGh@u*G{t3RO!NlAP9>}@lP8!%58*Uljqx2G3R#f zu>XH})j?$Es}lr3$Ka9p10j5nZ&*CdzWszg^3J_lvkR;I@0uLoDh$LRnJJ#Xj;#y- zgB?cM*2MoR16ue$u4VJp!KV*uZ77X3g#WR{m{uLyBq2;g5-=+4@63Y`2UxR;Z7jIl~p}UiBXJSwUp|oE|kgDwUJs$#G zhkKi)cLjm{doP0$#Q@urK;#Xh0`fo-8AZt}65Y+-`Zfi0wnxu6Dc{U#EI4lvD&ta! zSaCPKNh5Q~;4%yuQ(_!y9Tnxkn_}>GjG(l6h+2 z!Ux;7Z@_ULW`Erl2rB;uw331!8Ibls20sW&d=V)AS7#mru%h0s#-CURQ6d!L#(#0m z{A#S5`(lBX?1b)l>Mv=Z$#wDLQ9NmNh3wNeA?wBR%+%P=b2GyTYJT7>8L4+%1NO3# zb`ID+Y3ZLvQVMIb1gJ*GhY2IFI@Pf~g#QV|5?4jcJOuU^dRA}{o&b18BY9QyKslrL zPIGuLuO3zcf@LN}9Eh)mF>opVgp$mVqAnBQc6@IU^*XZ+MtfJghz{nLqPWSAK=!DP z3bCI5^Ro=L_p_1lTcfOLaQYo@GmvlQH%kl>SGKzzj;aS?l$(VgmvvK(_P(9-Sf@+^ z-XYD3A6vxJ<@KGNPM>g0;SZCYV&o3UXsl#f5<7CfSTxr}pQWRmHt~{Hw&Rv6Tooa@ zx`3QjdZPgpd^I@^iJos*GSA!s5iwa1a(UL!b`@LN{Y&3v@V>(&h}D1^Q2}G0vZAE; z6-eHQLnOg1>w)PzIYS%^MBCAcdUhFARR}t{J`UV17n{ zby81__}Uv1`MjG=A%Bh-Zd7eaNFT~pw}1LLV&TkffWWvtKn(Qe;E=hWJy>)Rrc4KN zaj|s4u2FSBtV9C}gyqS$%ynE<*)?KrpJ*`J2QYcpo2NfUJ=E1sYba&-ULUZ7v^R-{ z(j8vDN7G4WB8vWG2MAR=&E+%<`A@{}CHu0)vv%?)PqrsSXJI-n&xoj$cYYgWl*ssTz2|Y{YoUQp1>#4G?*7HVl zG{E7><$1q%?IP5Ht~0tj^~)=L!B=Byt5~wyvPkZnXz+BUm-OIU7%onwu$yo>*cX(M zCo}%>P~B@_W75Mgny9j&**;G0kLSaYBK`0?`WD`(5TTS#n-f+eObjcKLB3E+tH?Ef z`7#nQdn4olh;%j0en>6wXRpMnR6d^t39k9`UM%3$(4$M2a}girirr6uK=PxA``RxJN|l-P89{tJ=oYJ8@x}w#!}IrA` zbJ$iG&oBfqD7sf%BnmI2cd*jK#Ixa_ci9aaUtG7Gd`DUYPy{M=9PCCu+&Lc@2E(18+0xBbs zdx>)6V47!q+aJM;{ohPgkdyj%J@_Z^h^|#o!jGS-|F6Mln13(cmS8C<`S-S3ZUlt4* z5n3;HJD?-)=>DAfH*yu>6zMh$FcuECr3VOg)aUNX*R7PLseR?XyG+fL;0imlS+@Hf zITXIE`a7a`(m9-|CAcdk%n?Y`4_#URuR^_Jnqcfn-o?O=2N%=84D)0KSA@K!C>^o= z9B;`LgO_DYY=T{C=HKW8Tv)WkR^SPCE@z_j(q}}5BDy&Ay8;gv<(rQ{1JtX^jiRR< zGS|kw?|LTY!?57o1EIX)ru0h83nyiC&QhqseT1jqH1;`(}L=@jIb%g#czCT!OuezeZ zyrDn!1vP8B*%2#uK%biaYB*xu4yFy*?He$DW32+W14zNR1=RzUeHd{z0cXX{SJrQV z!&W0d@4ySx(8dqSHa;yWW4ux`36TdcFAY_NA4bpC0(_7$R#sQvnu?D(A@pE-Li^f2qzocC5P(#bD036a1q5nb&>>UvZuX}t zrK>LxKv|C!0#xeBJv@9Ba`nM)01v7TGD-(B1kDhPgSNfdjEEd^*b%q*51<^Q>!-6iUP1d|`^P^B@okT{c`jA0Sd(0XuhmN%J?I zYEvy>UywjVR1+!QfN!*JU6Oq4N7?;M-U0LG{!Wp0_c@lgx3OrD`{1ax3rM~k zN4T+|D+USo6p!8`j1?49+C-lau|FEZ7jt&Y=Rl@M6X?oDxACtO&hAxP>Ijxjsx;rL z>n|FUz!K?u_9zo&mvlL_Gvya0BF7kUs3NC8p1@SJQYG!fu_x0H(eHPG*}Tk1Pp9!z zzj=alO4G%{W*eQ1j!}7sSruKV3&^~mAJ-c&eufPDd zF6c2e{#2g&Z}LwnvRDoe^&mBWfCG9H>m$CGt1<`tT1_F6_|83jUZW_sH}R@8Gl39(S4hrabc z`2R3o>Q4d5OYttisayZ;KxITcv|Sjv5ZXrl=N&jlJW4UT6ZVrCn3w8{kbIg~i5&*a z@1q_l^5Vt7FH?XZI$hPmtSt}?>kMFy?x!Tc{(}(d^#C*UcYLbWRsflyx$II2J3rnX6vS6351|}?zl{rnrwxLgK{(knPCAUna8@3(e0+n zUw%&qAEO7K&QW>nanOb_=B75a70Q%`&+LSB2F2Y+nx6+9u0<*5>**~0%ySl8QEIR1 z#e9hfta6%bUgqup?gf&z)8MW0i)HHF8bm^9$Im3vF%3ubZ{)z1td9ui%aBAtw4|)8 zt;qwZc@^}Wjr2tWB&!6*c-Grz{@^5Oa~`=I`SM! zF%E)@L);!S9l-psZ#MqNgXTX`q2K?L1B~_!SpPjK3lYk$0+&jVuH(_Zg{n&cn3eYu z4SiQl9bZs(5yvWK*YJtm$1zP+@a8MD3mGG(o|^d%B;_BAvy%Iw&ae8J?$5>kW*{H@ z+}t{)Oe+snHd8Lz3KjuciPYmr-P5m?%-yVfPaF2sM@@UELUCenb_`MT<&i+a4A zlj;k19p{w)EkGkc;%EhpVcDw;poh#?9kJ|+52`dcvjISBqf==MaD5hf7oEQT7nfL$ z!ptDTXY%Ne8R0(W;-h@?6I@DmLMQTcPV-qZd)bAJH4Mk}#?>26WUC`w|$lGz7r?{)8(uNgod+zO-Z13jF6Lj@Rrv`@`xEFDo-fA5!V z7NQ`Z{pi-S-D%=9x`4;;bAUE|ZhENSu3j^y%%xV}hOXU$yEF~g@MfWM5M8ciWf{4$R;t<0#=-}Hq zLnUO+|IBT;*}li&0&21dfDFKBRJsbXclK(kGO?dLR-LvXl3TF!Pu5W?Yu*pclIjtP>#HZtO^)7o6oLYt zxjUO)K^eF6 zEB8(JEvOw_DZ$L2F*Z~0eDuuNAK8U}&OM89AAzQ!<5Fm!rD18)Zy>z$0m+Ef={u#r zkUzP1vKzR)S-z~y%iKq7wVClczsSOXZKt^JGiow`1=Al$V?>|?BD_qnjfJ+L{vG0m z&Tiyk)#$x1{Bx@5ilAkHT&S_dc)5;Vsh?GT9&SZJ@Na9czH z!Dbh-jNs2lAeBzd3B6Bc1026HdZK8Kz<$?<;MNazKuK4X;|juGiKza#GKCqVd5=}UYu2$#wUk-V+96B^ zRe3(|y)TWxhKLSPxWRzy>+2WBeXsKa<(S>|9L$O>M|~{1nD)Syfyurya1CP42S$@9 z9ZLVx==9u?bxJ%CA=v#+kEeDShNZ2(*26NuTm*fkr;DL&0zj(+$%en7&Ucsb?cI32 z@S!;m^tZ2kF5z%jBRf00-Ooj{MX*~;6co}Z3LNp)!ra`%3e!QPsAvAU=21_E{lk!m z!jkA?2pBMWW1J$={Ct#$lGc@nxI;JhEZ@|sj1}#ze{^c!96dj)TlX6J<>F)xbt{pZ zmMkKS)YkB}>-xQ_7tK_~6yCUnc+4JsCv6(Xy zhSOD_f5d<>FqGuAtJpOwJ(t-Da6Rl*_PrcJgSq5=tI_PrD#U> zL5Hs?9cP(A+2_Pp&G|vZ^CXw78G=tU2WRfO_hXqR2gR$^ymKMFiqIEHQ4$w(#)}HJ zp&nkaZqm7+_NoZ`II51*_C`b9BR!rhKoNO2kz_F&t>vfOVRq(B8+SrvS_pBlQ=Y3Q z)z7ZX%(=L@5K=Y|&~~%hZ13hljs*Tjx6=5@rS6?q1-{j`)~afJ{JAuG+ZtLN!Vb1q zWJ>$P>`f;bmNUSvp2i;uCNpV7EQR!~`$p^bZ&304;6sJus=Q9AaR3=@gG7VtF4Zd) zs^j$`l5jXD{@!#=iD$?5pS)Pa4A2k3ngpr~<3Hi&_^s~X8<57)*~y4jsg@O5uVJBZ zyH%bii8J-5^y3^|`;R2=mp;HBzm(=5xan`<2fuYY?cuhae8yYf-Hyu@UPu#i)7?++ zPw8I?L3*}>K@E`rdB9c3#(1+i*T)jVZangS=^$UZi^z}HxVeZXncSR3n@@Ra)u415 zWjD-6_CT>Sg*dDh&J_fc>|AdSm@Z>6cFz=!Wyq&DW6C|wr# zx)_LeKW(ujhvGJ2)f24M7U|XWfhEGFDJ-1Ei{e3BqoC`KK%DSWJ5nk6+*3q;nc;>u zQw6Rs2owM$BPlmS~oh3J6J;Ivvk!N31?c199df@J0Xpt{or2@KDPDt76RtllPxo4zn z8F-$jL}db8lo~X(rtHRxe)4SU8Z0lN_IYL)w0Uq@H?f@r*6}xXtFZ+j&WO`0YyCCk z57j^oZ?;E`?noueF`J?Ja|AyyJD= z9grj*Zlc2qL@#mAYIaUJ_@HQblC(3~!uye9aYGh-p0k-w-qSj1cTz|a|KoFc5u_~3 zexrEF0QAc6V!eb}86BgyFfwq!+z6V=m%uz+~6u9J9g(KHZF4t7#bhRE*y^eQ@!hpq@|L~y_ zNA8S-*r@Lh7dt0Q+Ws=Vh#Wq+>RRvpD81figkzn1_?{xUS$Y&?42TbHeRk3=2;&RLDS4d(_L%5A#C4 zfcyrXQG@}GSKjbq+TNP9(QV&w%xOu3xZSkzVqv)0WqTZpt5ue??r0us^U|VB4tckF ztpByd&Xx3f-T?Z-q&1b5<-ijrt#LObRpTVG8x-%(AbMjeWUdG;c@cGFYH-H@xGb-R zrBw()Fd@H<{$2XL8T?hh^d=$0>`I78Rc&px6)fD$vUIJz!%c#Je{s+kg%)3|quovq zrZ)WHCN9U44XJymV?l*#)$R=>r0QtP&zP18?%V5v64_`3<_z$Rn7{)>VDH<>((j1v z2+I(|s$1j^1Ry`bx4b-Bm4^eOCmtk^%ZeH=zKnEquQ5+E0zHje>ld0Q;+Cjf_bMyu z+=2$1*0<}EPAf2Af;Uf>cju34Qbb%{M^KsVpJnX8niTln%{^h!DvIh#L@mHgE63DYyR3tkZ0o#7f6%l&^IsWpmlL zTJAhWczGN7vV5Ti?PxkPSa&Gh2LAQ8pPi-<2HxYZ%S@5|y`xM)@3%hOi97Cmq7ZSG zINO<~o36Hx!%61rft}h|92+H@56#Uwo=iroCyg?#{@ILmyxI@T@v~HFuMZAFdDnER zS$77r8FN}d?8=6<{XL#WGm#R(92u^2GoKa!l{rmQKt=V{3U^%E$&ro3~!?Z)9B zI4PQIuRR>)B9B)y_txcOQ?|BN2ajGL-n2jbUF$;1czZN&pLv>|be5HPf#XRqg_aVu zC@u}}VMi*ZbZ|g+6M+^lh&&3}W16Q@p_^Xr)m%`fIDPbcmJNLMmLQ&|dnB4VM((X? z+{FC{wipNO${yhVZN3`kL%F7V=21KUuqLe+46Moa(HfBQfhv-70hMp7<`}JK%4kTA zubQMl$)r<$Fg&3ypT+XGZJ4ot#B)O9wlq;M=L#1P-(pP~;D8#S^gx-Q%h(hINap|O zaKBXykoY6#12uIbf!RV|M~(q}$@9zl2X(%8zgd(Br5~7Bs0Sm%D1}zQ>ZYh4-Hwom z5)d%mCvRO>TrCK6X?e{vF_(=MKY#{vh+Is7YlIWDzJT~X!i#>nCn{TDdN8DmiKjDq zKouO~4;96;bC!2gLfYlaHxV#o&}QOlb|9}hQWkY#76_*aburqM?pkN>z1J$`PI6xH zI;Q$U#F7uWOX^}{^we3`<6U$qMOJdh8qOR$} zvYVmE)+rw3p6}owz2koJ%pch*WD$Pp(Ml;|KK1b}g%)@vb0o<`P>fwd+Q$&7!cA_@ zdowzs28)sy90HI72xQ^V8uTn30h%XIE2aCfpFVg@#SKO>^K*R||lEyp1YzOG||U&7vP*<=N^*F(~&*f97{-)J7mnXjM~X zsLB59%v)zdfW{2Iw%*_D>edr|Xtwg_stOIGwfg}n(i+{kyT6X0YMVq+;lAxHhA}P_ zhYOn&!++brZI(e$P!Q|W%W*lTbQUivD=p(%1>$IMTN{@0@d;_I>!DRobZ>yiM830? zl0vC5*y@$n#%5ZPzI>MgWIo%ILzYY`te)%hKVn12VRu97^AK zqWjq!6jvXqxVSHV1JwF__|CZri<-(<#Bm-pHKw*Cts`CN%ogu-Lr=qAmQz4> zpZUw%?%BOoIGb~drFg`xs9dC@Q|9i1UUYlCKk9hWK``Y6v{F@;S%veLmb50b5xnJZ zw&iuo-sZ6yoHwu5p?- zy2>)tw$tEoL~~K~kZ6#ua-LJPo!th0Fj74Jt=BKV1ap!#S9YU0I-ENZyOZQ3;DVnx zFb#f$e<9RA2e%$=`F(*LIW2$Js+AEf4k%<}5V$uC-rqF2MN*_+1ySsb8=mRUij3b9 zyA5@nxg$qi|MT?JU1m0)OEkDka3ejd&gU7*`z}FgewMjc^@k-M1NM@s!Vi?9F+CiN zl|q@1618Lhtf8qt)sGQwN3nBg`%V>HOPOXxuVHTPk%~rlStmD*O_h5SBGGl40p+Pf z(LW6e@&*h?mIL*Ty>P(2f1#IXM}#r^Jt*Hw9Ix_oqM2DJqJetn)c{nwqM_VZlk=lDjV~X-oh|}Mw!8Mi42v8~fM_?7*USrF7 z5DDf<08!+S*O1zmmIVc%Wr*;_M5GHibU|8TaE-JdY0L$<+J2ye+J3EQi~mrQ6cdp> zq;+$T6iCqTJzk_q&O_Y)t?u`zN$)(UG_jk5^+E^gM0ot&1k&L~zA_N1qq`UAc#j2R zFhHHQG{g*ZrVb3C7Q>jzR-22idX1Jus>Ih0F> z<`_M=3;N*8RzQ@gmM22%;h9Y;=3N_jj$i_Q10YZIavy$YpJ&ieO?F2l?y&S?%nSwF z`0l7BkS>ZI`c7{)Khrq%Bd^ArI+>5rtEJvDr+x|G-ZA&&}- zH$R$S($g9JTz+9FSo^>y#V1{l%qs~|A&oqllnnA@b6T}m;x4~70iRiw)$nssbuK&< z*Y4z5;9ggcA3i)R>OOyb^jnNA&58ri0;vr^rIqjhaN6tSxcC@ij&0=@(f4*CDWs17 zK>E@3j8{C;u5yYH&GgwV!|}vm3HdCYMQ<-qGL*0heo^>Z9XPV;r*_+&H(N zc#(~Fp-%G&It4lXKWDdBCqu)Wo)GR!frozX<=t7~X0U4G`w-wrC=rZ;7dN!8SW0HQUkRF=C3(=h}_aojBpARDdSaa#L}o^D3|JR^y$!9QUgH{L--9=?&!T?~$OV ziS|0&bo~xg@{;6@G7STH%;3+kRAzbnAm{@~oWRT>Q~~9mD&)SvUA_uPlmvvrR7Ik3 zzxn!u8t#<;;)55;?Ah4lA`G`l(T_iRfL-WyD-~0g>8C@$R&Ar>=g`jq)a$SGKpNL2 z0;s@Mc-{mhsF8D~b;~{-M4Vi}Ez;K4b=Ce-;hQ9V?3N`wSawvI1-g%!zJweMA3yu% zpcE6fZW5D4sbbK`Zy>lbM~>UUJ?`-8R3!YJxyK#nS2Lv!GVBaWbbkN+fm){GQ&Mkd zDd(o6uQ6mu34SxzMx7K$36aDV7|mnsc%Nfmj(D6WTcRF|Mb>z&AvI1P-x`g$`I+R1 zc|^M2)rpYHKiRaiV_+^T*TZ*|O3d>GVor8ZS;fNm+yH-RL zB^nk(CXv!mP~8x%XuK2pS!vsdvd_~*L>19nU2qgv{6M+tD*SFAz5=+2Sdid)|Ly7a zL;@hdS?3eaoqTi8g8^b>X0h+m6KeZ+pH zBQ@uFvO(jXw$j=Gmc~sI2`QZEca zu~V5va~HURI5K0&&SmiVE$f&4>N=-&W&wm~5vy=}uBic=LO^xh*575IXrK&Y8Ew%x zOS8 zy*58^_uHEK1j|CIfang$qTvEd{A|H|kz5gC3Z|L54OxgTcbH)1z3AQ$2Lk07QKo7> z@O5n-ggT#vO1qZ_n|gN-d7@A_#GiIIUp`mfpNxlEv({OIW{#&e)kR+&Mnig0?5m>J z1gFY+-MHmBt%4d08v0m z=?-}W5h+mtX=&;15@AqUN*W}kyGvqd7#fCV=w|5t_B`)-&-GpBPZeR9x%Xac{c4q) z^beB}zKC5Il~H?yUn-W=nXn4pJxg*dHHKvYQ8Gch6o7Z#uLqe9iBbl=^SfGRLm0c0gbd99^wVD zOEV~o2_rDOpsV|13%c>;eJc4QqUl(%A?7a2E?O8bG%8^`S0FAQG+Xd@Z#& zWff>$nZErO_6N}^YPPdJH)}pU=$*nA7_9gUoIuw;lCNIO2|SAlsrJ$MHKv$|<=bkX zOTqIvpL2@F8zlX$%03;maSa{x>%M;)jy9BJ8S)~7N9INR3m1Bz0s6R z;79*>tC?%KbCyrjQ2aNUUj!Sp&RyQ5x`i0qC6a9^D$U;4NB3c1f5p~f=yGK$K4R*1 z(iDG`R6Rz4+J~y;foea@R}HB8e^D)!*0Rl>L~`aZVQMZ%+TT6i764KDpbLDsh0r9d zih5wR$g-NQLV?||Y#1a9R{+0rOpUb>^M-%!|H0xg9KQv!EZ@yizzjL&_TczSccW}N z9d}BdlRr!lV(mQSUH~;F|M?l`N9^2kP(jZor8P^Os|YWua%N6eSHAoc#AtAZ*_H!9 zBz$GesV_p^;(;ov6JB1;!ON9gB3(!1l08jr}tQFcKLfIsZi{?9yGF#E|J&>W21lTXcwpKncsn=K3Lzj?fhNc z`48wz2?nA9HuQQQ?Cl=>8h93u#+~kAFaN$MMkR>OV?~70j4IWGqwMD9bn5!czZV5z zEdoI7HB;nyl|hcfsE1Bdr9IYR;i;MW*YNXSW#DXo!|s*6Lz9;DPZ#rB5U!jFWDTep zhrwrQ#4WQxRKST=?&Ar36zYfwjR(SvUXWVCVlh$lVS$#Q|2N@o?!650kn$ItpEDi} zx}xI=q4eGwf1O87ohmIRl=gpj#)Qrov;}Ug60Zm;ruHZO=XBvCFrVu?-1B$YBjOlf zVUj@L5gv$z*n}Xnx7{dD?{q59uP`1`%dWMb>vd3Jj??V-&t;`RO$S8BoeHYCORz0V zowfw{tNtzo-qKb{QCrC0yFA^Sh$`u|=l`^5p=oweX1u0g4&&|qL4qG``LnfaDfxJp)id_N?xSw&>CkTt+C#VYHHkxhk1z*C(H?xP z!yBaJjZEJAKfn2&jR2oZyqH@Vq~~L_l89IMK-grapYyX~kuf8MM)s*9$j%$C+YYOy zPj#Tnz7jUM4opg8vctC9MGTV!A?sQz>s=Ca^eS;1uQEKHV{W5 zgKmLqkzt}o;`_kv+l^KSFfcScDJMQgC8XHI;~;QhurVWt6#OYy@z0EH0LQ)&W*A?F z$9&km7p3m#;JYdd;^4siGI6c5On%-$rUL??2mSz4PV$46ZJ@hk0UPcz*!7ykmWOsr zcF(;*#F{%pK3&U?ZR}N1u=&-S%w5>|ERHcPnTj1TQ(xO8dI~eesoY}61{j93%4%`) zQ*7qbh(!FV*X?I_WnS_M;IZCM;)A%Jw4_Ns$Cl4HK zG*{!lhiyKcVDxX4!)!|wZyodM(B$!3h#AHCjIqNn598f-TS}EWw+f`>fprt>9yl_< z$5_O&);`_{z9@0K#@;OO7I&i2wIZ0r6FdUAYw{!2vTlky2T#OKtB$1VYnEB~=RXc6 z+knspv{mfZcXT1y-)K8T;PvFc$k%v za-A@?+k$?}K*Q=bWW0QDgd%^DQPewaWv2sftPb;=si?1?69(q+p63EoUqKJhGR@FY7dZ1y;{zK%83s_qfTfx2OeO%`#ho^(-CWnRyLvHIR;i1H*9k@+1b#=1jJj^5*7EW4 zAGPN$))Lq-EU7gWwU+hmgR;&GFt@NR5HHYql(qvC291a^uPGM@v?bIKnu>}xUO={kZ-k*KeDo>0|O{2#BKA#NF~o9*OrNIdFcQ+7jZ$P@AWZo zH88@R`S~$uTX@4QSjjsY@ewN&=C_04Qm^R#xAnwzXEvQp1kX1JK})S4?)M=QRgYxW z$(KJ&q870c=pPP7T6gY98r*0Nni+1V#$~@_0x6TRkRN81ifWM)K@;Na1GDICF3xg4=p=( z*wf%_E-#ZOKfn;3Mo#^#?j+MgPkU!lD@BC(3{&g|p|o8#L^`6K>8AEuU}Su(9US*F z8eFILEyKp9WMFx{lC;rCbX3s6I~VZr_X0>S%eM**M}VCL>;N=;phR;GYUEM04B-=S zs6c+cI`@~Bd^(mH3S;(8S)#Ni+bg8{HVO-=4G+c3dy%d3<#w_SR%O zBd^0Xh!7&;sS(HF}{ZW722v|#fI|S*YJO^ z?Gx?f`e_KoKI`fZfl0zPVB$SOQH>vJdAe^|H#|NaNHV#JInL#Dgo^GR1D0jO1EPaD zzYnYc@bl>NG`@KjfO^)sO{|4^<7o8m_aWQ^E5$9SFLle=>@sTu+f<9`%>B{mFO#gG z!Itr}7HgTdPi5%_iu{l{-Rds|EJEPexNH8yd{*@GG?-BW`UkV2jUlzR73*RY1X1Lv z=c8v)k`EpyQ)`)^eOZ@{4D)#r6fJ%)GY~?M-vS#(Ta>bZ4{ncI64ogKkU0V_{>I#OOCZTsH>F&>h=couj3oGQ6E@p{C&}NB2 zo8wJ8@`=c_2hEssjU?D!J3a_Z#HKGtdSbg%p)t8d;M*TyZ&v?V%Ize>L zuMwUkKRoYo+I8?pvg@z)j`84Fzu~N&9j3=Fgk-(|Or@@A$!w;ovxgi#g3so&{Tfo( z`t85GMsgltO#>!wp>8~;Ja;#8!m8Fo%^hD(CykaX1>cyDf-v-!%t77z@^ z?LnjjLD*uQc)?cD_CL(QG_n#Vx*LIpD+Ns^TmIHy`dh4%S9QNkwj9Oy3BK^|56i3j zlQRZL=bNkZy4rhm0?^gI_zeAeU>-BO%#FJc=Aa6HZg{w7Y4`o2o zDk#^VkxE%dkVY4oY_It_cZ6%X^{7&kEau;SNFvoQ$DWcQ#++u10(uCjPX%8`TT2i% zgh%dCmBb&7Mun!z9J&%ZSux6e%jqhe(9eQa2wF;*^(4bq2I1BOTNgG1{a+0F$Z=9* z5AnjUS6m^`tqF?0t7-d`Z(Kfa;I+WgF%zzl^;(O+Zw7{B!EP z@7OId41$KnXdn*O7^9*o?f2gYiSQ6rOuv`ZiqI3o0i|yhLN#8}msMbZIl;&VU}BFH z%f}gAY?xEY!11&jSC-QYSw-iPL0It#Dbwayx=Aojz;6@>*q{6mdyMCo1>3!k6Emas zK$gHT&oUE{W)o1SKC}&{_|!zvcIdb&n@2mA1oVCoBQ*!0et30lMEif+>Pbqb*P`YP z=1Nu6k_H$nU?XvDZ~X(3Bn*GdQ$3HJN`l9$vt5FXx96lm?l_iVtLLA?OmvMDL%gC2 zvow_llSS3ntSw8r{Jmq`=w`npHUF2DjZf(wZ~TMJ{8<8yWMVg+KySGPlKv zlg`&UwC?=}E@uiS{K)~A=cr9TXVsqVc{$?V?*WI)@D@QM<;30xxUi)mB@)M;StRB% zo0p2mz&1IVKjC3Xw1CQmUYjOK_&Kp(C4`=me* zLY%bUheA&{Uol52-inr!>O<_;SVQ!uUN1A?jsL{h)3|*_)yIZ6cX+4Zt|nAg6PiQL zG1!XKq$KG#d@0m?OV1@aVB{GJ?Mh{Xra)K1)dLO$`()0#>MMjGDBZQ|0gs!OztIxD z=am)n%mL3b#NfMqt44Zxj!Z2VB-an>=#I43WA}6Yz5f8tlzM-4C|{jR-0};s>U=S3 zuw8tKOI))09VO=hIP|ngHB}al&5iF)`2?~LE!&sq6o_uO+P4ir!`5@O9{0#h?&h~+ zJm?abonQZy5|t|HVnw}KND0+6s%6#WQb+(m#ns{83nFm}SYrY9!AE|e5}6$_&^0TL`zcs04;RI$1VB+FZ29Dt#c2w`*Y%mw7#hdQMdg&Xbx}G>q z%^Qb5s%_VL$}_N-t5fF~8CKlz`$*UO+&E?n;03+lf_N_&(KKf2W(oT3wXPG9^R>C= zpT9g3M}Ib+&ODKW5k{$5eEjIXYWl#;6fXn=myjKv>+r!GzLE4gv;=grZ*D0siDmh) zCPmVDXVGS?SGb3p`0hdh`KF&!=zzZ66AbIHviXFetSA0#SQYA||b zJ^sNbG|`%Q7;CY=H^=t6(L!IWui+2I@h_rV&^>30Axd{Un2g`7MR%bE77wCkWp(mc zxdj?_LlIHsmjh-8o4BauX_sEP^7+`%`sdB~S)iSPldv>*BK@3q4Zv z%fI{X14;1rGDzH`y+99Wb*!oyUiS}xc#qD3~#B*RIa#SNnHnxJmgZ0nv+q3Wg zp!0RGT(TWr0{v4VjW}!ev7w#h&QEP4*SCcV0wEOp)82tgMQzB-UV`TLL z(kh8GFgX0w&3d6NAC9r7s7@SDBTmvgfD4PUGt%k$1(8$|f+$FxXyh+RlVpe%nRwEu zC#P6fG`#JUaedQ3zh%}bQgm=6RzT_b{KqX!rm1*G=M%N?vd*CAmkVFsbIxaPslat^ zoEj${uq20ZE+vOciP1O#n$-L>%mz>NPCRO%z76!sL^NI(`UCUs!k;x@Q&6GPIH-&k z!!JX#_Mu5XuqO2}vJyooZzuAz4J>90G^9npobCBJKlLdYS^nn)E}Svgv47vjk#YxQ zm|PQ#OF!z*NcPgA?Y%Bq@NsRDmIV03UN@b~3?mp1Vt|UFD_1oGJh^;^shrP+f#>e% zTZpyuGPz7HozokZ%U6vQt>)lz4%<3MMm$^oDf2KwkY8Q{bLXT7b&C^+v;fb3I2=Vwz3B7zjuG(v`#K3sLw7YLjtjXGmq z8Sz!__7h8qz9{sVbw{_>VpQYxvImkjyNaIZL40OSyvGB(3SXZt(I&rLWFGtsd(;o5 zZospJd!fJJL5fX&*3sJ+^l$#wgFh~fVm(y6yd_WGRtu)V6i|PmVIp%>J^yF})&nHs zV`{Vuf+6%6O;)oB^wK@6#4uUQ6niWo22l(bOH>00&i_*L&HfL!p)+9_=1J*`HW=F* zW+hFW8bP2D*KBmJOeqjdM1-5P+RqR|O+lVNRXZ<_;@ zSl`SN9Hyb?W!~37NUoUt58*BN0N(!oKC>WAF1`owtz+(Lumn1fxJIjb_v;#)(a3VJ zg{lP+MtQUwdX>SIzdC!v7dwr_TXIRPcnm~s%jBe>L1HS`C1RFQ4i+A%wl(oclEKt~ znAk;TfP0%ijSkApvo`BIZ8coyWI;5copu`CWr^<+K@^Yyq1XIkl+lQ}26-NI zP_)X|yLK3+#x!b%jcHK z7*haFP!ezbeAs@qu^C@fxA|PhRPtgysb!5Q za5ZMmZJ;-J1FIW6l>Xt{D>D{MDFy;oCI2tOncq|Ty6^^p(F#TAg5+)@X3Ka^0N>3; z20SBvntU*#mqCZ=8n8$=*t}*?VVL-Yf9}=(eHBc<&;y}4W%-j0%lv!Ze+7|@0J$pA zQ1$~JfF(EeQ}BjWf?K;=isiY?HEqy?e(MY>;2 z*1Htbia2Tj+)Z}G3|rCL!OL#7oKZ3ocjFdk z&=*7jX^0Yfk2kbB9UCvV&7HnhKU8(}6Sih{-`N2&%jfpS-IwOVat}A($np)bnffd7 zb)1~!gocm3$9Zb*=Uji@dW1Va^&pPmmlC)<*_mjJ1!U+meex15K#igT0OUkq08f*y zV`)n|10UQy$amrUqzlA{OqWvIgMDBWYXYnFs6fw$wTrR0z)>s%C8h?V5H!M{+Ai^c zfnLnWAh$0i>K2zN0zCEH^GmbX3rgFEg}|o)mMB>KmRnpJegbD_(ZYtQ02KR2yr;~9L7dAYC_gqO z-W5sOcb8oBz-f;I=Pe~(J#TFjvCuwx3zo9k`|)$RGjIQZzeu;(9LtY;o4_aE9Dcyl zpVW6D_TR(j4b4mWWBma)7e6J5?BCw@GpsGN9!H99bpQzW0Jk#Al|YEOV7(ifxiG5G6mEgHpD_DzWTFXtvH`(ShF}WYP z6-I7Jqa{W5J=d3A2EwJbDYVpQf!pQ|ngy5XMPf|F>(TqvTf5yb?_a;c1S&L-2Yt8x zNti{;SXe0nFtV@CO<2V_z|Xk;wZirnMj%UI`3=p=3BH|t{kLTOPfp6uxke8*GvW;V zQ_~#2(z^uvp+ppf5!@=D$xMLcwN6#**XKKJca3c*OTQqf{yZW)a@ zC}ctHh3i_?PnSq)-nE|ewRBMta^&0!VkNJ;F0 zf1cC(23oXkz;itTi7}(tiMx%by0~MF*C*5Nz7Oj-LZHHC1Z@qVfBF=9$o&8R;_%(niLm|mhl_8emu zy$~bt8l<|YM$m1^G)+g`YpM4S`1u}CHTEs8^iH#?l3TM=R(%^9l ziIH2a?g*w}D|vK(zAwHxuUbTG9IZDF!e+RqvuUKq;<^6$yU4q4USlxUNhRwyDc+gf z^>a2)HCt6pq@Rj1CjN(bN`|QS`E6uA5T@i2maW}mc;seW9CJRoYP_nrOt0+Lbp$Tg z53qEF^YcTsy?+A)Ps26uVGjg5&X!(?uJ#rmAGCoeOCcq}l zh0-0vBMTi^fR)L`jvB~+J;N%fZ2u7cnvq#8zWxwKEBUa}ERM^a3J+m$*8EJ}dq}vW z>E8lsM6nmOF@dIK#}pR!8auPUVM=F!A zzCX6XnNnf=oswC=uhtYf0nPnvj<0jJY0o(J^RL*+OBQXMfE{#f>hNH9XU6V<*`-BY zrqnKlUJTo{lJU3=nU)#ej^}1qYODkFw>{<2i9PuaKwFKMDFJr#@`cI*-!MAESm+=^ zO;+{DRuTtHNIsjw(u*lN#L6SIIIz+rQ`6(=$`U@o6pvoLVGGq2g@i{%y$FLeETjSD0y37( zTt{}gr*4Iv)05-5vVpm^*eR!?V1MY^+;t3JKSx`mR#7fruloCxpV?F#^`AsteO{CT z1WU|u-aIzd;>?BF+&cc}T>WvK@r>*4;1l%!xO5nqIm_MTxiHQmYF?nZYWs!h&D_!U z8)1E|;I2I@P-_*GL1%EWaZ|suIM;7@`(pAv1S0$xN=!e1Os|~cFtn4MP%Ib9(E7<& z{norECdOIyxX#>Ke5PI!{laeE4$tuHHY!Ym*XRwC8RzZ#Ou3+@QTrS5X_&`a^v7=s zrF$dFr}G!4>Vn}NQ~&whPt}L{stHf6Yky|f8qavJ?P2LIGFrUn-T#rNl+X4y{G_JY zai{#~XSSvUo2h#68ubl%>?#b}8^c$a=@dDbwGr!p905WinWf<09@*xL0uRT=TZd=P zhAY}OB}P!z!WqUByz<~fv8kx3lN4+!srcPQI*a0*{k_Tlyg$oy=Pv^p7Yo_}lxSTi z-v-XspTKDd11ZGmR`Lhw!j$38K$5?~K3EvfJScV;QUNgLRLPVMu$n4w_sewEPM%sT zoKlA*Ct}{VjfkL!i5^k|zn32M&W53OubJ11We13khOOEu;bBo^g5$-c7%rma;th zs?psXa;P!qf10LAe6X@?EQZUBp}ES%>>|G8ZQyO<_N8#OhQN0tu$8&5ajMpVE5+?| z%KyQ@V)cEWJI8`=%I(|g8tHprmoe}mOFG94Jt!1?mdt26J_y4&WN=tMK(ajS3+sPS zB?AN%D%Yft-v{X-a7hZ}k7SS8q@WoMca38%74R!)_`i%&Ved??v%Jb7n5axAq%<5DBumCJFwJOwffR)ru})?%u*mbgK9mXvqSOTgs~NSf!F9t_LTU6 zb%|?HyVh-i*m1T(xp#!g^}-ymKBz{MnO>LhXs0WS`FSXm*A;|R`nxKWH{~cW4G?`C z==o`~!qJb2D%y*UEh=2(TPN?3IgKxQQ7$3Xi=ecIR*vk%#gy~af4ZHKc=T#|xIi54 zXR{w(yJY*1SSF;Jv)b!b<1U+(75j%K=A1skNXCtd&K@|$jTU_&XLb1a zsiS$oacD!V$%NxdTSa#-ZI|{P`bc>c9Ac3_Ew_bV(Y+>-voV}TLN^=&S-G=;SgT5Q z6x2x2;UKD;(GpX?A=}F~Z>%-nK)8RcP|=!glIgureLw#v^{5qLuu~!MNs@i8=+PdK z$K=PXK_FOg-|(j^jMvZd=)sRh{$5Gq$3edIFjJ7f+&$^t9XaOeld0ZY>%4(OTQj%V*juvuj!W$_l_1haLQ=X#bM zXB=L=OPxO5ulct1SbPTGLavT)i^Xk5|3G^rCP!Bx!v`j_g>SxCRR`Yu z)qK@Oj@Kmu_D>_`zjjQ;oN<#79VHa8AJ;k!Xa7bdaQ5$rR;)9rBYt~@sK^%1@5Xos zTpDa_44aW{ELJ@lC)x2oq>BrKGH0OQYx|EB01Ni3jLgq!z(DD}!a_J>HFa6 zKP}?#dK+ww1Hyq7sKmiU<(SmR{!|OUY+OcHQ?2aL5sI2a56}wJ9|aY-h34Kj%i2SX z0IY$)&%OTzFjCcBT=so+qrEna*v`yD>v$hIquQA8d*?)LB9e*nItkwK8_JFMm|(;t zc#v@mod6_(Fs-i~AFs0?@G8EJsOu6Cm3piaKEX|_2-C%dlg(e=tjRHes*y;Z{2Zd| zHYb#Mxd^3?%`d8Z12ze;031ZExV#8oqhZ{@B04IH33z6j^$kaxeSFS=Qg&>Fw=P{M zMHS2>x@*z%lagAEr7ZR>-_ZP-i@-+!)rx@$?$yB~!XbSd^J4;G9+TYd#+=Y?%U{Xx zx>H*5J9u2q1s>(Qk&7UVU9`y-N38hGfJ>WD`z^V+ z+eK!%>} z^~g0>qt@K#3vYt*y|3{_>t|aS& zqX0)5b%YGH6{80A+}sSfd4wo8@%hr_<~22jna!qZB4lsxQ2Zgh@<_R zVq7}AE?!d~j7y%ic#H~Er^#y-(r1#f%6X~|R*7;(rz@?iP^g>1CAXODa1b&H(f!3Dnud%7-q z907~rLxIYjLFkpvxs`D|c(Hz>xEETjME~8TSL-%J!0G3Jj|JQD{XyQh36(Jd2hAm? z?8XEhRq}?G1)OHmap=dUYM6Lw&y1RcsKyd$e>Y{7~VF_=(Ww zE0@$)7Hn3(0sG^ay8u2!;i6HSqg+8f9b%F~pK%F``pQ&S7|}U$AEW51`e5M;U(LHP zXM6F@uF&Jz6&vu`#Ci7U<7aHY+xiQIxM4(qY0kpF?CzJ`>_*``kG>d}n zJZ%Qkqkqw~aZAwSKO;(8y*Cu}afVUMJsVb9J+01qRY9b-PPlzeeXqKn9NbXM-Z3ID zgZ2Tb)zHCVojb2HC+F6lO*5$ClagI?Yn|45JjlJ^%Iz99AV9tUmEt zTbp*wa0;~ZR4~177RMu`WQM*_{|QN>c9xLC@<)Cd1~$9nfi`(0B|rG?eg&v&pjkFO zn?rTH;lt{S5i{K;FV+KF%I(*Gz`15!k)e4ut1fsn9kDFvzUVM*>V@hjKXyzH+=%8 zQ#P6_B%&;F+cgm<3p}y{*qkw#Q661amCZeoNa&j*?>{B+llbfuQuW`^BCohTw{V3p zf&vdiG5yvZe>B9>u(3OqwBf~l8hGmZ;FkwrpMNb+U?NtGwyN{ob@$%!kE2a|3QD@O z*vT4P84d{GD2?Qt1tnIEq)ZrN2TNSd5Fi=!=)8@2+cQbL3N4Uu1kxiPqRC#P7GKQa zCNGZ$6pj_Kt2*7NHzii;MpyFN;j)U*+9y%A#gmagu86*uok4i4-_>WnE$Wip!suG&C*Y`!d}D#{Bpu~wW;RWip|JFh zaq{)xmSK_I!D8Fd3k(ev2%;k1-mlcQhao{iUrITda(kG0ozw;|A^LBP?#N5zXIRss zT{Xs9BjI*bKCMA? zby?6~bG=q9vk-RrkObR}A=DmjqP;HZcsM~$nHfcFwaEj4(_ff+WrC9TY4VWfh>Lq5 zo82kU{BRyd>wc8ztrC01>GM5@emR5iICrY_pD0-wRgN`Eq zz!pII?t9s)flX2P)B>C{(=`#DJ(GtoZwvM^Ne9PPFi$HYT|u$=qraD{PdnrCD>O3J zWtDRCDO`fa0R@-6kfOc~g@TGKQFqM^LDUBeNQc{3#9eHpYEf)_q&Qd}Ix)X}w?JYc z>SW>D%m}G>%MF*(T{36cVI0`ZZ1?^|S0 z!;(EOWi|rF?|-CNxwGs~d~g(VTXnOTQuDs+_6i}CsU;Hu`-K(#Exdxt{V4s3#U0ez zmfUX5w^S<{3dCz~tkWZo+}?4XKc`QS^0q7CJQd0^F9x~1GQ`x!@1Jb%r;6O2;mxjq z9`Hk2$u@t}_hl@n7asYu-QM%4`UADs9vOQjRw0ia^6==zt>`blug8_SVA{b}MBJtS zGkt+&wQ1j(2I{O(xoLW--bYsutkofFG<}8Uk1CnXj>*LQy=|r0c?U3 zBf9uCWN;4I%n_0v-VXD6(Y%m%)kA`ix(X}M4$)Ucp~hXR3*lvauDz3Ryo-q4slXI* zvSo)a>}UOrs-hW<$uJ0YB;Gk^ zE~EZvyTb)A5awFvp~D3mJzO@X4*B`Ng4mr9YB@U%G9Hy!diy2djhZHWW7Ue6LvB-~ zr}IGAykTVux8hRkCRQy+x#u9NbGhrF&Hn5x{h!wK41D9;MX$287VD`-n>gK5dIU>* z=M>(B>(#QIu+v2}{Iusrf!eGSW&z=jRh+E*V2Hc5{l&X!+rkA(OC>3*RH&ylHTCQ_ z%Kc61Vn%0p`*XG;S_sfI64TCcd64Wz&R)87r(D-RjhMhLt-^E@cSikc%J?nt4`(=u zLbjhXo~59_;p!qUf97-f+HxYZPF_#c=v`swB{S6FPWsHb^DXC;hkkeuul-Js+vusB zGHoPTPFU|obMGp7omkHoKeW&pED?K4+SPMaSw8A}v+Bq3ndf7lO+`4SEv7$mCJKfP z%(7QSL$>C7#XBSa=w5Fd$5&l>OnJB}2N=+cJSVBh=ibhXATr*SwfRx_V2~Q$6+6WP zWXOFOJOXTg7YHPIiZP=tPIh5M?9saNrCYHelht!I7P0^v+5npGt02UQW%Y$HfwTh20(05 zhmYL{iZ!;gv{Xm47Q@ae`TrOT0=4FhQyH*TNZQ2yQ>~_*G73?){q@=2LyTy-rB}J9 z)TSw7M6{}dk%uZPUO3#@Gk?jCMePR34{OqMa?rqqZT?;cM;+V3Cct9VU}i!kE(a zJa`q)ZSa+vADtXKO)j9@nzjLA{USkW)=ChxDN+wfPBRV+Vl94i(RPQlEe|Z}%0*d> z=BlEA|NMDZ1X(US#(Mo`UVbLXb{)=DWeUwH^aY7~u$CawSDcvsoFPAIS!M|tzUL_M zdOL=ye9s_Z-C#A8{Q+l~BYY0z@LaNlBN7>eFBDVC7nP~mB}sgK2=~TvOOsF5 zKDRL>rUTf`_{U-S44-j1B%@oG#Z`cAL@X9=6i%?;e6v-&eh z&DiX4K#kG9|MiB{W^uCgtJ`Z{>ge7KI+W4N=5?lx==9|Ak4qcSL=)uatE>ibGVM@s zTehnPR%wWK$)px|&5+44kX+wAEnJ|~fSjI7K9-}MO0(`6@Ag< zYQ+lEpv0~Y4XmV3lU!_^_=`M~ySYLxx%c*P9kM9lq%3qPrzuwSBQU+d#8Y8AAH-B+ zCIq+B2%yrLJBS=98es5p@geDh_8 za|JQXx@f;g*9=?-Fqs}&Ti*`Za4_hV)PW{Pm0o=~m&wd$^Spv@cvft=90g|x6(D`h z6ed!ON_BqFB`0adWj-G6xaEn``uCXu&pk3@eqA+8;vI$li(zxNosyGC@Z1ob^dq_v z4J!A-?bi@*FhR%KP$9*;tyM*(#k^`e~Z)4ytwFKLnB7{>|N z5?%bd7$CfeOE3&25fkisEXF7DSLmPWz_i8+s6-8F0NCGR-m5JhzIuTrcIsLVWTNv% zfS~8`JhOFM44^jzT;jXSLw`>G%bO)i0JU=K@ux&jOijmt160qP*@eo&6Oj&ss!4L}Qrg zBkZ$d(c5TA0rsE|A5o3>#;+bbeC&_VWW#n#{@zd&qNnS|QaDxh(wT0uXrc8DSFvby zZ>fz$9QID?&)GQsALPrc)GurCI=i?6(LTf@Wtz01oy)2&kX~WDSU2?@JoXk}nv$~* z_hu;9rrmr7qC03P4*jrj{;LJ($=2CgZW+3cp||XGahDZCBxf9M$JYJ*B)pe-P$Rty zzUgDxPOzCA#7I!1HCjh|p30^6As81*j)}Cb;yyQ?m2684D6}j9;<|u2M&kv*%rYx2 zZ=_YvLgg-ceJ!I*;2r!}!{C2h!H&u!Zd>B-fD0>Lmg+P$I$a6nE!kc1{S}?^{kWuF zBJ9Gu`qV6La^`MHk-3r+|BZ5MTNwBYy8P{5?4M`CC4TL_A0thKCf7_ff|vHWED^tg ztz`Fq!Z9{ZzPyDfcvOm~G#}Ykjn2^AqD=?2EyJvP=N}a@r^{c77XxWeq&G$kej42& z$JPqRF&0TQ;Irw1c|k*vZ2{<=Kc{QYOZzJuJc|BL0A!tCh~H0;UCEtG9{=PG4dKE# z&j;5J+yomWSpd@)t0;q;&IJvJG=8#1q|@~Ho%UZGKV7+PL`}9l67g& zhp%FTUNn_Vyk`gE4}PYsw*OJ0f%x`BP-nR!tFOlz?1jafC z6wNwx1QGaa?#h=tF7?~~6oLh?9US@d^}q#R3WeTMY9^#VJ--Y8D@BO?#`RU*&@wfk zpBJh~TBK@rVh1YqyXGaU#hiYoI&0GZiIVudujEk>zO0aitN(PERqm5KtYfq6g@4NN z(2nT2nHIe1{pEMA=TaH^x2SNol|tQJ^X5wEMJpJUe&S)oig0HJKv@mi#Q59=I2Y@J zpn=1^{GYPvq^H#ebEaLY2barlts!j6w>pS+wVde`-{uXs*VIQ;WEZl+Xu=5=a)W#H zb?vD(#YWe!X^HiEtF`87t}Q)VqB9#ecKQ`;YH7{Qr=d0bzqGVCh(1xe04Dsjom`MJ zIwyr&+yZ($>w3RECq>V~177@fkY~dh(gQVD8^4gFJ~t&6*!fIgZ8 znr8Xev?Ys3XNzg2aBulVxPrmW&%qTkx8OAcRh|UBu(Z9ZI z?!CvmL*9gZvn*#tw?p*CNqouV#C&pJ?o(Z1AIH{yD`GlCt z3P&ra5liim=ICm>yFP*uvfgH&bl{KY5RWRj%Gq-p%C>UT(%)b`YS{>m5)HQeBytGN|4C?pDP zFr9mkWqHm8X5e+8^T)FUXpXbEdMK&DgeTueaV~u$J~4Wv-y7U<85EnrD&_A zEu}@#TCEzjt4gazYSbpRHziht=t9-rwGyhNW^6Un)`-3LEMmr}#0nzc%lq^B{14wB zJo1o)`@XMn&bglFoaa+xq!a{QX3`0??O=7Iy^yfIW9`grW6>F+OJCxH*7H#BSmdYc z;}1xS?@0}uv4rk50XkQicxs|pk8t-=j#=A(*7+$#wn@)xGWjCf#@6!Y@lDY7ulHP= z?+Z`}Jyws*;kS+~p%jN1e2GUtm(*LU0BctL*8Jx+xiQJEdBCb)gp40?Bd+xvEl+HU z5)RBl+ORUyJ1KE8!_AMUchD0`%^Ga?`x9yWDZ5Tlv6%Z(MYsH)9k-^R!Efj0^}2E0 z_6F@@gC|-q-Zljs$dKQvbA~H&zevwK0Xll!Y#(Knb^YX4#_B`R+h?>EQp9`{P??YE z%7Mb&3+Za!K2rOyN^@?4lF6;*etktaC`9Wl&G~b{UOmGfaGcJU#(eP2{y%W#$i(PR zwbyiG4_$f9kNY1$oo^3Q-t&ClK`W3SRF(?=fhTwP0!Aq|v*Ut7UG*cx1_z*$Ix96& zP`6rD4d=RT_ykV3IQ91}W^dOAG{)v`G(AYW+EZBF=5&SZOm-0`OwANn55y^!ShQb} z+V=M4d!p5_%Y6C5BgW~QFrkgjYNxPtw!+JfOL=)Bbod0nn ziy_D>l~iZf%awGvR_U931tT)kQ~+D-a`5{UECtF4MKYevmSqo{Av7QqBxr`F!@dQW z#8TaYCy?- z7GQL_Q1-ETteiOTE6OiR>sd5sregDnjf(>zv*(|1dK!L}LsZhq7eU4XrnJXPRzQW8gGCs3lrk*w4##uNwQdJfwQE}IiN%msx!0q7E zgeYY5sJEl>GB!{FBT>=(-0pd2!__)n8PaYB{|$k?umzD6g-KMoE=o7e<)-tj0{J6= z!Ddf!WS_XCCp;J#$6jr}+}zjPKW0f;3oyhg8h?CvuD?QTR>%PH$9{-0bP-TW2@07e zy-l7ESy|bMt{`!a!r*ql*d5i(sYO1S=jDjFEW;Y1sVsZ@^+CHTx2!6rM5bZKvM-K# z@gF%h?zd$LSZ-I@6Uu!AY`23z9TljpDhub36)WN)vLyy5;M=O4?{=M{^nw5Kq7+dX z77y!Rm0!u*zN0Q_ipZ~92C1Y?l}D!2lVW-OZKDBs_#<@dwd8jR&dzP|G~t3jE9E|g z1d&3{Au|D6PXk$6gM9+NZ-SOp2S!(5G5gve>QCS2N-^TcUiCy9=OWR=O7{f4K7skL zU=R_Pd4~6%>leN2KvjfO=#22!Dw?tZQ`P^!OjCm*C>k5$QXgipF!)(%qvp+p?_JG0N;*Ur3pWOK*` zF!vCS`+r-(6T6o3N7HfY%)A1KP z3{NhJ(=B8PcFX#TY}qa)9XBr=_Y%F`rvUj5@`4O0q4KTYu%?vQ{Mpg*%uFZTg2kxO zV(PO$3DU2vV3WBe#b)A$Xf}z#&KTU|-;bLmoE){FUbuf>*$-zer7GZ-Rdde=y73YI z<5q1k8>br%f~TqtU2gP> zFWfqmt1wSvzpkL?CFh>#RN&8AXZ0qP~^QN!-z z9mj53n%hT)ZTyxK_1;#$v8faQx9Bh}ZhNUHB?ecv5lO5#-$MMzJ@x{Pt!{$^s3#O4 zDs+91IHpO7?1w8lqvSs3lDgNKBLrT-NXp{)O38bjW};rWfBhsXHSPNk;+2}Ddl`PS#uL_{I|JSB)iJEtT&{2#Th&2W@m;`UVG^!xXI3y4iHUBSD2MtG;ap?h6o`M@CTsRb zDhk~HrF2_E4lq^+*5S-al7|1;I!z+r%%lDDbW(@ZVRyfS3U@ry?&QrTYIYiNJ`*~f zfN7o-5b_;}@aVelz+toQG?0@kwr(QyRZ>R3pVr9wx=_$QT>5pi1XVa58Cy;CHK%3x z$EV<)N3`_Lt69-nB&`=GCEJFA#IHn8e;`gdwB{q&h6lE(M>GF<)&+14+wfnIx)&+t zgIp{)dVR)^nv29HC`-K5kyxv)ge4RPW`a7lwSC)2dfm#M-y)XQYZc=0#$LrCqg6_b z)V+e$PPl3XbW-;6sLJ9S3a-R(t6IepI%RUqMfm#4$*Y3lr|z4keEIU9U+|y&|J$qhqf+7Gx5qcq zka3tIo6ei_cfZJMwip4F^XA*jP}JD+xb_z8qvD&d!HpC*0pE$X{=Hu!af@n+!a9Zo zKp{B$FVgm2Qv;w&n|CS{$jPsfH7W7Psn<8$*pn)rZQ-i@b17}RBjzqD_^$s>yN-Nf zaJ7VK{RCD+U__?;1QT^vInX$^L1_W^ZgKu!*aTW~O@Nwc+m}QJnvI}> zhu``WL?-j{6NOI?Z#kZ0{O}agbVuvm=y57x8L;^K7L0?AG5P%^)IS4Bz`QN=G1?3; znbS>P*GHKX&ZOy?D{Q?vvHT<8nBLsAAu8l!s`^ya^NU5kpa3hq|F~&879xKSBvnzj znG>+GX2XZ|FZBEl-wPrs_J%&zup}s-K=Ff0&4iBXqU4T&sJo>i9Whm`&BnApYAfxW zk&}Gw_^_x!m~Eot)U(an4w_|QEw$5_G!S(#UlOsM_50Cl=8J}Xf0G=*&q|g45#E>< zpLVmoof{n&8Ne=r6QLILk-fL`lS-Uk1W>3`6(#ATbj59jZH{RUr1rqmR+31#Y0uUv z3UxijYBXKG#J9QZWq0>DE;NaFVPuY(R z)(Qu%P^h1_p89nWN0!$|yPK=i$ar(~cH-In%J@)d^=(CpxS{x{I3?V*-g(POysCaY ztB;ztL)s1#u^Mdy#iG<&_rU!9<+Fxkc{PI7^A3iua4PvFb8TEiiy{0Y*u1x1n!_Kz z)rF9Kq~aXRy0>7swNGBodT;=JU(%I!sFNTF6@+T0@S9E}RgD%+lG9hYGM5*omaKQb zXok;cMMGLXaZbl7U$gTMt0w}jxz{Pzo+yvF*Y2<60mqC3bz$ah^qkP#%TI<&ZM!)p z1)5=#ph4=I82-2VF=ZXcx|s9+R@oC7k0*dn2R8Ly^O!}wM~ScT&a0)cmkx{1WF8M( ze0y*0HwS$>Di8Kl@&OPt8vHm3nuGgtUkd=0xZu-~zNNN_O5@pdWNV6yB_R^Skq{_! zvq{>uiu}fBGPKa%D@`!Oe{#H}SP*&SX1MuVrevX#E*`m_T56XNwr7zpEB05SYHJ>} z&8?TY&Ifhdw0cUhs&$QvEc==-f4K|HZk}FS?mY!CHrTdr#@Ki|21j0A9A&ufeV4sv zhx9C6xI^nVZFe#jsao~Zc)(=m_WAKN;s16^ zj7)Q_+_C`F7``#Pfd9p+)WuzQ0*x7}G#`PxGqOadFfAwimGVH@+&+{AJ z{80~dxkUIxPkvUa()p@=?jQT#pFsY>2*~p?hfKwnqgQWxC0Crs%5sLNfStp^7~oob^Y_Al$n`aAAg`da@d>oY z#aB-Gs^QCJ%lj*{{w<#2I7K+UC2iGmiGf?ihePkXEw3EY^B>Qy3P7B3@jtf2NfkrV4V7`MDy1w-qVi?RucWAG^ESk(~uzr*!;CJ`8>|Cm(0nH zHRW_ZmazxC55ex&Zn2z||L13^z75!0+X1m+V&##QOJn-VF%yB(cj4N9PmgJBIi58o zV`@9+T@cNToV=MeUNM)wr+FKModuOv2Gn^j))xg`%r`aNN9k+$4(8sk>n^xY?Z)!D z4s}J8A7y9|TmKmsCTfY`Zd;zk85Y9lNXzOQ!C}`0*PsYR7yq3zRZCO8+8Y(gA)l%% z2cx8&^VHT-N(moQO1|%C7`o304F>K#9)H{F&oIBv>KZRx2aTTL4u0)>6md)Jm5Thq z_lvlr`!~jZcpZngjJat-)Gj8%wWN8}&pVzDjd~*fH<6RqL`lndYjqkj9))gr&X|}g zpGKHUbctnQ5{m#pb$dpuqjB|X5XrrJ(fZ#%#ds9X zGWcSG)*3YKva@SkMkf)^D>(yar`&q0=(!9tOX#Zf@9K;>V%1HQ6bXZP**Elr-fa6^ z;}YL%YIb?(rmb}3>o|8;MmGL#&j4)~Khk}Bcki{vdDg1BbdA?J{xI>hfVsHI{mS7O zJtm3RVCe~NxdZP+t<2|oE=Lg@LYBU}F_j#M7eS^J$PMj{iBE*epo`THyw~L_b8EHo za<}Ag$rtm}gjzfehBEgR%6?Ns4_6XINt<4x*{-fP^jkgGUBi9Ve7A_aOcgj|H1UvZ znMz!^sa@$@F;E{^Rhb*~b7AU@|Ab!kmalTq>-6o12zj3jNtuY_wjs|~Bk^w>X9JL@ z+oVs;)7g0+?zz#C%_Rfha|WyVQ|1#d%)*8h|2uQ>6#@&mP+kD}KLSWQ>!uWf+-pJ& z+-J4tj%aQ}yXfqYglHN3A0&E50av{xU73rlaTe3|H_~WRIZk6C^&r$TR;2~_OrC$ zV$FB0rzOTZIE{~Ts3(hYBOH)Y-(09tx899ipXRVz-2P{G6ZopjVjYhZ5W6$hhFVnm z!wsJe>J+G8c*&^5@#M{$bEmkZ9-X}OO!t-I#nW`r>F+`=ez3ZG-|*727@oU}JfCAS zpZ$i`ZRg0;)GTz>O;#eLC;A5riG?X$IXc^u@ZmyfL}6lfw~@^UD=$TO+BrncO1^bp zGc-A=-tX`FGG0N!y=^!=4cXSZoTwlxmR37H;qk}UQS(PFW5;GkX(h8LzI2SV+}J7k z5`*-|dhA0m_3{!T_DJ_G940%LI4!#2bTlfvRm``&n~JC$ z<0a;;Jgo`rEE3!Dh2(@zR;=wfD<<((Iv4#uW4}I81&=;?rub*q2U+@QL8qG4lJ>rn zXW66Z=TieZ9^whptMzN=eY~`9I%EKsMCq=5yB?>bdCTYi)NcK5od+OwU9^h&@Lk^w zewXjb-B6dBwF(c=o4-iszh2p|DRXxb3dC37!T&ZtO@Dhrm;L1wAi5n*joM$eRY>ug zaKj(!%0Y&RiHSTVlQ|WDXP|6Q&p6AuVw886S?C}uvYb^mez~mKfTP zaEjfGVEqte70IF8uvRfG57-xFAU_$s{iy+@<*=Z`#9Lk?5BuM?3st@ZS25jz?a9Qe z#6mL7?B40gtpC*6QEk1$8P5sz@3-k;3h%wt*|ztsuSjZ(E#3SwHxMdn#D6}#PamRZ z>|9>fctwpz8REr?0~Ix3=r`4E{M5%$`GH<;(9l(v>g8+?kQiK`YeRjn1eG_8d%}L~ zRmtT;Mgl_BOW&56(RsDPjh(%->KRC^J#fw`+l~p%>SUqnj(J2wvI`PS1lNjIwe5#U zbNpBV5%fZSxyl%Yj8?1JGVekPT9r9ju6MyiH(ZJ+)%NAxg|hr?zlrmRdouGI@{zAx z^bEX{#GIRB>~p#Wljl7*Un`^~n0>4jPSZ2-9;F+1#Cac3+i1aiuKQ;MvON_PxSfmF zvh8mB9&tIGlrDYX^jn`sG9Ugw&QEB2vHtg0!(q?|H}1zK}l zxXx$HzRJ3}oC&69dau(oz-A1dC&UcRBy8vG!G}`Q`m)EJVuq%y!pqwB+ePe*)ue7c z6=sQ=)<#LUNY=E~$BZ{+2Z)ZF?j+voa*p2(@1Cd1P$fEO0tJ#n1@$vqWiu>n-<`cD zc-Ly%2f7y5O2}RIi?=EuFv%(YPD9IbF+|gR^J}j&);^uilwZ24jJ+ZRS{yO7Rx$B+X;N*Ng`{K)4B7z zE~tgV8qMTK{#oZsQu?*`>Wqc!UyM0{*%#t%+eoX|POjm=d54y@r;hqRk1Sq@G=$k? zbyiUPjBI1Y`|q>mKk%5iS-Ey zrRHH!adRnlY}`7rj2^cOW6P3q)GV8>@fh>XY3g4H^}oLuQrUsrh*3TA=~3XAOZD7A z=&OMdeh`TmzGp@rBq1t0-BNvo+m(J3>GytTnZzUQC^g;l0k_7C%_pt<-Dh?S_j6Lc zjaD8B;f4cDv7EVUnzZt5%lK{mmd&ci{+Lm!{#n_f67-@^#h7TPVZg%o&P}I^B|cb} z{o4rJFzbrc%H(>B0i%3Af-09n1vUS@UUZAXQK_NJy zlmsYZIhEB+ww=h=AA>d&TMXC#EUSa@VjcmI*4EA?vySdngb$i1I28Eq)-}t!ZI5E{!V7v zN7mF%n~DV=>DG?Nhbk(GX~k9vhEmy-MIY%A;=>gs#|YcCvZjiZyX0O==jrB>x*WZ6 zU9??gkzqz$3}#G~(eUjqAda7ZnqCJq+tPn6E@eh`L2?j4wY#4gA{#9`*~v^4Y&lpl zLyTd!`Tt)nz`R8jF#AFZ_Jn3O50u$LdCVwb-2f4De z$E?{R6Yftmo_;xfxF8v8njky4UX15Z10-y^)gUuL=8}OhYlkh`yQ97@%F2k_JIXTs z9Pv+m0IICp?5pMz+UY)A(FGL&X3)AV)y;2o??XlEeT*D(vfRBG+T!#2wWmtYK#*-P_i}CG_-aL2H==1O0 z+3xfi06dkTb?hID3i8G7?qz>rOEB|YR#%Fx2CZ8TsHL^Sp2S9PvQM>}^yi(D2B7CpVc9N*kut?i+l8Hos?`knVR(22^ z9?;0mP$;4ETm8{C7Q-DWD{AV$J*c{#E9)d^oyk`-g+{EyDao9Nf6uBGz7%eYT_!Xg zQ8xk-6B+y}dNhUAyVMW72KE0DT0PN#DjUZB!nN;?yBI++e{&fUAl+N+E=4FGD9EZ` z-l>7L(Pm+ljxyBgDV0h`GJKt{@EYr8o=ojfiqs=G!!{HHo2~STB-(a;jn;#D`X*Pb zirN<|v#P2IR~Q)C2VUzla?F1??LUSMCD!2sHmBMH;9<>DBD<_3aFK`fwQaOH*dgo2 zCgK2rKx_t>=+{@$Sf|@}NrxqCBzAN=Z8q6+*jTclX1zlU#)I7sdW<{79?D|v-?6{>eYmz^^D+IWeY}*4Aa4kYo4p#!Q>HMOH)^W(Xuxvt|A9KKXM}oN(t~| zbefYxMoP@?y6oN$h;;lG{!^kpabpu&i^T!FAE|c4MEN}3@&ePH)+Nv#?l@#>n^xAm zl83oQ5N9s zcEf&fFdJi?Xv*78v;a*AFk8p`s^&MGW5@mvLkr$_u1hl1E3K{QY&tEkh~3%EIEtjr z*40WN$!13!=sDWn)RFuE4LnfdaI>q&mGSn`)hqO zDIxB&rQms%?wHy&I;UDueDUaExis1t(K)Ty^@ zf>Z#H@U$s>#E-M=i9AXBX)ZS4D%~afp*HL1KIk~!=`K$-)Yah}o8yeDri3)Df%7QJF>gR(rgOt@QASGSzV~;= zobiSEHPfLfuxDcmYu2khns3+=Oa>F{x3bCrqeQpuu!ULY#E;Ziia1PcO$yU@hH*QI zgL8!zND-+lp#D2cZ```RWs#=>(*)km@UBqJmbU%oKZL%?!%hQOCxxW0R4$i$)bv>9 z&6q%!QkvvI0KF35Fyo+CC5>QwI9!rOCaGlMmSLEUHC*NRPtr|V6NNlAocs_sT{9qy z8{QZ_gQxVm_(ksS$xY4e`b2`Q2zL{}N#bD*jhE&$n0|VHQ#+hm#+5)OkI);t5~H_X z^1f7X7jqYXOO?fWXU!*eQ)Zf2C>~v`*!q=R`-L&bT|wNM|I*OzPgnT>vyPjO;|=1# zGWFSo)*f4q>A5=U?w(n_jAVTxdJeoHA(Pg>hTAh`lNX7C-G|pxA5rXR&Yz|!b$J0c zxZ21B)S#P}SZn zJi@m5rlS>tb1l57?wioYjOA%Y=4}oi$N-gBTJvr!>9@oE`CwK7k~c?h-Aj8q#JXb&9SqNts$j${muq-t zm?FHa*fO7xw#4U%Ba0)~iz0GfL3UYA5tq^ZYD@ zAF?7Z2B^fSJRmF^9Tr8Gz3xtv_1yrqhLn)>s&vPuYviZ;5a^Wmw7&oYzQvo}^@s(U zo?85v;8vOe!Z9Z!tzMSpS^egF?PsbO)COC;(VcrLB?eR zIz?uX+;bj^e}P44Ws^K6-%A=Mq&C`<41(E7A3Xq$g9$jC<0P9pm-15t>0aUX2eIzG zafi$}ZPe-)fx;GN#_}G`E+S|%Yh_b21sPB&ecr_HX;G5$5k4O|2GMdmBi#4{tHHY2 z+I{&S|IMqec2GvUkrLxv@GB6(AMhB(u;dPr!>9E@-xTW4;CdMk2Z!x={g;i%7g(;h zJARoX=qyQBV_R#D4v??R{DfUiSLTu{U9$7NW*2uxM7D~M zjRId?IMZ?W8zRdZW;Yt5w~#8^+47X0jeAhmr*wH#(-L-Lf$iG%zk(INxer_6*Nsgs zKb*w|P>EK|_G~KynOsFh=YC{rkMr1i0Da8G@b*E`8L55!t{36)MtP*7^H=3Td?(N^ z5byBF>AN<7lf#g?m> zzY6#laEvcV4#x+-dUhO+YS`7+emA7bzDOzl^`Rh&~&CA7tR*0LArZ0WQtenob< zcxRu<)01?Sgy*);L&?BBR)gwNzxfKnpCPe{zCsoGV?{@q`jXOK2a|`1(r5;Wk=xxT zM||8t?AZlto&=%cuE?aCzf-*?$G4TaqpaZ<*7t~Way!?1@Q3p~c+Ut7#lr;+!|wYi zCVLe)`;uA<*+dho-XRZ6SjWQeDD%7p3O?br2AbLnKQbfQVyAg~)juH|ZUra&=eYSE z9NeZOH1wg=gZF$>qwz;T@}LWn5&O7=?dLQ{z~SarpPI-b--POEL!ZSE&kN`-sm0XV z{>lUXQ*mMu2P4$+Pm$C7$n)IF@Iv6DjuOzRl0mNod*Uqed`eK8{4Ld>Nh0Q34q%6> zz?uQ=AUA2!bA>h^)$0Zm4ON@Z>XAgpHHhuh?{TXO)0r8q%&qc)NYs{r8!^mSVa9zq zD={0S0ECGTn1{Y3UlT>Ux7{=J-qL|OLZ!*ETw@^dCv|pv2~+g!a(>{n)03uxM=sP) z^fLZ{Y;N&;)w`)bmyn-YvD4Ib@Ax491)Rt1EhGy~IbGPUlAe#V_xrputEsO2$cdZZ zh^|O-imaQU)|Vg_JNW%5pG@XSqAL{xb$0n+V~07xAtaZf`uk;;KCL&8S)=i@!pbG? zFTZ8d6wGiT)_Vp3tTLRU8fLT#VC$1XE;EzP;@`fK@*DHZK8tDI{b28>9PJO|7C!L8 zd6?m|PNAcFAHT%5HE>C#D7PMbrrTrRLNlPRKAAC>`r$&qRyMCtlPVAw^Ixe{97Fce z9$uk~&-D(|{++W=g!jd}#muD5dDi|ceYK2Gtyv#yiyav_Be(Wfvgl2w^O>GU~LwyZRo!8lmydb+g1JY~X`pWLOnW*-YV3=BQe?eE%Z8tKZ z{Ch!n!N^7t#X=$Q?`uv;bj4C=#NnIJVuGrWyTa^eZqdnccm~pyrL*a>M0@#m1dY66>W2L0imQY(yCl6ZnCr%ZA{9ZIfiFM_@@&*5B8lk-THut@oi`bi z#;$eo#K85Ra}m#k=R*cmbDXbqlL9wQ;6Iz234V6uc2cQ?1?kEo>ShpIp8`6delgGs zP%)UB{o6excP~~8I_D)ibW1JM!+RjRJL`z;;j^BfrBvA3@!1N-PQ}Vo|Hc+bX&!D= z=SwxbZ_LfKO*1sAJJi<8`Zbq}8W`1BP2MVIxi-MApibYXr6aq}v>%%J{u~MrQ&Xu~ zzKmo?XT(0**fL@hTkcn4jtP}@XYQb~KLexsPg(%)|($yRSvXv=NDJ+52> zyD*kbi!%@4mLCrEvQ+1-@s*=)^;ey1`F`^(-sSd}lpBpcqoz+X?$X`A9sf2;*B3y6 zeaFD6U)?u3#-iKL&C#Z*SFhi*a_4OF0K{v^lGs?p{hzTWF^9W^D~$22K3~RaT2JoE z5~7scPdLq>O#d7+^}9i0UZM=I+hKA65-Se>b1P%hord&P?Y9Adw^WA zT~qU}zr%F3j4p=d>!aiFmzQZ8@Rnwpp7ll=2`&3veLn2r_|Xi~1~=15Zx6Spcl zpNElVZe~8IeDq2We>6R$?~zdDOJyqi7@ALod>!q%wWL`L)=i6!4X}+5xC} zH{UXacJP(DZcov7TXMX$;JzM89C&1W+8<;9<~v0N>ggjlo>^YsH;^MAWBJ>~e#LY~ zBs}vZ+80+me`kNhFJiBWoyp&+RG2Jpf%>vLGAq~X6C}Swcv{BbFX$DopR{zeMW%9f z4{VKPSNFL5bZS3GON`U{YiZFGG0tl!$f%{8^ULsCi`tWyJrPn1eDLTr3+~|;Eat+> zy%#ZbK6<}^a6_xB?c4J-KHGsiR{D5l@g9Pqtg3!Bi@WQ$$ylc=Vc3-o(3$5*)`#4AYIiFx34qwHhuCm*@w_wSzF zOEyfm*sKaS=+QM-1n)cvznr3o8EY?AekbyImvY785&frY%;dGT&-Wo*%?W62KRzrE z%i@O2aKAAjebvRe1cL0~Wn4`R^w|DtaJoljUCS*;Hbf(faCV*xA@m|;gk!iS{PcSl z5FO6?iZPw6@`W&$zcJKQzxal49Gp%CM4q@zeRhacJMA!4{mgR3AGz6-=)TJ5!g>%g zC&vJyorV5n+@}bM7n2|eaF6I@$7057K}6EY`4{hZ+Ttc#*hqdybJ~Jv<3q`5KbYCO z&4a^c}2wim_S4sSOd9h#NfISdNE!agToE;<<%=;{8; z{mKf{ph)iP{O6^Yqwtl{#Cw?381#$QjqSJ|BU-OhwaUhzc@nz#aoV&a$1g4v=qr^O zpLvX}mt;Oke^2oH;n6M*ZSTl@8|LPhcRV!vBkThHPC_UB^Seg>7*OVX#n`}m&Axa* zrHazWL<+gH;y#D2^g5khvZTMaY)Mqh@0MCC>nHuklq^>=cHnYuAkb?v>c;%Wg-{-+ zYmeVr@5hn8WemwpcZKjVmMUAYES~qfCZFckoJ2vQzP+*ikN(8k1D=QTW?wKXvzdw? zhPm1l1(Wx4SOmr5-9J(b>DSH_+pS=#dkS;n*jBww?Ib@d>nIEcdTC@$93FqXfX@t> zuD*r?9y;R8io_3-y$Lacryk zS)s)}`p~tnxwl8TL~8D|D-U*}nj&pIX^>r%H>EnG&V%UVF`fZr3n>b6X3jabLFKj_L~xE>(S9YS8hV|hI_ z9lkjYIFQjI00E`kD|UY&5mvS|s)D|t)2WpkUJYuK$jtRZ9=ls&O}P@HMf}g)O2|Zz zxyv-IOaQMgE$ZRZ;5A1PubKISeoZ<<)DxLUzn0A?BoqD}+`y-oumJFTvRaLqui5eC zwPD>k|NFgnr&hR(O~~D}Ft$-E%<6Y)W5Fq|8c&38YM}RK3HQ%GFKPG2Vs&F$^qmO4 z%qzU6)aMVT{m7jYD6bo1qJ~#@zo(~Ruj}6lL>Q&AVt--?ui*;HBi0Dhpq*k$6^oVx zdZ7GG21V?<0+D$wSpyGdX>_aq0K8Dd^1&TIl(@kSCqwWqO&efLVRpurjSD@wJ07c- zqWEG0W{1ba_rHY-x6x?;Nd@yUkiT^|2SwPEab(C=>SGh(w)JLII+0z*!8dpNn!ZUi zT5~;s@}qjRf222OIH3mv9{yUvLfUZW@bP7ytI2`&kgQs1hA<@$)o~4WkU;{}rmrB; zj2u2X2=Fko9)~F@a3f?pi5L#BV7L|YP{x<9E1V{L=#Xi9B)8ef3~zW#za}yA=Hub% z6Of-ZfC?DK5bw*ot+kRO{PXVzLWuXcQ>g~hA(@YSc$Dl&`X(Ftz7ewh)#o(0RtVmY zYr}wbOoL~P8G!|!z+w}%R09?(bNF846jrz_#h?~{;NqDv>BB8swFd4WHk9TwT?Zz~ z_0s{C3I>j5r;QM6JvYGBrpo*4`b0g8VA#peu@le0!f!o&{p0v?V0U7cM^X!1Mf7Cz z-yQJJuD=^Os{!_^|C3LFt4}LucfpnKyifbp?ilv?{hMLq?Q5qle4#L3NL{^+>`^?M zb)3Wo`&@JRtiqn6H0_W~W}KB!-Snt2cB#6148p(_r}T_n)4TwMvj^Y@zyNAcDUl&= zwb@T#>>FdNz=Qa7@R1@W{ldYexN;tN?dH<2H8Zv&opKfm4x;Z{4uc)*vRbrSnE-|b znb|V3115{jSoWZx96aPSzxDyyP31O8on_O+z4b2qCb-ovurGTFZyT;;{lR03r${7+Wv4q=oCgvdY1gvM772e zYY(Vu(0%Qxj@E1l%aYvTzXnye%u_=Ec>6bZZvK1Z@dEI;66SaoOs-p?w>BG=evS9q zksA&Umg)K>$O;4aKs7L+!xh-0aH;S9gKvNV)hAphcY(*SWVD}_1iNHgF2vz1-_7?% z&!l=kM^dQ{zyFL_O7{v4{cpdFOoRQxhEV6LZURf`+hxv!1F(@SBbTkpj(6CZ6-z|- z|IEtd$gC`?VDP$|Y;S?Hth2HmE+C2ThZakm-Y|T~fBjxO3&?6ENWG$HgaNpu@Ec&w(H?pf#nJzt=wL=DJ-y z&Q(*L)K7S;3oaw|6Ea{596`ua-`Ndtng4Td#~ZL0wRe1D%#jqIsbVl{5Dz}w8u)-@ z{{STiOk*?i}ord3JKA ze0k2*f^*lgMvwY)cDH9^09z$%?qkqLd0Qivky%Cql2>^6HcXhI-V<)m_gf*z7+^L) zv*6IG$7~2+HXzMVFg(r(`J+od zN0h~W0JOx_Z-%?_Fn1oKG5yCb!pvtT(B@+Lj%Xc->5^>hDuD&Z`0tGJnF7_07xe33BOq!d69@%~97C0==FBx^t-LAUfvzs*wVvT!+>nuDK^e&H zVzB;ej-X!Z$gTSC2l_tf5h<~@eeb7dp~M99sc1eaut#7hD}Yo(Y*XD-e1X+;)G~sc z+u2o3^J6%&G#!|p_8<<`jQm^z2t~Wp!-wwz+X2D|jint2U{5&{;Y28PMc>Y;&cIwvg~mB%iic~h-1afC-xLRsqxRJCW+t=3BNggmohv6uW&Y) zK&i#wO^-lfsiWD&zSZ8rsT9{*>dtS9N=iejPoFA?T}xDy-(0y|bR%|R56nv%d13aJ zxD@ccGfz z|03TB2y(-LiG}4P+q*WR@7VX$#^d5GAW)KPm5Bk-=6iz?HvpPpMEqvxM>ph1E!>XO z=cTREJqUW4^?gA7-HqHKr|Rg6*ef0Y%b3FYgDKTOLF~%=5%tYrg+p`HT=C`KhPG+( zDBqPFm59Z;Df@kcTdC%Eep%UoF5}J#`d2Vzs#HoSx$T zd?FOJI;In8bNdaeSSVZ*{4vkw{msm;qZS{l^9&!^wan-?=JYhiUOG-0$c6~DTyh%7 zq+KqGO~;rS{0IyB;@tgsu0s}Xe=3WE8hOGnHm>U5pHTPrmu}vdxO6c&wGf=D(qDkp zJ!+je&v07(^SP;G1?XXdIxW^UJs32}yPFN%F3x_@&9wz4=uT2gK3MieFX%hL0rIQ5 zQd!xnEa3#FGt{k;=FgoOuh*9MZodhBt2$?kg7ZS!`pkI)c%qsd%>0f3jh=!?QK?qL z26DG1)i_$Wuzqe2BozwU{-ffo1|6=X*LQk^PLBe_4jKgH&Tl(R#Peirv z0SB1G`i@_(033mSki$E(p=;EEXYZ!070}52<=TvM2f2kxrkY8%+H-DOy?BD}$!%$g z<@l6bwkUOZXbbcG)0M4-;dJxogc?hpp_a$?XJF;pf3x{0f-VD<~iHxR*XZ0nXua!u}lo#!0$2UgV-j^S#eG(?X+o7*-17I%h7# z@}^#EJxSNea?QuLTj6N48w5>vtaNp)Y^i`2Qmp@#+XpKYq3TU0SX=LYJ$c2S6M;m1 zvMFY&Hu|IwtnRz~QLR25vo+q3pbvgE2Ysc-=lZKBH=)4mD_93KYjyy)=Sq6Ikes?4 zu&>M{=QYK9iA9Lrb3kkP_*{2hf;s7bNBrrSZ&&P}-}3ax&Z5I&YqimWqZcn^*S`4C z{8=MIZ*9@%_M6T6>)~r!Zw^7{5~0;Q^mCKF*&&kt-__9`xSz^q%AXu*`v)AlHw;sv z`M?&ShlM%wjf096dDbU`3?V8()(WV}*5RMqdi5$`#c?i+o1mA}Q>J{rl>2?T{>zsB zM6UcT#=0Y#!q(;~I1z~QdeU@U_c*+U@Riw#(87HmpRN6aFq-PU@z?c*Pj#gv=t5DA zAJ@0-Bu8nR~>*#e9f*)S(eiI~X&B!qlvjvb5LpwXZy7wR$;dkxJJ8Eb+yH^J?14ISh zvpLJBL80Kq3zuwV181By(%}?*< zxIc1+ZYAmL_NH<DdKeJRZS!!1*Vy>$8bBHF#L zR}4#Ev=b60{qFYObr4MdZhMS46~QmeYItqhu11lAiG}UwhpG)qXv?f}V&?bk@1M8q z>+4rlzdwxmkM1dzCfxhM=F91xOG0b>2BDk#Xs_Oeo7`uvY*XjL-Zgpo`4x`=xFc~b zYW6}P>*lQYUU>Md1$31 zhidaymxT{okwLzaq`*<7&)NU$ZJ{8FsAcmc{B}0sWipdwZ~`{0zDrU99prghhxt8) ztiG|p=k3wMs3hO-QH7MKxfsNo_QPk0Uvu_ zPOGoo#p{CP-KpbgJ$K>Sgpt8J)OUrub3Hv4oXTg*e`0Tl zm5o^|$+1$hxJ3CYdp z2>UoQGO&hScFlWe0c+7m7+wBxu0ue0Esjs?u}Q%^MCO*OguEBD8ZkJ8*P>P3V9lrcey;? z+NT9bDW^=1pE&32+_3|!;BD#!iyD61xE$G#3DFu-j{#X5rX8+>176U zXX|d?Pn>MMS*IG%mudF`+lLkZN4(b5s<1(2l5e3mxppceBjgf2KjnXb?*(5TldFpv zGsl@nR@CrQv`r60q&21U6bimG>crf8MdR+9mEMb|9l}N~N)MXpoxXo+^73CCjPY{~DxiaQQ!HDT+=A!c^Nc0D+1 zF=p)3@Qf!T!W!Sxaj`HPT>W#eK&4PBzvtUbFldZ__LcSK(D`DU-dEqcxH#QE2g&Q- zln4&;{bIHhgj`yBR6WF_30wLcv}N1#>bGK+Icy1oIb;fjf|9|^W zW69G>U-I^_+S~sZ|Nj5Da30CCfEZ)I{%Otp|JnWg|3BECty2Q%FaKaaNApUbrR~9J zStkHJRRL7#vY|kK@icVO@Kk#T_L+(CPt`~@{O&Oj^=1qNkNXD$8_-@8FlgYu&vEbZ zH926rJ5;z+6O}sw&=g7-SCt#z))+Ad2R|Duw@?}DvEo2?52Ya8GTOZ}90X`1=O`pV z6BwLO-a29}#Dwe|4|0>rALNhr9w_a9Dh$A1nU@EzDMtn*r&+f*R7fC_C1gQvtzAD! zRBj)JadY^7@GZw<%7!OP-(`)s&a1LF$wDql;rY_!7y=Wdz47)}(8X%VDAdaaucLk^41|n$ zj(?D(Y>8lho25zg*st`>@8G7`{PeBoUj8-WKgIuV@z!xs-_FWgGy|KMX=Gc#vQ7>U zzkq}FG=Vp)CNcmYu<)RPU1J+D;jdo*WV$a?MyKK1#vvCgjAxW#^(k+ z-zPO~2M6&-+b3doB10tjI{UuQkUzJj_!rEq$DezbeBiKwXSAJQ3jOtLVOdkQmpeMR z?yC%6aD)lV{15Z3t=GrNN-d+8q?60B7#`*P&95QZ?rdV9uF)^Yv@s>t+qwWBX&(}@ za#&KmvA|Et@(xSF=$QF;Nl?~i{ZGzQI(oxP$E~9u7f!SA-6^)7NQny+pH2>Yv%EK@ z`BMoKwpLix+({ZxvQf?x@nQuFyzqN7v8~4aUOh{UpT!t<1{eu;sUS!2rLJy`a(ocT->4`MSZ7L-EKpDJ&tTu zOtUibyukxP-?lB4SXQ4i=3eJ7#8FHSiB?9=Y=0MOa^8iP&Y^R=$O(IgttiyD@pLxj zKR%l^TaQqOYSUbr^hb|}eFO_qk845KPrOsdK(+@2KahUzWd|0+YqpMh{&ok2R-n9CIMXup+WzppK15 zT}c#H(uF7NC9Zok71O3Wj81gxoNT*GPTARpWkWqYW!wza1(!p><5r%m_@^J&^wr;s z+i*|DZwZ>U*^Isa#i>1$DV}??3$5m*bgng8x%>U8>7YS<)RtUjLw&S+pJS!5flLLYdrCCCHC0MMijF3Sh{9Mi%EsO`nfhl zyr6){pB(P)5jh%tOZ)jZz%pR^hIK9NO8J{swjHZjDloLY#8CqCFZKy_a_koKu<9G4 z5*V?t65z-uWxLI|Lr|$KjFXKnB*apO&AQ|dTfC5WlHSY7sG{1Wy+L{B<~v|jAcA!7 z{l8Ilg$Ed}fxKvg_UJThyT7BAT zSkhtVF?Bi!DmsmoP=_IE37r8~r*C(WLrWiT@+kdMcbnqzXMxI{#OCU{Pqk~ql3`_` zz78%tMB;YK(ca71mMr)~hu?`Z>g02y&qz9>9#elF9t(u^>a9rWg!P-C`A+6sGz&%^ zHcVtr{b}{@S6*>Gym;~s*2(S47aHwRS}oqS^FslfuE93ub?=!j6A1VqauivLT-M?< z<4&0Q;@I*os(m*HyG^*(L>RVIr6O*_h6yFymdp7GhFv|`^#@avIvzIBYXsx0G~4Gc zv)Ck$BAc3@A$6X#fS%_CyS^u zxmMjU`Vb$J>iEbGt12EB@zgtV2Wxt{qVDHhFJsBjJW=GVt;e9htO3al%Tayd#20p{$+|bX$b?I zsxxEdY0$i&q^yl;e`vyq=|M|aN5)=4FM0tO_FxDErMWi)Tgn4Nre$WNUN4GvyfbxQ z#FyP7{zgmDW>ZmeyJR389ENYFCx=z}(o9JuvCxcwx0#xu7YCzLWl?*>>RBPnZCrxf zH?Ftm;|PE>`ZUO&_4sp|w(bt8Of2LOt3-IObR=gNQz%y}?R6F6B_D@2nNMN&$N4Oq zC_l}Q4eMd#wpgZ%vQH*Ixol1X=zX>rvRET{R=eVU$zJoAqC_cq=#_v%s2{P;4U4Wuh|;V z>(?hxCofO?kP4Vm=H}AHmYp_pwg92Gf4D4F<4sB$tG@64{5+24e&hA)4Xt2#))*6% zWUp>-Xp2)kxIB`hW|BYsN4&88T&Di6Y2`OZL(j36;nMQ`$U?EhcZl^$XtRW^BlDD= z;|&lsTIL&h$w+1;tn)s^aj+w2lOA~pLyCT-e6L|5cY5~d!g0zPvyBzPO{BeI&jCc@ z$j@j5{zB*cSMN<>fwRl$_qSrcv;xLidDavf#>VBmFR^_Ym<)aojDq@i3P4?S{E7N4 zJ?3E9%B(4KKW*P;p&kLh3T9$f^18&_Cllgzkj5I=rL@>Da&Lc>^o^cgCiKrLt1?w` zX7W_I-K&Ov+w%xYTZAq@pzZ@8)YBqn^`)XywXRMe)9_Fk>?o|<2JSIVEkf*m)KJp! zw4UzCA!gGEbT_7Zmz0lnxrwC`>xv|Xd6LNHh>l(q)-Vz(h5DITFQycf=gP(-o zBd2E%+@+G1K9TUccb?!r|0t95{ELMUffF*&nke3f6`F(}2B!zDjlbLOg;l`68FANU zZ7;8!ggK6^vxc2lH{%}FoO7FdI26tjTbm+JiWB$JL5(kNni+Q043uKX(m2`6d~c4g zh1Mv~yO3XPo`W%Nq0>`z%yy8C)TkNxt-1Uy$27v7Ad-i%gzyuP{*0a%Bg z(K2@kr+U`O12mK>;n%cR)l#=34eRH2?``8((steDMzV$9AMD_6qwYQq`&MzQIKQ|< zVktj8$e`Gp|e~woZz-can_<}1T zKX?$m@!(*Ufo4|c>E#t$Z!M-nFmvc<>ErXqsq+pR1Uk(t^+Yf+d6FK!Gy|-UibrTt z(_H-4OJfr?&#U|XhOTnoEfjaNw;H&MOL@Up(h|c--Rhbv+ZrS zy9Su>z&?XQ@YtxnrCHbDSXc{0OtWC8qm51v4EF>!klUWtTTLHFldCb+!n%=~M~Q3X zY7(!hc1UoFNj69VMzs#=%D@Lr_9oQY58l*EU9TJ9s<;Kqa~GOH_)aY4pod&yXm=s^ zVMe^tF!=5aX0@OXNZQFc^)P*ITuH}*NK?~3Y2s71q3?Qe3W|wTsm;lECBng(lDiST zd#y8jBhFCBR^U48A(v?(y<^)2u= zPmz+P{OSWvzHjs){YfzprkR;_(vZ)SJ2<-aS7LgPllsqzksa2C#pifGqdL$V(@@ja;Nm83*W zz7LPOfMuBH0K9^!8n7nt`H8fcTaWIB9Gg8`aB6i5Q)C*P61tOd-Xy71f$UykILnlmmg{9JSbOMu#Hy- zBYo3ii6&IXbFH+gw&c)&8W&b#H5K1sz4&SGg%4Pu@5>uSs=J&S(*xD3enR2ps^~M) zlee3@G-kbgHC&`+bj*M1`sFWcgSJK)d%XTUabB60P`l=`u1SmveCsLR+mY4<%sP7u z_iWtdeBv3~!YLeHL%z9CY z%~s9o2yyq=&GAy4@d>)E!ivnx+W(b0HU)g2FBKt4v@0*~O4HVtYwtC{{QweRLMHpe z@!N+C*Ypj~N1ln+dvc7GfEgYE&g6B#41brho709YH~<>Fe!zIK_ouCDRRcNupZ2`& zyAJ;_X~rpg@*ez2#Ppj|3m~x0NKzrbxi+vpvMh20zim>u>VjMD-7i^1t{AJ zOku}Ffk4@-a^8Iw@+vH#Xt5_}egufv0esg|&z*r1(Fh)D?T}P< z35%MFVi;vKZR`}z7*rtj7{LhH4q=RJnGdIbjf82cM7Y>dlU3%GQ%`%Fp|pkQaiC-! zcOx$LlkX^)#$j_X4B4kxyTZ^Z9^jN0y8j72L{!I>MEiueoB`G6SlkXdOyQm%yZM>n zT!EJ2(J4A9cc;2K>}9nvYC)2Yel5ya|I8C{DFj!mmlt{>X7#j>Z0w8RQyf=%G^U8xfNXC$V&@fRct(oZdB#>#$L(SfBBYGt0r)Ql#B9^WfQPuQlS zAM}BdT-n|?Y$i;A@!Crv9V&u%Pe3XQ5f#$GT=UTKEneq>jOdqYs^V7(IzbCV*Ob;G znpYD=SOzl#67i z7=Cz8k6EVU=!n8TFjW=XtJ|oLJgNC}PBV1OP~vIfHE**x`;=mV`F@rneYl~5(pYFX zJ{rP8G|4AkQ~wBedL-L-CzJR1`pUhTDCG`yK{F3C4MGLtOIX7={*++wS0?=;X}ohS zW21^E3L6Fk^v6?M-5i`vbd8W2)@$FoQ&p?w$o>8 zMI7*lbb7dq-117+Nv(6Y_*=a2O7LoqQ{rIP zt-FMx#Wnfs301{Fu3x5RMr*Wr(1IjF(yQB9oPNQe_ng@a5WEgVq&}}KEF%8{!KKA& z;>5Kj+RXkd>H;QgQ0dQc3aHq@8r4je6=93t;XdzVUwNpK7NXbojFj&P-~V40Aej!d zXAZzI>B;#z*TYf?0p-GjoZ}132OLm}!NlJj?!t4vB$uqsn6$FFU7@cR+a}GGGBCco z{SwZ_A6I4?rdisIdg=|$UU0PijHY&8lE$Y*i8t#*$QoEk@gh95Cw%eH;Ov+gsl*19 zeaN$|kW8}9yn>IX&-KNe(h|>sbA;I`QjDY#dLhNVOUO0>?D*R$!3Gc)!brXzNQrqm zi-XdZ=`HGK#89`dX1VQ2<8(>wfHOm&BW~;6gA~b4=P7f=?&v_aFD81t=EZmRe41)D0H$#G7qVslRF8x3cs`bdAudZB=TcX!4V)ZlMPBQksIb*SK9h0sd} z37FpEUr@_aK!?8WaBgS2m<&d>m(N6k`YwldoqScs|9XZmkxTDd&<)OI!Rt=H1ctfN z%^K@;+=q<1kLVmAdO3iG?P56|J|MCw7D}%i25K|HWY;n6>9VPcj{jmfha4AIw+7?x zAp32JS*ELd^#kDfvMiE+;N)9$i2c**O|xTbKuAbtqeF6O-i2hEH17i#(oplKU#y#^ zq%|TmJjS#V6{3j~Zg_R`CG12PrPJcau5O|qJjx%ooHllwdda_twG=Y5r4*{i{cR0K zlCaNdZP6#uA*#i(u(&R6)*nJRZPeE$hb<4vTsXj044ZjQ>~zh^oaocn+cA+|EeS&} z{@x*t9xf22$5vA4MbcH zj%*Q@U3w;VCX6fQ??CFsqnFM!>&!=1X+c^!6?dO(imaw*anWkNI6-WtpQg}+m?D+C z+tjz}AEe&@p@9>W3DySdu;_6oGU02Wx7LL`9e6a@_)jir_RYt(jC!*~rR7)>R=YMGA)mLrH=4{n z2b7lY)vpxx(@N-0gg+5Q3blLCIq;Q})%w|)msJyN!IT@~FAk3Z+IE06%$*G@xaIoz zjpvC9ulNxa6ch>#)%>sh(HFN%Wq^~4CS z=#orKGiaUjb)i*)LmgpVf}n)l-<>sSh%bG*F@pQU=A522UpL*Q;P~Lw2UF-VNS734 zzdOt9S@^(glIq=qTr+OR-Kn>~u2Z+ijK0DlMDYciPW_iifwBSy%W@Nv9aW%JBuzBzV$ota z;q}!utOA6W_A}%I41E)x%%Zq*9>sk^k-1aCv@(-?D=;6!Y_94<8|ZI;UcY=>ce0!g zlS_T#qV12}RU1tg=tb0rl!ubq#8~$ecZ^I6;j6ND`Np)D9Mz&yxzY%g1g+}U$t!9B ze=FrW?;>^P;#;L}0JXAg7s#*3cM_)5JfT{Y`A4o-M5g=Z2X!r1B_#&|qC@oh`Mq;5 zKse6&_saygAd=baT}YBXFr2l}my=kF>`l7iIuW!h-{Vl^EE=X8gb5=V$KmQKi(a@_ z#jO3dZLc3x&3GzTD4=RgR$qP6hXG3alARUJ?!jFmU=y@gqu{pxt3*5h3`l+bm~kj` z6frzKZccHI7xeGj=kDPEPIamh!KcNjy)}t$#AK!1#`7y|m-D`e!kgfkwmw12J=gy7 zS@AhOB&TJGA?dN7N@z#*J2+`d+f`#DP2uhBo5X*FW*n=a=u7=Teu8yEvDk*yCyF1 z?Y_fZW+qsk5M1e@9DIE70-}Ojr3Z^{elvNKT^i=XHJi|_$X2vl8l{C4Sy(bx1W-U4WaU0=x zHC;~OqU@!&xq6E(J`AhFh4~GW4oSqOk7t0+LmA zOEm995_CDXymyrWK)-%5j{iNNSt>VvBlHvx9NIl(kc(2~$Y*&bx=zec=rTm>4_{rD zx+Y7m1=!BDlhXacTm|2mQ?%dTM|8a`-3I;3qk{MVQr)yV9oY|yW2<&v$WIIRqDz2L5 zUJy-f#X|B*VR;?g#|_gjK51n1WoYcQ!q?7FQ(Apb7KSq@m-;nL&#pa?jeG`d@9wLg zTpk?B9uynObNJPgwCqZy<7*e`JEFpjUU(I$+D|JYOY$3z#Xoe)Om~-8xvxdnc81wc z%k>y|soh=)*Q~`K6-eV-I8E1;L*U?b%`7rzCGs&jo1U9FKkV z_nyhg8!9F0xwqIizcPTpIkTnX(4(o5XKhVDR0Gz(j5SgKyp}$mflV#IaZnZmT4Rx! z5m8!)b74nY3P?ZosXwsLE*b3Iy4z^s(F9xe54T&+>fDA!(K(*C{ZT0#udN#y(=FvD znznztSp08^{uQ;iES;`VW5E612whbuHkA5Yqhkqxh~t1IJ#YU~ZpLKH)1dVGi1<5L zl5UxSdrlfnDU4Zo< zhkP$TGn;rb_XqQ|;E=sB_Kf>N+Q=09vNozjSgnK=AzB!xzTk$PTK$-wjev%G#aE2R zVtYP+$&B0XYPh@5ZZ$R>c=z*u4x2XfGPc@?I8rpXyQ9NKkU#EvUk9QXHWUMVNozar z-yx~0eS(^H>yL#abV@`STZ9zZ+lmk213|l)?g#1@txJUdIZRNluZ&=q zsWJ59y|K82F3LH;EAl>do-}6uFe)wEqB zT|VY#lyZ{^ovh+Fb{pd-Li0P{jAP!}Z2w_y?mBBncrcq5-nTP$lNKXbCeqdojKAY< zf*e(8>2Kaa#iA}Bx=uC6f3-s9DlsNeyNr|9DTReG za6?@v`?1GAF*hFzMQ^)|F|*DbMV|9oizX=G{Oij$rnnSil*5w+?La>q-L6l!G=}YI zrwDH*9c3fWL4xcf8ckxlE_kZbxKMd8%{l~JT(`t)W8RJj>V}aY5X&*^gVzKQ zfDc6>wGCY(@M*7~hpG!1Fzkt|O#vaQErPo{Zg-Z*)W%5|@e14@pzXBodHg9{ z6~S_b?~WI*k{Nm8TF2UmT!{WNbK+(~+gGa79@?e|Zgag~=H30lwA@?rU~(p1F4Ug( z!^thG^}Q?Z?xBqDiMj`AY;T-FV`$BTBNbx4Zw;8_~8@FOG6?DR8BcUG+nN&xz z@RdN0&xf3VFsgwDY(s5B&OfbO^&#jtpk6MtE+Y7#>DP+3(N0FVvc8u7_-`KtpJ=}< zYk9cc)iwFM$$!@X2*>WPNITbSvdcbi;qIsdR1WJ!#+6=T*6erAq@|LT$bOWzU#}Mx z$Yv~DzCDYF4M)bS?A`8ud%4aHTwfBN)^qrGtIrw9#0xIU)D|Mv--EqgGvAB9%H95k zATe0_##h_zI)9hv!lzdkhS-}A%I^;r|I}@t+h3JfksCDI{q|EsZ}L7t?C9t4t`(Mf z@_V0dwwyTSh4SXdX*Fca2H8*hLGh5pi*W$~)RcxHRygnOxGjZMrdAbcp2p>yMg1qt zsT-D2eJQ{1@OA90T(yM*W_^B9feQ+TK_A@^1+0_>Ko&qpgd^U9B(e7*cg_ z_B=m!yanLipuO2MIV1^)m5yGXfy6=!Aqo1`{E3=HE7Sf)`oA4IpBv}3wTG$kLdEjSxV-NB0!ANmCmnwASY$aTr`hRUGSZIodEd$)0^sO79rucL!EYxY-X@swKnHq35713odG9^RSG^cJv>2lbxJRYzJQ|4zig~a;| z7c}KUUApX^!!y}fRS%=|wqz{|9^biC$lLK&L)Woi)9-0I+A3swF(9^~r^EZTTg~!6 zqEae()0_!QbQ~@Ma;D$CpPN|`d_V{h!*0753gTO^g2R}c48B8l_7@BizI<1Hd-Gj^ zpO-b}^X1|38GhG(R*-@7vXEEcQ(GOn#}_XeYh9@8zlWCg@|VuNoNh?E*j^l1cB_;# zGBl*@Opi-h3KwXwzxW%+VT2|^)ih8-p!*QxDZS7I%BbnAqPH_;NzD;u@B1hel^pbXYmwtPQ*=RSsock2 zfLAzV`gOrR`?1fjH+Z|IJJqk3)F0?Wfq^4B|y6P`2GzBSierF z1EYss%n&?D0dn{bAU*$YwQN` zUqKwI&!f`T0Y`&)|2`9|sH*YV?kM#O%<=*2PjjAvrS}OJal{cKyq z8q^LX{G}waHRp~*dWuSmeeDxGj+v*#owKFz1e=6R|AEO%k*A<^vCwH&RKk}s5j?sm zBuurjvY0RiZmta_MHM~cNXbh11qM%;H7i^mzO3(;1YI)PTCY3_CJWN^M|qKdB>d3Z zE^HcyedTGZXPKJs7u(B}ibh_Ys#$s^wHk0h0k)++1RTiT_<=2z!*j2L)wp&tlkg$Q z9dD_o;DsS5A2aVbgoJj+C01SRztVpd@@1=CESzC_ z^9F_IYuHvzSBYm*93=rr6uWt^{YxLiT%T0Yd47?MNKc0x!BEk|QROYhk*0~0(=hSk zPMO7W3%5#(3-0|X{c)viitP_@rQw-Im&I_`<*HOx zPlK>m*?oL_1p}VtMyG7pMTZ4O7bQo5)rLsXm5cw3rH4E1ouL#JKV^?~N;(OAo`cen zF#1#eP07Z2aQdQZjIvsKsD`9r+?~tixJpd~9V|4vy>!6XZRys;7)Xp&myMt>Hvrxc zfi8=@FwbujsM%F~qI4my<~LGLY^ogAKMxoWU-!0~r@Pz)IYuZLPqHDQ$9j;i+Zy%) zvic!)260p-=eI8A+5$FZJHjEvN5%$;hSqBo|EXw&HU>wZtE+Yaqte)6bp*-5?Yiwn z$W!g98P(85=9Z^ZT?3h)Yh94pnv9*9YxtbxlvruXq{)HKjzPm;M^Pt0H1U%nR0GLM zoRP8m5ruZT>wYJE7%hRj6KIs58vjlRP8OMYma$e|_1Pz#>VOUQ(C0qZk>}>_9F87N zm+?=Q+pK9aHYBsJ-&gz1z(KQyuRAp7%%g9%C}&ccLhqvXLr%*1-)y1AcQ)l)Z2kr) z=3^T9e(gBiBd%7i*|@HarWfw)m$VqEw=+4;EDR{s%DCB)N^pbKj@9_I$wWv`V^_S( z`tSaUb_wQXSEAZ`@xoqs1T95*UJ>tiU8P?$#&b79-%qwI zPw%tj<*Yml&LqOI6~#V>yu@1n2b3?JkhRVo1}1Zh#8odVz$U^SE}uZa&)W_Lciutq zypVJ_k{^88T<=C)c%I+F%i1@Dy_Dn&&z#Oz`FWw!HF#lzi=ssfMx&uX5!=mZ>SQXg zIZyO<`-@J3`tSS$`AX+<_Y?<^QmxYCua%}XS4bdBxHXyzP2|993r1>s;dW7L3kp}@ zZyaAtug&it%qDZN=$AJxuGu;~qWmel=&xf7I+;4yZr(WCoL5krfz2#j*hzYcZq^{3 zaX9mX$Ke5^f{z)32_YcUtUs8BT7iu~TR52$fUCtjVr{UwKaQQ)AA1c#$6Hky54el@ zQE~(J103U1!ZIScmA)xFmZq=2On}2vOmTN~-wu51GZ|>>t8|S<-T*Zhnv}TSs5=U$ z?a)?KECj&By(-PR7bnqQB&w;Z-lT`Hg%NXm8a8X_hu&}{@%8A{&0+zA8%_?DeZr{q zE>Qd*SE6cDCPYh_s8FrX6r<^R_yw)+!2nO#pE^etKddlXVZ@z5eeGQeAtz)ar$NVq zCvG(z&U-p7G)gt?rz(5%blKV4kKCA!G%pu>*99@KQBy43`r;$$ZmfSAn~xjOYZ$d0 zEo(j60GO?`INc-T6$`RCJ}17Ee$b|G3LQ_3;Vu#$uqD=+W3>up-~%I|5J-~*WBMx3 zO3Tzec|Jwy_2(M914>>;DB2(KxC2wt^Y2)7@~?l{fsfftUL zAO)eX7I#MxUrfn3k7FQift$b2_TyLCLs6O*2DG9O>nVbo%ToZ)8sGA{;^5rya8@ZZ zs2`u(t#bU>cbs+L07KT$ zD~x1wH@`*=hLGzrS1~Tb@hHChk1jpe!DmCyq6l3%%fGfl57K+Q2ilz-)^00toeor_;@VGQdI(q2ckNl z3t5XY)T1s4_|35vRe~*h&qXJ-bMglV!hjNwyvpI^cnxK~>0*0--mGB$mCc={!v-!= zX=ENdR57Sj3a@Y2g%26hekHe(+Fju?(#wjJ<3d*NP+l&!vRd{#D)TKRCD^QA_v5x2 zT{J1RSI!mK4xru)&^;V=^*L8_RriTGH~FHx-kbGX4VMox_9Bn&1rLR<2#nn3{`Lad zZN90~{R5|Aup#3lD7Dj{3e4|;eD%mlYj<4{K2UPDmm8*$VKfQpy1uJT^M)D%gwz1P z9=OlV=^ws6b4A88zvxj}bPW%-B2;AlB7dracVptPXSRKscR78aJ49KtiByng$_YXU znWF(ANABJ8)$nn6@o_(AM{LKA<>}3wO`9+>XH)fQzBdI<+X!EY&H4+R=1U~!+&=d> z&Qe(siTXberjMYUNVAIh#}WfKGdcIwoa=`O=!w9j&9Taie^#b;g{st0Fuc7cLUmO6_v1wx z&$B|RC2~@8g{h(+=-Z1IANuMMb#i;C-zRMe71nm^m?y$ zI^dN`4f!Sip95V5{fMH>2zxwe{P} zJDg2odCl>>Cm!6hc^hys6%@CheJl_}R4k2sRzQak^*-m?+D^y**~dWC7oRMeb>Zs* zed=Yfj`{HGoozAU#BHbX@0R^VYYNf?VdUcZ_4um{hy^tSHjFZ)&FQy*0^$xdB`!`! z=Y*B;+j3tSd)o7!=EryPV+2_)ruwiZx>5|PvVM$9#zBH!jI{<+}T>vvGla$B+Ss#j>_DTU%HOWR{`7hyB8XWf65ESF`uh;(2w1 z>n8TB3C>tU#!z2L;|17#0pL87sf*rgEooTL6F+cKx`D(IUK`e01;1#5zi3Q|aYe&i zKA0Rbw@GHaqV-)Clsum(`my%nEWQBAC!(%3OzaO_chvZ?y~KQ6Sxrb;h@4N1y}hiR zbD%^J$d3v@YeR6bV78MeKJ}kZ5{$*wr0W$t`pw)egvwY0J2I@>ndj^b<1^@Js=ZCv zN9c;cn49I}3p`ntmn)p^oVj46sO3yuDy+Kgj4BsKdco=pcj7diXRe6X-md|*tnlqV z{FxK>90W69D1iiLnQhg)&R}uUB@h5BduH$I3Emgvww646uWRSDl>;L;ZUm)A~&NDjU`p z%2UfPr@otiaOSFGaQW1q$txprD z7PMZEzUj5947iCxbJrYe z-<@R8hq73$L;c>@ju|>}(MCJ{q zn5H6n^n#cIZN9mg8GuQVp&Bf2PEhrgZwz2YGpdFDytA^RgjR1p=<-O9t9)iWB}OUU zdY?9;dDyBEc{S|9v26qFm$RaN_z4(#0m6a|jP>lWC157c9u&CacOk(^9LB?otWa$d zAEj#o?J-$yi(rMG%@^w#hat=SE2ks3Nw&6ki!!!WqE7854cMfDC&OD^#HM~bborSHZR zXBwp#(jQ+zkN#k88(@obB)xF0pjg=I)qd7dY1Yjr^*KX>+`5I7uCK3uwMZyZhEgCq zby8F_qztWq`bs@+X+Rv^^Z=s&Z)3kD&K;@VbSZ#X*0`t-R6|5*tC9IktI2Y8a`G&l zx?yZaj?9&Fg64ty2 zwgx~y!;!}a>M5fmF4r1+YVa z3GmANJOgLimep7GF?`m)t<4lF)2m86H@}MtL$|ThV%!FT`j5-sv8Itc+@vwds6qd{ z-t&14M`qNE>K}R^TwH0!OUUQ>h|8sWoFf-un)RHh-n8cUZ7s37dU%xp3 z&iheax0*HE-St%ioSsr0G2{my^+PGuwm}P7)b`8M{m!tVfYeD@`ASx6cNaoj?Ut>d zG7PQq!+o<+>4%D2!a?4Z<@Sj1PVQU9uEQ~*PG)4u9xIAYn1cB*w~prls|g7Nz*Jvz zqL1I~U4r35erhm4GTXKZT=DpHAx5xQK?KVQI z>c>6_EZEKBquGX)>O04~xYw?X5SQ<9-W3FlNRZvEQJBl|9*{Og>s=dTn-_N76?NHC zhBkeFY+5#WAFV*rYazvLcYt~#<9{LWEhJQ6W$_C4T=JatM-r8&2u|1!C{@c#MnT7jNYJ|#?qoQ;N$#k zge`R&n@^0ZnlQx+#N8d%=GqG_`vWj80|!xs`u zf;(=Z*xbRbng^@v>sjvwwY$vWA<`3q89(0c^gHY(_$Ih27wIY^}F&iIhUGr z)M_T^S+~O%B0ukZ3+--g3fo!&$tei(2A%hb+qPvlqpec+d=ZkKkN+AXa|2)R*wL^5 z;Ig{m`76l`sH;Doe9BM%DJZisD~px(Jv+a&CkFlt zlxT$hFbBIMBge|uYz8RGcPw$;9{TaFyBv!y?oqx@9gjW z-{b1UbW>_il+{k1%cF~rtMksDzxOly!<-dEn7FD6I6GS?e)(#`rAv2ZCEaSH3unDl2QGNrtvXn9VPLAy~wJiwX={T;cD$Y4acW@G~ z6)X(OTC=zj^J}r+1;R+|x!fxE&T@A|i*oAzIRE0X6tDwzFc-t$QH05ybF@}jAyMR~&j}H4!UmC!HSAv?*sqFgZskvuB z$S(}DazWmC6|Y2PG(_!0Hy9Q!yK+f_LpHt1mS&G0oT0Ze70J7xX8(#?bU`IXfHP8< zue?x4%amn$iQe$q*3l3{Blb)@*RdU#cu&Qt(Qxe?#LHN0M@6ZpYii%XujSqn{W15M zameu%FR#!0xw;Z1y)#a62(%~3eBlr<+&BkmIm%Gd6xQCA=-#`10N}jwPYxCmnXVGf z`uedyWd7UttgmPX_fF98*7p{s>8wZcmlzRVweW`9n*7D+bh*}#J8s2Gf^DTZOU7*xbkEhXN++1<}BK*M-K<$Z(8r?f1VARu;F!7i-qo^LKawe znH}Z3#K)XTjAm+_%L4GMtVpsoi;sb3BKE z!SJ>`l0QpM4I)li4sNC!8oeluo<0^sla*_JIa5QsSi^q?KR6qJI<{oi5NjYwQLk+U z5m@`ha?2%f&`>;YYUC}XmYL&k&)pY}457Ec4Y%PmSV+K$`;#a07pRcYl^dodB~fMm z#$VM&aUeFS^>11Oa?|IoI2yTe3TU8U>|GhZocJ>>SN;w&K8FhNF3!}!CsT=KyF^hs&rAeJhdD0n^WnF{w8ARRzAkW zdiYiNEn~#Gv{&n|yGV0|+MNi`?+F`Ycf2H3k^&Y%foEF%WZ+ew&b4cQFH>&snjQcCi#-r! zNc+Cs+(BUif4xjhgIcZb1hYaP4oqHb?BZP)-u%~t5i_Mo@{nUfF1P(fLX$nkNlf-ifc>BQ>raE(Lf5&0?#+F*>$wn`Zu#Ak-h9607*v>52a{~! z^+;XzZqm z4%AtQCnJ{aPCHJ@rp>vEUezw#ZymKd0l@~?sLYD{?a4Sz=M&IRUzR3xAJcBAfZScM zlhR0ctf*rP29;*W(SEyuOsjggtg%Ll>#mvv%c=*b&oJbFUx{=`>J#`tzbwrGRqH@9 zSERUa;*(~ov{eng_z9iVXL~{H2cntd*79sMJtmvm z@NqvZ7<)FVCVF9{J6EFhww!gXrVoE2p#W(dilAouIn*x0taa@j^1_ zJD=OM<{ws&QhwHf->;Mr+kv)m&wz z&Yk~dea7ZVwbplu4-_iI8;qb;ZT{6F-rq!s7YZJeMs)lGyZ9MJ+tkq6Sn7Huj+MVV zSYdMQaSclSL7hhruzJG!f)>?HCHSI^qU!eB=t{HK8blI} zYrkPdgU;Z@eV$G2vM z;}=XXqBXc>%Chg1CTLfM3Rl{NHYYgU$$CJ(#BhFZTf*MaE<2`FnBM4~vJgdZRK{?52OeNl@=7klb4hyDFbbs)2C>~QB46IywCBHP5ym?D-k3oEAr8nT z#TQuKdD}@^Josc|)sw2>xA*oRMW>KoaQa9RRB=IL#7c_jok^V2j?bWj>Fh>q3a^$5 z0AZv>%KqE(EqyQAn3o61lsiut9E@;ivDfTQ1;;)#NLll+43_`P9UR#oxRIV06zP)^XZS5lVKo9@csypuBPyIdK)UV2t0YxmAwr2^D01Tgq zgqyozTtnGhrH|%P{pNyS8Y@6C_UrJxI1p8z=VRgVn@BTCu|F{m1^S0DxKmS`Yab68 z5Y1`+>w>Wwew+kmf%fy)Cv{jLOo(}iDEtKsPeolVeetGyCPm%By=eD)>Xs@70aGpm zuP`$^-m(z)eN&a#$SgcHLZ*}|>|uRKtU_%%Q|w@?c)3S!x6VT23i9pOwtSvxOVPC8 z01jCR%Iab!8SMN!w5h!M4L%gydSF-P9(@J=dH~RmbW2sGwQ`lL$P;@eMf(;0Yn&EK zmJ~TZp4@fZTeW+eefb;IQo|8x0@#ntJc^&6aM5%| zX+Ut#i2ICKUHyo`> zOa%||8qS;j@?Sz6=`N4-#N0=_SfoHFU=7c}fP}Fyz7{d-%?AF85g05aJoQm+7ny}> z`p=x!%GdU#29l@&PV%XkhndqeQ#IiyN7?v763e$-$Jv^)%s6DGTSfGtrP0tC=NC$k zHSKDuz%>DIyhFWt#LUwE z=mfRv+`M12!5Hu(z9nX~-g0VgE&XN{;+`Bkt>V}qrPv=B&2Ru<$)IkXex-qLttc8@ zxg)}N2xIXeByoI*rd)@t4=Jo?)?q4TBLRM~@PrBMI2qA)cbqATA9onnP@LWC<*G|` z_*;Q{4_arRTb4p}wXgMv2KsIe&|Xh$tPbbgQKfcly(9F#lUoL;8@b{>71|~J%(!{) zZ!g)FJL^W6_$b)?8O_x=TH5?Lv`L>+r*Ue6bWZ|? zHfulkZaFb2o!ssohvLdi>&_C$0$*{OYjZFF#-g{W#|02}={LlMe`EJxCs=lg!%DC7 z^u(0KG^q7s3J~2!dr=pmd2b`kp=p`cW$qsD#_IKo_f~qufS-(6=-8^LW4PKV^Mo#J zAm1$CW#Z;SF>r;t&f`K4MkDaa`#K@nR4!VvSG=0jCK=v>dumv~#UN_#V5|d#vqY)O z^rP#(&LyHzH&cPvHmi`0(7?_9L+P*e7suX+Zlx|JuH~_aX3Xt*I&IW?OofTJIYA^D zH264uI0d5*qsfvKRbXkvuW3nk)#DhXJ}IWA!rIW&X04$fnolckEH-5q6$#5X;61dc z=8;cUL^n!|I)1t}y8C)#p+VDk5-V^MPKK`U^!1I~?I_W2IsQ?4J@Rwu?Zs`hk#Kj- zQq2WF3d`hbB+}cNT{n1k9LmgZy+sA3_9^ln73|X&i(nif-I^*l8D8hWYn@BRIg5s| z8%#+_0$tizAmi||q#XA=M~R8ckz4CI@?jN3IgSe(UAxjuwtUjCq~X@s>4bFbOwW+1 z)TvHC*768AoDJF?9@lOD?)E4D)X=46>+tl6&oF!^bYXmIhr}p$BHhuoJ$q}r46g!t z7l`}Py2WNscR5uOb-0wX_r+mJ)Ky&z6Pw9VGYVbM&+7!ODR_-=A7nOmaUKaTXvmM1Rw5g%qFI9!<^ZMyP3;Pu~z zPx8C&aKuX9Ml>(5ft)V<57S`Zq)id}9orEc1V%0E0Q>5c-+UKgFQ(SGo^sw$AF{dc zW5EAgEHTWimcd7+2DfKV&!itUceDUl0q6#3I5gV3D0|2J)OKo1*8YPT?Xh>3&zfnK zZ%Q$`J);z`ZL=)hBqhS?v#)xU0nzkp`#BCTx$L}r?cdb6Tp19gK5t0!(;xvOd7E0SK3{lb6j z{(DXes5Z^x|Jm9gzNT|-%e->uu;$FBIi&T7Fa1vPy0%q0e@R>x?D(;!z%s9)4O9cB z=~R>1qwN!P5jnf;;}e2qb-N#U@o{g&#FghnJ0?O|Qz9enGjKf&OeZ42s9_ z(k}X|lq7fJXu6b1V%EB-i2+T|31qOa_-&ZziqDEBp`$3dm9VZEo%eNQ@UNF-d`nqV zvKg|(cd40>7a#1fVmhGZbEp#kFTd<#W!|=isah?3IIX(FqDh}?hXuz8pWhUAu}f(e zm^{VvIRK8Mtp(v0(Wc77Lc{BFrHRb~n7Z;IB>c(r#L`1101;ho~9fNG8p zh$V6VbmL$8ZO?Jt{O&pjM~sREKQ2)6xqQRJ9~*1zYFtgqu$+#xcBPSy%?(RJnp z{>hU0?X(G0RN}GLASzluLHQ{uVf9~xQYX|&OO?#4D zS(7Ohxl)0SNWITI1OWo;0(<;i2!1jaKZ~7MBFYY`mqkFwav6ONHp~9iIZ(zH?dU2| z^&2D{0i7sjQ=9~(c-Jxe#diPuXbu~3-gZ=2u!|GAWt*U@qTgv-Nq?*oSz&j3Sz$Xj z(MTz+=|rWAO5p#o0HbU3-a&Qb#9}nss-TG%an>rUw~<-4YJ7QAbUOM?Ow5XcY*Dg} zmvl!A+Am`%p3~^qN_Y}?IzqB837bZV+PS<>>@KEF8EEYIAP-We=QMi!ZY~u^sF+u5 z-N;B(Bbk&m1&@n=88#_d$0?kpl`h>E2w6#GZk+4h_{hWibqJNqs3l!7ul-f;5m+!X zft4P3TNn-2iY@Lqq*nS@@<4UN!Ga^ZVpPd0=k+sHgh^S>MZ#bLeFxPn?;ab4m+}h3 zXOADEjtAAS5NX>YCyH@{%J8}898=0I+;`a2Aw-jvw@I{FS?Sx6qiB#91208ZY{YTg z4ZRN0sV>*FMy5Ox}5Nlj}qkEsM66*>&c-|6&cpC{&yGMzc;VP$|u)S zw4yScrgVpTJbhoyZCD|=AKLy~%5ylDN$UW=h)2EU`YU7XEnJZZV5cA{b7&$KiY!J9 z`yZS*nU?YLfk~ zqj~&!^|=3_S!`D;&WHvhBd?<#!=P1HHl-)XBk!jW=(taE5|fc2${gDZ3;A!)(IOZ) zZ8IY<)2nE;u1?Ay(?1njit1XBCJh8tVi;dc0KFdCcf7Zv*L4ibX{*nPzkXK?x6D9X z4c<(nrc79}+I}omY7Y4k2R!)S8XK=gU*T!;!vU^$AU^cnDf8@S$Bmba?nkXiHv6o*%Sx07CA0qlC_;_#t5* z?PWC9l<}5~_x!M&DDydYTILS$RnQDiGO}=RoU3NnZ)6Cz4m=RZTmB1u=w+fNQZW3( zsO_~^o4+eHdqA@uq`bQRi@L`%K#R4DM}Np41A4~2We$AV&~fF3U1EygkraC``|49J ztI$6O{qSQ2T)MQlfTS3xS_#q-;6t)HJ<$y3Adn9?)_Y&kN=amo&Mm|5yiXC|SCSKR z5JBCxLKcWEGZ9qFzbBWsUww;rPuiz6*&qjAnGsf*q@x`A0%eLaqx9?hO-&EwJ;|*N z+H|NVBz>|2`m)wC4qcfKbpqEj4G4YuEi>1dbBumFPg{Qi9lr+>+BfY96Z&Rjrk&ml z4C`E=enD#f6=c((ng(uu5&v2~CE6F0!}>$q@fp|ug2bK=bsKj*ouaEfE5Fo)&s31Z z*4L#{blYo$c5^tuG*oUYSom{?1DM6k{mKsR;G=o2#DFEM*%Dl$a-;_8kc~g^9RD3m zODLyvE=YW;>g0YfxdoCg!Vtr@*r3AmFX`T?;AA*d!FNn!FO+f-YaJ<0^)yO^D#5!){h9uHmk_?};*4h?aNrdm0PH!E}4 zqc`#k{-N9R4g<4?sK=tNM)G&e%DDhzxUbA4W`k*(0@ZfEe|CVIL!j!7zxE3T3DoCP z4n5ov>AYs!e8=Z)WI%gXEe{4G%bw=t@+^xQx0mtHOjl8znnKMZvBH!2MLHCD8`_ z!K!J9MIJ3xIO`MYdB-qKW_e+!MD{m?rgSuVJGrzz>EajUm|LM8`XJzUL~63k=v`Yz z(|pMy-O;0?Pc>BssFtdny^3~$2o6}7oRN#0HWWA*I$xSL8aKySYdN+!=b=3d__eWW z?!%B(RET=A&}3RVacJQ8)(Ss{-DbjN$aLkK9#*ex5sT*3R&DA?4%SocOVPlLu>@by zO^3Cw($;R2uMy6IOqyO z)5%P!w({!R%2mPR{r6TiMH9MRzsH&k8{ip-R*;|V1Efsx;rSPV3nO0!8_hO2Kt(cT zKVg3u(rUFmBHB+ACUCzp@STd7viwoeotOB3gndo0cMSr1hxU2Q7W@=O5Ix_U9f9{q zAr9qmItpXFMcV}HW>sL3-bEJX=nFckU+w_+U#C9C;;K#NjC*SMKY47BsOh!&Jr3-x)1g)kI=@NAE1L?$FUP(VI?m4|-94l}>S6_(K`2-L{dy{>> z^l``2C)OZT_`o3+5HOSWTjZoV)d5IlD)pY-O+ieH>@8!nZ$V+>hs6b-dKsy zR_iMt6HBDAiRKAqqh!48EX#QW%Ea}xu>ox{A;qb(mEph(FUG;q$A?$jM+VBr>{2VD zG%*GQ-1Q~MwuMp=Wwn-l`7fOK-*NXmwQINt7&F{tEO?3BN`P%apLSlw#%DyVXg7D` zPR{->Enn_QWj4PMzU6r9XGmcWj2K>R2gC2k-$C(Pk_O)q?|QX*EBD@?li}81!XXCV z(P6iqnU^lV?33uyu2Lqk26>SZs1)8Irj_@u6kg7FpQ+IZrn8u~jT9iePJZL9a)4VEIMRDL}>zG7- ze@DH{Ib0?QoBf>{agUgOV@JY_c_*W)v%ZS0x;MkVRErPES2CFm=3)FX(P}O;CE46+ zq)EF^wIGbGDvVxAXA;aCL)Ne4(lGa*ZK)G@?YM??w!TuI9n*~-N6u5G?)BTWNHC<5 zu6;8Dr@U$^2R1*fKHIaxsB$_Tm?6$TWCB zh$I3NZZ&oh6e0BWS-a)o(h&@n%AHTj61Yk8H|*|4*H#;RzFC)D`*wMfAz%Ky*M_V7 zu1$cA!*4jgr;Eeg?OS|e`e~rsAOI;}pO5EHF$=(d`a122(~0Y`@a0+fBECYhJ5=jK+?v^$;nv1og#mfX6rb>koF<{ zZS)%RH?2p(S+5|0Mqvr+D~pYrAbQAUlAv z()H*3TJXlA>aDY}wj(#oe(%^EOez30lfEf`ZRuc@tcdg^EqCjriXJ{r)0O}(l!iJX zYh&F^U0}@p%i*kIUOwxo<>qQ!?p;1}04-Kt8cR^!?||Mk#j7!Nm7A8|h?Z850On1d z7|@dA?MGVr#^e5UVq|vx5xG%)9F6$0a3E;CB%0;W;CA=y-l8PwU88l!E=q__tx$+> zL3lherRf>O#{x2>uM2iQcF{Q~ zr9JR-c%5_(>$Yo2k=Yp_=1%l1IvF&c%|)yqG*_!(vo9k*KqMfvj~ji1=5RP$Vyv(D zBNk02cBpF_)68`((n{g9G00#3b$$?_Sbr5KXUNqdS;IvAR2XQ-Ah(u%@n6e|_Cb_4 z`p1o>2(Y=>(_Pfe62QNtQzty@x5a$;p9|XE#NgKDatSn2pz!A4(4{OVjve6qi{H;1 zLR#wkfxEL&s+R%5Cz+OvV@lhpyOSvY{=sDJ`cvyo$Z^k&9j5fGlY;v0!8!y+!9Hy| zaL$Q>uEt7L4;t4|1n>@x`_@=d*V|XXX)ThBga23tX;a+4t#iJ@Sl<(1fA?~kZ|4u1 zT$w=E*;NhDc4Iz=+imcOrrTuSne^qn=~Xj$QZp4K47(qS_Y-FC|HuI^o$tOe|8o-g zxsE0?2;C-f!!lf-Cre_5{3*|rY#HhwGqxe+w&tlEm+B{Z$$yShg?#}VAYD+3#PFOF zy?YW2Me?r<eoanx6G=x-qnTazi4s}Gi zI8qL;Rr*AXUPFGOA9}fhqNP{f()jHA5cl4M%U6YOIV|Ni2;W%1d}JMUvV=?8I-+RH zHLiD+Le+7c*RhG0x8>z4qP>4I2z3h|$;r2~C)csi=pe@LdkV?7$#Hfv7}Ijec87wY zZ(t$_IEclWa5`ym(Y?lPfmNnWle*$PGu)E%(=#0st)mC+R8D<}Errmu6nFZVb$NRl zx8~#(s4LUK*vl%jyY9_t-<0Zo5f>(50uxo*p7sEf@jV&r*yqRsnWL zAW`iitVP-6T$bY=Iw`(v-KC1fZ539*Xm-i&q?vw&0o|bU$XJW7RfX1q?$09#!*U7H z7HDQU99_#xU4ug4Oa()L1LWyf6rvU>gQws8hv-A#5@^@R{rbhO(iUh~CT;4-OFqwY z!*{oxELv&9+pSVR9U0L0W?;zUv7|oD9#dJFr167%YUpJA{LPh6#BzvqQWmb%cPvux zGStg8%`7LMrpt-L5Xd?=dA_AE6~H}b?Na^Rx8NAK6nT- zR7E6IrjG_!;~dyt!uI7B*=OzjN8&V>ek^2a{yQ&JU(pk>j)l{XX>T)Z>mR=a9jIsa z%Uq2yv4bn@`#&mHRzhf8vcK#Wo3Jk|LU*0gB;;1XbSZ@{HLvGno{m|2z~1zM zeG^~7Pa}{)EoUBi-EhGsz^p&C?6A4rAKSGX!LdOih!l40ZHSmrIYG4}zwfpm|8VV5 zYYz96Vtd-SW3lu@R&}wQ?iX>_V<*wL8*wTl4LAr9Z&#W7meJ(g!_99lJoKqjj1$Op zl+5<1)+2Cr-N;HW8ViPP(*p59Ew_z`*WgV$a%eJYT5;VeF=k2ppLlh)S?`-Re83+z zXd66AdSXEW3p363BH+4{B}AzD$49Tu`~rhIQ>p08o*854erxFzLKhtsNhk*-DD9TrO|>^sCObsaTqF!cUaNotC0 z5vZCxSbgbvU1Ifv-M0k$>z%(iR`;#f)9?0kl_NnM(IRbelREgV#hVN|v2F2f#S6Qu zzgQ~I_gA$dmXHMo@$oqH%r6B1OxYvXv#tgA z?WP5p0ZU37stB+-jAH$xysRtp`}OD6%huNWH@TaanqxidHQHo;)BUECIIwd(C`t_> zzUeDB6}BPRT2e^#5 zb9XQEUW?wa*(v=G`ViMJU9e1EVe`ai*Uam zTgTrDjOrA&a{4X4tsOf&Wg7+KZ8i5*80SRmb?aXW%wV|vqP+e2IdV@7XDtNqzgW6o z76GUAohEZSX7|4SVp?H8er`A?hd|D0lO5@FlZK%^cU-!P0Uy>X|J9JbcsR9Q&oSK-q&Ny*0fg{DP zf|tv7K>K`;t{3(uJ2`AIQZjJFepkmK@|PH`jQNMN=0a**$QAbikb0bxHCVeh+E-yp zMI$X5Zxs3;OTd^qjOYh;Fw|b}_F>|BC{+n;I$qstXY1nw`7E{9Tt7KKS>hEzBF_JLP`HmG@k)@~aWqFPwukJzJPwyGj)7@q?(6jnNlH;g4TNi!!~1@L$+@ zF)8uH`8|1c5dP{iFqwj3Um^_20gQV&@~_GMF69R*_OH=5U{s4xoBeM}5-dH7zLxl9ah^dc?aUE|z_v zncQyVIS&{{RCY?!Lf(bl>QOjTrlOZet3nb0^@VRM%A=&|1!I)x>_5k_^uE#fv-~{` z$(8k-w`{JnDPgj52-1kpe8uOz-e9dOboUujj}EgAiA+=NXT_zM(|~XT`5-zztNH`W z04Y_g2%AV=%dR+P*z|kYbS`hrT3p@fOLH%}#jv10K1~I)*?T*c2VFIk3Wtm@oH86~`ab{*~pU z>#BD6lWnc6c$tQ)lI8)fh5FS+%>7N#4oU{t=QUVzNamGSyi9N&Q&sskX6jNR>GHQ( z=BWD6Q5ev5FRhaV{h<^0o6EIJ#y*Q&AJ+ESjRGJM$4s@<>^58Fl!HhuLPb?T+sLpg zP7&vX5-)bd%zo;%s7uY}lCtM84%|^rCfO_Cwe2_Jyrs}Z>=DsixE-W8HLP4@Psy3GDq0vO_#j7)?HcrDA8Su%W$Yia zl0qls?+to63Y+2XYGry1t&LGHHTrEl-Jlk2D(DJZR>Fc0s9ff!O#_@`<`WE9t`FvC% zx~{gqtz?aB&dU2{wH7K3KzDs`(=|>(V99!k?a6eYRY1J}|Nne4D5qWQRQ&#Q3hh7r zzhL=yY0d4CbBT?XhE4)oc*U6EbYp!8Yvsi)xdF0>eg#R!&4cdN|DTSItG#8qmwhDE zQY`$GQwmNC{ZFBQO%Diukr9S=6`A@4S=F!m;jy$`MW!~W%)~YD=f47N*V|s5`sX^G z#+}}EL4czFB=at+IOI)*J4sv_Jel>k#uQICut93LN12p>P0gDEs|>8TbJSsF2Ha&_ z4;%@cPyt7Ky#-dQnS>m|xIlT5#r-QG`*05XUk=Oe2*0acqrp%5SnXJIho&gSi96Wm zz!K+`Oy~<@Wd5*-dsC`2<~q^`9`Cd>COZ_%w=-52u6fW)w@nQnaL6=EOno9c{vMXZ z6^__q8MjDJFmabwD=9CQFHASo9@bhZn9W*;E#mLSkLXU9ya2X=hgz3HP&Y#VqFy)s z(?@-&?ekzu0Z6B7E7M1tlpI~I%?%oUyX+w6U^E+t*Jo;KKfRsIas!JoBYx6pmt$jn z^XSyb`6sN8=JJFR@<*VT{E<(J@-NWGtRt(MAzT-Yra(Jw?urv#$tU+$G zbXXCm)*OREx>wqKh!9JWw!n4zTFWIyW{64(M;%ejE?u@e^7C}BlR8pEtR<&5XQw94bbD8^RWquxk@-b|z@rXGh9=B>^>VD=*p~N#?`9rm z>C9B|;U+S2reu?$@jx`7>jxAuSwwQ6@P9`tG0am8%t56-{OMgkY;mCLBa&Ff?M-55 z{P#SCalcMQPyNN4KUQ(m$gJOLMp;3lNB%R}8{1;$97I&0wyeagz5l`o0cJx~OomWT zn`?!JjN#&2UW@L5p)727g}^3mP^db*w;Rlg|yf z8S%m|cCtJAj3{N4~n}88&4!yv!!P#DN(7#wf6&E0MtE zA1!k?$X|X#IY9VS-6b1lfP7TY95Iu7)^4A|2XF9vb71V&HO#(&@jRufm!x|?`2Sdd zvWTec0~zeXF??~Z-w+b3XA+ie&%gME-M7!CC0YvN8s`s?czM~f#Q{r(@qvBCxmkBT zk5jEvz@H!k`X)Bs{^u5n#>H{Irh$@rVuk3|ouXd0_zSzzaNxu<2hn*``Kv~*ubQjM zi*6#m`{~&gBJi~)n1#2Gi%XEf63F1ACq+uV>GnG9FLUlj z(L}kzby$TZV^XBp`O|A-8&m(f($&<6S$AgVv0$8=gPW0jPy0uI$N>`MKFJ2WF0MHN z2)$LDpsGh+qk6T=narS=XtTK%S8)t?037#7ezDnYZI}aUTU@cCCU4-OcR25o3G}5e z)yZtv@a=Q4{}Y$`7Cpz467|C&?DL}suVU_KsPtIB zJ4A-CK7Mv!Wfh*+`2v1vyTCx5`#mUlU_1}K^(C0?MKqMzCf#Nk9xt3gpJ9B{Z*~o5 z21I_jlkNgro$}JGcn7R_n0L<;0VWsQOy#m4dGvU)-?NgAT1$mteSQt0h4Xd5M&v$hqNek?c8QTAmtqM{`g}gXxUfUt0o6 zvuQtUblWg{e03hwRj_${Wi#ZiB)+zqOKE#sz2>34ZRFtFPL!0R@FZ?@__j9j2!lD= zg2j#eBX3oY!Y5jWO@v*2e)}i=SZPqN0?>lqW=c!kMK^Uf@;(L`pd!JJ!&iKJ?y=&x zHnjl?_#V2VE%cLjmJva8mGlcUGkic}pNG$VisvYUuSGq^tyIH6t&F6U1|LcW>eaFH z0{f9BHTObSm@EWfwg(p6CFQ=iep*xGAA_b;8J*uQEG`L@Fd`P1T#0plwzyt6p`QzH z=}j6ZTTmFPNg=DKI$mWk07v?#ys27Mzy6v9qnSl!cUD`7gAD1#0Kj=@`9O$xx}+M$ z`*hUIzC}mTA_x;rjd}0C)c~_~27q9%jB@p*gjfrx?{}A2dsX<`Wx~iSErO=17})ea z8a!*UBW`9T<7&V3h00kP3prdY-rN+&gB&pO{^5#is_2%ccmrbUmHBN6n_; zCUP_Wq~>7eC5JQ|MEUC|MEW7Qxu7w<@&QB1z4#Sn+SO=i4<}^Fto~0+;eAttsy*o! zg=FL7MCR5bC2{*E`x1jfcpc4k=M%T(2Ha2l{WRY@m%H^wC*q(eqv}*nmP;Z`;Mf^~ znK|M!n~o61Q}8z;SpUA_He15}50ZD)gcU2GCf0wH32!v14*e}`7|5*q0^OiqsLa}! z-C$nqQbljDd0}oFS$l;ATny`$zP6RN1lmKyk(~bJAau(Kia;0j>s4M7)BIybr{>#4U!# zUGm1+V&ZixfQprG>3l@hCX9fZ?Rvg6o37N4&l- zZX=`5i6fF3%bU4=3YNpqdaU3oKN z!sp}8urCM<7eXJ7p-2}1Hx4-we5=}QgS%>j2w~@^6vmWvOU6~S96Bw<&CE1A%N+Go z>TAM|I=oBYp?{p)tH$S{Wm)UebGpN)h$9Ggu%3uBnlx_awBGoyrnOt8Q0xlNK+fxj zo!DX__qCQAaa6D{m!rEi?ZsOlW`-RSWs5u+pZ%t7kY|a%Vr2yzyK#6w>{ndJrzWjI zi!5kCJnR=B6y5IaNo}^|jV3Y{Zp_uBdBhIEKEO^U^iMavln=uJqMK3qV)cK}vy)Oc zN?>zU+WyIcIfu0Tl?rT`ZO0IVE)QZX%jSYRY<?EL_!c=e)H*vjZLEhBmcH!cBD$$mNC-)^pH;U ziiQjSF<&^`UfuG__gVxp|mdTGqlWVe1puNO$y++IhDJfBLS1@S#P} zr40J&@@c`4jZC1VOZ4PZ4bUax2Kr)56tC?foNQ4!*V_)+h|F3sJ;qiBUe*qB`N*}( z!cE{D?N$c%V@&ds9+6p;Tz-|=4(pGyuHS0$QHfwhQuM_XT)x)^DZk_)m_CQcsp{%Jp{PHLCy;+J7sS2 zO?2GJ_;6F-bo#Tn=cNAxCE~nSusmgQ5G~2Js=Xu5ab{Q{zpJBI(v^~rA>I&6TuO>3 z;>YJm5381o9S1h}TfYG~(2dfVF{_AUROa}#f8Iw;>9OT~dEXe9>y@2iP`=&ybT|TM z@iz{al+@}YdQHx_{p6^Vb?Iq~=j;VmcmvnQ#_IT?*y5J6=;jeA>zsF8lEdm6YF|@& z%MC^aFlWq^6lA_EQ@Hm3-?AGeRTjDhKV8OAT($0ux*iehRa|_G5O)&ISq58+)jHn> z>f2n_!41`hM-*3bCM6wxy6WAmaSE~LJ2}Q?+F{hb(kiXt0>!)=za)#{J2JFiHhyQd z$2Q2*XQBRJ%k7_B--@==Ia3)yVcHrt-tIpYRa~Xtp(}j=d8_8iDF4!ACEhR|HxCVl zbP}eE-MM9dU?FHO_bt9{(kcL38xd6BdEw^Gvc%eQ*|57s{5FQd&G>j*R4@J`|6ec&Cd|h26GcTD-X3z+j?w zlOr(B^5N>$L4`t=k3yp?JfQPNIwjq8zJ(0Y^|C8Q^X5XmUiGFtPSwK|Viql)O4Yd9 z^O;{^Kud0a9BLYnYx92SQ%r#OLG!uRDeFn%>_Kp2CzabTG^5LYdxt12dtZBuch&Qt zl^$`Bwi-uhbbG1JnCK&P*}7|T=-iSR4|O{kZs&4O=ah5^XIx10^!HcAdJbirnb5VV z&t$ZOodpH5Mf=U^_=wUhX?upK7Km(FY-#Li|gg2{zv%vr1G+ zH<;xreRuT1+Nu17Ybuc|PV*(Iuy>uEWcbf480XvAfLC-}-qnE3NB|}a`@IBH@Zk*D zlO1*FDFl07`+;S8YJu&t_4M0NGf|50-7{GFazseXgi=o*6%<>Su_yAIWS?Ch1$BA0u^8$+3}g21jEa~%cb zU(?B(qpuApUI5-?K)?BS=Hk`Im^NK(Ld2)T42Qp!{^GbFe#c{->}Ve({mmB=pvuf8 z{JenS=z(mQaXw(xdgoc$OR_v7{D9f~X_GOr(tWkm$cijnnzbk1ZknmmiItJ@d#-f@ zidr{uwj_>2Ihf%e+>+pBG!CdYLgD%z&(avJxyvxQU~6vq4WaNT8n|q0%5HW(Kejk= z7d>p4WT4CIYA?o~&c#+)c~H%J(+xU`*`N-!b+cz}ZGViV&ilaO9@kpvJ%+20@6>jP z%>)DHlFJ5M7z3Kl`2%8HdO>x9s5PF29P8r>sj+WxX~q_1{fG?OP?ix|i=d`%?3^4# zB5>xXywvbSYGoztndl8Ws49&`J7(439WjP~Qm%NHa!*K;kKxwV<7cT64L)%}kIkd_ zkC`d}n15kBJw}Z|wYiCzp=pn&B1s$VY3Ny0+EIqo_fx5;g{Ww`dpiv?Pd8X{6Q}gp zgSxq92?rch_uuMNE|Ca+3Ln`#3?muL`n?N@4C7aMtC#*I;D@{z6OR+`PrugfK^N!T zd%?`2DimVo1h&V6Inp{?$ZzEOCF7mxUEhB@GiZe>pPrQKEJiFquj2?G9U0XJ)I%L1 z$L*E~nI|iDxiJ%UlnSY?E3_Ex#9*Q0G-`wY|zfF6+^%lb@_FQC})wT`gYC zZ?eVp3V({lZL{qOojamV41NE8!8sY5YaH0k;gw6K!hY2&yMkHSZu4+o_VLzlwphL? zX?y3p!6q}%E4^0SWkAXR;u%&Ui_T$F@>TgRuvV9MxKcGcUYA+Hm~38C->Y~QG#x2I zQ(%x)AvED_b9<%71VsxlWsxKVR*JWmw8x` zRX4g;k%bXD{gsg(1Y*wmCg}J$5D&_%uR$P@`?ZUsdrlTz9j)m^#6xS}QoU~NhWYeL z+y9?RV_7OOWM=yOe?*;!J6nJJ_G?oml-i_d=`d@LBrS^8s%q`6wYMVn-m}%Bgcz++ zBh-q$SJkS$N$i;*#D4O9e!u5>{(_wAI-hfLpZEK|U$-l* z8*WpCMSX*JWw7X|VW>`mJMAr(!o12O1~8csB6zz*kx##+J=M_R6Uw{jAXJDn33|f* zIwi{ffup$@Vuhmqq3~4_;OUKp+O>rP!p7yymcw#D|E(hSoql`Jp;=;kiZ4j=F8q>T zsEcVo{DPjVn_qLHJB|C=io!?ebhY6uBTZIx=SAb60W3RC>ylls;2Szf1})KZ>j=*jB(dbX zoP?sgHl+OKXUd-V$A#3?a}2bcGtVFfrROq1KdJB49r9>#=m&|e6L}x~YAQ*z`CsW> z6Wqe=OgDw&sd$l%CY8)<1Dq|HgioOV_)SLy(GTN9keNqrmX}rQL7Xyy=xqD+i#9dt zC4y51%_-e-f&a}y$$tD&!H8o(x=hl!O3hR$d?r2N z?~<`=WbDDV*!~^wozbWRCPlo7#&X!K;>1xSq{P6o`|4N^+L~@|bj9%Zlx;TnysW%r z2}O1d*)bTNwX{f#%uPgZ*`L?C(@5wWk0!h3mS_LV>V17~!nKmN_3Bu{UYx7?<{Iee zIafHU2QGoQ(K?SI+eCY-joXFK1`5&!goB!N_4mGz$-9LXZfU@h;L#H36|2(;-Z>b# znX57zk=fjGWd6wel{ln`Wcq`3jMNp`e)JJ$#q0(b#kMgqe0>JjTIA?##-EL)U zI2_seUcTVtW@o`l<>CXV`jR-)6_vl6$@Ot}>p8c+5Yuv~?}~-6A^n|^(=iX%SMoFS z3z^rehA6AWs~H>g{!$%9-GpXkXxdKx>gAhxCb?r~&s66Z2((9iY3t<*K-jU#tO=Vd zDKr2dBg$`fEPK*@AuQc@qRHYf5rulSDO+$xxpOgvtNG$t ztA1n&3=CdK^sz2GLqojid)83>@+MN=Bn3r!NEcJBA zb9e%p&U|T~xiBQ1kG-2daB^;kV+542-Oofl+f`huVCv8st(ZgFnUD$3HfqU39oH|Fh@&NBFH zK@rYmVH4U-S(?g<5&7qo)!mMA80^d{()N7T3Ryl;fgLBp|r#>z#Hj8>hwa zIQu$ZHN}65+m++0EWYhz5XTJ0AyT!K0DK19fkvQ3xs*@d%gttEEl@X+MV&+O!=4C| zOtUnKhCs=?Xrk?6ESd~o=LwYH0Ay~2B}^h(n+|rimKDQYinL?xuDNzW)R8RJ;}rTZgcS7(}OiXa9K;Xgo+C+F6f`9tClQ-fVB;D z1$@b)XUq`TW*`|k(YSYlN<~y$Akj%KXNCcNCxHN)Ns2g$X4dQk;iFvPGnYGu??LoN zC@t`C3BYEi_8`bT31ptk^%c1CHK5S(HhL4|+w9vX74Xsb0V2*cSGPZ)a+G=JoIl`e zi-Jb7)cMoX)SyF7=LW(SB1s^rl-e%~^s-{+8U!s9>eIRw<-cr~-h87)AgIiR86f-? zRy+CsYAnVIT6uv3pC8p0a6+cehK`0E|0++8mnBqwhUI=feDh zUA|7}vKW_<(Z$6Yc+v50e|P8uA~$VVcDV3&VR{>OKK_x2;)u(lMc-vsoBS*d@wl70 z{b7E4N%_O%g_P{$9~yqgwxihM%1nxYKP~j9KeT<510}esTr*9UYvn&4am0npozQiV z)nx5QnH5h#>D7bLD5Ax4&6J*-McN11xwhA*?S^>kp2_K*SNpdr&VYhC3 z??Y|YWEyZXYXiBMNf7IQ#X;Trx_PfN0Il6^|7lGJDI7Xvc3*%dYqq}Cvx|kkPZ4J_(}hh!n>?FLD@jP=OzrIqtiam zizK3ZIj8!-#HHFV`NXko;1B7obo|8HCc7(um!g@2j+(rV(bQO!JWt-zXImOKQsCe> zzJfWrxS#OL)qhM5l;67LHt5^L>r_L}1lQ>29(OQh(h(n-^Zzh4)xShP1&g|nhWCA^ z*lXglOH(@})?U$~zFxO6{gw`{6{Ssdw2IzT$NPbwT`Vc`3Pq19cykSR5AWqF?pDQ-Sx_e)1fH5n%0*jk@T6u)K-Vqa z$Hj|i=O?M2tZ}hVAEO&GzK9K$*kjn6W?07*8(RRqtc9maRV+jM z)+I~_4i>jK$iG+l!F{*AGeP2xq{0b&u<@LW*2prh!x!@U&}XJ7X(RjXmC6Q{ehH4`rGzAnLHfiPs-x-IFwRvO_6!O+mi)lrrE!0+>qH*M_CHt-fo!tl;tE=u$kvJ%h{(*61^2tO{WHEFhybVG zE?lq1D1h@7ud_O4j`wTI$B!nI@wbv(Z&7<;UOTl(nUgq%l(b-^Jq4(bs~Iy}u@mE< z^gL!An~US5D6ZM2vrgz=&YluER}l_38C;TmAva-|ZI~7z)b!jbvdq7T5LxzfMswqQ z+r2?9_MvBE_X+&XiggnFu%03<%x#Q#h5|AT{mB;A8cpvRJ}lVwYvI%Fd1EIXlI-*G z!dmY)KRgff{l*F~p8~q+%0q-B9V%X|v7PrB*KI#mT$e;3w4V|x{qzz%=2U~d(F#y5 z+O~ZpvDro&_1SY5r!j_>wpwJg@mGj+#r&pRhs1TRzz-R-eKh-4+Cndi)6|kTp|Tj~ z??j*E^>N;vqu@hI+yPRIre8WC#+px4e*8Z~oAdO?G!wSdZYkFX*AXg6(Z;q~@a0zK zl>4Pg;CKH0d_+flvtgBJ7|Ebmz2djz>C@IAK9Q#p7pzs;@xyBci=li-Lc&;z#;$I`%c0>{_B-`ofb~aAda;nG z={bk4f<$@wT^_AiC_El`|n$XLlwN1+=Wk9Qs6q%^qQa--Bc znfDmh^{ZOZ&suk2Au)m#X8%zGjDfGVv|Jp3ro!NHM>Ah}{UocAy<_)^j!c8f!KQVg zi(=17Ti3fRB|Vj`FbhS`iV~H6vz=SM3od~kzqMiD+l{V5K?f)1RhCq>|HjP87D&JZ z#Q?WARu>q(#wkM^RB{j0I_t@%+*oCzE`2TqU z8Zlut`OC|6M$x=Y>fl%sTxvOSD^B{H|0arp%Q~kRMSgyF=RJ7q#Z3zCLtwD*3TUjS z4etMQsXbwbp@2)e#uat2Xy6y*U3B0;e1B)ijBwE8RccCc*Mw)cnk@r4#FLILMcZ#qbuhi`I@G8#`; zF9w7fFWnqI2Y^30othh+{vZr_|E%oJbo#A?8_Qqpda!|w;!c*yfro|C$q4`T27lF{ zWgWLwut*lU;M5V{-r2h{DHng8kLO|1Sl_7(8{o-|=j2j~-?|F$qhHNBFYwGv0}<@7 zjcMjAd(*NNW?ppOqX{Rx%#2#^7p`Xd8e*FhNrZl3eN6)jujJj8|8Bv%a%2g7n{xQp zQMDT4C-%^DvCRln-ja%T?aXMPusyPVcD}Hweq#GCcRAd+#!G7_cPWZS=(wKx|q7MQNE(G;<^ano!Ff4%^4j1od6ipaTcOSV#au9aW51E$9 zuNE^xpzZ-~tG*)doUMZ*IjVycn%DH|wT6=mdno-(i~_oWwi;a7$1%3Y78j56*k}D- z0V6M@Q+J}BaAf4Aq(QWmo~C0_bH}#>-wkZW8pX|tN9=QbnIH4Mse;@?bf(zFAL^H` z6kEoc#!*L$A|mSW05hyaR)@45^Y%0K5b6N%p?4*T5yriKhZ{2W7ld{|N)A)d##vRU z;oYhgJan{H-eggj%^mE)%5^u5K_m+XLw97BA3{oS)pi$NTOfRfganjYXB=up133wD z@udt37%kj1?I~zEwBYpSqy{bq-H^}}8uxn##g26_k-Dp$^Gx~Z_xQi-`u*#s;KlI%aB;! z89ml{1FJ_4#;O^EI$k_1@EJ)2i3hNe4nBB`cu{eSzg3)GNkM__nH@SQ{r+zQItFS= z-G|(VY~Nq#J5>yYc}0JvdCX*f#!3HqXFZ+b#iiDr329eQ&{)ykTiwAPG5(j1yGk#A zc*!Kn+o}lk_Yh0+Yx<;RIQH=Utt?r;AOTLd()%bS2lLgzJWw%9c5Z@9XAt(%!{Vy#58I&odz{x0SHp!9?{aiis`@T0WtM(N2Wwy2jR(1(i>)4N+luky%6!_yy{ z`D1G+N>{Tq9%gv(u*vzE4=Dq1RHF#|_sb1EybU%Z0i=YToocB)i*v%$Sy$Cv^gD@i zU$3#v#Rgd+D6~}sW}fGTNGWHIQ~FjA2X@ek+GR7DcimBsoLPXm13kmw48uy4r}%cC zjT-%oiNBMTf<42#6i=t$HN^^J#aCa*)vl`5=hc6VGhh$GtAH^H3Bz4t8CU_njLGDte7z-1@QD~3wO zu`_9hRc?tzuJmDBF~5=r^7}b8pqmVqn4@g0r*l^6u3c++un&d<48vQZGM--aZ2=&LsVKDuKU6iV4Ll+NbcypUH(F$T9J%+>_BtBK<7pUkqs* zSB#}3cO)XO<9pjgVF}Ud)0=(-#CZJR&ctovqV({mhiPTzw~3V1`-Js3d@DZXQtVBu zYsTqJT`aLL4Msbi{k`(QfEG7AQHnycX4n0SR%osI{<_0A;6EDD{ZaS4&ys=DY}tPl zH>9TyEV(c5N$E0UKE%OM<2<^}rd-uW-Y0a- z+-guaE%8z!oS^7|hSunwZw>}m7 z_F2iqU&!|E2ynG=rst=k+5XesZV&LWDx)>7;Pkwt2+<012qB2bN<-dL#9G0kf^#lB zr#04u2YdU1nty8Dq@Uzu`2rXcQ*1tQ!>?N)XO=mGbTD^n7y~D@C zhj$p7kXH-IQ?P|Q-gN%79W-XEK_Z2wd-8I|3VZXg8H zmI^7KT05B_KLl!ZQ{i;s=f{OoXY9EwE6L3A&4;ytk!e5a){}Ex8 zbY(qI^2cUS4N}b^e+i>o|bd_=*W?;G;Xe8@8A;xNLx zeTr^Aa=^C|b6D2y)RN;eJN;;KnGiaZ?YSjo{`0bXY(k}hx~!Mqs<`=BT87_w;{7#E z?FhxV`z$PdS*Q64jTDJG5bSSu^z&R}BVzdQ-hR<52H?Fj2Wb<-B!G88J~&+Eg*ns2Uv zwz5*rYZ|w4m*+l}Tb#=l_RLyW*=*`ScdhyiDZpLDjZ%|2l-WZ0e4fkY(XqFi-BmmU zPc8fo?aHUGl;8EUg!VI=hMs%k?88OetD)S15e4fqmG|sO$pEE5RPiMX{Ev$9tJ39m z*Y;uYd-XIrPUcmW?}Q)R;4JZ{2U0EV&zsZWD@8JW4)FO02)9Smj+fh%LxtsS_oTu9 z->^M0&?dlwp4oUGq|X|g0){wt+u!5#o! zwn0CG$XB>W+Z`F~w;HJE2*>LUj-OWY3w_W$znMEgT2Tk)?iV+E@`^$*+=P&sNwejo zyj%Jvi8SJ(x6tvt1`!a@xm9>$v}1+gl?|UQb4FKxqIAKBjs4oe%Va-H#Xuz%J;y&_ zBM;)**{lL5$9_#9v$+1iV19o^&78eNdS+XPGsc>307(R5Pg!JbSXz3CDQzLHG5ZZ{ zqYbi3l)b|dPzX&sI=)@oqqb(V6jImkGRqxMb)M0D_HBu<+4_dlZiq(aF`(62Hecdt zue?Q(7n_SCxiB0#=$YDbWr8Y3k!G^+Sr5&N!iiZ;(q}A7S-y{z)Xrwl`|>#}%iR zOH*A_E(7qN(AkvdYT0ykYJ%KRE)>&<)0YgELw!H!u7hr#ybK_GKD6?mEP8VK!OfdFYbt&L z4BurfOWwb`mkDpUXj%)!(fT@w69op3iKGZU(26|q>$x>&5y7H*efV^UmtU$33v*NU z%fg3>E(WL5uFwRTgUg5)&1zR+qEaue$3SNwqZ$_1Gu&v)h&ybd< zBYfo#=ItC%_Ds%IM7teEO+qSM$@`s7621h82>V`19;hvD+-PaSZyGMa1(u@43r_8R zYcKO6#1?wC+=S2mOkIu*O0^z+mkxfsjYJNG{oda&os`3QmHP~lC2Y<+UX6N{bE?+m09IbRQ2hl{_l*#PtlO|EeS%H^Jq1} zO+d|>=mW)>j(V~_3iOQR!#&{-W2ol~w}|F%G2Jcmaih)4s~^9^-K(ma7A!dPWBph; zmeh~oAQ((U#;s&LWAs_?0VAivm#88-2AWWcpS5d*7Vc;i0JBQi50%MY|>x?AL-0zWQa!~gns4Uyg|`7DXwb8c^(0yN8_aAjjNm%q>m@! z9TxGEiX!1m2T#ZV5~&r4gXAeT|F{^!bqDBf-!#tVVYwY`zl_rp+iZkzA3!?Zhf-FOm-{|)_8%!<+MhcDg2zhf??{xYVRJZFGN8{0*9Zs978ffC z#8KG)w9a_6p8M2NESoZn3PXsI-x2*FHiXYvsI}qUeFt}CMG;%r6M}v8k1*OD=x*kl zBDVniZM7Id(%W$gjc3d9>WCtP|k!#*Er8cYtSN%y7=P-vLMyc|ab53>}gQeV^ zFfnPO^2FhTXo|ggW|gwIR*}0y2GP;i3b4BSIl~pV9EgH#5%8m&MEI5^7bcGx=C^-3 z+rch?^Nrhd)h+u`k^q=>O5Am1Ljc}ZNnOPaeI)8ppyv`>g&vRgXYy>yVD1H0s{YWc z6Zw^Bu!)rduK_{Vev4v0&*wrD2bZBqga+i}A;Jv{+(B=hH~kD85uy&AsYVal3q;0p zvZvrPT-KHz1OZ%(doAk|VkHNlMQ^jcnJp~B$fV?)-&Z{Tr#h zHnp?7^?Iq6#Wme(UO>-3UM~U{^~6M;MQ#aMFgsS3gfiM=Byra+|3_6eH*&mSw9qTJ zS}fcAh1SDppCH8-I)^I8BAp$K?XzIt)SzFD-vh$h5A~gmhJVwpr^whIaD`WY|I&*2 z?Hr)Kx8?$_s=JlyH>M3xi({~IrD;fkaY{We`w`96D{E-}(cqS@U~iaL>y=opMDfc|FGGuTbTwnej#AFM(6-NjT$#gBnLme?`LolX{bTi>{@_Wt96^ z6#uJ6E3z1<`g{X$N@YWuy*8d&twoL)nG^oyEDU2P70CxrQ zT)Fs1R~>R+9EAnkIcL5S6(sJh-H){?)T%X0zRv0W88)|Z+?W8~J>2|>n?x-P$~QO& zItsZQGuSUDLPwl4G!;~q&04%%YH-Ple4s>s+(RbN`1T9Aj66`4?;Ag=l7gbsYW}o> z)rM+HpYt-8phldM&XNNav;~ zR(lKgB}>p-20KOnqIJ~2YIA_*@FDlod22wpy^wm2=*4r|Y3HoYOqV`C{ojW6yB(t< zK?p)VC=&vY=QSjzwpE}b0|3@?W!NLdSzD56X*ff_^OFAUNc9kBP~pHv@CiNYU=ovv zBfQlsrz3T9X4pm?o|iXm|FV|qCM~XO(~5twFZlXCKEsxsTfj>n`H%EIyJ~L7lJ|Y` zzE&Da)u@PVbRwihB6?Af^u@dJCUgmT_zffPsggS5A745)N6qJ^zd!38^_|j_C6Dhb zi&=(ryTmQy=+xL;9;7~xXnPW!!9Wx5z4w+eZF>a6l0rV);~tu({6>Hm+83J;bh|$9 zfRkCguaEC;^hnjijwlxB#@z!IxRD>8$Qjn-FtPieIvY@AJ>Hwhn&CPzcSD$)JGGa%`Gf7WIVeoUx;nMDDZ6 zPT{hwxF;IF-j^S6!z;<15@tG*0J|c=ark)40X|LnDpetI>1pQWfM)!8>Q_d#+1PlNRvTHEVrjYCemzeG0lx`YuA zGqdW0%GiU1mv>@^3B^!(+!9hW=KrlyF9%NDh3X4KyaW}l1swZpyvDuji)MJ7qxrEX zTVVj_xYKp#a(5oMeP;ow3w0}-U0hqmJ9$4F8HMQeenl^luR%`PB_1D`6FIM*r22 zP`tDap3!moW@YM9K2*~da@tn?=Vd~~;7V#FSI+$Raof{>&sjA0Xn$e$iw62`v z2oc4AsTHHCNUS@9R9NLbZ!9-}5@mrAr?zm{)1af?rsVjhD8dNf&-;~te9>%rr6gyp zV$9*YxyrEjSGy@T#?ZxP?bVeTMu#xD@r%_t_*yr@KTA)628c%UE}!6ok$P6q(fGus z(4@mxT&PDab8UUY{*;;1aiFduwoWcbvaklvhk)4_W~f@QjaAF*#WQDEd0a}r7Q#)V z@;x9>=hQ9F@%6IYR8LwLoF$ax()v;nJgTX_2(==dC^TWO{uiicnfb?a2igNyAz<0{ zjj4-{Drmi@nIZ8sJgdr7(Vc2$(HfQ|^+pWmyMf5)j4hN*0L< zV$#1x319nN7zhU20H=d)_-4o69*3AlIV^ugrWvZZ6oXjiyND1??&o1%B8wdHa-eDV zE#R1A&B)R;A$7ygK83%n+vy!wfyoj)E~>(C5-1iwg=>Dyv>)sY#nE;C+BXI`rrkMXd`>S{}B;_B)|E@eYExktq(~Xhc7@@^5 zv=Geo?XV_i367O`1J%yqdN*pLF1UK?wdh zEVF-l6d*Pf%O4|U{J15xb1Ug`xG-&WMZU-i&Ew3l|C!7?{Xs#1H?YNBSU;C}#O#_d zWR;}-82H~}#|z>{ig5iHkfQNz>*MzH#-5E2uT&!;ea8$$xf~WB&K%n~BD}*w&JC|q zPR|X}W#2WHK?Qfpz4YVO z>C0me=h*|>xy~+@!vIdX?apxt-d!^5s_Y>p$4{DG0#y#$w5OG>Kj9vo-A~NQAJ$>V zay9t zEEeI9WxuHh2FdoOPZ+eI74;FcBQ>~Td@z)5r)1@gN)`DBUaB%8<==v4{~pa0Zr^i! zHTBu1B0g0`m|pnYx1QprVb;ASjg32dK2vy}VsXr)qinUrS1oDH#_G$!F?Xhp-6}HK zt!Qt(V`@Sw&`Y@TN$vOp<9{{XcW(aO@2bS=`XkU;8}Jpz#ZV(dwQlOF9#X%p4%Fhj z`w!(3ZN~$SdOq*1JjV{*1>6K|>8d=is*)ol<@kf=7;c$+eoYO>gs9xl1s<6Ub(p!l zGY3UnKU~KvmezZLE{CT4X%DtEF~-KrmaagXyJlmSd8Q8kgRMwJ$SaF*^SR5ye4}q@Tr~yP-4e*916;Rem!^ z)2?V(mho?cx*xQn$jTL&+b8gph@bB<^|G0r!|O3qa{L)7(kG3c!V;#3lMLRnAFX}997XrQ;eAn>y)OFKTQr7+WG5e@xcgl2-_#G~9MMqv!s zy1orvkn55$UIUU3Nv*op$!jnd!W5pkj{S8qT^d_kTo=}g1(ysi6``$<%N3W^TmpJ~RTDSSRpv#~ zUd}hoMjWFSUH9b=xxn!Sk0vL$S%kbg4r~9P7ohf7bG!a*BsoE2sH55kJUuPF7H_J( ztMW9w5lJF14)?8S<@juKVgSR}57%717tvX$NmB&rs1(XfQzdrFdfrVOaj;OuB>=3MeXs4<^)(FOJ$eoaU)zv!xSw%t< z?Qof{Yr7Z_c;^7-m!U`##=Z@1L?MQ#PN&NJHkiQgr~$H@%Mk=ToO!2>S=TWE_F1== zbrLAgw3u|1>u|>IPnWcPXCD`<*OV9V7@omk+85=&m=tEWF5YA_r*DoNb)K7clOA|d zb!+*B7t!NqL`9U6(TuKqA8wgHPbGQtIQ98E?(ypTCbvv@SH)CQd89b9$QZ+CD~vEN z#~In!Q)lKZ)0K(ak$bgs>?;*^@SNaB4Q><`HXaEuk6G0=AXn@LZ_;JuXMOPK8~q$* z<+FP}<9P1YF8Lp!tX z&~Gt3t^BYuXiZDDa1o$+^pbMC?U=n{k5$F}d8vJ9w6vqm(XG3MTawBOQSu`qN1qEi z^KcXps6KFVyNETOHtJV^K4KwD6>;l!hR;&noJ(x52eX#%^M@#Q)7bYM^*3}x=Vo?? zBq2W*QH2_m*NHg}lxyFcDp?NP3L(-FmnpI}&Awk>4gIdm{|L`$e;!fqf zLaSU&4~VDdX@i2s8v7?;$?6If)e*epAv3aj3J`_yfDU=DG9S#29w= z$}(e10L?7;Vt0(~QOnEA9R<=xy1p)AzX2V~Cl<{;G`O0c>E=kLs5satYs? z*It8Q4A&jLnX-csR~B-uLFmjS$9j$MFG=g%nq9y2_v6<5q1f&;aY)=l_z^3bjse^m z`P8!l2#IF*hmJE|e}Ung#Whav*9OiT?;hBj$4g15@E)@a>#*W?{)6{fafw(+UXm>6wh0$sx^c!NxE?3r55qy;3P?9oa;YQ4L0h_+5D?vEt ziTnQwl%hQgS5&?;Os<(n-*QLMjS)Avw3^2(Q^bTZE5 z_9Q4?N8|0>GGpt2j8#NZy}{kU*pGpoFQ?PZbQC9^fTGxJ;&E+zE1=Bn$MSd;*uw+) zIN?jv{WuC(hL(i}Xt@d+o^+}3VQqsq5wGg!RfTAX={#@5fAOfSPp>X~%Y6N-@{O4Uv zRpPlW0w83RMynxJqMBB2Gm!>Y^#0x{xBYv4W+vCmd`Xwim;=!hn5={V@{Km$@i{x% z%5cOAgFl>|rJKyT47`H|;ZHk(;JgV*2$~QZI7R08Y|;z-En=`Y?3Do5%TFO!A|IBo zwDuo9Ezk8r?XADVeYGRlC=c5C$DKHkV*`Y4GKH39asvO+ErPJy&0>q!+V+^%EnjAp zZZXz(rmuC^o!a1UA_jDBpdHTQQnm)&0?>byv5>QrfH?;w(0_%YQj%5-pJRHOYUJ$H zG&)_i8K;MO=1$bxOZ3zmrUJ>Rs@yI-ZYUHE#D1CYUg;9N(cKH-#He09m(=J7uxx4j zHQ24o-%d(+nH1UiM_b+oG!%o(G)ZIX~K34t{^xPJLd>C4r4jLN^W7GbK8O z%pLkUxEg6<0Dc{cGDTY2Vw?R~&z4;>Nj&@2P)EJS8*w)HN)>+AXF>gO8uqs6HtTg8 zXJvV76FO1OXg5~pJSH=EoXpb*)IqV@74~s#sR=*N;l^~u--4Y$WKT!~Gz^=zt(2XN zQ(DitYV;F-Fk2ge-(?;LjB)j}m+v~5C?rumU4_7YiuUP&kK~-!+v}>K>`Yq$S!q!_%R{~;BxyZjvMg$<>L&`nI0!Q5Ay=1M@__>VjQrZ2 zmdmeATxb#a&)0beA3HhD4UGBBZil0P=|GvBm2OmN*Tk-Dt|{yO)Gy~b9F=jP9Au6c zPg@XKnTQFC`j4GF8lldwb<)Cmy3=YF&u2I$tdP$K^z_Ut6Wq6hv22Q{ACO6(n}sH< z4oB}gH%qw3VeVq5Y}8`GHk~W=aBkd362`>8J^sOvlI~sE!S-ZU$DBun zI#`p*qjBA)+4@464xI@TNu97QvmrZ<$p@Gv$j#Bsk(eu0MH{m*X4DNzNHq=7 zTG2(xQ$YGj0wO)1A6OXqrlgOm{NcSqAr(0)C5BedeF5k9G)oTh#QKe3R0rMPU~}oa zjsFg&DOQ_%f&npNN5!JEt%1$uEGckz6JvwAXB2D?X*UQvzm1GK5_m*0GFw8)ERd$e zRkb!0w0>X3qas0Oi*?B0(vrR)K;Q1HRT+O4jd1fuNdm&EwA@Ea3>$D782?x$W!w7F4}06D~Yw6IgLVpH9O zr#?~Umg1-A^9YFls(<;x{H1laJz0Xr;IR}K=W!BHggyVTqr5FG5XyTjA-ctJGz9+z z=ev@ps>8D0w2wB`k=HpS>?eglj57r-@^Cybjlt!eQtSw9SyG-VDG<%RG(CB=>+pFD zD!J4>74Uc2TjtL2)(7!txNqyL-%Wp+E$g7SgIXXbK6p;aenFW~>Q0VYb2$kb8xgak z{`SS=?i)f!w3Ca`f0jo#gz~_S9j(`E&35w30hwcdS1U2d{&nRGd}ZqlAPU&%(rzfY zz?NOGcoL9PJ}|SHFP+VjD>gIy@p`-8{%}QH(zNV=)w$ZJEStUO3Mp_a_|~_CpW&1r zUW?s676|0&GQC+isBIdh9ep4&PB8kp(mgTX5DU0_g(Poy4Jj3YK4Odw2_5Q*{Z3r8 zB9C7_t?Q=EA5BI-6AjDa$c^K&FVhWt);E zwvLHotOWeCN=>mFI215XG6?YtcadvU>y%O@FHjC3{mwwmwhs&p#axA z*}vAhZ&r&l10B02 z9OLeRBRtxj+}8T)o1Gmqq@XZ9&A_{%_%~T=fR-u@P0HFgYu)(CFo48;Nfx$zC{Hj8 zZ@dNk+GcyB4mZ4BY=EW^mETM7a#xt|zlVR!|F-a-e!J?1jSk{0K4B*4YHFb_6<^vE zVdwhhPMn<=y_Do$469d&-Bknyw0&q%jinArCML1v{*OkHEdYC83ue^(%-QYVhV)^A zbh7^CrV3=zKGLn|v!zxkipbwFchFOCq^MHTeUfCTs2`;U!^g`LFiu>#x*BN|NgL)? zXFqgRmI;Q)L_d}d_nT2#+Kg7L^YlnSN`i;&kA$?5g2=41Z-{EPP8(@Wkg?e%oy_Vp zzmi^&iFI19Q< z%(zY7qSS}(u`AaJ{n0uAZq6W7T)wvMaTW#Wqu`O2PstB=57a@p>Tb|2LE*A}!;W7` zOikRnzYVqw^-GpBn?3?_mT=l+rb%^f_tbJuc^A^h&I zxH_z-mOFi0qJaA?+9_pS5oAsqXutZB#42x~*|Y3d!|hsCiv?lzhK&&p~v|u)TT3%`JjJWp9BlTD{Vo~u6JSj-3rNn9d-8vH{BKf`6)VS zHrjMX4dXLZZmwY!)lcq1oJ~8KJY$(B1u>4-q$@K;viNLpkwb^I% z@7}YWe^%=m#OSVM|HaTXszDj=;)lPO`d|Nk1{?OROVcge-jlQ94!|f#!BYdF3-C2> zfPXdYwBC101M|FNjQZwfvsqzeJXakBTTaMII=8QNXR~so(oT{XF9`M%J?%K9RFbj= zo?lt5sTVmkvbCf4-(ZG(W!_FAyyB0{9l72+LGemW976ZIQW%U-p>HHuwd9c9~)=!0fqs z)Z+onr)r+P#9Q!{ZT~}+*UX+uhZB-bjJIX~eo1wM-x)C}oL${RZQTbU=r(?@S%0e8 zmU5p|DxHN?j(>*B*i`)zj+i^d4fl^fBZ$w-GV?@T>8zF4yiRjp|6JelT=DCcTwW;l zQ!us2tcIFMTO!Qx@J#91?D$#uA!NY?{GL1Xm!HsPdb9(Df6LcK%Fyr5C)14nkkauu z{@@o@3??cyx~{F)hoaW%*VJN?$^ovCE~MIb>iA$$qi zNVSv|$jRj`P1EkgA7k5>*qHLpOj&8{rQ3U8HZsfDHOp=H3kKT69 zS#)LW+Wro}s%BS=H%KY)>>S?!(=psi^50I0Mx< zpQC29P+oI%6#|UL^)RJ98V)$+8aD}=xdu90l*fqNJRvR+$GAKz9R z=X1#d$|bCgW_yXHl+>6`VDYIY1=s1r?}y3-f2*n|`pJMb>I*i8 z*2R%*A)bn*u&;weFZW|fH)CQ>sMveAR@GFwS=kxxLgUGSoHeVzGc+}Q995*w;C9^D zvc3M~D{0u)$9u%d0Lu!lia?=@oe7ckVsCeL^jq7`;1fTf>K*|285AgO^Cz!i<+#MV z{>X;A62xgc$3>VJmoa6~--c_$JUqS0{ZVO^$fZrOE(Cb4@1L#0pzi3~#*VLfV?1fx zZTYU2CaG}ms|vgg2#q{emZw~b6QFB4Dho`iQMaUj zetoQZE@Mkww7RrLTR(dXmRfA))@oL+UUi07hxtpoZ3LT*V{}Kp<*&Ld1yAR%J-Zwm z*eUhzeX5=hnAohuuCsdAUcXJ;ug=r1cz*VS!>KDS>$lA`-vFyMEob6`1v|CPxxlS& zScJh|74PB9%d94>Hndb3<;M&d8W-qc*!&r)BE~qiN_MH5YjL0?>X_|sI6V@g3v&)y zx$>DtHz|0UhMR5nRQ0bq&f{Pc_!hp`zJxi0s<}W2fT|;+!l&+BMbVERHpg6w9AkEy zxfh~oC%<;ou8g^w^~ONY*~1t%F;>KdC5g(y`ko;^AO+H{BA7jluj<39E;5(1hD4m+ z9VOx|M@>V=*u(Up&0YGiouvEgik@(2;d@cXDdvefjChA$?vAF_Q};}?>ybV27iT_{ z_h9aaDHI^-Mz;Qwn@l98r&HBkF7`E7M6PPH-4gyj>oENjUhOzW zq#dSJ)l%{$5o??LlGdKHYA9@3R%T}`I2-Za*eW{1HS$J~Mjf4o3+&>QWQvDK0Z^hF z*iNLK?~^6uJ)BWV@rO9*gGNeL;Iz!2d&nw9C9xV89@gihKNhCC;jZ(KQxzzQI)Phk zeHKy)w@-%{V!KLJ>7lxArMda zs6U6==wK`114tg}kp8?}Cs8|`{*XmvOBmD!Yl)}{)ktTyr&{Z|neEY+Gru0`+xzW{ z%80R4cM$BwMgKfWd>ZLdOZbyfy2pYxv|*M#V*!IYLiVg4&CUE$$Gw6RZ>}`{%9WONtb- z>hhGnu*Q!@v%$Vf&dQEJSBbS*ct<~fb}uVdvT1bOtb@8M>hh$%o;U)<81tvo3?MBw z+?IF`AbGVxfBpV8Gi3=%ycF+?;-Rfr{|F!)Q7c=eg>Z6F_LH^$rX%cU^Ml2j_#5Nz zUt{jB^l38HDG6>1E8@vgvoj2y#Xw=Bvy@;Rt(frvVd>eY-~+$9yJ52oy>%*x0m~E3 z70T?96t696P>%<82wEHKfsyV7*@9N1)e*5)-iBcDCOk{Nn7)phqUaBX>|WkFG%q)p zlb+sFqFZ%znCqr84J+juDIT2n3)4`dUKM)5;@P*e(ciiyo%2;X#!p$l&&Q*eu5!+( zdw_31VjjPIqDFL&v^4OsY2=zaid_1gMr1f6;d4lB74tn6{kdmH!j{8w$a^|<>D(;z zNBJ@+b*%lESkrdwI5(8&4-DF^$5^Q!`XV7=Q@$AEL&TD+Af!iQ0kV?f50SXGUK?oY z3O;LJcBoj1lp}Umk4Z~;%UQh~aeC1+TEOYN{iaV*mO_&hPW$ij=>f&)zr%L4i_$Gj zO{{h+DH`x>HONrvwzyPb@hwcBt@?~)ld~hXuj~9->!9eyvl`dRfj1gjhln7b+2VMT zamr%^h=U7WS>n|7KZeLeuskrt2PpsVcwe~U41AxCgzv9E7^6bkQFNG8T<~^-mAL7Z z>@;f0n1&sdDcBHyTi|QNGhPMr&R9kn+5l)qEsa26scIPXXZ71?<;oYjVAf2Bnb?ZQ#*h zlJM*0QX^}^C@^xscF~Ykf+#|}Iv+*K)Oj+sR9!KGz>Xh)t9*779XL7y`32@4_JLu) z5);kZv8-}4VaG1uvifZEh{&1uq`9wR@#64y!*W%Rqq1~Z)F38K)EhTCEuA=zO4JKt zjJAui(FjeDD)B1RtBQqpY~M@f804~U@M*F3Se;!pl+Jn;f{4A+vMoNHVm%gft;wk* zpq#;sZfZ!cYE%H=_k2riPUu;C`*o94YClN-1G79|{%R*icZ?&`zTb?rz55t{Wg9gXWfA4A&Wm7?uPNa4ZTvh%y{5)3c->d^^ z?fRLya~>sQ8yW{_U{sM5APZlasosGrqDhm))$hgYGCNhL6PzbC@4;%?D~VV>2t{)r zrKgpG1Xv^tld~;ff`@Z&Q8D%f4T8lLG_8J0my`|J`lX|Dq+w%b1iJk1{oGtv5xzYR zCtvcbd`Ean0M}}2aDhf#3Fy*1>BY$>>LI8DcQMv$J03_;aw2$T17Pz=8Q74kpAl^` z55VRI-_wa;6UucrErO}kqx>jU=I-*LWSTdN z_kQ_tslC7D+&f(9J5dG}y`ZZEl(x5|0Cvr1sEA*RJ*=lxn3!g2z653|XjuuNKJJyT zRe5ZZ?s^K`a`JUaOj)Ed4Qw6;6$$uPf}rjW$4W6@{)1 z=M_y!(Lm`$CRQfTYfk>h{M<FZem=gZV9DTY4w^MXP#)lLuT&{+|~h1!v;9j^y=f zD|0Ducwul->BY?K1TF8;S8Wc02zrWp;h*xMoV~+Psmifd1$yhH0Q?jE%_3#mG4@XK zj3b`W@gOn&(6OzYhB$D}Q(FV(rh&K2AJhd~((vu5>TAB?Z|9Cfegqb3Y(?hx$@SDL zRZ^CA^!=RqMss-8!HKHX8|h81HFqiWyVxDFa69t@O-K)A4s8DyI&J3Wb~F)<-p-VV zE=&b3u%Y{_`ls)&CYjbts#->Wsrh@=inEXwZOZX&6`9}W4UtaazuI$CtI%*w$`fF= z6({@wp8ajEvv(lL!_u(Vow2W7y~D2=IyVMEgs1gv5*5L*=VEc|+jo}(6w!NPk7u-=rMHM`FYSQhl878Jv-*-P1_sp zA;iCs!>+FBoAwNUM|e_r2B15|%&*c=_BKZ})Egq^n=eQii%FSXf45+})(n=q4+U|tzMlfu z8+>!2X9m3(i=F2ooz!W%SjQ8(`7#BSeEzeX zm4CQR(zCQFPYL|kIk#5@o`xMu6+(8Gh)I^aRQo+IrT3xzlIx!o`250@ci`mk6n`87 zYR@k2PIjX>lT0K@c<6K7%$*`_1FB&M#>afMxXKqAY7*yKf#g0zMcR5>SwhEJz=fxX zq)^s}^h{6wBQroa%DwTJX|@r68N;(R7Y?k$e*6A|?D-P~zOfYcR;Hdu@RT>_$s4Y0 zprh~c!q)<{lt(D57(RzjviD7H7Hs@{&I8)`CwEnCFGH?O zte2yus9VMfOPH63JtiBPiUT6;vpZu43czP-M_p=iAh4!Z1Ir&~$U#T-gVg@dfqJV6 zjCZZ7Z}D9yi6q<$lds_ibC|KWip(p2@%ma6-@hd?DODha>KJO>o zw(#1F8dAn9r7&x#Yv8-dA6ctmwe^pT3>(RkBbxfug?&wUS!v{Ru~~Nt1I@VGH=0`@7q>dLEIb# zv(DDpqq8QB(|&!F*WK2*ArW2^d`v!_93_upK;8l$XFP`^3+PDD32th(ujXKCEh^gf z&7x{8{Q7zd^9R2jy0dHUzTpEL9`_@SixZ*$S-j33IjV=)Yqs1mrIpQ1~}qOrYzmbJ!yE zvz(TRLjuiOX_dF0A>!sy+Ne5Cc)6AycBh%J;zp#fymXHoE$)Pv$MPY?(6VP+!h+P| zFG2VZRS4CQdlTJyj=v(PqTR_~by+hPw?2Ra2yx^6(pS0t&yk8wHCXhV#AoF$5#_; z`99MAasgpUDFj2Q;Q+L;8=ch{)L9g*W;yhsO9so2R<2F?GHN9kgzS)sIk-I2Z+UR$ z%>jb56G)W+@l=o7R(uO{1E;xWR~$`SG3cahc6+H1#Ke)w0Sk@K`~N3jKOntt&Gp#g zg#)%l#^N2zD)!v^saF`kmM-qm2{%*)d1#vJiCb5^l;i`~BGMn9eVj8KI_5(Nzju zNk-c)ldoYV7AmhW7nP8vrTOtoICt_{UPzlX2b-Otx4w;a(`2 zO%V*mEDC1K8OL8(Y4SJ37x~wG;eji?uQ(p|(U2-fLDE1ZcLo1iw(8a0LvVID9$LuL z^=a@uPf}3rqcO<kAH#*U@(+IjZqxAbmU1mXlmpB@~?ubK%HCymTwf9)eHFMDyHbM2I^I2HuN-aVxpC0SBEpE zHx!fMizhvZ?fMOWNDlIaB8RggegeFmC14U>Xp60!8%FVwB4xPX(6P0djY>GCQRUv; ziJE(l=(!9!zeH1QI;yV)$d=k`UMFokE2<*XC2BjWaWxh1!sJZ~THz|2yERn0C3M}t zAz$RjO4m-EU@3AKy?*ptT>OAez4YC(3K~P50K$C@JMV`+vA*i2xoX;$(jU0jpA5JS zw@{uj1nVgk&1Q-j#KviZJ`1{*ob{i%8?lx6z0a~Qv7hYUQiVN}i=-OnuWLuXfV%Cq zZl}ohI%HAVmPjiB(Y$^`0i8Dvou!VcPqGZ1^BlApa2KxXGt!;p*~0+kMAM@J>G4}SXjRh9*DM!>>(HTA`9f{B(E_w#ej$j z{y@XDI7e5WJnmJLbK`%(@{s)Z63|wlC4ene*XVo6W~Zyx9H3sub5t*l-1eYAmWD(& z8>B!f%nF>m<}a9>@q3CM{MO-Ym69jl{Dqj^_J;AXQ5?mur>Ab~y=A%V2lx@xeKn#XzNcNMlX@1r((!7Cw1%(R{Q-qqMN4#qYk~Ofa0w0vY` zM+|`?%pC&RQ{ourponbcdHG=N{X8Trr32~|v-I=Nvg8b2?;90z%*och4V~#CEUv95;ih7?SgaSaWc~^U^tYZk1YI`( zNfF~G&e3GS_AvQt-!VY5{kPQ{CRMS~k|!j0k^jHp(bgLZUQZI$*IgPv3vDxqrm#puwg z!PBs|^9A5V<^;iu+a`wPIHI()JtL$}nqkg~aS(u*_a1>##ql2Oz?tFqO%}+7#k$Sw zsTU;HUF11qGUyCw|GWP2o7cyS#)H)mGf~96;1iwEX;bA|&A^MB( zwYlSG!hKIt(W0%{$i1S`ka!8tmS5iY(-v+DBc%<W~14GU`H+ijWA=xxj#+v~@i5aMOD=bRj3tYbK+CFlJOld;s8}ZMTJ33TxGNh(B zL*^@Q`^YeI%kt_|+BJ7{?XMKZ+Yb4*@s{4HGJQ@EiHxn5l~0yF`JMd=bt#?Oaa{?r zl#@;hST0^3N6H(m2&|J3?|VjdbY znBu@|QJpx<4;EV8k@S~5blsR`_f-@FXvN0~LUO6o?1ZVu)tfD6-kN3(+SWcJw%dP< zczlRi=m)+0RdcVs)I;%Xj2gvOr_hX5wemnGNSk8Vdq#tTvzhMN)3AiFKdLh!3e?2dX zYpdo>>WkwMm+HR*!U5c|OI?ryH_0v%!wyUXPE@Vkto-pBL^?L{hz>04gOT}`m$<*g zJFq=O+rXdd7>7;P!9b?9A>kDk#h&{uE{2c~#44n(R1S^d5q;$A)Vg+_SjQpWrgTT* zJN+Z*^E>nQ_f{gNi5WB?l@c)PI00Id;8jg8n5*OOWvSt7NuRE-=|2L@eP!a8bM+O5^g)PDM1QOu?1Oi`MmTOa0@Fk zCxkk2)YRQ$4598C3pE=E^5$1sAlxGBbQ%5UnHRuXjG5B$*3(J^{l z?s!}XFWf4Fn<2oy)z=>!6q*FOGH(8qL>ZjwIE6fG_ zg7P86eeJx=XvDxeO<$b9QK;hB+7ZQjG`tBMvhV?*xM3;@%;;~3y`d@HQHv7pGxSMg zoYf4xe}<0nbHz=9<&WuraU3zRMXAE?RQNmL(+h=xMJEE6e5Zj@=N=+)%T(dMSH|sI4 z)Ziy}AI@(WgQLuknFE2+=Yz_Yl4rp!x2{NLtW*oCwffR%^lJz*pJ~m=Bj@qoo3MJp zkj=aG81t)#UuUkohgHJDjg>H=vUi=lRq0Vz7l~KD&6G&Qx{s?-g9uLLrMuPXfCRlI z79e|d0g`2K)zQigvCg~lB0Q$~3QaHVzG8Jbxa|E_(aDRLaR8Q6V>|l*3O42A9xo6^ z476mP8K@Lv8_gm(s-c7b&Q4e$DaMG_z|^|fVLZU`Bn!}H!UPK8&wu9CHy_N1V-=fx zv)G@5B*+Lh9X9l4XPLyDS$ycH`x{#^Tro)!?n z;?u%cNaGBWLl;+dg;whNcLis<#{DGxEJ*?x^Qwi6h9FEaW{^xSLj&HQ=~?xGw&G9# zN+D|5A%JIPPU$y)r_f4qUAIB#vV04FcGAzEOUt;%GfZ~fWXSQnSRTH0E~LEkm@?jm2BS=BB4a-vI*SZ6bl`<6}wVDY_CULRe?%gCi=2-ftLT zl}v2C;KeU0hGL3M>EK|CSi)&Yp9|95126_1ds_+7V*Vc9F8d_;axwpMegJI;%oRdr z_e0NLk!F!kteq(8N}JX>&keBF*pMZ{=;j6fh5kmi^5J|}m?3J|h2z{t1$%x1a&7$A zqs=&cF{`YulvlR)6OPezu$ICgS{y%nMHQaNjrE8H2L)3a7^wX*&1P_+3wB5H`e8cr z_*2)Tj;X=r)IIi_3SPbzRW$9fa)@sY47g3rj(-b|p!$Y?Ks7D?6C0H*9_P-;LoE?5 z6ejcU)>4CRAcMp)i=|BkOxA=zp$9?mU2N7jfQgT)TV3EG1N>KU7gHV>=aXJOZ_TVC z(&wL~U^n+=I)MLs4WBbQ2SKtx|KtCetP{+XrHcfvY{`$>XP z*e}B8s^h@@P0%m>kW$Ny1dtnlRsLB3B=@S&1eJcm|DLuZB|Jq>zbz={>tmWaowBj) zG(U0QA2r`}A$v%-ngbXldrk-Xy(Io0I{cc(0NLh<9d1TtnxMw_B@h2`1k&Y|rOA2) zYoE6K<88kx8CFn_3p1+uaLKcgm-3GTQg7uYXghdXsQhWZ(i+h^2dt9&qYyUmE%~)q zuUBnv>kq(deebHR@A5~e~qmk(m1SQ`G=6X!`m&E8lAucssR+uU$u8xeg z-g|_`Bb(OlIAsxrzAxKJ^Y4N&e=bVY9fqF*%G)a{a6qU_1QOt#IQ$7{U2V|CG z(1HKv>>{#6q-Jg{c!ZKMyHN=ruFax$GcJv5S+ioSM z@zIqo)8eVh8zLT{+yztAF5RbdCf|dLB`&`-tIbw4%tUO~o7;XZuki+fN^kq?lBX1r zalAh*=eQjec#NCv=r1w*`K9On67+;@K5}~xC!z9>35)1`oGon?UE%YX@n;&z5S|AU zs%clq8-u#$sT3RaTP_G$6qrFxkAs@BcXpSr5!$&m*Fj1u)2k;Vwfy5}+5 zh49minmx&m7{DjejKa( zY3m)I2k+vAer?z$iZJfKrlaZ-+NV@Z;u!kzBY_)}K<@Zr(hsj=--zhmXfA%PIT*f* z?u?H`VbaL|jB`H!z>xOI2>3IF#(v9jJU)HEWKz@4-PO+~sg38Q_EJ!S;Euy2GixJa zzzPS%eu2u0>?+Q+rY8hGYPtI^k=OUO?uRB_wK~A^^=Wf}d_fF9$2-OP?-ht6p;s2~ zA1`=F31_*CEc6-h5EFASWIuM$SJ`RV4fr(L0i7Y?QxSgDh?}_S1(;MZ)88yWh6aW~iTF3kGOIAL#9)X+*zv4cRNbSbmmIHjn}ob*DU zl$3?3m2ICRjB&n7aeox*B6%FwTz8bN>==+uwlI;Rc=UMM@B`S|@m2IJ1=`o3arB~M z==0J5^2jpp)<*&@wUz(kS$4klnzHrs#mv;@*;?1Ei5Zh=4#nyDc>DkzXvWpoN#yj7 zMIu+w9Vv0I1)l4pf}EShZ{+^@C@m3^>&lHxtxw=_ts8SliCe!lf_|TFaGKhMZ~Bd1 z36CWNV_vxr$@#|h9Oc(ip*xtl-U^Z{=Jo7&T6}igFdE~r6bQ->9J-Kbdq0Y|rtiAG z>|_k-6wJHz3C|qXO-87qPGp>a8xWPp&5rW<>XqEzxUCSPQbT3c;$gL?$lJp;uVf_K zB-?U$#^HQN+|2$^bR z+n6&9Sh3S9Pt>hUq5&u2jtZpdE1hlU@a`omT=4H z{DE;!nWtSsJ7Ry|Auk=~Gy6)wNsAIse%phe$-m9OYgbL^bsT-EaaVi;Qk&+RHEFsV zzj@!MUwMo38s84+)j>Mx;RZ#v*z-1gi95l+)d6yQp#!_>4xH%U1J7}h!UGA-PHgw` zG1+Gc(m{8rx5~~EBsY}|k@8{+WL|@5_z`Edk!3(1hm`XFx0Q7dr!PG}Vl;}ica2qv zM4}33EqSOrVufpUsv=0t!M3uw4F?|!>(}jD9cQT<9N#!3NYO)LiAP)?so}A9=l`nPJG`;FLzR zUq=KC@~6<3_ha~#UetSwhEgoYC%6zKY;pNuOi5<1TXNMv zaQF}DXC1iR>0^_ZvcLF2maF0hu*b<_9zs=e6Xidj7yt4%qpYYzMh zI^shg!P*ddtF@>G8s725!Q<@2!E;JjoLplyKJDFxROY%@523HN?oY^7G}Ze%enWuz zy1|?s?D9rQBltSh-E&nAaq1Pm-14xUrrAZIe%;@FOwjY4VqDn4i2&CBZyaM4O(a(^ z*(FpUI(0M7L^c}-NLx6T`1-N^N@@%TM88Nn5#Cd_Me)v%2U0~Jd#@sWaqnM^^#KQ# z=5L%t+RSGtj5W9zqkOR^=CZ2tFY( z!heMrymFLQO^n>F#WysnS`10>!Z)&EHO5?ymW0PN&j$O4lta1-7vM$5yh2qd!rl9`Nv^C9J%D;Tq zsqooZsnX{8>ta9-uSwobqpQ8sO}^##v`h4!cDb4iWor(BO8^5oG(SN=F+#DFBq%(%vKxk-6zIiqN#3iM? z=rD!+)^MX+ER4;7o^2qm2E0~zQ^!C=9>GLLT=o1(z^0-Y-tlTooOATI4VUl3>PGKZ zol%|ZS%I@j7SlVXS4DJio713o)5UR?=YdyqG<(9^0R1A|N`H$&lp>%eB&{3lw6LLlb*Qo3Z3j&RdD{tS; ziTo)us={xeL3FC>B47%j7JS1l!O>@>0l`6l*qYt#+%)SFz!vNEZJPWejs8D5@U`_W z$RD8WQU{i_#Yo2^LXe-_azRR{xZl>u5x-6v|8Jk#+|y`tSH_QxZ~->pL!28TGiLc{ ze&vABqcNI&kO4o~3+UT{JF}Q@x8_>}!x;1yHx0bPaJ^(S?``j-rcI^b_1xjg*Ojr1i28F% z`hVc%Y{4W!Ek_sCZ7F{GWT4kQysRyate_mg7;UG{wPS*EoVzKM9hU?L?L?>qH;o z@K`RffdwSb#mdbxs}@hKxanHdk*3c6T05PeJ)AQ99y8EwD+JrM<-W4u!Su2SC!^aJ zVHXuIjN5mIQL<185bhpk7D67aE_{`am+mwCaeMielSGlQd_1`Zb>!@4tyk-&!1nF0 zmdnV61iRffEfM62O;ULRMQeH4Iz3X`3U6k7m+1}zhUN}DLs5=JK0d@j0^B{AMGF(Y zk;FE_uYa?6h%dBwb zcdBWAWvzS~=aFbds1ZHVj~k}j41|BH2f0!(3$}B%i=eY8fMP{Sp)Ko6if1B&?oztj zilFoCl%GCE@cRRHG7wU`@sh&UXXTh>QufYaQ{!mNOrdRHTy&KtV?6?uAeUJ`)tV8A zP?}c?cc9G9^X_%#jcgKPRNZDDk#|1*oV_#Kc^1>eB7xjWXO#C&x?bQ8`+b{G2uOM- zM!h8>3oSKh;8+ebx!8iLfz>mmpz&p%zdqm`;L(@4#;_p|?)7?^Z_NEd;lp0^+eZTs z!ppxLTr$0C?OvfOMUvD*>gY)IRb8uD_SQ%ffj=HC8)zAc4Ws=w^*q8KzjaWD6R)q+ zpq^A`!{V4u-+bqxp9jSCwW3~Tz0-&MS=~DsD-OPES#U20Q=9Vev5MQD^scC*JMz=) z`PAO(Wim=51YhW;#FX*K5JsFga+p)Lv)pPt0E1~VFG)MBvsNj~TP(EQM~d0lczyTq zsi$JikY`~*U%fEON=k?q1KbQBYTO6%9W*81iq$FF!vV)4~Dt-LNPSX_P#CT70Cvj#`AP95$q0`28*lC zIhre5YI{&XZR@~VM=qNbt^o4fxj(VP0R-+z^Zqz0a-&zVaZDjamKi&+gX!KV$1WaI z87(g37ghlFWNT&}n{K%C)8?+}opBw0BzCR2+CrHWhsu5@U_&DZS;dc%ek^R0N?hp~ z9JsJ_P>D=HNvqdrU7t0lmzA86ueU+=-~KMf3H%&aSD*#_;bsjGBlm(XFEQFX@0=lo z1aBg_TVW~UwMoib^a@fN_atr&D#l`Ci8w$KJ?1$OBb+^ayX7~qHe-~qME+1vr9`iVoh_?EzO?al2RDkkgn54W+XcC$gnN_5yFA)xs<6t|0XLp`r%Z*c;M>a}qrtb9Hwf5C}@yC(zRqd~*J;?1g)C@fo| zlccfvN_zAKaP$2tlp@#fbTLI~I0(j_+Cv^qWimki1=Q;iNRPyrbKe1hSpx5;&ECxX zVY6qx4)C~%91ymT=P9@8;ai|c!rp8(*z_^zf-^7Bq1KV+4 z570_evd7we%g1rR#|nONZUsNd&FGx#wddTI%2+V3n$4(7yXNuoT{m~m{p&-S!NTia zVH1+SP%EpiKF4KI>f}b)rOpYvYU5lEI#mkmbi;~Xy@17Ww3PU^+dvL(R}Z;$#OL>C z`NlKjg|DLMkCq$N?8sN6qyGupMFQgeaQJfoQeMC<&%IX>7p8RvwQaEE)xbQ=VH?;x z!<$Ik+w5-!pr`dRyVT~mP(2HuCD~B!>qr<#RqYU>A})Zs-gU!1U}RL{)I5JbzbP#% zbcp}5R&MhdIOs+^s1IhpOjs3Ain|Cb#B(q^yshF3U72e(N?P{e^{oFAM&VgLyrBuJ zWfOEa57|V4q+GOr*M%K?QQa5{I^k^zhE&zCesVC#Nf4Re^y-?2)+w7p4uUsKCFevY zp!OLgD*-12tvzq1Ku)^W~sF;jqw~{a##|mcORs6)smRx7|iii%397k zt9}!#Nb%dW>%jV+CfERKFRm~X=ZK;StXufH>`rPs^*H7uiiH!hnheg;HxWD#g|gLO z^)#SiF&Hy76dCw8x~4xqGb%;-7bNCc| z8&iQtLr$yombxy6wG#?1*Z4AvT$Mx+!uyy$-_O&}vMYMcT>NJ)qJB?IfY$K@6jaL9 z!abTipcBwjbMTh%cOwI_&V>t`QAu30Xs<8+D$U;wI7Wgl|BZib`5^6goTcDsMQi&i zm8EaaVL$&_dBa1Hvf*y9Kg<_1yEPCE=U-#GCDEFQPV@Td zX+-B~_HVMFt`*D#SLwNXcBSAMNI%7`Ps9>|BIfFIEkT-& z`4c=3Y++biOu-gs;?;k{5_3|-o4Rw4n&h-pkOtTp-KZ`|?NvM}ub!@}P=6(J(`Hfi zQNZ}c76U^@JHqi&A#Y~G3Ur#rG}+vl6H{^;Hd#oJ!Rt}5YRbGKVoLClG|I0|%37Wr zCUS&5v}w5!zMF5pNjD#Xsy=`WbaJLXZK+!A^#JB^Hvg;MunC)BJST{A;+N{X>Mn~& z(EU12d&#e&>BJKWG{)EO@yaRlJS)W>NJ>a)HuJ0#{XOoY+Jqwm*=|-=;R!bzR>A)L1piv$m+|+7@)K{o{NWC&&+=(&J9s7wn66+F?8beZZ(%TK#YnZYs*v7I5zhLk0w}o}qb*M8z-@a8Y1?@KRQjYlrVZI#J)R{vXx&a-Lzu)g7dPLwncVpDUA zD#20nM-o9;d8g98`2kPsqrim$zyhcFBX3$AABF_RNL`aH&W)ng;9)h(IwJN1vc0XbF}T$b)Y!PwsN$_@WW z;+OcfdHh#rpG2<}cZ%^o(DjhC;wRIih%`Jjt<$q!JtT?FA!7Vi&_cY7&nf|_g#DUX zmd=UdaU)L$;~6@>Kpjd#cRFwuR<(^?6`%I^mj+0Y|K;-mKQm+wk1m1ahD!6ov&6ye zec5@v;W`|?yWU7^$?N`4ZS60EN}J%1{p(mC|9$D4Y(z5L@&as*K4vuRFmnE8drYgr z6IcFp|Nh)IPqKqZ>mR3`2Tt4E`ZyA3A?55>W0z`vUAMgddz)5f-A>yTOj;%>19dzy z=fe{AtCi2!rs=&vP&ep^-0+WxY@d?PSLQymqv3i;G}1MHNi?rR6lA=-RYi<#cP;Dq z+U&5^#|D~r2&*3-_flBIzbssQMyx=%wi1zN=FFSj##=C7Y)UK1I#3Ix;sf5*iuZ!G z5fjCibeNOWeKeR7U2tDj71KJ1+tOZF&H;SU%(>YMv8tu{oEm+pX3y8~Mpgu`!Yprx zh$XmG%l#1t-}xx>eSXkUHrC?Z8}ZhskJjO8>xt(QOnsDfTu$7AAtkG21w@}AVW`x0 z!T(|Jy@Q(S!gX;K75xxUQ9wdb`94sQCM5JkMMOnFMClM9GzlH)O++a|Kt-j4ic+M6 z&}-;Hfe?_AP(zUf2t5q~2{+$4b7t<$y}!Bhn>l};nf1rc%%04iwby>vv)=c4pT{Dm z>6Ip$%D=F3<+=#9ToLq`Y^%G^h0}ZEgwbI7Pojemw@aYoy9@nGL;F9zv)Zd~@EI}6 zi4Z`V9qV@*$oENvpDp+Vj%HbVhCHCQ{z8%TMz(q7DbhV4HYZ!3liL!ThG?Rl^@DY|Dzjw|*sU zQGB<}LOG?X)`F`o)xEu37!|TSF)wcZ0%FVFH`78AyAuh~-t`hhtFG7>9~&b>|N2^H z=XvF$5c&6ST*b5bPh|QT<1UsHX7+4whF;v$+0-Gob;nbR%8}_V%@|pXLi5sBVWAza zlf%B>gX@~!ckXNJt+(^Q=6KaIJ0!^?aU)YDV~rFUmu>&GJu9;}O$8$jnl7(Z_9J&@Wh2oc<=Z;4-&i?)I9$T9}Vq`odGQZ}YW3{MLA+qs6ka1@aayLW`>}1M_ z>8`LvbS=hggcIiW)N0#;via-qlp)QR8!IiE2=BQ=lEFV%$WOD{bH_r6{AyE#(8D!H zaEXvz%2%#Pzi+@+ek=eWAcLWuo^KQHx>p}te@+BkRb!*O`Wo)R&ozalh6Kw;iZJVs ztVati57Q~`*K?EkirRxS>~hx@75LAI3??pL+A%l!WgC(NiH}>MVDQ2sBQ3@o7rj_$ zOukK4l<%df7lK=mW`bdGI3FLVXMi7JK8FjJ^t=_da_JLIabDEC+uz4nCxNomlVpAB zm2-qKL+TukB7UYxcV??Tp$itB}4x3g$!&!sVq%^mw9u zeshesyO7b}vLnA6jp88fmTY8rx3gPrsBB=O#Q1yU4u5j{!p>Wqy_LH(yOYTE=Obu~ z7LSFt{RMkx9v;uNNufFW8F}@V*lVu7IIMa~`6Klos18*}>i1{+a>-BJW4h)H`Lsuk zS@KQ}b`wD8DGUt`)>C-_^Lf8!TIk~hdg%$yH^a1gJ$RM%(fTQrilEF5(fWMRT-^SK2GpzOWCl+4J#!f-j{6OL%`2AIuwxTtd!sq6_EW%p zxD!K0w2*4p6o`^%qk!Z$f?H1mouv2gDh_z9d}wgi!BMXkhDScL&EaqEvFa_Wo35?T z#j{1iYAz^p79AxJ0$+@OLo0>yLh~YTmF0ZX4X2m5%C8;n7^RP>DmUKSaUUqoePggM zkXMCSl?l*!LnqMYSkifQ0!eCvHk&sCKRb)TSJ+l1NK&Vr`gL@otYol#U7nFbP-u69 zLFh4wdmARqrg+{dS(}r*Bz<&&TC9p*-SFP*!*Y#em7&-!ajC(qB^#~)OsJCY57+lq z2@?C0Gsie%8%v#V;)-kd^2=^IjNFy~r@>B8zqB#2KD$SHw>Q~O4_XARQIM-G!_#YS zxA4q7D|fV>sZfUK!8*gnhc|XydcwTzw!fe+ha6hi2{^aGf4m9^{nfIniz41z-;$U3 z70|!H;gz)5gsOBOoxXMOwQglkDcmaMXe#|~f*zy~rhLqQwy&Ax17Em?j{6vTD-akJ zk)rv%)xjV5(0ju*Bo%#S@BETV3U^9HDBEy4FfZ}sMxm^QRO9>`ju`Gcma+0edHKt; z^WjLdA6RaAdF}-@D+b@Cl)Y%3;&v`lIG=Q1_O;duN>sRybqQ5D5iTKBN$nPa{;tsX zeC*#{5vA1T9e~hRj2iq3h6x^zxQT2CK@{%YPzZM!5femrG5n@t*vqGP9(4ErQJ74W z+EI+OcYb~%INxQZVbq+Q+Ua;ywzK4YtA>F-1>|XNL?FAvJk~tRw7}Vpvg95(}R4`xGrx8c0xEd18n7FEq=QbWyS=p;p*q$H3 zT^te{QomjlplMOUp?-;*szJMy5nZz<11M*tIzoU_wHDsB=BUW~Ut1Fn@92ngi$rsG zn|3!lmEK4=MZZwFaqP7GkwaiU;33iW!4a0kRr*q8qrjCX3Elo&An7Q-K{ z`TKSFvvPT_XXl`d$~5`r*<*?p1lPQXiQ`sB-pm)iyZI9+At|hPKFqNCvZbEJ9kX{& zt|#b8g6?j{Q7wF)xSc+pI4leVro>;pQF8U4#}~^^2+Sw!PtIaeFr8^#0P=!2nU)C` zlkzLRdi(KPC;z)H*?5gJrhGpfF|OSR7pvw!zJ$5BI^Vq}%9YX+B}dAOH1qxyKC$_k zcw|8B=S^W01rhkBso`Rn$3JPRzN^L2)i?WP_Ay33OE7xiOH?r+SbD!cH~qb-7=Iwy zG|Px!DoxHF$Z2*mM{Z>iem`_yLRi{dzOwo-d~i@*_EPlCzXiGkTN8K$Vb3E4@qbi~ zyz+Nt2jpyP1k2{hW+&nou&?b`3O3azMO zNixu`ANUi2t8y5faD@-#XZZBKz}SxqFR`n_~?C6xcGU@cm|}cxDRq zTX_gcn&a!m|9>C&&$^EwBfWl0Kh=*`lqxau==VRuM zqdJ?rzN3DKknWtK8`^}eH;_BLn$~K$4qz=s(;luK6_6~qcy5d%5iUG- z_m#Ma{&uf67WNwv=n*6I^8)$&0p_3D?t5ObF1!mL^nZyo@aH>-wI>R8-$4&etG!K# z@TD@N4u)b=2ehsUb|+C;T2Y-miSC)^vEQrh=AxG0wl-Pin|K)nwZljzw7^;v^kx(kAZ9!=7kmOp<4E1Q#7F4 z163@Hw|dHc-iNUAo&g`->se{X^cqBnAu>}P3cDWJq-ROD7V_&hVc~D0w)2B;DBz#!=a^5$=lN9l@Q16~=-Mp(Dwq=+(0Kz-sv^2aa#6B=)H`y3#XMYCVjs+DlaxgN)kmv%D-fJc44Uro@U zLot0*%IX#<>0MxX?tDc-?ba zt;poRxB#|!vdpENg-wffiI8u~o|pyNiqfUvQ(6Rw=2gibvNvSe0(qFc++76=Maj;L z7AWp=xx@SVm@W8Puy%b;zwb4^26A15BP3yR5ptt;9c zjcdPOGh<54da^CE8RFxi@CzKUHDmnyuWA7+-lXq_Z%ocrit5K>L9=0yfC0;ec&u_7%`ajTBP`D$SdjD7m=7S zgowx^2<^o{la&B$x_*meMqKh!eSsDnMeb}4>S`%C+1@G}HZDq2m7IDhKdNtY$EE_o zDk4|Z&g?er;eux3Qj20%z5v6l?n2{ct-<$g3olu~&dSvb3zTy`p;}%D`uL%12MWAR z_UP9J+P$|5$u#9~FC)fgda9y`Ik2z+`rjxupwax9djcgs+ zSgI;@?xoYT_Sa2-vi=&h7%30d1#Igp_&5v%Ww|{{i4@+e zzKvET`t-PY_!vme*Rvipi=cb&hrDI`m&@V43Jr>sU>Bc-i%vsJ+hALIecugxgYf=f zRJ1w8yX%YQ?bJ6!ZS%EuU`KIxzQ*rsZmy1HjQQa|?d~Chtzq#I6GtF#D6?siaR-Z6 zv)bUnyoKZUy)Tn#(P-^gcMoOlX5x0OY`;rA-yL21_$N$Vq4m=kK1K5fy(|LSlnbBi zEG2&{8C0NKgqKB9EdNx9R@=SP(ITCN?u|E;41Al>tYdjJV`{`AuyKCz11_y1Iv&@jXF?^I2^@fR$j`D-~C4&#Co^6s`;rfH~KRM0|> z=;yGXDugefj_0k35>Yt*(1=rvCTiy~Ww_lyipso1h5poQ-HKr=&Hgxc%;b>VANW3) z-^<$nqp6bph?p_MLA(0dFqhH7d;s$}*3m5{5wfD}IbA6e&qwEo<@=>aXm((pgltF{4=VWC-shN1ymW0Stdvj`~wq@Y{ zZ2WJkPyV#kHc2V1tn$$5;hTqCyC2PQcgmDHm!4LM0DN5>KOr(GPW5uab2rs^-b2C_ zW!*AS8u^uZM{bs)4wWrgzo1Fk<+4{@6;~T6<$NF<%Ucl{NiWHgU}I$_v}d-Gc>p0b zSH9fW2dRqOBeA5|MZkEmo3CFBdU({SJL}f?@8VQI7ThG+p{?)TmFL7GZ-J78hVFPJ zc%Aq=iiJmUu-B!+>J9eSyraUTM_=*i4F;chej>fId72i}{O0gc)hw@Y-4@?}0<{78 z$HkNfwBG?xYB=9~jf?NU%~fv32j4w?b3%3Co>*An8CMlXMMMA8ZeQyRqaPG68FjhT zPvCG8Eo6?uYh9%h1z z(i1X8Ms)%*H$za?Uy*rd4Co0ID@3V4I@c| z$M2WwXJ4}EmEx%I20BJjsai?zb;XVuUhwU2zV35z|4dg`^xYWTu7bvbjbn7nVijWV z%-z}d!S59@1zdv9X#pF3UB$qpTQ(Q0wYHscui*3L&D%d}e+o#0boMtNOLjO> z|Jk;9h@WlU_#88l{l{EX?j1*c`Z<+a8pNZg!?(8jy`az&97H&?ccL+&-1h83oriwRUOtV8n7Ve1Z^ z25AnqM}()|#4pV@@EN$vcIvsSP?EBk+?EocW#{!q!~nl7n8NmIR1pdOW%lbS=w+Cc zb@Q{wr#c^KcZC1RunOZ+K;;#>G;gV*hUzq+@w#76*T07>v2B{m`+d~g@ zu9Kbo1MLM-*JAAt4@jeDZ#wb|6ba48O87d!o+sNUx>AEAsGlY+m#Dk(Q3D#3OUZxG zhDsiHu5Tf%H(j|E4!d9uHLrCu$yGalcXQb|Ds&-lZ@tNTkL06%f_#=qN^88~E{<+D z*6z%Ou!r$=SQYnpQH)%dP-}P8fZpKQgK32CbX1H1`w4N|UJB6BAMLqw!mDrX4}##s zPfu6>OLu1~d)zGhsno<&XDj#E@RvxEa;?C6uP2|3yY|8CQ;&4*Kf3iLoO(M@=8wbs zvVuY)`5yQvtm_HOqw>Kn>nm~UG$QYus~-;A>-R?VXI*eode_GEQjd{`>f5G$bG6RmRCn>L`d^>>TGnNF7F6&)=g0{NojnOg7SB2hc@XN`c`mYqxAby$ zyHm^8ET=yz1E#n_0YKeUr^${5;supGC1g$VMCtX5@`$gHa~s=hS(g(pZ=YM&yHmRL zs7HHW`#*aN4_$xd;9iQz+dPixn0&)u4|v#vn**1Q#dI96F~AOrblz>YFnpCz-^whK z@Hy#1K5jb?S$%!xW7Wb{t~}~tZ-*?Lh0~R69~LzTfURoprx4v6r)&5VeGO94Exwe~~z-zbPd4 znn{+qipEUtT0JZxha(T-_=`t9eryQw*59fgT!E{9nW5HT#r(357s$qg;*fKNmTe++ zN<5IZp~WKoP+`b|rqW5ZkwnX>(StVmspB#g`aTYi(fz~3O|wRw><_x2Lqpcv-B-6R zl@Ca+!Z^V-k%v+~CT4^=9#QP1&nk1ETRV)GJ^NX?Nk|_E!)SfpKSJAuDUi~nC=CnS zHR$P$z1Gqgc>(ufZ!~W}B=606;LYnHtq5_|gsF#0e8@c6RwI>9W$m7*c8*ULy1<(Z zpU5YebdEoQbSKx%gj#n#6XmO0R22~5p1VNF~nZSAX^=V74^G=RSmIyClms9E5c zRJ%I2!%zk~s>POqZUOcKjM9s71=yji5hqaLm!kHWzSxSJ2e!)TEu;22BJvX$)yDH> zx9v32D7-PA9cPTo`_zJS{gbvGR^kbddPe_Rh+ZuD6=yBPT_zi|Eq*8LP>R-_j`f9=rPz_#usq48Ka;sP)@w{)Nuz>Pkb%c)$OnLaOmyt% zTs1D1*%7X<`d70dv;=J3*PeqZGw7IaRCtzDFDh<_sCg>UZcGyj6%4E?c%AnxHWc%E zQ%EOQ(c_EBEY{t{w(g7&E7ha9C#EcF_QqK9QtayY$%t;CAHnQG(2`pbhHyXYq+DB=oh-qMA;L-5v3t);7lkEKHmBx7YhdcH)tX4dQ)awsI`9a5jm} z^tM5O?lcwfCrD_JthPURcXMk>pSnKGbX(c@)iSgq$9VMiX5si)KAIxAtbpZP#*I;vO`SIbS^2GWOh-i$*=4AKCb* zl92X~)C5oU&oGB$Ih|qjPn+Ooyf#gKK5qSsae?z-wL>WV67hS=$IdZ@Z2VLeq{`j3 z@1nd*R*nF7y z|17lRWVKDYJafb_SWec~wF=q9wwr&bUCbY@Z~6^j29<@-cTxCxNh_j+6?J?KKrC=6)8r9`nvf%%;N!MQ!U*H(4JU=oVzm? zyeYkR-|ed32k)v}^DWv?w_@yv$@0SnrKZ~|*o44EaYz0-o3%{S`oH()b+)4;WxZKp z-+f5QQb7k>0t0hnz}m$x*{1|Mnr2J(xk*B`eT(u1OV#Ghg)W2bnr&FXP-E0iMsT~Q zO)F~r+|;7L7w%T`TtD>i-GgtZ2}ev{3;5o? z{Z>HGFyy=&ka-t&da{iLrwd;4z)_c6KX}63vCA>S@jn#d(bFexc zS7-Z_>kJ;%rS<$&7*ER;J-wD|dT)PRoHh_ShYW2=b8I+w?EKEjYliQxNgO-+O-}Ev z*fQ|&sV^}jH*X)IsDb^-hGro0x3@xme!&dUu+<30IJ{h=btBs!ySvJaFxN>q(xoJz zEBude8t4k>%&S`f50Qt7e8hlkY!2coU|d^s#u0OT5v2hzO#IFf1gyBXe+d_n;S)%_ z*CST~+L@V*-)S{ONG)BzbN$VS@u-RxzU)MWTlaNNLRk;!0OU%s@p#3RREy=W>mBO3 zQlJwGoC)u63!e|7cMmBGY<6KT^Fjf4jP41OBDI}VK&~o@K@6&Hrk*4Q

>tIOV}3 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 BK$HLg literal 708448 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%0AuR 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

w%_)j4+wt0O?jtUMJ%GO@yGtGcmUq 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

a1ml2WE4%I=GZ0navv`F8;P{$;{R?YrB6=3Yf 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≦)WCA8| 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%0AJc{!WVgJW$_KuX392&IjJ( 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 H$vxqa{9X-jar0qbDVHH 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 KYE)jfkNkf`exf)4 diff --git a/docs/images/threaddataloader.png b/docs/images/threaddataloader.png new file mode 100644 index 0000000000000000000000000000000000000000..565df8d0d4c2c48d44ff7589a71245d8e47f3ac4 GIT binary patch literal 411731 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

wMLj&gn%qw9Au1v`Ih`rVURduETH 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 z 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 literal 0 HcmV?d00001 diff --git a/docs/source/highlights.md b/docs/source/highlights.md index 141c0846d1..b84e93ff2d 100644 --- a/docs/source/highlights.md +++ b/docs/source/highlights.md @@ -16,7 +16,7 @@ The overall architecture and modules are shown in the following figure: The rest of this page provides more details for each module. * [Data I/O, processing and augmentation](#medical-image-data-i-o-processing-and-augmentation) -* [Datasets](#datasets) +* [Datasets and DataLoader](#datasets-and-dataloader) * [Loss functions](#losses) * [Optimizers](#optimizers) * [Network architectures](#network-architectures) @@ -25,7 +25,7 @@ The rest of this page provides more details for each module. * [Result writing](#result-writing) * [Workflows](#workflows) * [Research](#research) -* [GPU acceleration](#gpu-acceleration) +* [Performance optimization and GPU acceleration](#performance-optimization-and-gpu-acceleration) * [Applications](#applications) ## Medical image data I/O, processing and augmentation @@ -56,8 +56,15 @@ transformations. These currently include, for example: [2D transforms tutorial](https://github.com/Project-MONAI/tutorials/blob/master/modules/transforms_demo_2d.ipynb) shows the detailed usage of several MONAI medical image specific transforms. ![2d transform examples](../images/medical_transforms.png) -### 3. Fused spatial transforms and GPU acceleration -As medical image volumes are usually large (in multi-dimensional arrays), pre-processing performance affects the overall pipeline speed. MONAI provides affine transforms to execute fused spatial operations, supports GPU acceleration via native PyTorch for high performance. + +### 3. Transforms support both NumPy array and PyTorch Tensor (CPU or GPU accelerated) +From MONAI v0.7 we introduced PyTorch `Tensor` based computation in transforms, many transforms already support both `numpy array` and `Tensor` data. + +To accelerate the transforms, a common approach is to leverage GPU parallel-computation. Users can first convert input data into GPU Tensor by `ToTensor` or `EnsureType` transform, then the following transforms can execute on GPU based on PyTorch `Tensor` APIs. +GPU transform tutorial is available at [Spleen fast training tutorial](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_training_tutorial.ipynb). + +### 4. Fused spatial transforms +As medical image volumes are usually large (in multi-dimensional arrays), pre-processing performance affects the overall pipeline speed. MONAI provides affine transforms to execute fused spatial operations. For example: ```py @@ -67,20 +74,21 @@ affine = Affine( scale_params=(1.2, 1.2), translate_params=(200, 40), padding_mode='zeros', - device=torch.device('cuda:0') ) # convert the image using bilinear interpolation new_img = affine(image, spatial_size=(300, 400), mode='bilinear') ``` Experiments and test results are available at [Fused transforms test](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/transform_speed.ipynb). -Currently, all the geometric image transforms (Spacing, Zoom, Rotate, Resize, etc.) are designed based on the PyTorch native interfaces. [Geometric transforms tutorial](https://github.com/Project-MONAI/tutorials/blob/master/modules/3d_image_transforms.ipynb) indicates the usage of affine transforms with 3D medical images. +Currently, all the geometric image transforms (Spacing, Zoom, Rotate, Resize, etc.) are designed based on the PyTorch native interfaces. So all of them support GPU acceleration via `GPU Tensor` operations for high performance. + +[Geometric transforms tutorial](https://github.com/Project-MONAI/tutorials/blob/master/modules/3d_image_transforms.ipynb) indicates the usage of affine transforms with 3D medical images. ![3d transform examples](../images/affine.png) -### 4. Randomly crop out batch images based on positive/negative ratio +### 5. Randomly crop out batch images based on positive/negative ratio Medical image data volume may be too large to fit into GPU memory. A widely-used approach is to randomly draw small size data samples during training and run a “sliding window” routine for inference. MONAI currently provides general random sampling strategies including class-balanced fixed ratio sampling which may help stabilize the patch-based training process. A typical example is in [Spleen 3D segmentation tutorial](https://github.com/Project-MONAI/tutorials/blob/master/3d_segmentation/spleen_segmentation_3d.ipynb), which achieves the class-balanced sampling with `RandCropByPosNegLabel` transform. -### 5. Deterministic training for reproducibility +### 6. Deterministic training for reproducibility Deterministic training support is necessary and important for deep learning research, especially in the medical field. Users can easily set the random seed to all the random transforms in MONAI locally and will not affect other non-deterministic modules in the user's program. For example: @@ -99,16 +107,16 @@ Users can also enable/disable deterministic at the beginning of training program monai.utils.set_determinism(seed=0, additional_settings=None) ``` -### 6. Multiple transform chains +### 7. Multiple transform chains To apply different transforms on the same data and concatenate the results, MONAI provides `CopyItems` transform to make copies of specified items in the data dictionary and `ConcatItems` transform to combine specified items on the expected dimension, and also provides `DeleteItems` transform to delete unnecessary items to save memory. Typical usage is to scale the intensity of the same image into different ranges and concatenate the results together. ![multiple transform chains](../images/multi_transform_chains.png) -### 7. Debug transforms with DataStats +### 8. Debug transforms with DataStats When transforms are combined with the "compose" function, it's not easy to track the output of a specific transform. To help debug errors in the composed transforms, MONAI provides utility transforms such as `DataStats` to print out intermediate data properties such as `data shape`, `value range`, `data value`, `Additional information`, etc. It's a self-contained transform and can be integrated into any transform chain. -### 8. Post-processing transforms for model output +### 9. Post-processing transforms for model output MONAI also provides post-processing transforms for handling the model outputs. Currently, the transforms include: - Adding an activation layer (Sigmoid, Softmax, etc.). - Converting to discrete values (Argmax, One-Hot, Threshold value, etc), as below figure (b). @@ -119,12 +127,19 @@ MONAI also provides post-processing transforms for handling the model outputs. C After decollating the batch data of model output and applying the post-processing transforms, it's easier to compute metrics, save model output into files or visualize data in the TensorBoard. [Postprocessing transforms tutorial](https://github.com/Project-MONAI/tutorials/blob/master/modules/postprocessing_transforms.ipynb) shows an example with several main transforms for post-processing. ![post-processing transforms](../images/postprocessing_transforms.png) -### 9. Integrate third-party transforms +### 10. Integrate third-party transforms The design of MONAI transforms emphasis code readability and usability. It works for array data or dictionary-based data. MONAI also provides `Adaptor` tools to accommodate different data format for 3rd party transforms. To convert the data shapes or types, utility transforms such as `ToTensor`, `ToNumpy`, `SqueezeDim` are also provided. So it's easy to enhance the transform chain by seamlessly integrating transforms from external packages, including: `ITK`, `BatchGenerator`, `TorchIO` and `Rising`. For more details, please check out the tutorial: [integrate 3rd party transforms into MONAI program](https://github.com/Project-MONAI/tutorials/blob/master/modules/integrate_3rd_party_transforms.ipynb). -### 10. IO factory for medical image formats +In digital pathology training, due to the immense burden of loading images, the CPU is preoccupied by loading images and cannot catch up with preparing the data. This causes the pipeline to become IO bound and results in under-utilization of GPU. To overcome this bottleneck, [cuCIM](https://github.com/rapidsai/cucim) has implemented an optimized version of several common transforms that we are using in digital pathology pipeline. These transforms are natively being run on GPU and act on CuPy arrays. MONAI provides `CuCIM` and `RandCuCIM` adapters to integrate the `cuCIM` library. For instance: +```py +RandCuCIM(name="color_jitter", brightness=64.0 / 255.0, contrast=0.75, saturation=0.25, hue=0.04) +CuCIM(name="scale_intensity_range", a_min=0.0, a_max=255.0, b_min=-1.0, b_max=1.0) +``` +It has shown a significant speed up in pathology training metastasis detection model. + +### 11. IO factory for medical image formats Many popular image formats exist in the medical domain, and they are quite different with rich metadata information. To easily handle different medical image formats in the same pipeline, [MONAI provides `LoadImage` transform](https://github.com/Project-MONAI/tutorials/blob/master/modules/load_medical_images.ipynb), which can automatically choose image readers based on the supported suffixes and in the following priority order: - User-specified reader at runtime when calling this loader. - Registered readers from the latest to the first in the list. @@ -134,13 +149,13 @@ The `ImageReader` API is quite straightforward, users can easily extend it for t With these pre-defined image readers, MONAI can load images in formats: `NIfTI`, `DICOM`, `PNG`, `JPG`, `BMP`, `NPY/NPZ`, etc. -### 11. Save transform data into NIfTI or PNG files +### 12. Save transform data into NIfTI or PNG files To convert images into files or debug the transform chain, MONAI provides `SaveImage` transform. Users can inject this transform into the transform chain to save the results. -### 12. Automatically ensure `channel-first` data shape +### 13. Automatically ensure `channel-first` data shape Medical images have different shape formats. They can be `channel-last`, `channel-first` or even `no-channel`. We may, for example, want to load several `no-channel` images and stack them as `channel-first` data. To improve the user experience, MONAI provided an `EnsureChannelFirst` transform to automatically detect data shape according to the meta information and convert it to the `channel-first` format consistently. -### 13. Invert spatial transforms and test-time augmentations +### 14. Invert spatial transforms and test-time augmentations It is often desirable to invert the previously applied spatial transforms (resize, flip, rotate, zoom, crop, pad, etc.) within the deep learning workflows, for example, to resume to the original imaging space after processing the image data in a normalized data space. Many spatial transforms are enhanced with an `inverse` operation since in v0.5. The [model inference tutorial](https://github.com/Project-MONAI/tutorials/blob/master/3d_segmentation/torch/unet_inference_dict.py) shows a basic example. If the pipeline includes random transformations, users may want to observe the effect that these transformations have on the output. The typical approach is that we pass the same input through the transforms multiple times with different random realizations. Then use the inverse transforms to move all the results to a common space, and calculate the metrics. MONAI provided `TestTimeAugmentation` for this feature, which by default will calculate the `mode`, `mean`, `standard deviation` and `volume variation coefficient`. @@ -153,7 +168,7 @@ If the pipeline includes random transformations, users may want to observe the e (2) The TTA results of `mode`, `mean` and `standard deviation`: ![test time augmentation](../images/tta.png) -## Datasets +## Datasets and DataLoader ### 1. Cache IO and transforms data to accelerate training Users often need to train the model with many (potentially thousands of) epochs over the data to achieve the desired model quality. A native PyTorch implementation may repeatedly load data and run the same preprocessing steps for every epoch during training, which can be time-consuming and unnecessary, especially when the medical image volumes are large. @@ -221,6 +236,11 @@ The `partition_dataset` utility in MONAI can perform different types of partitio CSV tables are often used in additional to image data to incorporate adjunct information, such as patient demographics, lab results, image acquisition parameters and other non-image data, MONAI provides `CSVDataset` to load CSV files and `CSVIterableDataset` to load large CSV files with scalable data access. In addition to the regular preprocessing transform while loading, it also supports multiple CSV files loading, joining tables, rows and columns selection and grouping. [CSVDatasets tutorial](https://github.com/Project-MONAI/tutorials/blob/master/modules/csv_datasets.ipynb) shows detailed usage examples. +### 9. `ThreadDataLoader` vs. `DataLoader` +If the transforms are light-weighted, especially when we cache all the data in RAM, the multiprocessing of PyTorch `DataLoader` may cause unnecessary IPC time and cause the drop of GPU utilization after every epoch. MONAI provides `ThreadDataLoader` which executes the transforms in a separate thread: +![threaddataloader](../images/threaddataloader.png) +a `ThreadDataLoader` example is available at [Spleen fast training tutorial](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_training_tutorial.ipynb). + ## Losses There are domain-specific loss functions in the medical imaging research which are not typically used in generic computer vision tasks. As an important module of MONAI, these loss functions are implemented in PyTorch, such as `DiceLoss`, `GeneralizedDiceLoss`, `MaskedDiceLoss`, `TverskyLoss`, `FocalLoss`, `DiceCELoss`, and `DiceFocalLoss`, etc. @@ -249,7 +269,7 @@ add_module('conv1', conv_type(in_channels, out_channels, kernel_size=1, bias=Fal ``` ### 2. Implementation of generic 2D/3D networks -And there are several 1D/2D/3D-compatible implementations of intermediate blocks and generic networks, such as UNet, DynUNet, DenseNet, GAN, AHNet, VNet, SENet(and SEResNet, SEResNeXt), SegResNet, EfficientNet, Attention-based networks. All the networks can support PyTorch serialization pipeline based on `torch.jit.script`. +And there are several 1D/2D/3D-compatible implementations of intermediate blocks and generic networks, such as UNet, DynUNet, DenseNet, GAN, AHNet, VNet, SENet(and SEResNet, SEResNeXt), SegResNet, EfficientNet, Attention-based transformer networks. All the networks can support PyTorch serialization pipeline based on `torch.jit.script`. ### 3. Network adapter to finetune final layers Instead of training from scratch, we often leverage the existing models, and finetune the final layers of a network for new learning tasks. MONAI provides a `NetAdapter` to easily replace the last layer of a model by a convolutional layer or a fully-connected layer. A typical usage example is to adapt [Torchvision models trained with ImageNet](https://pytorch.org/vision/stable/models.html) for other learning tasks. @@ -366,10 +386,15 @@ G. Wang, X. Liu, C. Li, Z. Xu, J. Ruan, H. Zhu, T. Meng, K. Li, N. Huang, S. Zha Wentao Zhu, Can Zhao, Wenqi Li, Holger Roth, Ziyue Xu, and Daguang Xu (2020) "LAMP: Large Deep Nets with Automated Model Parallelism for Image Segmentation." MICCAI 2020 (Early Accept, paper link: https://arxiv.org/abs/2006.12575) ![LAMP UNet](../images/unet-pipe.png) -## GPU acceleration +## Performance optimization and GPU acceleration +Typically, model training is a time-consuming step during deep learning development, especially in medical imaging applications. Volumetric medical images are usually large (as multi-dimensional arrays) and the model training process can be complex. Even with powerful hardware (e.g. CPU/GPU with large RAM), it is not easy to fully leverage them to achieve high performance. MONAI provides a [fast training guide](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_model_training_guide.md) to achieve the best performance. + NVIDIA GPUs have been widely applied in many areas of deep learning training and evaluation, and the CUDA parallel computation shows obvious acceleration when comparing to traditional computation methods. To fully leverage GPU features, many popular mechanisms raised, like automatic mixed precision (AMP), distributed data parallel, etc. MONAI can support these features and provides rich examples. -### 1. Auto mixed precision(AMP) +### 1. Profiling the pipelines +First of all, MONAI provides several methods based on `DLProf`, `Nsight`, `NVTX` and `NVML` for users to analyze their programs to identify the performance bottleneck. The analyses include operation-based GPU activity and overall GPU activity during model training. They will greatly help users manage computing bottlenecks and provide insights for the area to be improved for better computing efficiency. The detailed example is shown in the [performance profiling tutorial]( https://github.com/Project-MONAI/tutorials/blob/master/performance_profiling/profiling_train_base_nvtx.ipynb). + +### 2. Auto mixed precision(AMP) In 2017, NVIDIA researchers developed a methodology for mixed-precision training, which combined single-precision (FP32) with half-precision (e.g. FP16) format when training a network, and it achieved the same accuracy as FP32 training using the same hyperparameters. For the PyTorch 1.6 release, developers at NVIDIA and Facebook moved mixed precision functionality into PyTorch core as the AMP package, `torch.cuda.amp`. @@ -379,16 +404,16 @@ MONAI workflows can easily set `amp=True/False` in `SupervisedTrainer` or `Super We also executed the same test program on NVIDIA A100 GPU with the same software environment, obtained faster results: ![amp a100 results](../images/amp_training_a100.png) More details is available at [AMP training tutorial](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/automatic_mixed_precision.ipynb). -We also tried to combine AMP with `CacheDataset` and `Novograd` optimizer to achieve the fast training in MONAI, able to obtain approximately 12x speedup compared with a Pytorch native implementation when the training converges at a validation mean dice of 0.93. Benchmark for reference: +We also tried to combine `AMP` with `CacheDataset`, `GPU cache`, `GPU transforms`, `ThreadDataLoader`, `DiceCE` loss function and `Novograd` optimizer to achieve the fast training in MONAI, able to obtain approximately `200x` speedup compared with a Pytorch native implementation when the training converges at a validation mean dice of `0.95`. Benchmark for reference: ![fast training results](../images/fast_training.png) More details is available at [Fast training tutorial](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_training_tutorial.ipynb). -### 2. Distributed data parallel +### 3. Distributed data parallel Distributed data parallel is an important feature of PyTorch to connect multiple GPU devices on single or multiple nodes to train or evaluate models. The distributed data parallel APIs of MONAI are compatible with native PyTorch distributed module, pytorch-ignite distributed module, Horovod, XLA, and the SLURM platform. MONAI provides demos for reference: train/evaluate with PyTorch DDP, train/evaluate with Horovod, train/evaluate with Ignite DDP, partition dataset and train with SmartCacheDataset, as well as a real world training example based on Decathlon challenge Task01 - Brain Tumor segmentation. The demo contains distributed caching, training, and validation. We obtained performance benchmarks for reference (based on PyTorch 1.6, CUDA 11, NVIDIA V100 GPUs): ![distributed training results](../images/distributed_training.png) -### 3. C++/CUDA optimized modules +### 4. C++/CUDA optimized modules To further accelerate the domain-specific routines in the workflows, MONAI C++/CUDA implementation are introduced as extensions of the PyTorch native implementations. MONAI provides the modules using [the two ways of building C++ extensions from PyTorch](https://pytorch.org/tutorials/advanced/cpp_extension.html#custom-c-and-cuda-extensions): - via `setuptools`, for modules including `Resampler`, `Conditional random field (CRF)`, `Fast bilateral filtering using the permutohedral lattice`. @@ -396,6 +421,26 @@ MONAI provides the modules using [the two ways of building C++ extensions from P The following figure shows results of MONAI's Gaussian mixture models applied to tissue and surgical tools segmentation: ![Gaussian mixture models as a postprocessing step](../images/gmm_feature_set_comparison_s.png) +### 5. Cache IO and transforms data to GPU memory +Even with `CacheDataset`, we usually need to copy the same data to GPU memory for GPU random transforms or network computation in every epoch. An efficient approach is to cache the data to GPU memory directly, then every epoch can start from GPU computation immediately. + +For example: +```py +train_transforms = [ + LoadImaged(...), + AddChanneld(...), + Spacingd(...), + Orientationd(...), + ScaleIntensityRanged(...), + EnsureTyped(..., data_type="tensor"), + ToDeviced(..., device="cuda:0"), + RandCropByPosNegLabeld(...), +] +dataset = CacheDataset(..., transform=train_trans) +``` +Here we convert to PyTorch `Tensor` with `EnsureTyped` transform and move data to GPU with `ToDeviced` transform. `CacheDataset` caches the transform results until `ToDeviced`, so it is in GPU memory. Then in every epoch, the program fetches cached data from GPU memory and only executes the random transform `RandCropByPosNegLabeld` on GPU directly. +GPU caching example is available at [Spleen fast training tutorial](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_training_tutorial.ipynb). + ## Applications The research area of medical image deep learning is expanding fast. To apply the latest achievements into applications, MONAI contains many application components to build end-to-end solutions or prototypes for other similar use cases. @@ -417,3 +462,8 @@ Starting from v0.5.0, MONAI provides experimental features for building learning The following figure shows the registration of CT images acquired at different time points for a single patient using MONAI: ![3d registration](../images/3d_paired.png) + +### 4. Reproducing the state-of-the-art Kaggle competition solutions +[A reimplementation](https://github.com/Project-MONAI/tutorials/tree/master/kaggle/RANZCR/4th_place_solution) of the 4th place solution of RANZCR CLiP - Catheter and Line Position Challenge in Kaggle: https://www.kaggle.com/c/ranzcr-clip-catheter-line-classification + +The original solution is produced by Team Watercooled, and the authors are Dieter (https://www.kaggle.com/christofhenkel) and Psi (https://www.kaggle.com/philippsinger). From 64fa255b1c584a8522b8f888b1e1d146539afc17 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Thu, 23 Sep 2021 23:29:34 +0100 Subject: [PATCH 47/89] 2914 release note, and what's new for v0.7 (#2992) * release note v0.7 Signed-off-by: Wenqi Li * adds whatsnew 07 Signed-off-by: Wenqi Li --- CHANGELOG.md | 56 ++++++++++++++++++++++++++- docs/images/nsight_comparison.png | Bin 0 -> 184240 bytes docs/source/whatsnew.rst | 1 + docs/source/whatsnew_0_6.md | 2 +- docs/source/whatsnew_0_7.md | 62 ++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 docs/images/nsight_comparison.png create mode 100644 docs/source/whatsnew_0_7.md diff --git a/CHANGELOG.md b/CHANGELOG.md index bdbd23e7dd..db2a29aeed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,50 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] -* renamed model's `n_classes` to `num_classes` + +## [0.7.0] - 2021-09-24 +### Added +* Overview of [new features in v0.7](docs/source/whatsnew_0_7.md) +* Initial phase of major usability improvements in `monai.transforms` to support input and backend in PyTorch and NumPy +* Performance enhancements, with [profiling and tuning guides](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_model_training_guide.md) for typical use cases +* Reproducing [training modules and workflows](https://github.com/Project-MONAI/tutorials/tree/master/kaggle/RANZCR/4th_place_solution) of state-of-the-art Kaggle competition solutions +* 24 new transforms, including + * `OneOf` meta transform + * DeepEdit guidance signal transforms for interactive segmentation + * Transforms for self-supervised pre-training + * Integration of [NVIDIA Tools Extension](https://developer.nvidia.com/blog/nvidia-tools-extension-api-nvtx-annotation-tool-for-profiling-code-in-python-and-c-c/) (NVTX) + * Integration of [cuCIM](https://github.com/rapidsai/cucim) + * Stain normalization and contextual grid for digital pathology +* `Transchex` network for vision-language transformers for chest X-ray analysis +* `DatasetSummary` utility in `monai.data` +* `WarmupCosineSchedule` +* Deprecation warnings and documentation support for better backwards compatibility +* Padding with additional `kwargs` and different backend API +* Additional options such as `dropout` and `norm` in various networks and their submodules + +### Changed +* Base Docker image upgraded to `nvcr.io/nvidia/pytorch:21.08-py3` from `nvcr.io/nvidia/pytorch:21.06-py3` +* Deprecated input argument `n_classes`, in favor of `num_classes` +* Deprecated input argument `dimensions` and `ndims`, in favor of `spatial_dims` +* Updated the Sphinx-based documentation theme for better readability +* `NdarrayTensor` type is replaced by `NdarrayOrTensor` for simpler annotations +* Attention-based network blocks now support both 2D and 3D inputs + +### Removed +* The deprecated `TransformInverter`, in favor of `monai.transforms.InvertD` +* GitHub self-hosted CI/CD pipelines for nightly and post-merge tests +* `monai.handlers.utils.evenly_divisible_all_gather` +* `monai.handlers.utils.string_list_all_gather` + +### Fixed +* A Multi-thread cache writing issue in `LMDBDataset` +* Output shape convention inconsistencies of the image readers +* Output directory and file name flexibility issue for `NiftiSaver`, `PNGSaver` +* Requirement of the `label` field in test-time augmentation +* Input argument flexibility issues for `ThreadDataLoader` +* Decoupled `Dice` and `CrossEntropy` intermediate results in `DiceCELoss` +* Improved documentation, code examples, and warning messages in various modules +* Various usability issues reported by users ## [0.6.0] - 2021-07-08 ### Added @@ -25,6 +68,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * Fully compatible with PyTorch 1.9 * `--disttests` and `--min` options for `runtests.sh` * Initial support of pre-merge tests with Nvidia Blossom system + ### Changed * Base Docker image upgraded to `nvcr.io/nvidia/pytorch:21.06-py3` from `nvcr.io/nvidia/pytorch:21.04-py3` @@ -34,11 +78,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * Unified the terms: `post_transform` is renamed to `postprocessing`, `pre_transform` is renamed to `preprocessing` * Unified the postprocessing transforms and event handlers to accept the "channel-first" data format * `evenly_divisible_all_gather` and `string_list_all_gather` moved to `monai.utils.dist` + ### Removed * Support of 'batched' input for postprocessing transforms and event handlers * `TorchVisionFullyConvModel` * `set_visible_devices` utility function * `SegmentationSaver` and `TransformsInverter` handlers + ### Fixed * Issue of handling big-endian image headers * Multi-thread issue for non-random transforms in the cache-based datasets @@ -269,9 +315,11 @@ the postprocessing steps should be used before calling the metrics methods * Optionally depend on PyTorch-Ignite v0.4.2 instead of v0.3.0 * Optionally depend on torchvision, ITK * Enhanced CI tests with 8 new testing environments + ### Removed * `MONAI/examples` folder (relocated into [`Project-MONAI/tutorials`](https://github.com/Project-MONAI/tutorials)) * `MONAI/research` folder (relocated to [`Project-MONAI/research-contributions`](https://github.com/Project-MONAI/research-contributions)) + ### Fixed * `dense_patch_slices` incorrect indexing * Data type issue in `GeneralizedWassersteinDiceLoss` @@ -302,6 +350,7 @@ the postprocessing steps should be used before calling the metrics methods * Cross-platform CI tests supporting multiple Python versions * Optional import mechanism * Experimental features for third-party transforms integration + ### Changed > For more details please visit [the project wiki](https://github.com/Project-MONAI/MONAI/wiki/Notable-changes-between-0.1.0-and-0.2.0) * Core modules now require numpy >= 1.17 @@ -311,9 +360,11 @@ the postprocessing steps should be used before calling the metrics methods * Base Docker image upgraded to `nvcr.io/nvidia/pytorch:20.03-py3` from `nvcr.io/nvidia/pytorch:19.10-py3` * Enhanced local testing tools * Documentation website domain changed to https://docs.monai.io + ### Removed * Support of Python < 3.6 * Automatic installation of optional dependencies including pytorch-ignite, nibabel, tensorboard, pillow, scipy, scikit-image + ### Fixed * Various issues in type and argument names consistency * Various issues in docstring and documentation site @@ -336,7 +387,8 @@ the postprocessing steps should be used before calling the metrics methods [highlights]: https://github.com/Project-MONAI/MONAI/blob/master/docs/source/highlights.md -[Unreleased]: https://github.com/Project-MONAI/MONAI/compare/0.6.0...HEAD +[Unreleased]: https://github.com/Project-MONAI/MONAI/compare/0.7.0...HEAD +[0.7.0]: https://github.com/Project-MONAI/MONAI/compare/0.6.0...0.7.0 [0.6.0]: https://github.com/Project-MONAI/MONAI/compare/0.5.3...0.6.0 [0.5.3]: https://github.com/Project-MONAI/MONAI/compare/0.5.0...0.5.3 [0.5.0]: https://github.com/Project-MONAI/MONAI/compare/0.4.0...0.5.0 diff --git a/docs/images/nsight_comparison.png b/docs/images/nsight_comparison.png new file mode 100644 index 0000000000000000000000000000000000000000..9b918265134d1bdf7c231245037e7748b40da05b GIT binary patch literal 184240 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

i$7c>5M~wnZsKOiw{7rT4ETn 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 Date: Fri, 24 Sep 2021 01:05:40 +0100 Subject: [PATCH 48/89] delaying the removal (#3015) Signed-off-by: Wenqi Li --- monai/networks/nets/dynunet_v1.py | 2 +- monai/networks/nets/torchvision_fc.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/monai/networks/nets/dynunet_v1.py b/monai/networks/nets/dynunet_v1.py index c6a54807e4..4c910157c9 100644 --- a/monai/networks/nets/dynunet_v1.py +++ b/monai/networks/nets/dynunet_v1.py @@ -24,7 +24,7 @@ @deprecated( since="0.6.0", - removed="0.7.0", + removed="0.8.0", msg_suffix="This module is for backward compatibility purpose only. Please use `DynUNet` instead.", ) class DynUNetV1(DynUNet): diff --git a/monai/networks/nets/torchvision_fc.py b/monai/networks/nets/torchvision_fc.py index 1619f877e7..d5bd6e9f57 100644 --- a/monai/networks/nets/torchvision_fc.py +++ b/monai/networks/nets/torchvision_fc.py @@ -73,7 +73,7 @@ def __init__( ) -@deprecated(since="0.6.0", removed="0.7.0", msg_suffix="Please consider using `TorchVisionFCModel` instead.") +@deprecated(since="0.6.0", removed="0.8.0", msg_suffix="Please consider using `TorchVisionFCModel` instead.") class TorchVisionFullyConvModel(TorchVisionFCModel): """ Customize TorchVision models to replace fully connected layer by convolutional layer. From f06de43c3f6d6ccaaf7fef675897426341206c08 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Fri, 24 Sep 2021 04:03:33 +0100 Subject: [PATCH 49/89] update preview version tag (#3016) Signed-off-by: Wenqi Li --- .github/workflows/weekly-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/weekly-preview.yml b/.github/workflows/weekly-preview.yml index df0b5dd759..d5c4e5ae05 100644 --- a/.github/workflows/weekly-preview.yml +++ b/.github/workflows/weekly-preview.yml @@ -33,7 +33,7 @@ jobs: export YEAR_WEEK=$(date +'%y%U') echo "Year week for tag is ${YEAR_WEEK}" if ! [[ $YEAR_WEEK =~ ^[0-9]{4}$ ]] ; then echo "Wrong 'year week' format. Should be 4 digits."; exit 1 ; fi - git tag "0.7.dev${YEAR_WEEK}" + git tag "0.8.dev${YEAR_WEEK}" git log -1 git tag --list python setup.py sdist bdist_wheel From aa4eb5ddc2e2cd435617ee5fc3de2fc30cf7bc77 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Fri, 24 Sep 2021 11:53:52 +0800 Subject: [PATCH 50/89] Enhance 0.7 README doc (#3017) * [DLMED] update README Signed-off-by: Nic Ma * [DLMED] update what's new Signed-off-by: Nic Ma * [DLMED] use whatsnew link Signed-off-by: Nic Ma --- README.md | 2 +- docs/source/whatsnew_0_7.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e9facef64d..e08b1d07a8 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Its ambitions are: ## Features > _The codebase is currently under active development._ -> _Please see [the technical highlights](https://docs.monai.io/en/latest/highlights.html) and [What's New in 0.6](https://docs.monai.io/en/latest/whatsnew_0_6.html) of the current milestone release._ +> _Please see [the technical highlights](https://docs.monai.io/en/latest/highlights.html) and [What's New](https://docs.monai.io/en/latest/whatsnew.html) of the current milestone release._ - flexible pre-processing for multi-dimensional medical imaging data; - compositional & portable APIs for ease of integration in existing workflows; diff --git a/docs/source/whatsnew_0_7.md b/docs/source/whatsnew_0_7.md index 8d0f3947f7..5a0a82130d 100644 --- a/docs/source/whatsnew_0_7.md +++ b/docs/source/whatsnew_0_7.md @@ -21,8 +21,8 @@ a performance enhancement study. With the performance profiling and enhancements, several typical use cases were studied to improve the training efficiency. The following figure shows that fast -training using MONAI can be 20 times faster than a regular baseline ([learn -more](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_training_tutorial.ipynb)). +training using MONAI can be `200` times faster than a regular baseline ([learn +more](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_training_tutorial.ipynb)), and it's `20` times faster than the MONAI v0.6 fast training solution. ![fast_training](../images/fast_training.png) ## Major usability improvements in `monai.transforms` for NumPy/PyTorch inputs and backends From a9cd2d88168107281a2abcc2f63efaed80580e79 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Fri, 24 Sep 2021 15:32:40 +0800 Subject: [PATCH 51/89] 3020 Enhance what's new for transfomer networks (#3019) * [DLMED] add more doc Signed-off-by: Nic Ma * [DLMED] edit change log Signed-off-by: Nic Ma * [DLMED] add command to get transform backend Signed-off-by: Nic Ma * [DLMED] enhance the doc Signed-off-by: Nic Ma --- CHANGELOG.md | 2 +- docs/source/highlights.md | 2 +- docs/source/whatsnew_0_7.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db2a29aeed..7dea15cd0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. * Deprecated input argument `dimensions` and `ndims`, in favor of `spatial_dims` * Updated the Sphinx-based documentation theme for better readability * `NdarrayTensor` type is replaced by `NdarrayOrTensor` for simpler annotations -* Attention-based network blocks now support both 2D and 3D inputs +* Self-attention-based network blocks now support both 2D and 3D inputs ### Removed * The deprecated `TransformInverter`, in favor of `monai.transforms.InvertD` diff --git a/docs/source/highlights.md b/docs/source/highlights.md index b84e93ff2d..44ab949a95 100644 --- a/docs/source/highlights.md +++ b/docs/source/highlights.md @@ -58,7 +58,7 @@ transformations. These currently include, for example: ### 3. Transforms support both NumPy array and PyTorch Tensor (CPU or GPU accelerated) -From MONAI v0.7 we introduced PyTorch `Tensor` based computation in transforms, many transforms already support both `numpy array` and `Tensor` data. +From MONAI v0.7 we introduced PyTorch `Tensor` based computation in transforms, many transforms already support both `NumPy array` and `Tensor` as input types and computational backends. To get the supported backends of every transform, please execute: `python monai/transforms/utils.py`. To accelerate the transforms, a common approach is to leverage GPU parallel-computation. Users can first convert input data into GPU Tensor by `ToTensor` or `EnsureType` transform, then the following transforms can execute on GPU based on PyTorch `Tensor` APIs. GPU transform tutorial is available at [Spleen fast training tutorial](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_training_tutorial.ipynb). diff --git a/docs/source/whatsnew_0_7.md b/docs/source/whatsnew_0_7.md index 5a0a82130d..010a62824b 100644 --- a/docs/source/whatsnew_0_7.md +++ b/docs/source/whatsnew_0_7.md @@ -29,7 +29,7 @@ more](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_t MONAI starts to roll out major usability enhancements for the `monai.transforms` module. Many transforms are now supporting both NumPy and - PyTorch, as input types and computational backends. + PyTorch, as input types and computational backends. To get the supported backends of every transform, please execute: `python monai/transforms/utils.py`. One benefit of these enhancements is that the users can now better leverage the GPUs for preprocessing. By transferring the input data onto GPU using From 453a9c06e4e8f4bf83e0b261c3675d529c96e08c Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Fri, 24 Sep 2021 15:56:18 +0100 Subject: [PATCH 52/89] Torch `GaussianSmooth`, `RandGaussianSmooth`, `GaussianSharpen`, `RandGaussianSharpen` (#2971) Torch `GaussianSmooth`, `RandGaussianSmooth`, `GaussianSharpen`, `RandGaussianSharpen` --- monai/networks/layers/simplelayers.py | 10 +- monai/transforms/intensity/array.py | 53 +++++--- monai/transforms/intensity/dictionary.py | 38 ++++-- tests/test_gaussian_sharpen.py | 83 ++++++++---- tests/test_gaussian_sharpend.py | 81 +++++++---- tests/test_gaussian_smooth.py | 91 ++++++++----- tests/test_gaussian_smoothd.py | 89 ++++++++----- tests/test_rand_gaussian_sharpen.py | 159 +++++++++++++--------- tests/test_rand_gaussian_sharpend.py | 163 ++++++++++++++--------- tests/test_rand_gaussian_smooth.py | 85 ++++++++---- tests/test_rand_gaussian_smoothd.py | 85 ++++++++---- 11 files changed, 617 insertions(+), 320 deletions(-) diff --git a/monai/networks/layers/simplelayers.py b/monai/networks/layers/simplelayers.py index 52f19aab29..3acf50d210 100644 --- a/monai/networks/layers/simplelayers.py +++ b/monai/networks/layers/simplelayers.py @@ -10,6 +10,7 @@ # limitations under the License. import math +from copy import deepcopy from typing import List, Sequence, Union import torch @@ -24,10 +25,10 @@ ChannelMatching, InvalidPyTorchVersionError, SkipMode, - ensure_tuple_rep, look_up_option, optional_import, ) +from monai.utils.misc import issequenceiterable _C, _ = optional_import("monai._C") if not PT_BEFORE_1_7: @@ -393,13 +394,18 @@ def __init__( (for example `parameters()` iterator could be used to get the parameters); otherwise this module will fix the kernels using `sigma` as the std. """ + if issequenceiterable(sigma): + if len(sigma) != spatial_dims: # type: ignore + raise ValueError + else: + sigma = [deepcopy(sigma) for _ in range(spatial_dims)] # type: ignore super().__init__() self.sigma = [ torch.nn.Parameter( torch.as_tensor(s, dtype=torch.float, device=s.device if isinstance(s, torch.Tensor) else None), requires_grad=requires_grad, ) - for s in ensure_tuple_rep(sigma, int(spatial_dims)) + for s in sigma # type: ignore ] self.truncated = truncated self.approx = approx diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 3be205996e..7b73aa63b1 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1030,15 +1030,24 @@ class GaussianSmooth(Transform): """ + backend = [TransformBackends.TORCH] + def __init__(self, sigma: Union[Sequence[float], float] = 1.0, approx: str = "erf") -> None: self.sigma = sigma self.approx = approx - def __call__(self, img: np.ndarray): - img, *_ = convert_data_type(img, np.ndarray) # type: ignore - gaussian_filter = GaussianFilter(img.ndim - 1, self.sigma, approx=self.approx) - input_data = torch.as_tensor(np.ascontiguousarray(img), dtype=torch.float).unsqueeze(0) - return gaussian_filter(input_data).squeeze(0).detach().numpy() + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: + img_t: torch.Tensor + img_t, *_ = convert_data_type(img, torch.Tensor, dtype=torch.float) # type: ignore + sigma: Union[Sequence[torch.Tensor], torch.Tensor] + if isinstance(self.sigma, Sequence): + sigma = [torch.as_tensor(s, device=img_t.device) for s in self.sigma] + else: + sigma = torch.as_tensor(self.sigma, device=img_t.device) + gaussian_filter = GaussianFilter(img_t.ndim - 1, sigma, approx=self.approx) + out_t: torch.Tensor = gaussian_filter(img_t.unsqueeze(0)).squeeze(0) + out, *_ = convert_data_type(out_t, type(img), device=img.device if isinstance(img, torch.Tensor) else None) + return out class RandGaussianSmooth(RandomizableTransform): @@ -1079,10 +1088,10 @@ def randomize(self, data: Optional[Any] = None) -> None: self.y = self.R.uniform(low=self.sigma_y[0], high=self.sigma_y[1]) self.z = self.R.uniform(low=self.sigma_z[0], high=self.sigma_z[1]) - def __call__(self, img: np.ndarray): - img, *_ = convert_data_type(img, np.ndarray) # type: ignore + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: self.randomize() if not self._do_transform: + img, *_ = convert_data_type(img, dtype=torch.float) return img sigma = ensure_tuple_size(tup=(self.x, self.y, self.z), dim=img.ndim - 1) return GaussianSmooth(sigma=sigma, approx=self.approx)(img) @@ -1115,6 +1124,8 @@ class GaussianSharpen(Transform): """ + backend = [TransformBackends.TORCH] + def __init__( self, sigma1: Union[Sequence[float], float] = 3.0, @@ -1127,14 +1138,19 @@ def __init__( self.alpha = alpha self.approx = approx - def __call__(self, img: np.ndarray): - img, *_ = convert_data_type(img, np.ndarray) # type: ignore - gaussian_filter1 = GaussianFilter(img.ndim - 1, self.sigma1, approx=self.approx) - gaussian_filter2 = GaussianFilter(img.ndim - 1, self.sigma2, approx=self.approx) - input_data = torch.as_tensor(np.ascontiguousarray(img), dtype=torch.float).unsqueeze(0) - blurred_f = gaussian_filter1(input_data) - filter_blurred_f = gaussian_filter2(blurred_f) - return (blurred_f + self.alpha * (blurred_f - filter_blurred_f)).squeeze(0).detach().numpy() + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: + img_t: torch.Tensor + img_t, *_ = convert_data_type(img, torch.Tensor, dtype=torch.float32) # type: ignore + + gf1, gf2 = [ + GaussianFilter(img_t.ndim - 1, sigma, approx=self.approx).to(img_t.device) + for sigma in (self.sigma1, self.sigma2) + ] + blurred_f = gf1(img_t.unsqueeze(0)) + filter_blurred_f = gf2(blurred_f) + out_t: torch.Tensor = (blurred_f + self.alpha * (blurred_f - filter_blurred_f)).squeeze(0) + out, *_ = convert_data_type(out_t, type(img), device=img.device if isinstance(img, torch.Tensor) else None) + return out class RandGaussianSharpen(RandomizableTransform): @@ -1159,6 +1175,8 @@ class RandGaussianSharpen(RandomizableTransform): """ + backend = GaussianSharpen.backend + def __init__( self, sigma1_x: Tuple[float, float] = (0.5, 1.0), @@ -1194,10 +1212,11 @@ def randomize(self, data: Optional[Any] = None) -> None: self.z2 = self.R.uniform(low=sigma2_z[0], high=sigma2_z[1]) self.a = self.R.uniform(low=self.alpha[0], high=self.alpha[1]) - def __call__(self, img: np.ndarray): - img, *_ = convert_data_type(img, np.ndarray) # type: ignore + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: self.randomize() + # if not doing, just need to convert to tensor if not self._do_transform: + img, *_ = convert_data_type(img, dtype=torch.float32) return img sigma1 = ensure_tuple_size(tup=(self.x1, self.y1, self.z1), dim=img.ndim - 1) sigma2 = ensure_tuple_size(tup=(self.x2, self.y2, self.z2), dim=img.ndim - 1) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index 07a6045870..e95e00880e 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -48,6 +48,7 @@ from monai.transforms.transform import MapTransform, Randomizable, RandomizableTransform from monai.transforms.utils import is_positive from monai.utils import convert_to_dst_type, ensure_tuple, ensure_tuple_rep, ensure_tuple_size +from monai.utils.type_conversion import convert_data_type __all__ = [ "RandGaussianNoised", @@ -897,6 +898,8 @@ class GaussianSmoothd(MapTransform): """ + backend = GaussianSmooth.backend + def __init__( self, keys: KeysCollection, @@ -907,7 +910,7 @@ def __init__( super().__init__(keys, allow_missing_keys) self.converter = GaussianSmooth(sigma, approx=approx) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): d[key] = self.converter(d[key]) @@ -931,6 +934,8 @@ class RandGaussianSmoothd(RandomizableTransform, MapTransform): """ + backend = GaussianSmooth.backend + def __init__( self, keys: KeysCollection, @@ -954,14 +959,15 @@ def randomize(self, data: Optional[Any] = None) -> None: self.y = self.R.uniform(low=self.sigma_y[0], high=self.sigma_y[1]) self.z = self.R.uniform(low=self.sigma_z[0], high=self.sigma_z[1]) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) self.randomize() - if not self._do_transform: - return d for key in self.key_iterator(d): - sigma = ensure_tuple_size(tup=(self.x, self.y, self.z), dim=d[key].ndim - 1) - d[key] = GaussianSmooth(sigma=sigma, approx=self.approx)(d[key]) + if self._do_transform: + sigma = ensure_tuple_size(tup=(self.x, self.y, self.z), dim=d[key].ndim - 1) + d[key] = GaussianSmooth(sigma=sigma, approx=self.approx)(d[key]) + else: + d[key], *_ = convert_data_type(d[key], torch.Tensor, dtype=torch.float) return d @@ -985,6 +991,8 @@ class GaussianSharpend(MapTransform): """ + backend = GaussianSharpen.backend + def __init__( self, keys: KeysCollection, @@ -997,7 +1005,7 @@ def __init__( super().__init__(keys, allow_missing_keys) self.converter = GaussianSharpen(sigma1, sigma2, alpha, approx=approx) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): d[key] = self.converter(d[key]) @@ -1028,6 +1036,8 @@ class RandGaussianSharpend(RandomizableTransform, MapTransform): """ + backend = GaussianSharpen.backend + def __init__( self, keys: KeysCollection, @@ -1066,15 +1076,17 @@ def randomize(self, data: Optional[Any] = None) -> None: self.z2 = self.R.uniform(low=sigma2_z[0], high=sigma2_z[1]) self.a = self.R.uniform(low=self.alpha[0], high=self.alpha[1]) - def __call__(self, data): + def __call__(self, data: Dict[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) self.randomize() - if not self._do_transform: - return d for key in self.key_iterator(d): - sigma1 = ensure_tuple_size(tup=(self.x1, self.y1, self.z1), dim=d[key].ndim - 1) - sigma2 = ensure_tuple_size(tup=(self.x2, self.y2, self.z2), dim=d[key].ndim - 1) - d[key] = GaussianSharpen(sigma1=sigma1, sigma2=sigma2, alpha=self.a, approx=self.approx)(d[key]) + if self._do_transform: + sigma1 = ensure_tuple_size(tup=(self.x1, self.y1, self.z1), dim=d[key].ndim - 1) + sigma2 = ensure_tuple_size(tup=(self.x2, self.y2, self.z2), dim=d[key].ndim - 1) + d[key] = GaussianSharpen(sigma1=sigma1, sigma2=sigma2, alpha=self.a, approx=self.approx)(d[key]) + else: + # if not doing the transform, convert to torch + d[key], *_ = convert_data_type(d[key], torch.Tensor, dtype=torch.float32) return d diff --git a/tests/test_gaussian_sharpen.py b/tests/test_gaussian_sharpen.py index 9d078e65e5..9130e33656 100644 --- a/tests/test_gaussian_sharpen.py +++ b/tests/test_gaussian_sharpen.py @@ -11,50 +11,79 @@ import unittest -import numpy as np from parameterized import parameterized from monai.transforms import GaussianSharpen +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( +TESTS = [] + +for p in TEST_NDARRAYS: + TESTS.append( [ - [[4.1081963, 3.4950666, 4.1081963], [3.7239995, 2.8491793, 3.7239995], [4.569839, 3.9529324, 4.569839]], - [[10.616725, 9.081067, 10.616725], [9.309998, 7.12295, 9.309998], [11.078365, 9.538931, 11.078365]], + {}, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [4.1081963, 3.4950666, 4.1081963], + [3.7239995, 2.8491793, 3.7239995], + [4.569839, 3.9529324, 4.569839], + ], + [[10.616725, 9.081067, 10.616725], [9.309998, 7.12295, 9.309998], [11.078365, 9.538931, 11.078365]], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - {"sigma1": 1.0, "sigma2": 0.75, "alpha": 20}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[4.513644, 4.869134, 4.513644], [8.467242, 9.4004135, 8.467242], [10.416813, 12.0653515, 10.416813]], - [[15.711488, 17.569994, 15.711488], [21.16811, 23.501041, 21.16811], [21.614658, 24.766209, 21.614658]], + {"sigma1": 1.0, "sigma2": 0.75, "alpha": 20}, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [4.513644, 4.869134, 4.513644], + [8.467242, 9.4004135, 8.467242], + [10.416813, 12.0653515, 10.416813], + ], + [ + [15.711488, 17.569994, 15.711488], + [21.16811, 23.501041, 21.16811], + [21.614658, 24.766209, 21.614658], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - {"sigma1": (0.5, 1.0), "sigma2": (0.5, 0.75), "alpha": 20}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[3.3324685, 3.335536, 3.3324673], [7.7666636, 8.16056, 7.7666636], [12.662973, 14.317837, 12.6629715]], - [[15.329051, 16.57557, 15.329051], [19.41665, 20.40139, 19.416655], [24.659554, 27.557873, 24.659554]], + {"sigma1": (0.5, 1.0), "sigma2": (0.5, 0.75), "alpha": 20}, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [3.3324685, 3.335536, 3.3324673], + [7.7666636, 8.16056, 7.7666636], + [12.662973, 14.317837, 12.6629715], + ], + [ + [15.329051, 16.57557, 15.329051], + [19.41665, 20.40139, 19.416655], + [24.659554, 27.557873, 24.659554], + ], + ] + ), ] - ), -] + ) class TestGaussianSharpen(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): result = GaussianSharpen(**argments)(image) - np.testing.assert_allclose(result, expected_data, rtol=1e-4) + assert_allclose(result, expected_data, atol=0, rtol=1e-4, type_test=False) if __name__ == "__main__": diff --git a/tests/test_gaussian_sharpend.py b/tests/test_gaussian_sharpend.py index c795b11762..4b84eb9c12 100644 --- a/tests/test_gaussian_sharpend.py +++ b/tests/test_gaussian_sharpend.py @@ -15,46 +15,75 @@ from parameterized import parameterized from monai.transforms import GaussianSharpend +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"keys": "img"}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( [ - [[4.1081963, 3.4950666, 4.1081963], [3.7239995, 2.8491793, 3.7239995], [4.569839, 3.9529324, 4.569839]], - [[10.616725, 9.081067, 10.616725], [9.309998, 7.12295, 9.309998], [11.078365, 9.538931, 11.078365]], + {"keys": "img"}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [4.1081963, 3.4950666, 4.1081963], + [3.7239995, 2.8491793, 3.7239995], + [4.569839, 3.9529324, 4.569839], + ], + [[10.616725, 9.081067, 10.616725], [9.309998, 7.12295, 9.309998], [11.078365, 9.538931, 11.078365]], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - {"keys": "img", "sigma1": 1.0, "sigma2": 0.75, "alpha": 20}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[4.513644, 4.869134, 4.513644], [8.467242, 9.4004135, 8.467242], [10.416813, 12.0653515, 10.416813]], - [[15.711488, 17.569994, 15.711488], [21.16811, 23.501041, 21.16811], [21.614658, 24.766209, 21.614658]], + {"keys": "img", "sigma1": 1.0, "sigma2": 0.75, "alpha": 20}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [4.513644, 4.869134, 4.513644], + [8.467242, 9.4004135, 8.467242], + [10.416813, 12.0653515, 10.416813], + ], + [ + [15.711488, 17.569994, 15.711488], + [21.16811, 23.501041, 21.16811], + [21.614658, 24.766209, 21.614658], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - {"keys": "img", "sigma1": (0.5, 1.0), "sigma2": (0.5, 0.75), "alpha": 20}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[3.3324685, 3.335536, 3.3324673], [7.7666636, 8.16056, 7.7666636], [12.662973, 14.317837, 12.6629715]], - [[15.329051, 16.57557, 15.329051], [19.41665, 20.40139, 19.416655], [24.659554, 27.557873, 24.659554]], + {"keys": "img", "sigma1": (0.5, 1.0), "sigma2": (0.5, 0.75), "alpha": 20}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [3.3324685, 3.335536, 3.3324673], + [7.7666636, 8.16056, 7.7666636], + [12.662973, 14.317837, 12.6629715], + ], + [ + [15.329051, 16.57557, 15.329051], + [19.41665, 20.40139, 19.416655], + [24.659554, 27.557873, 24.659554], + ], + ] + ), ] - ), -] + ) class TestGaussianSharpend(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): result = GaussianSharpend(**argments)(image) - np.testing.assert_allclose(result["img"], expected_data, rtol=1e-4) + assert_allclose(result["img"], expected_data, rtol=1e-4, type_test=False) if __name__ == "__main__": diff --git a/tests/test_gaussian_smooth.py b/tests/test_gaussian_smooth.py index e51977fbee..24ecfb88e8 100644 --- a/tests/test_gaussian_smooth.py +++ b/tests/test_gaussian_smooth.py @@ -11,54 +11,83 @@ import unittest -import numpy as np from parameterized import parameterized from monai.transforms import GaussianSmooth +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"sigma": 1.5}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( +TESTS = [] + +for p in TEST_NDARRAYS: + TESTS.append( [ - [ - [0.59167546, 0.69312394, 0.59167546], - [0.7956997, 0.93213004, 0.7956997], - [0.7668002, 0.8982755, 0.7668002], - ], - [[1.6105323, 1.8866735, 1.6105323], [1.9892492, 2.3303251, 1.9892492], [1.7856569, 2.091825, 1.7856569]], + {"sigma": 1.5}, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [0.59167546, 0.69312394, 0.59167546], + [0.7956997, 0.93213004, 0.7956997], + [0.7668002, 0.8982755, 0.7668002], + ], + [ + [1.6105323, 1.8866735, 1.6105323], + [1.9892492, 2.3303251, 1.9892492], + [1.7856569, 2.091825, 1.7856569], + ], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - {"sigma": 0.5}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[0.8424794, 0.99864554, 0.8424794], [1.678146, 1.9892154, 1.678146], [1.9889624, 2.3576462, 1.9889624]], - [[2.966061, 3.5158648, 2.966061], [4.1953645, 4.973038, 4.1953645], [4.112544, 4.8748655, 4.1125436]], + {"sigma": 0.5}, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [0.8424794, 0.99864554, 0.8424794], + [1.678146, 1.9892154, 1.678146], + [1.9889624, 2.3576462, 1.9889624], + ], + [ + [2.966061, 3.5158648, 2.966061], + [4.1953645, 4.973038, 4.1953645], + [4.112544, 4.8748655, 4.1125436], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - {"sigma": [1.5, 0.5]}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[0.8542037, 1.0125432, 0.8542037], [1.1487541, 1.3616928, 1.1487541], [1.1070318, 1.3122368, 1.1070318]], - [[2.3251305, 2.756128, 2.3251305], [2.8718853, 3.4042323, 2.8718853], [2.5779586, 3.0558217, 2.5779586]], + {"sigma": [1.5, 0.5]}, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [0.8542037, 1.0125432, 0.8542037], + [1.1487541, 1.3616928, 1.1487541], + [1.1070318, 1.3122368, 1.1070318], + ], + [ + [2.3251305, 2.756128, 2.3251305], + [2.8718853, 3.4042323, 2.8718853], + [2.5779586, 3.0558217, 2.5779586], + ], + ] + ), ] - ), -] + ) class TestGaussianSmooth(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): result = GaussianSmooth(**argments)(image) - np.testing.assert_allclose(result, expected_data, rtol=1e-4) + assert_allclose(result, expected_data, atol=0, rtol=1e-4, type_test=False) if __name__ == "__main__": diff --git a/tests/test_gaussian_smoothd.py b/tests/test_gaussian_smoothd.py index 3d7eb6195e..ae358dd59a 100644 --- a/tests/test_gaussian_smoothd.py +++ b/tests/test_gaussian_smoothd.py @@ -15,50 +15,79 @@ from parameterized import parameterized from monai.transforms import GaussianSmoothd +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"keys": "img", "sigma": 1.5}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( [ - [ - [0.59167546, 0.69312394, 0.59167546], - [0.7956997, 0.93213004, 0.7956997], - [0.7668002, 0.8982755, 0.7668002], - ], - [[1.6105323, 1.8866735, 1.6105323], [1.9892492, 2.3303251, 1.9892492], [1.7856569, 2.091825, 1.7856569]], + {"keys": "img", "sigma": 1.5}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [0.59167546, 0.69312394, 0.59167546], + [0.7956997, 0.93213004, 0.7956997], + [0.7668002, 0.8982755, 0.7668002], + ], + [ + [1.6105323, 1.8866735, 1.6105323], + [1.9892492, 2.3303251, 1.9892492], + [1.7856569, 2.091825, 1.7856569], + ], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - {"keys": "img", "sigma": 0.5}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[0.8424794, 0.99864554, 0.8424794], [1.678146, 1.9892154, 1.678146], [1.9889624, 2.3576462, 1.9889624]], - [[2.966061, 3.5158648, 2.966061], [4.1953645, 4.973038, 4.1953645], [4.112544, 4.8748655, 4.1125436]], + {"keys": "img", "sigma": 0.5}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [0.8424794, 0.99864554, 0.8424794], + [1.678146, 1.9892154, 1.678146], + [1.9889624, 2.3576462, 1.9889624], + ], + [ + [2.966061, 3.5158648, 2.966061], + [4.1953645, 4.973038, 4.1953645], + [4.112544, 4.8748655, 4.1125436], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - {"keys": "img", "sigma": [1.5, 0.5]}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[0.8542037, 1.0125432, 0.8542037], [1.1487541, 1.3616928, 1.1487541], [1.1070318, 1.3122368, 1.1070318]], - [[2.3251305, 2.756128, 2.3251305], [2.8718853, 3.4042323, 2.8718853], [2.5779586, 3.0558217, 2.5779586]], + {"keys": "img", "sigma": [1.5, 0.5]}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [0.8542037, 1.0125432, 0.8542037], + [1.1487541, 1.3616928, 1.1487541], + [1.1070318, 1.3122368, 1.1070318], + ], + [ + [2.3251305, 2.756128, 2.3251305], + [2.8718853, 3.4042323, 2.8718853], + [2.5779586, 3.0558217, 2.5779586], + ], + ] + ), ] - ), -] + ) class TestGaussianSmoothd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): result = GaussianSmoothd(**argments)(image) - np.testing.assert_allclose(result["img"], expected_data, rtol=1e-4) + assert_allclose(result["img"], expected_data, rtol=1e-4, type_test=False) if __name__ == "__main__": diff --git a/tests/test_rand_gaussian_sharpen.py b/tests/test_rand_gaussian_sharpen.py index 909f96f56b..4804fc2422 100644 --- a/tests/test_rand_gaussian_sharpen.py +++ b/tests/test_rand_gaussian_sharpen.py @@ -11,88 +11,127 @@ import unittest -import numpy as np from parameterized import parameterized from monai.transforms import RandGaussianSharpen +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"prob": 1.0}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( +TESTS = [] + +for p in TEST_NDARRAYS: + TESTS.append( [ - [[5.2919216, 5.5854445, 5.29192], [11.3982, 12.62332, 11.398202], [14.870525, 17.323769, 14.870527]], - [[20.413757, 22.767355, 20.413757], [28.495504, 31.558315, 28.495499], [29.99236, 34.505676, 29.992361]], + {"prob": 1.0}, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [5.2919216, 5.5854445, 5.29192], + [11.3982, 12.62332, 11.398202], + [14.870525, 17.323769, 14.870527], + ], + [ + [20.413757, 22.767355, 20.413757], + [28.495504, 31.558315, 28.495499], + [29.99236, 34.505676, 29.992361], + ], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - { - "sigma1_x": (0.5, 0.75), - "sigma1_y": (0.5, 0.75), - "sigma1_z": (0.5, 0.75), - "sigma2_x": 0.4, - "sigma2_y": 0.4, - "sigma2_z": 0.4, - "prob": 1.0, - }, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[4.1071496, 3.597953, 4.1071477], [10.062014, 9.825114, 10.0620165], [14.698058, 15.818766, 14.698058]], - [[18.211048, 18.16049, 18.211048], [25.155039, 24.56279, 25.155039], [28.801964, 30.381308, 28.801964]], + { + "sigma1_x": (0.5, 0.75), + "sigma1_y": (0.5, 0.75), + "sigma1_z": (0.5, 0.75), + "sigma2_x": 0.4, + "sigma2_y": 0.4, + "sigma2_z": 0.4, + "prob": 1.0, + }, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [4.1071496, 3.597953, 4.1071477], + [10.062014, 9.825114, 10.0620165], + [14.698058, 15.818766, 14.698058], + ], + [ + [18.211048, 18.16049, 18.211048], + [25.155039, 24.56279, 25.155039], + [28.801964, 30.381308, 28.801964], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - { - "sigma1_x": (0.5, 0.75), - "sigma1_y": (0.5, 0.75), - "sigma1_z": (0.5, 0.75), - "sigma2_x": (0.5, 0.75), - "sigma2_y": (0.5, 0.75), - "sigma2_z": (0.5, 0.75), - "prob": 1.0, - }, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[4.81077, 4.4237204, 4.81077], [12.061236, 12.298177, 12.061236], [17.362553, 19.201174, 17.362553]], - [[21.440754, 22.142393, 21.440754], [30.15308, 30.745445, 30.153086], [33.99255, 36.919838, 33.99255]], + { + "sigma1_x": (0.5, 0.75), + "sigma1_y": (0.5, 0.75), + "sigma1_z": (0.5, 0.75), + "sigma2_x": (0.5, 0.75), + "sigma2_y": (0.5, 0.75), + "sigma2_z": (0.5, 0.75), + "prob": 1.0, + }, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [4.81077, 4.4237204, 4.81077], + [12.061236, 12.298177, 12.061236], + [17.362553, 19.201174, 17.362553], + ], + [ + [21.440754, 22.142393, 21.440754], + [30.15308, 30.745445, 30.153086], + [33.99255, 36.919838, 33.99255], + ], + ] + ), ] - ), -] + ) -TEST_CASE_4 = [ - { - "sigma1_x": (0.5, 0.75), - "sigma1_y": (0.5, 0.75), - "sigma1_z": (0.5, 0.75), - "sigma2_x": (0.5, 0.75), - "sigma2_y": (0.5, 0.75), - "sigma2_z": (0.5, 0.75), - "approx": "scalespace", - "prob": 1.0, - }, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[4.430213, 3.2278745, 4.4302144], [10.325399, 8.507457, 10.325399], [17.494898, 16.5609, 17.494894]], - [[20.87405, 18.06946, 20.87405], [25.813503, 21.268656, 25.8135], [33.93874, 31.402481, 33.938725]], + { + "sigma1_x": (0.5, 0.75), + "sigma1_y": (0.5, 0.75), + "sigma1_z": (0.5, 0.75), + "sigma2_x": (0.5, 0.75), + "sigma2_y": (0.5, 0.75), + "sigma2_z": (0.5, 0.75), + "approx": "scalespace", + "prob": 1.0, + }, + p([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), + p( + [ + [ + [4.430213, 3.2278745, 4.4302144], + [10.325399, 8.507457, 10.325399], + [17.494898, 16.5609, 17.494894], + ], + [[20.87405, 18.06946, 20.87405], [25.813503, 21.268656, 25.8135], [33.93874, 31.402481, 33.938725]], + ] + ), ] - ), -] + ) class TestRandGaussianSharpen(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): converter = RandGaussianSharpen(**argments) converter.set_random_state(seed=0) result = converter(image) - np.testing.assert_allclose(result, expected_data, rtol=1e-4) + assert_allclose(result, expected_data, atol=0, rtol=1e-4, type_test=False) if __name__ == "__main__": diff --git a/tests/test_rand_gaussian_sharpend.py b/tests/test_rand_gaussian_sharpend.py index 9ba29ee71b..3508ebaa19 100644 --- a/tests/test_rand_gaussian_sharpend.py +++ b/tests/test_rand_gaussian_sharpend.py @@ -15,87 +15,126 @@ from parameterized import parameterized from monai.transforms import RandGaussianSharpend +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"keys": "img", "prob": 1.0}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( [ - [[5.2919216, 5.5854445, 5.29192], [11.3982, 12.62332, 11.398202], [14.870525, 17.323769, 14.870527]], - [[20.413757, 22.767355, 20.413757], [28.495504, 31.558315, 28.495499], [29.99236, 34.505676, 29.992361]], + {"keys": "img", "prob": 1.0}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [5.2919216, 5.5854445, 5.29192], + [11.3982, 12.62332, 11.398202], + [14.870525, 17.323769, 14.870527], + ], + [ + [20.413757, 22.767355, 20.413757], + [28.495504, 31.558315, 28.495499], + [29.99236, 34.505676, 29.992361], + ], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - { - "keys": "img", - "sigma1_x": (0.5, 0.75), - "sigma1_y": (0.5, 0.75), - "sigma1_z": (0.5, 0.75), - "sigma2_x": 0.4, - "sigma2_y": 0.4, - "sigma2_z": 0.4, - "prob": 1.0, - }, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[4.1071496, 3.597953, 4.1071477], [10.062014, 9.825114, 10.0620165], [14.698058, 15.818766, 14.698058]], - [[18.211048, 18.16049, 18.211048], [25.155039, 24.56279, 25.155039], [28.801964, 30.381308, 28.801964]], + { + "keys": "img", + "sigma1_x": (0.5, 0.75), + "sigma1_y": (0.5, 0.75), + "sigma1_z": (0.5, 0.75), + "sigma2_x": 0.4, + "sigma2_y": 0.4, + "sigma2_z": 0.4, + "prob": 1.0, + }, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [4.1071496, 3.597953, 4.1071477], + [10.062014, 9.825114, 10.0620165], + [14.698058, 15.818766, 14.698058], + ], + [ + [18.211048, 18.16049, 18.211048], + [25.155039, 24.56279, 25.155039], + [28.801964, 30.381308, 28.801964], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - { - "keys": "img", - "sigma1_x": (0.5, 0.75), - "sigma1_y": (0.5, 0.75), - "sigma1_z": (0.5, 0.75), - "sigma2_x": (0.5, 0.75), - "sigma2_y": (0.5, 0.75), - "sigma2_z": (0.5, 0.75), - "prob": 1.0, - }, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[4.81077, 4.4237204, 4.81077], [12.061236, 12.298177, 12.061236], [17.362553, 19.201174, 17.362553]], - [[21.440754, 22.142393, 21.440754], [30.15308, 30.745445, 30.153086], [33.99255, 36.919838, 33.99255]], + { + "keys": "img", + "sigma1_x": (0.5, 0.75), + "sigma1_y": (0.5, 0.75), + "sigma1_z": (0.5, 0.75), + "sigma2_x": (0.5, 0.75), + "sigma2_y": (0.5, 0.75), + "sigma2_z": (0.5, 0.75), + "prob": 1.0, + }, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [4.81077, 4.4237204, 4.81077], + [12.061236, 12.298177, 12.061236], + [17.362553, 19.201174, 17.362553], + ], + [ + [21.440754, 22.142393, 21.440754], + [30.15308, 30.745445, 30.153086], + [33.99255, 36.919838, 33.99255], + ], + ] + ), ] - ), -] + ) -TEST_CASE_4 = [ - { - "keys": "img", - "sigma1_x": (0.5, 0.75), - "sigma1_y": (0.5, 0.75), - "sigma1_z": (0.5, 0.75), - "sigma2_x": (0.5, 0.75), - "sigma2_y": (0.5, 0.75), - "sigma2_z": (0.5, 0.75), - "approx": "scalespace", - "prob": 1.0, - }, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[4.430213, 3.2278745, 4.4302144], [10.325399, 8.507457, 10.325399], [17.494898, 16.5609, 17.494894]], - [[20.87405, 18.06946, 20.87405], [25.813503, 21.268656, 25.8135], [33.93874, 31.402481, 33.938725]], + { + "keys": "img", + "sigma1_x": (0.5, 0.75), + "sigma1_y": (0.5, 0.75), + "sigma1_z": (0.5, 0.75), + "sigma2_x": (0.5, 0.75), + "sigma2_y": (0.5, 0.75), + "sigma2_z": (0.5, 0.75), + "approx": "scalespace", + "prob": 1.0, + }, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [4.430213, 3.2278745, 4.4302144], + [10.325399, 8.507457, 10.325399], + [17.494898, 16.5609, 17.494894], + ], + [[20.87405, 18.06946, 20.87405], [25.813503, 21.268656, 25.8135], [33.93874, 31.402481, 33.938725]], + ] + ), ] - ), -] + ) class TestRandGaussianSharpend(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): converter = RandGaussianSharpend(**argments) converter.set_random_state(seed=0) result = converter(image) - np.testing.assert_allclose(result["img"], expected_data, rtol=1e-4) + assert_allclose(result["img"], expected_data, rtol=1e-4, type_test=False) if __name__ == "__main__": diff --git a/tests/test_rand_gaussian_smooth.py b/tests/test_rand_gaussian_smooth.py index 889ed7d6d5..b4d4304b67 100644 --- a/tests/test_rand_gaussian_smooth.py +++ b/tests/test_rand_gaussian_smooth.py @@ -15,48 +15,81 @@ from parameterized import parameterized from monai.transforms import RandGaussianSmooth +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"sigma_x": (0.5, 1.5), "prob": 1.0}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( [ - [[0.71806467, 0.9074683, 0.71806467], [1.0718315, 1.3545481, 1.0718315], [1.0337002, 1.306359, 1.0337002]], - [[2.0318885, 2.5678391, 2.0318885], [2.6795788, 3.3863702, 2.6795788], [2.3475242, 2.9667296, 2.3475242]], + {"sigma_x": (0.5, 1.5), "prob": 1.0}, + p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])), + np.array( + [ + [ + [0.71806467, 0.9074683, 0.71806467], + [1.0718315, 1.3545481, 1.0718315], + [1.0337002, 1.306359, 1.0337002], + ], + [ + [2.0318885, 2.5678391, 2.0318885], + [2.6795788, 3.3863702, 2.6795788], + [2.3475242, 2.9667296, 2.3475242], + ], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - {"sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "prob": 1.0}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[0.7686928, 0.9848021, 0.7686928], [1.1474025, 1.4699818, 1.1474024], [1.1065826, 1.4176859, 1.1065826]], - [[2.1751494, 2.7866683, 2.1751497], [2.8685062, 3.6749542, 2.8685062], [2.5130394, 3.219552, 2.5130394]], + {"sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "prob": 1.0}, + p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])), + np.array( + [ + [ + [0.7686928, 0.9848021, 0.7686928], + [1.1474025, 1.4699818, 1.1474024], + [1.1065826, 1.4176859, 1.1065826], + ], + [ + [2.1751494, 2.7866683, 2.1751497], + [2.8685062, 3.6749542, 2.8685062], + [2.5130394, 3.219552, 2.5130394], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - {"sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "approx": "scalespace", "prob": 1.0}, - np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]), - np.array( + TESTS.append( [ - [[0.8128456, 0.96736777, 0.8128456], [1.2742369, 1.5164697, 1.2742369], [1.2800367, 1.5233722, 1.2800368]], - [[2.3825073, 2.8354228, 2.3825073], [3.1855922, 3.7911744, 3.1855922], [2.8496985, 3.391427, 2.8496985]], + {"sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "approx": "scalespace", "prob": 1.0}, + p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])), + np.array( + [ + [ + [0.8128456, 0.96736777, 0.8128456], + [1.2742369, 1.5164697, 1.2742369], + [1.2800367, 1.5233722, 1.2800368], + ], + [ + [2.3825073, 2.8354228, 2.3825073], + [3.1855922, 3.7911744, 3.1855922], + [2.8496985, 3.391427, 2.8496985], + ], + ] + ), ] - ), -] + ) class TestRandGaussianSmooth(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): converter = RandGaussianSmooth(**argments) converter.set_random_state(seed=0) result = converter(image) - np.testing.assert_allclose(result, expected_data, rtol=1e-4) + assert_allclose(result, expected_data, rtol=1e-4, type_test=False) if __name__ == "__main__": diff --git a/tests/test_rand_gaussian_smoothd.py b/tests/test_rand_gaussian_smoothd.py index 2eedc9071c..2c80b978f2 100644 --- a/tests/test_rand_gaussian_smoothd.py +++ b/tests/test_rand_gaussian_smoothd.py @@ -15,48 +15,81 @@ from parameterized import parameterized from monai.transforms import RandGaussianSmoothd +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"keys": "img", "sigma_x": (0.5, 1.5), "prob": 1.0}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( [ - [[0.71806467, 0.9074683, 0.71806467], [1.0718315, 1.3545481, 1.0718315], [1.0337002, 1.306359, 1.0337002]], - [[2.0318885, 2.5678391, 2.0318885], [2.6795788, 3.3863702, 2.6795788], [2.3475242, 2.9667296, 2.3475242]], + {"keys": "img", "sigma_x": (0.5, 1.5), "prob": 1.0}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [0.71806467, 0.9074683, 0.71806467], + [1.0718315, 1.3545481, 1.0718315], + [1.0337002, 1.306359, 1.0337002], + ], + [ + [2.0318885, 2.5678391, 2.0318885], + [2.6795788, 3.3863702, 2.6795788], + [2.3475242, 2.9667296, 2.3475242], + ], + ] + ), ] - ), -] + ) -TEST_CASE_2 = [ - {"keys": "img", "sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "prob": 1.0}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[0.7686928, 0.9848021, 0.7686928], [1.1474025, 1.4699818, 1.1474024], [1.1065826, 1.4176859, 1.1065826]], - [[2.1751494, 2.7866683, 2.1751497], [2.8685062, 3.6749542, 2.8685062], [2.5130394, 3.219552, 2.5130394]], + {"keys": "img", "sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "prob": 1.0}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [0.7686928, 0.9848021, 0.7686928], + [1.1474025, 1.4699818, 1.1474024], + [1.1065826, 1.4176859, 1.1065826], + ], + [ + [2.1751494, 2.7866683, 2.1751497], + [2.8685062, 3.6749542, 2.8685062], + [2.5130394, 3.219552, 2.5130394], + ], + ] + ), ] - ), -] + ) -TEST_CASE_3 = [ - {"keys": "img", "sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "approx": "scalespace", "prob": 1.0}, - {"img": np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]])}, - np.array( + TESTS.append( [ - [[0.8128456, 0.96736777, 0.8128456], [1.2742369, 1.5164697, 1.2742369], [1.2800367, 1.5233722, 1.2800368]], - [[2.3825073, 2.8354228, 2.3825073], [3.1855922, 3.7911744, 3.1855922], [2.8496985, 3.391427, 2.8496985]], + {"keys": "img", "sigma_x": (0.5, 1.5), "sigma_y": (0.5, 1.0), "approx": "scalespace", "prob": 1.0}, + {"img": p(np.array([[[1, 1, 1], [2, 2, 2], [3, 3, 3]], [[4, 4, 4], [5, 5, 5], [6, 6, 6]]]))}, + np.array( + [ + [ + [0.8128456, 0.96736777, 0.8128456], + [1.2742369, 1.5164697, 1.2742369], + [1.2800367, 1.5233722, 1.2800368], + ], + [ + [2.3825073, 2.8354228, 2.3825073], + [3.1855922, 3.7911744, 3.1855922], + [2.8496985, 3.391427, 2.8496985], + ], + ] + ), ] - ), -] + ) class TestRandGaussianSmoothd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): converter = RandGaussianSmoothd(**argments) converter.set_random_state(seed=0) result = converter(image) - np.testing.assert_allclose(result["img"], expected_data, rtol=1e-4) + assert_allclose(result["img"], expected_data, rtol=1e-4, type_test=False) if __name__ == "__main__": From a4779053770d02b434dfd84b8045bf168bc7a8d8 Mon Sep 17 00:00:00 2001 From: Jirka Borovec Date: Sat, 25 Sep 2021 16:39:21 +0200 Subject: [PATCH 53/89] apply pyupgrade (#3026) * apply pyupgrade Signed-off-by: Jirka * exclude monai/_version.py Signed-off-by: Jirka --- .pre-commit-config.yaml | 17 +++++++++++------ monai/apps/datasets.py | 2 +- monai/apps/deepgrow/dataset.py | 10 +++++----- monai/apps/utils.py | 2 +- monai/config/deviceconfig.py | 2 +- monai/data/dataset.py | 2 +- monai/data/dataset_summary.py | 2 +- monai/data/utils.py | 4 ++-- monai/losses/deform.py | 2 +- monai/losses/dice.py | 2 +- monai/losses/focal_loss.py | 2 +- monai/losses/image_dissimilarity.py | 4 ++-- monai/losses/multi_scale.py | 2 +- monai/metrics/regression.py | 4 +--- monai/networks/blocks/activation.py | 4 ++-- monai/networks/blocks/crf.py | 2 +- monai/networks/blocks/dynunet_block.py | 8 ++++---- monai/networks/blocks/fcn.py | 10 +++++----- monai/networks/blocks/localnet_block.py | 10 +++++----- monai/networks/blocks/patchembedding.py | 2 +- monai/networks/blocks/regunet_block.py | 6 +++--- monai/networks/blocks/selfattention.py | 2 +- monai/networks/blocks/squeeze_and_excitation.py | 8 ++++---- monai/networks/blocks/unetr_block.py | 2 +- monai/networks/blocks/warp.py | 4 ++-- monai/networks/layers/simplelayers.py | 2 +- monai/networks/nets/ahnet.py | 16 ++++++++-------- monai/networks/nets/densenet.py | 16 ++++++++-------- monai/networks/nets/dynunet.py | 6 +++--- monai/networks/nets/efficientnet.py | 10 +++++----- monai/networks/nets/highresnet.py | 4 ++-- monai/networks/nets/regunet.py | 6 +++--- monai/networks/nets/resnet.py | 6 +++--- monai/networks/nets/segresnet.py | 2 +- monai/networks/nets/senet.py | 14 +++++++------- monai/networks/nets/transchex.py | 8 ++++---- monai/networks/nets/unetr.py | 2 +- monai/networks/nets/vit.py | 2 +- monai/networks/nets/vnet.py | 10 +++++----- monai/optimizers/lr_finder.py | 2 +- monai/optimizers/lr_scheduler.py | 4 ++-- monai/optimizers/novograd.py | 14 +++++++------- monai/transforms/croppad/array.py | 2 +- monai/transforms/intensity/array.py | 4 ++-- monai/transforms/utils.py | 12 ++++++------ monai/utils/jupyter_utils.py | 2 +- monai/utils/module.py | 2 +- monai/utils/profiling.py | 4 ++-- monai/visualize/img2tensorboard.py | 2 +- tests/clang_format_utils.py | 6 +++--- tests/test_copy_model_state.py | 4 ++-- tests/test_csv_saver.py | 2 +- tests/test_data_stats.py | 2 +- tests/test_data_statsd.py | 2 +- tests/test_efficientnet.py | 2 +- tests/test_generalized_wasserstein_dice_loss.py | 2 +- tests/test_grid_pull.py | 2 +- tests/test_handler_classification_saver.py | 2 +- tests/test_handler_classification_saver_dist.py | 2 +- tests/test_handler_parameter_scheduler.py | 2 +- tests/test_handler_stats.py | 2 +- tests/test_integration_classification_2d.py | 2 +- tests/test_integration_stn.py | 1 - tests/test_inverse.py | 4 ++-- tests/test_inverse_collation.py | 4 ++-- tests/test_invertd.py | 2 +- tests/test_lr_scheduler.py | 6 +++--- tests/test_mmar_download.py | 2 +- tests/test_reg_loss_integration.py | 2 +- tests/test_save_classificationd.py | 2 +- tests/test_seg_loss_integration.py | 2 +- tests/testing_data/cpp_resample_answers.py | 2 +- 72 files changed, 164 insertions(+), 162 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c36c96186c..71f9ac71ef 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,12 +22,17 @@ repos: args: ['--maxkb=1024'] - id: detect-private-key - #- repo: https://github.com/asottile/pyupgrade - # rev: v2.23.2 - # hooks: - # - id: pyupgrade - # args: [--py36-plus] - # name: Upgrade code + - repo: https://github.com/asottile/pyupgrade + rev: v2.27.0 + hooks: + - id: pyupgrade + args: [--py36-plus] + name: Upgrade code + exclude: | + (?x)^( + versioneer.py| + monai/_version.py + )$ #- repo: https://github.com/asottile/yesqa # rev: v1.2.3 diff --git a/monai/apps/datasets.py b/monai/apps/datasets.py index c766914026..cff2df3ac7 100644 --- a/monai/apps/datasets.py +++ b/monai/apps/datasets.py @@ -111,7 +111,7 @@ def _generate_data_list(self, dataset_dir: str) -> List[Dict]: ValueError: When ``section`` is not one of ["training", "validation", "test"]. """ - class_names = sorted((x for x in os.listdir(dataset_dir) if os.path.isdir(os.path.join(dataset_dir, x)))) + class_names = sorted(x for x in os.listdir(dataset_dir) if os.path.isdir(os.path.join(dataset_dir, x))) self.num_class = len(class_names) image_files = [ [ diff --git a/monai/apps/deepgrow/dataset.py b/monai/apps/deepgrow/dataset.py index acaeba0bc3..a6bf59d243 100644 --- a/monai/apps/deepgrow/dataset.py +++ b/monai/apps/deepgrow/dataset.py @@ -97,7 +97,7 @@ def create_dataset( image = os.path.abspath(image) label = os.path.abspath(label) if label else None - logging.info("Image: {}; Label: {}".format(image, label if label else None)) + logging.info(f"Image: {image}; Label: {label if label else None}") data = transforms({image_key: image, label_key: label}) if dimension == 2: data = _save_data_2d( @@ -154,7 +154,7 @@ def _save_data_2d(vol_idx, vol_image, vol_label, dataset_dir, relative_path): if vol_label is not None and np.sum(label) == 0: continue - image_file_prefix = "vol_idx_{:0>4d}_slice_{:0>3d}".format(vol_idx, sid) + image_file_prefix = f"vol_idx_{vol_idx:0>4d}_slice_{sid:0>3d}" image_file = os.path.join(dataset_dir, "images", image_file_prefix) image_file += ".npy" @@ -177,7 +177,7 @@ def _save_data_2d(vol_idx, vol_image, vol_label, dataset_dir, relative_path): unique_labels_count = max(unique_labels_count, len(unique_labels)) for idx in unique_labels: - label_file_prefix = "{}_region_{:0>2d}".format(image_file_prefix, int(idx)) + label_file_prefix = f"{image_file_prefix}_region_{int(idx):0>2d}" label_file = os.path.join(dataset_dir, "labels", label_file_prefix) label_file += ".npy" @@ -226,7 +226,7 @@ def _save_data_3d(vol_idx, vol_image, vol_label, dataset_dir, relative_path): label_count = 0 unique_labels_count = 0 - image_file_prefix = "vol_idx_{:0>4d}".format(vol_idx) + image_file_prefix = f"vol_idx_{vol_idx:0>4d}" image_file = os.path.join(dataset_dir, "images", image_file_prefix) image_file += ".npy" @@ -248,7 +248,7 @@ def _save_data_3d(vol_idx, vol_image, vol_label, dataset_dir, relative_path): unique_labels_count = max(unique_labels_count, len(unique_labels)) for idx in unique_labels: - label_file_prefix = "{}_region_{:0>2d}".format(image_file_prefix, int(idx)) + label_file_prefix = f"{image_file_prefix}_region_{int(idx):0>2d}" label_file = os.path.join(dataset_dir, "labels", label_file_prefix) label_file += ".npy" diff --git a/monai/apps/utils.py b/monai/apps/utils.py index 36fac955fe..c54184d8a9 100644 --- a/monai/apps/utils.py +++ b/monai/apps/utils.py @@ -81,7 +81,7 @@ def update_to(self, b: int = 1, bsize: int = 1, tsize: Optional[int] = None): if not has_tqdm and progress: warnings.warn("tqdm is not installed, will not show the downloading progress bar.") urlretrieve(url, filepath) - except (URLError, HTTPError, ContentTooShortError, IOError) as e: + except (URLError, HTTPError, ContentTooShortError, OSError) as e: print(f"Download failed from {url} to {filepath}.") raise e diff --git a/monai/config/deviceconfig.py b/monai/config/deviceconfig.py index ff45b29531..db786a88ef 100644 --- a/monai/config/deviceconfig.py +++ b/monai/config/deviceconfig.py @@ -122,7 +122,7 @@ def get_system_info() -> OrderedDict: elif output["System"] == "Darwin": _dict_append(output, "Mac version", lambda: platform.mac_ver()[0]) else: - with open("/etc/os-release", "r") as rel_f: + with open("/etc/os-release") as rel_f: linux_ver = re.search(r'PRETTY_NAME="(.*)"', rel_f.read()) if linux_ver: _dict_append(output, "Linux version", lambda: linux_ver.group(1)) diff --git a/monai/data/dataset.py b/monai/data/dataset.py index 2549041fbd..ae1d88a4fe 100644 --- a/monai/data/dataset.py +++ b/monai/data/dataset.py @@ -989,7 +989,7 @@ def __init__(self, datasets: Sequence, transform: Optional[Callable] = None) -> super().__init__(list(datasets), transform=transform) def __len__(self) -> int: - return min((len(dataset) for dataset in self.data)) + return min(len(dataset) for dataset in self.data) def _transform(self, index: int): def to_list(x): diff --git a/monai/data/dataset_summary.py b/monai/data/dataset_summary.py index a8598eb6c8..dfc22f9bc8 100644 --- a/monai/data/dataset_summary.py +++ b/monai/data/dataset_summary.py @@ -60,7 +60,7 @@ def __init__( self.image_key = image_key self.label_key = label_key if image_key: - self.meta_key = "{}_{}".format(image_key, meta_key_postfix) + self.meta_key = f"{image_key}_{meta_key_postfix}" self.all_meta_data: List = [] def collect_meta_data(self): diff --git a/monai/data/utils.py b/monai/data/utils.py index a5cb5057d4..6b577ebdf7 100644 --- a/monai/data/utils.py +++ b/monai/data/utils.py @@ -1029,7 +1029,7 @@ def json_hashing(item) -> bytes: """ # TODO: Find way to hash transforms content as part of the cache cache_key = hashlib.md5(json.dumps(item, sort_keys=True).encode("utf-8")).hexdigest() - return f"{cache_key}".encode("utf-8") + return f"{cache_key}".encode() def pickle_hashing(item, protocol=pickle.HIGHEST_PROTOCOL) -> bytes: @@ -1044,7 +1044,7 @@ def pickle_hashing(item, protocol=pickle.HIGHEST_PROTOCOL) -> bytes: """ cache_key = hashlib.md5(pickle.dumps(sorted_dict(item), protocol=protocol)).hexdigest() - return f"{cache_key}".encode("utf-8") + return f"{cache_key}".encode() def sorted_dict(item, key=None, reverse=False): diff --git a/monai/losses/deform.py b/monai/losses/deform.py index d96fa1440a..b9eb15f798 100644 --- a/monai/losses/deform.py +++ b/monai/losses/deform.py @@ -65,7 +65,7 @@ def __init__( - ``"mean"``: the sum of the output will be divided by the number of elements in the output. - ``"sum"``: the output will be summed. """ - super(BendingEnergyLoss, self).__init__(reduction=LossReduction(reduction).value) + super().__init__(reduction=LossReduction(reduction).value) def forward(self, pred: torch.Tensor) -> torch.Tensor: """ diff --git a/monai/losses/dice.py b/monai/losses/dice.py index 325c5300ea..6bf9680bca 100644 --- a/monai/losses/dice.py +++ b/monai/losses/dice.py @@ -419,7 +419,7 @@ def __init__( wass_loss(pred_score, grnd) # 0 """ - super(GeneralizedWassersteinDiceLoss, self).__init__(reduction=LossReduction(reduction).value) + super().__init__(reduction=LossReduction(reduction).value) if dist_matrix.shape[0] != dist_matrix.shape[1]: raise ValueError(f"dist_matrix must be C x C, got {dist_matrix.shape[0]} x {dist_matrix.shape[1]}.") diff --git a/monai/losses/focal_loss.py b/monai/losses/focal_loss.py index b4b3698e5b..157ce9fd01 100644 --- a/monai/losses/focal_loss.py +++ b/monai/losses/focal_loss.py @@ -67,7 +67,7 @@ def __init__( fl(pred, grnd) """ - super(FocalLoss, self).__init__(reduction=LossReduction(reduction).value) + super().__init__(reduction=LossReduction(reduction).value) self.include_background = include_background self.to_onehot_y = to_onehot_y self.gamma = gamma diff --git a/monai/losses/image_dissimilarity.py b/monai/losses/image_dissimilarity.py index 33a532c387..9eb4540a6b 100644 --- a/monai/losses/image_dissimilarity.py +++ b/monai/losses/image_dissimilarity.py @@ -87,7 +87,7 @@ def __init__( .. deprecated:: 0.6.0 ``ndim`` is deprecated, use ``spatial_dims``. """ - super(LocalNormalizedCrossCorrelationLoss, self).__init__(reduction=LossReduction(reduction).value) + super().__init__(reduction=LossReduction(reduction).value) if ndim is not None: spatial_dims = ndim @@ -196,7 +196,7 @@ def __init__( smooth_nr: a small constant added to the numerator to avoid nan. smooth_dr: a small constant added to the denominator to avoid nan. """ - super(GlobalMutualInformationLoss, self).__init__(reduction=LossReduction(reduction).value) + super().__init__(reduction=LossReduction(reduction).value) if num_bins <= 0: raise ValueError("num_bins must > 0, got {num_bins}") bin_centers = torch.linspace(0.0, 1.0, num_bins) # (num_bins,) diff --git a/monai/losses/multi_scale.py b/monai/losses/multi_scale.py index 6f9326420b..0e60cda362 100644 --- a/monai/losses/multi_scale.py +++ b/monai/losses/multi_scale.py @@ -67,7 +67,7 @@ def __init__( scales: list of scalars or None, if None, do not apply any scaling. kernel: gaussian or cauchy. """ - super(MultiScaleLoss, self).__init__(reduction=LossReduction(reduction).value) + super().__init__(reduction=LossReduction(reduction).value) if kernel not in kernel_fn_dict.keys(): raise ValueError(f"got unsupported kernel type: {kernel}", "only support gaussian and cauchy") self.kernel_fn = kernel_fn_dict[kernel] diff --git a/monai/metrics/regression.py b/monai/metrics/regression.py index a2a2f0853d..2bf565f543 100644 --- a/monai/metrics/regression.py +++ b/monai/metrics/regression.py @@ -57,9 +57,7 @@ def aggregate(self): # type: ignore def _check_shape(self, y_pred: torch.Tensor, y: torch.Tensor) -> None: if y_pred.shape != y.shape: - raise ValueError( - "y_pred and y shapes dont match, received y_pred: [{}] and y: [{}]".format(y_pred.shape, y.shape) - ) + raise ValueError(f"y_pred and y shapes dont match, received y_pred: [{y_pred.shape}] and y: [{y.shape}]") # also check if there is atleast one non-batch dimension i.e. num_dims >= 2 if len(y_pred.shape) < 2: diff --git a/monai/networks/blocks/activation.py b/monai/networks/blocks/activation.py index 9841dbd060..b136eb7f1f 100644 --- a/monai/networks/blocks/activation.py +++ b/monai/networks/blocks/activation.py @@ -122,7 +122,7 @@ class MemoryEfficientSwish(nn.Module): """ def __init__(self, inplace: bool = False): - super(MemoryEfficientSwish, self).__init__() + super().__init__() # inplace only works when using torch.nn.functional.silu self.inplace = inplace @@ -156,7 +156,7 @@ class Mish(nn.Module): """ def __init__(self, inplace: bool = False): - super(Mish, self).__init__() + super().__init__() # inplace only works when using torch.nn.functional.mish self.inplace = inplace diff --git a/monai/networks/blocks/crf.py b/monai/networks/blocks/crf.py index 49ff5bcd04..21da3bb74f 100644 --- a/monai/networks/blocks/crf.py +++ b/monai/networks/blocks/crf.py @@ -57,7 +57,7 @@ def __init__( compatibility_matrix: a matrix describing class compatibility, should be NxN where N is the number of classes. """ - super(CRF, self).__init__() + super().__init__() self.iterations = iterations self.bilateral_weight = bilateral_weight self.gaussian_weight = gaussian_weight diff --git a/monai/networks/blocks/dynunet_block.py b/monai/networks/blocks/dynunet_block.py index fc37fc8999..24fb16018e 100644 --- a/monai/networks/blocks/dynunet_block.py +++ b/monai/networks/blocks/dynunet_block.py @@ -47,7 +47,7 @@ def __init__( norm_name: Union[Tuple, str], dropout: Optional[Union[Tuple, str, float]] = None, ): - super(UnetResBlock, self).__init__() + super().__init__() self.conv1 = get_conv_layer( spatial_dims, in_channels, @@ -126,7 +126,7 @@ def __init__( norm_name: Union[Tuple, str], dropout: Optional[Union[Tuple, str, float]] = None, ): - super(UnetBasicBlock, self).__init__() + super().__init__() self.conv1 = get_conv_layer( spatial_dims, in_channels, @@ -188,7 +188,7 @@ def __init__( norm_name: Union[Tuple, str], dropout: Optional[Union[Tuple, str, float]] = None, ): - super(UnetUpBlock, self).__init__() + super().__init__() upsample_stride = upsample_kernel_size self.transp_conv = get_conv_layer( spatial_dims, @@ -222,7 +222,7 @@ class UnetOutBlock(nn.Module): def __init__( self, spatial_dims: int, in_channels: int, out_channels: int, dropout: Optional[Union[Tuple, str, float]] = None ): - super(UnetOutBlock, self).__init__() + super().__init__() self.conv = get_conv_layer( spatial_dims, in_channels, out_channels, kernel_size=1, stride=1, dropout=dropout, bias=True, conv_only=True ) diff --git a/monai/networks/blocks/fcn.py b/monai/networks/blocks/fcn.py index 0c4fa3e320..1170dfa7e3 100644 --- a/monai/networks/blocks/fcn.py +++ b/monai/networks/blocks/fcn.py @@ -36,7 +36,7 @@ def __init__(self, inplanes: int, planes: int, ks: int = 7): planes: number of output channels. ks: kernel size for one dimension. Defaults to 7. """ - super(GCN, self).__init__() + super().__init__() conv2d_type: Type[nn.Conv2d] = Conv[Conv.CONV, 2] self.conv_l1 = conv2d_type(in_channels=inplanes, out_channels=planes, kernel_size=(ks, 1), padding=(ks // 2, 0)) @@ -67,7 +67,7 @@ def __init__(self, planes: int): Args: planes: number of input channels. """ - super(Refine, self).__init__() + super().__init__() relu_type: Type[nn.ReLU] = Act[Act.RELU] conv2d_type: Type[nn.Conv2d] = Conv[Conv.CONV, 2] @@ -116,7 +116,7 @@ class FCN(nn.Module): def __init__( self, out_channels: int = 1, upsample_mode: str = "bilinear", pretrained: bool = True, progress: bool = True ): - super(FCN, self).__init__() + super().__init__() conv2d_type: Type[nn.Conv2d] = Conv[Conv.CONV, 2] @@ -231,7 +231,7 @@ def __init__( pretrained: bool = True, progress: bool = True, ): - super(MCFCN, self).__init__( + super().__init__( out_channels=out_channels, upsample_mode=upsample_mode, pretrained=pretrained, progress=progress ) @@ -251,4 +251,4 @@ def forward(self, x: torch.Tensor): x: in shape (batch, in_channels, spatial_1, spatial_2). """ x = self.init_proj(x) - return super(MCFCN, self).forward(x) + return super().forward(x) diff --git a/monai/networks/blocks/localnet_block.py b/monai/networks/blocks/localnet_block.py index 4e008b128a..844c5c0eea 100644 --- a/monai/networks/blocks/localnet_block.py +++ b/monai/networks/blocks/localnet_block.py @@ -90,7 +90,7 @@ def __init__( out_channels: int, kernel_size: Union[Sequence[int], int], ) -> None: - super(ResidualBlock, self).__init__() + super().__init__() if in_channels != out_channels: raise ValueError( f"expecting in_channels == out_channels, " f"got in_channels={in_channels}, out_channels={out_channels}" @@ -119,7 +119,7 @@ def __init__( in_channels: int, out_channels: int, ) -> None: - super(LocalNetResidualBlock, self).__init__() + super().__init__() if in_channels != out_channels: raise ValueError( f"expecting in_channels == out_channels, " f"got in_channels={in_channels}, out_channels={out_channels}" @@ -165,7 +165,7 @@ def __init__( Raises: NotImplementedError: when ``kernel_size`` is even """ - super(LocalNetDownSampleBlock, self).__init__() + super().__init__() self.conv_block = get_conv_block( spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size ) @@ -225,7 +225,7 @@ def __init__( Raises: ValueError: when ``in_channels != 2 * out_channels`` """ - super(LocalNetUpSampleBlock, self).__init__() + super().__init__() self.deconv_block = get_deconv_block( spatial_dims=spatial_dims, in_channels=in_channels, @@ -309,7 +309,7 @@ def __init__( act: activation type and arguments. Defaults to ReLU. kernel_initializer: kernel initializer. Defaults to None. """ - super(LocalNetFeatureExtractorBlock, self).__init__() + super().__init__() self.conv_block = get_conv_block( spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels, act=act, norm=None ) diff --git a/monai/networks/blocks/patchembedding.py b/monai/networks/blocks/patchembedding.py index c1fcfa9af7..8170106dec 100644 --- a/monai/networks/blocks/patchembedding.py +++ b/monai/networks/blocks/patchembedding.py @@ -62,7 +62,7 @@ def __init__( """ - super(PatchEmbeddingBlock, self).__init__() + super().__init__() if not (0 <= dropout_rate <= 1): raise ValueError("dropout_rate should be between 0 and 1.") diff --git a/monai/networks/blocks/regunet_block.py b/monai/networks/blocks/regunet_block.py index 29fa3d5d85..18770a0d48 100644 --- a/monai/networks/blocks/regunet_block.py +++ b/monai/networks/blocks/regunet_block.py @@ -100,7 +100,7 @@ def __init__( num_layers: number of layers inside the block kernel_size: kernel_size """ - super(RegistrationResidualConvBlock, self).__init__() + super().__init__() self.num_layers = num_layers self.layers = nn.ModuleList( [ @@ -158,7 +158,7 @@ def __init__( channels: channels pooling: use MaxPool if True, strided conv if False """ - super(RegistrationDownSampleBlock, self).__init__() + super().__init__() if pooling: self.layer = Pool[Pool.MAX, spatial_dims](kernel_size=2) else: @@ -235,7 +235,7 @@ def __init__( kernel_initializer: kernel initializer activation: kernel activation function """ - super(RegistrationExtractionBlock, self).__init__() + super().__init__() self.extract_levels = extract_levels self.max_level = max(extract_levels) self.layers = nn.ModuleList( diff --git a/monai/networks/blocks/selfattention.py b/monai/networks/blocks/selfattention.py index 9dc45cccc8..649f757bf8 100644 --- a/monai/networks/blocks/selfattention.py +++ b/monai/networks/blocks/selfattention.py @@ -37,7 +37,7 @@ def __init__( """ - super(SABlock, self).__init__() + super().__init__() if not (0 <= dropout_rate <= 1): raise ValueError("dropout_rate should be between 0 and 1.") diff --git a/monai/networks/blocks/squeeze_and_excitation.py b/monai/networks/blocks/squeeze_and_excitation.py index 76cbbb5037..46cd48d6aa 100644 --- a/monai/networks/blocks/squeeze_and_excitation.py +++ b/monai/networks/blocks/squeeze_and_excitation.py @@ -50,7 +50,7 @@ def __init__( :py:class:`monai.networks.layers.Act` """ - super(ChannelSELayer, self).__init__() + super().__init__() self.add_residual = add_residual @@ -181,7 +181,7 @@ def __init__( :py:class:`monai.networks.blocks.ChannelSELayer` """ - super(SEBlock, self).__init__() + super().__init__() if not conv_param_1: conv_param_1 = {"kernel_size": 1, "norm": Norm.BATCH, "act": ("relu", {"inplace": True})} @@ -264,7 +264,7 @@ def __init__( } conv_param_3 = {"strides": 1, "kernel_size": 1, "act": None, "norm": Norm.BATCH, "bias": False} - super(SEBottleneck, self).__init__( + super().__init__( spatial_dims=spatial_dims, in_channels=inplanes, n_chns_1=planes * 2, @@ -315,7 +315,7 @@ def __init__( } conv_param_3 = {"strides": 1, "kernel_size": 1, "act": None, "norm": Norm.BATCH, "bias": False} - super(SEResNetBottleneck, self).__init__( + super().__init__( spatial_dims=spatial_dims, in_channels=inplanes, n_chns_1=planes, diff --git a/monai/networks/blocks/unetr_block.py b/monai/networks/blocks/unetr_block.py index a0852d05e0..ccc055e889 100644 --- a/monai/networks/blocks/unetr_block.py +++ b/monai/networks/blocks/unetr_block.py @@ -46,7 +46,7 @@ def __init__( """ - super(UnetrUpBlock, self).__init__() + super().__init__() upsample_stride = upsample_kernel_size self.transp_conv = get_conv_layer( spatial_dims, diff --git a/monai/networks/blocks/warp.py b/monai/networks/blocks/warp.py index d916c026ff..ccdfdb964e 100644 --- a/monai/networks/blocks/warp.py +++ b/monai/networks/blocks/warp.py @@ -50,7 +50,7 @@ def __init__( See also: :py:class:`monai.networks.layers.grid_pull` """ - super(Warp, self).__init__() + super().__init__() # resolves _interp_mode for different methods if USE_COMPILED: @@ -148,7 +148,7 @@ def __init__( mode=GridSampleMode.BILINEAR.value, padding_mode=GridSamplePadMode.ZEROS.value, ): - super(DVF2DDF, self).__init__() + super().__init__() if num_steps <= 0: raise ValueError(f"expecting positive num_steps, got {num_steps}") self.num_steps = num_steps diff --git a/monai/networks/layers/simplelayers.py b/monai/networks/layers/simplelayers.py index 3acf50d210..0f9f78b4be 100644 --- a/monai/networks/layers/simplelayers.py +++ b/monai/networks/layers/simplelayers.py @@ -455,7 +455,7 @@ class LLTM(nn.Module): """ def __init__(self, input_features: int, state_size: int): - super(LLTM, self).__init__() + super().__init__() self.input_features = input_features self.state_size = state_size self.weights = nn.Parameter(torch.empty(3 * state_size, input_features + state_size)) diff --git a/monai/networks/nets/ahnet.py b/monai/networks/nets/ahnet.py index 5ca6813efe..0a3f938b96 100644 --- a/monai/networks/nets/ahnet.py +++ b/monai/networks/nets/ahnet.py @@ -35,7 +35,7 @@ def __init__( downsample: Optional[nn.Sequential] = None, ) -> None: - super(Bottleneck3x3x1, self).__init__() + super().__init__() conv_type = Conv[Conv.CONV, spatial_dims] norm_type: Type[Union[nn.BatchNorm2d, nn.BatchNorm3d]] = Norm[Norm.BATCH, spatial_dims] @@ -87,7 +87,7 @@ def forward(self, x): class Projection(nn.Sequential): def __init__(self, spatial_dims: int, num_input_features: int, num_output_features: int): - super(Projection, self).__init__() + super().__init__() conv_type = Conv[Conv.CONV, spatial_dims] norm_type: Type[Union[nn.BatchNorm2d, nn.BatchNorm3d]] = Norm[Norm.BATCH, spatial_dims] @@ -108,7 +108,7 @@ def __init__( growth_rate: int, dropout_prob: float, ): - super(DenseBlock, self).__init__() + super().__init__() for i in range(num_layers): layer = Pseudo3DLayer( spatial_dims, num_input_features + i * growth_rate, growth_rate, bn_size, dropout_prob @@ -120,7 +120,7 @@ class UpTransition(nn.Sequential): def __init__( self, spatial_dims: int, num_input_features: int, num_output_features: int, upsample_mode: str = "transpose" ): - super(UpTransition, self).__init__() + super().__init__() conv_type = Conv[Conv.CONV, spatial_dims] norm_type: Type[Union[nn.BatchNorm2d, nn.BatchNorm3d]] = Norm[Norm.BATCH, spatial_dims] @@ -145,7 +145,7 @@ class Final(nn.Sequential): def __init__( self, spatial_dims: int, num_input_features: int, num_output_features: int, upsample_mode: str = "transpose" ): - super(Final, self).__init__() + super().__init__() conv_type = Conv[Conv.CONV, spatial_dims] norm_type: Type[Union[nn.BatchNorm2d, nn.BatchNorm3d]] = Norm[Norm.BATCH, spatial_dims] @@ -178,7 +178,7 @@ def __init__( class Pseudo3DLayer(nn.Module): def __init__(self, spatial_dims: int, num_input_features: int, growth_rate: int, bn_size: int, dropout_prob: float): - super(Pseudo3DLayer, self).__init__() + super().__init__() # 1x1x1 conv_type = Conv[Conv.CONV, spatial_dims] @@ -244,7 +244,7 @@ def forward(self, x): class PSP(nn.Module): def __init__(self, spatial_dims: int, psp_block_num: int, in_ch: int, upsample_mode: str = "transpose"): - super(PSP, self).__init__() + super().__init__() self.up_modules = nn.ModuleList() conv_type = Conv[Conv.CONV, spatial_dims] pool_type: Type[Union[nn.MaxPool2d, nn.MaxPool3d]] = Pool[Pool.MAX, spatial_dims] @@ -356,7 +356,7 @@ def __init__( progress: bool = True, ): self.inplanes = 64 - super(AHNet, self).__init__() + super().__init__() conv_type = Conv[Conv.CONV, spatial_dims] conv_trans_type = Conv[Conv.CONVTRANS, spatial_dims] diff --git a/monai/networks/nets/densenet.py b/monai/networks/nets/densenet.py index dc2c07bb12..6a2c2fb4e1 100644 --- a/monai/networks/nets/densenet.py +++ b/monai/networks/nets/densenet.py @@ -62,7 +62,7 @@ def __init__( act: activation type and arguments. Defaults to relu. norm: feature normalization type and arguments. Defaults to batch norm. """ - super(_DenseLayer, self).__init__() + super().__init__() out_channels = bn_size * growth_rate conv_type: Callable = Conv[Conv.CONV, spatial_dims] @@ -110,7 +110,7 @@ def __init__( act: activation type and arguments. Defaults to relu. norm: feature normalization type and arguments. Defaults to batch norm. """ - super(_DenseBlock, self).__init__() + super().__init__() for i in range(layers): layer = _DenseLayer(spatial_dims, in_channels, growth_rate, bn_size, dropout_prob, act=act, norm=norm) in_channels += growth_rate @@ -134,7 +134,7 @@ def __init__( act: activation type and arguments. Defaults to relu. norm: feature normalization type and arguments. Defaults to batch norm. """ - super(_Transition, self).__init__() + super().__init__() conv_type: Callable = Conv[Conv.CONV, spatial_dims] pool_type: Callable = Pool[Pool.AVG, spatial_dims] @@ -178,7 +178,7 @@ def __init__( dropout_prob: float = 0.0, ) -> None: - super(DenseNet, self).__init__() + super().__init__() conv_type: Type[Union[nn.Conv1d, nn.Conv2d, nn.Conv3d]] = Conv[Conv.CONV, spatial_dims] pool_type: Type[Union[nn.MaxPool1d, nn.MaxPool2d, nn.MaxPool3d]] = Pool[Pool.MAX, spatial_dims] @@ -299,7 +299,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(DenseNet121, self).__init__( + super().__init__( init_features=init_features, growth_rate=growth_rate, block_config=block_config, @@ -326,7 +326,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(DenseNet169, self).__init__( + super().__init__( init_features=init_features, growth_rate=growth_rate, block_config=block_config, @@ -353,7 +353,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(DenseNet201, self).__init__( + super().__init__( init_features=init_features, growth_rate=growth_rate, block_config=block_config, @@ -380,7 +380,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(DenseNet264, self).__init__( + super().__init__( init_features=init_features, growth_rate=growth_rate, block_config=block_config, diff --git a/monai/networks/nets/dynunet.py b/monai/networks/nets/dynunet.py index d65cd9f5f4..fb1d55d2cc 100644 --- a/monai/networks/nets/dynunet.py +++ b/monai/networks/nets/dynunet.py @@ -122,7 +122,7 @@ def __init__( deep_supr_num: int = 1, res_block: bool = False, ): - super(DynUNet, self).__init__() + super().__init__() self.spatial_dims = spatial_dims self.in_channels = in_channels self.out_channels = out_channels @@ -193,11 +193,11 @@ def check_kernel_stride(self): for idx, k_i in enumerate(kernels): kernel, stride = k_i, strides[idx] if not isinstance(kernel, int): - error_msg = "length of kernel_size in block {} should be the same as spatial_dims.".format(idx) + error_msg = f"length of kernel_size in block {idx} should be the same as spatial_dims." if len(kernel) != self.spatial_dims: raise AssertionError(error_msg) if not isinstance(stride, int): - error_msg = "length of stride in block {} should be the same as spatial_dims.".format(idx) + error_msg = f"length of stride in block {idx} should be the same as spatial_dims." if len(stride) != self.spatial_dims: raise AssertionError(error_msg) diff --git a/monai/networks/nets/efficientnet.py b/monai/networks/nets/efficientnet.py index 453916758a..7de7e4e521 100644 --- a/monai/networks/nets/efficientnet.py +++ b/monai/networks/nets/efficientnet.py @@ -534,7 +534,7 @@ def __init__( weight_coeff, depth_coeff, image_size, dropout_rate, dropconnect_rate = efficientnet_params[model_name] # create model and initialize random weights - super(EfficientNetBN, self).__init__( + super().__init__( blocks_args_str=blocks_args_str, spatial_dims=spatial_dims, in_channels=in_channels, @@ -594,7 +594,7 @@ def __init__( weight_coeff, depth_coeff, image_size, dropout_rate, dropconnect_rate = efficientnet_params[model_name] # create model and initialize random weights - super(EfficientNetBNFeatures, self).__init__( + super().__init__( blocks_args_str=blocks_args_str, spatial_dims=spatial_dims, in_channels=in_channels, @@ -677,7 +677,7 @@ def drop_connect(inputs: torch.Tensor, p: float, training: bool) -> torch.Tensor output: output tensor after applying drop connection. """ if p < 0.0 or p > 1.0: - raise ValueError("p must be in range of [0, 1], found {}".format(p)) + raise ValueError(f"p must be in range of [0, 1], found {p}") # eval mode: drop_connect is switched off - so return input without modifying if not training: @@ -708,7 +708,7 @@ def _load_state_dict(model: nn.Module, arch: str, progress: bool, adv_prop: bool arch = arch.split("efficientnet-")[-1] + "-ap" model_url = look_up_option(arch, url_map, None) if model_url is None: - print("pretrained weights of {} is not provided".format(arch)) + print(f"pretrained weights of {arch} is not provided") else: # load state dict from url model_url = url_map[arch] @@ -852,7 +852,7 @@ def _calculate_output_image_size(input_image_size: List[int], stride: Union[int, if isinstance(stride, tuple): all_strides_equal = all(stride[0] == s for s in stride) if not all_strides_equal: - raise ValueError("unequal strides are not possible, got {}".format(stride)) + raise ValueError(f"unequal strides are not possible, got {stride}") stride = stride[0] diff --git a/monai/networks/nets/highresnet.py b/monai/networks/nets/highresnet.py index cd0950804d..2937cda32a 100644 --- a/monai/networks/nets/highresnet.py +++ b/monai/networks/nets/highresnet.py @@ -70,7 +70,7 @@ def __init__( ValueError: When ``channel_matching=pad`` and ``in_channels > out_channels``. Incompatible values. """ - super(HighResBlock, self).__init__() + super().__init__() self.chn_pad = ChannelPad( spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels, mode=channel_matching ) @@ -146,7 +146,7 @@ def __init__( channel_matching: Union[ChannelMatching, str] = ChannelMatching.PAD, ) -> None: - super(HighResNet, self).__init__() + super().__init__() blocks = nn.ModuleList() # initial conv layer diff --git a/monai/networks/nets/regunet.py b/monai/networks/nets/regunet.py index 4cf747f650..b800364c67 100644 --- a/monai/networks/nets/regunet.py +++ b/monai/networks/nets/regunet.py @@ -67,7 +67,7 @@ def __init__( concat_skip: when up-sampling, concatenate skipped tensor if true, otherwise use addition encode_kernel_sizes: kernel size for down-sampling """ - super(RegUNet, self).__init__() + super().__init__() if not extract_levels: extract_levels = (depth,) if max(extract_levels) != depth: @@ -262,7 +262,7 @@ def __init__( decode_size: List[int], in_channels: int, ): - super(AffineHead, self).__init__() + super().__init__() self.spatial_dims = spatial_dims if spatial_dims == 2: in_features = in_channels * decode_size[0] * decode_size[1] @@ -371,7 +371,7 @@ def __init__( in_channels: int, out_channels: int, ): - super(AdditiveUpSampleBlock, self).__init__() + super().__init__() self.deconv = get_deconv_block(spatial_dims=spatial_dims, in_channels=in_channels, out_channels=out_channels) def forward(self, x: torch.Tensor) -> torch.Tensor: diff --git a/monai/networks/nets/resnet.py b/monai/networks/nets/resnet.py index 49d4f3d2fa..1086a21e46 100644 --- a/monai/networks/nets/resnet.py +++ b/monai/networks/nets/resnet.py @@ -59,7 +59,7 @@ def __init__( stride: stride to use for first conv layer. downsample: which downsample layer to use. """ - super(ResNetBlock, self).__init__() + super().__init__() conv_type: Callable = Conv[Conv.CONV, spatial_dims] norm_type: Callable = Norm[Norm.BATCH, spatial_dims] @@ -111,7 +111,7 @@ def __init__( downsample: which downsample layer to use. """ - super(ResNetBottleneck, self).__init__() + super().__init__() conv_type: Callable = Conv[Conv.CONV, spatial_dims] norm_type: Callable = Norm[Norm.BATCH, spatial_dims] @@ -192,7 +192,7 @@ def __init__( n_classes: Optional[int] = None, ) -> None: - super(ResNet, self).__init__() + super().__init__() # in case the new num_classes is default but you still call deprecated n_classes if n_classes is not None and num_classes == 400: num_classes = n_classes diff --git a/monai/networks/nets/segresnet.py b/monai/networks/nets/segresnet.py index 8be562aadd..cd7e89c7e0 100644 --- a/monai/networks/nets/segresnet.py +++ b/monai/networks/nets/segresnet.py @@ -226,7 +226,7 @@ def __init__( blocks_up: tuple = (1, 1, 1), upsample_mode: Union[UpsampleMode, str] = UpsampleMode.NONTRAINABLE, ): - super(SegResNetVAE, self).__init__( + super().__init__( spatial_dims=spatial_dims, init_filters=init_filters, in_channels=in_channels, diff --git a/monai/networks/nets/senet.py b/monai/networks/nets/senet.py index 65089afc2c..34582010e9 100644 --- a/monai/networks/nets/senet.py +++ b/monai/networks/nets/senet.py @@ -87,7 +87,7 @@ def __init__( num_classes: int = 1000, ) -> None: - super(SENet, self).__init__() + super().__init__() relu_type: Type[nn.ReLU] = Act[Act.RELU] conv_type: Type[Union[nn.Conv1d, nn.Conv2d, nn.Conv3d]] = Conv[Conv.CONV, spatial_dims] @@ -317,7 +317,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(SENet154, self).__init__( + super().__init__( block=SEBottleneck, layers=layers, groups=groups, @@ -345,7 +345,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(SEResNet50, self).__init__( + super().__init__( block=SEResNetBottleneck, layers=layers, groups=groups, @@ -378,7 +378,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(SEResNet101, self).__init__( + super().__init__( block=SEResNetBottleneck, layers=layers, groups=groups, @@ -410,7 +410,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(SEResNet152, self).__init__( + super().__init__( block=SEResNetBottleneck, layers=layers, groups=groups, @@ -443,7 +443,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(SEResNext50, self).__init__( + super().__init__( block=SEResNeXtBottleneck, layers=layers, groups=groups, @@ -477,7 +477,7 @@ def __init__( progress: bool = True, **kwargs, ) -> None: - super(SEResNext101, self).__init__( + super().__init__( block=SEResNeXtBottleneck, layers=layers, groups=groups, diff --git a/monai/networks/nets/transchex.py b/monai/networks/nets/transchex.py index 1ec5039e6a..2e161cc95f 100644 --- a/monai/networks/nets/transchex.py +++ b/monai/networks/nets/transchex.py @@ -48,7 +48,7 @@ class BertPreTrainedModel(nn.Module): """ def __init__(self, *inputs, **kwargs) -> None: - super(BertPreTrainedModel, self).__init__() + super().__init__() def init_bert_weights(self, module): if isinstance(module, (nn.Linear, nn.Embedding)): @@ -176,7 +176,7 @@ class BertOutput(nn.Module): """ def __init__(self, config) -> None: - super(BertOutput, self).__init__() + super().__init__() self.dense = nn.Linear(config.hidden_size, config.hidden_size) self.LayerNorm = torch.nn.LayerNorm(config.hidden_size, eps=1e-12) self.dropout = nn.Dropout(config.hidden_dropout_prob) @@ -217,7 +217,7 @@ def __init__( self, hidden_size, ) -> None: - super(Pooler, self).__init__() + super().__init__() self.dense = nn.Linear(hidden_size, hidden_size) self.activation = nn.Tanh() @@ -331,7 +331,7 @@ def __init__( drop_out=0.2) """ - super(Transchex, self).__init__() + super().__init__() bert_config = { "attention_probs_dropout_prob": attention_probs_dropout_prob, "classifier_dropout": None, diff --git a/monai/networks/nets/unetr.py b/monai/networks/nets/unetr.py index 9990cb6643..b75bc15892 100644 --- a/monai/networks/nets/unetr.py +++ b/monai/networks/nets/unetr.py @@ -70,7 +70,7 @@ def __init__( """ - super(UNETR, self).__init__() + super().__init__() if not (0 <= dropout_rate <= 1): raise ValueError("dropout_rate should be between 0 and 1.") diff --git a/monai/networks/nets/vit.py b/monai/networks/nets/vit.py index 35e05727e2..2707e5ad1d 100644 --- a/monai/networks/nets/vit.py +++ b/monai/networks/nets/vit.py @@ -70,7 +70,7 @@ def __init__( """ - super(ViT, self).__init__() + super().__init__() if not (0 <= dropout_rate <= 1): raise ValueError("dropout_rate should be between 0 and 1.") diff --git a/monai/networks/nets/vnet.py b/monai/networks/nets/vnet.py index c7eea67e62..1b1d3bfba7 100644 --- a/monai/networks/nets/vnet.py +++ b/monai/networks/nets/vnet.py @@ -30,7 +30,7 @@ def get_acti_layer(act: Union[Tuple[str, Dict], str], nchan: int = 0): class LUConv(nn.Module): def __init__(self, spatial_dims: int, nchan: int, act: Union[Tuple[str, Dict], str], bias: bool = False): - super(LUConv, self).__init__() + super().__init__() self.act_function = get_acti_layer(act, nchan) self.conv_block = Convolution( @@ -65,7 +65,7 @@ def __init__( act: Union[Tuple[str, Dict], str], bias: bool = False, ): - super(InputTransition, self).__init__() + super().__init__() if 16 % in_channels != 0: raise ValueError(f"16 should be divisible by in_channels, got in_channels={in_channels}.") @@ -102,7 +102,7 @@ def __init__( dropout_dim: int = 3, bias: bool = False, ): - super(DownTransition, self).__init__() + super().__init__() conv_type: Type[Union[nn.Conv2d, nn.Conv3d]] = Conv[Conv.CONV, spatial_dims] norm_type: Type[Union[nn.BatchNorm2d, nn.BatchNorm3d]] = Norm[Norm.BATCH, spatial_dims] @@ -138,7 +138,7 @@ def __init__( dropout_prob: Optional[float] = None, dropout_dim: int = 3, ): - super(UpTransition, self).__init__() + super().__init__() conv_trans_type: Type[Union[nn.ConvTranspose2d, nn.ConvTranspose3d]] = Conv[Conv.CONVTRANS, spatial_dims] norm_type: Type[Union[nn.BatchNorm2d, nn.BatchNorm3d]] = Norm[Norm.BATCH, spatial_dims] @@ -174,7 +174,7 @@ def __init__( act: Union[Tuple[str, Dict], str], bias: bool = False, ): - super(OutputTransition, self).__init__() + super().__init__() conv_type: Type[Union[nn.Conv2d, nn.Conv3d]] = Conv[Conv.CONV, spatial_dims] diff --git a/monai/optimizers/lr_finder.py b/monai/optimizers/lr_finder.py index 49d4427b3d..08395afb53 100644 --- a/monai/optimizers/lr_finder.py +++ b/monai/optimizers/lr_finder.py @@ -120,7 +120,7 @@ def __iter__(self): def __next__(self): self.run_counter += 1 - return super(ValDataLoaderIter, self).__next__() + return super().__next__() def default_image_extractor(x: Any) -> torch.Tensor: diff --git a/monai/optimizers/lr_scheduler.py b/monai/optimizers/lr_scheduler.py index 9416b583f7..5ad52c5286 100644 --- a/monai/optimizers/lr_scheduler.py +++ b/monai/optimizers/lr_scheduler.py @@ -33,7 +33,7 @@ def __init__(self, optimizer: Optimizer, end_lr: float, num_iter: int, last_epoc """ self.end_lr = end_lr self.num_iter = num_iter - super(_LRSchedulerMONAI, self).__init__(optimizer, last_epoch) + super().__init__(optimizer, last_epoch) class LinearLR(_LRSchedulerMONAI): @@ -77,7 +77,7 @@ def __init__( self.warmup_steps = warmup_steps self.t_total = t_total self.cycles = cycles - super(WarmupCosineSchedule, self).__init__(optimizer, self.lr_lambda, last_epoch) + super().__init__(optimizer, self.lr_lambda, last_epoch) def lr_lambda(self, step): if step < self.warmup_steps: diff --git a/monai/optimizers/novograd.py b/monai/optimizers/novograd.py index 62e42cc9ab..6ca011d9d4 100644 --- a/monai/optimizers/novograd.py +++ b/monai/optimizers/novograd.py @@ -45,15 +45,15 @@ def __init__( amsgrad: bool = False, ): if 0.0 > lr: - raise ValueError("Invalid learning rate: {}".format(lr)) + raise ValueError(f"Invalid learning rate: {lr}") if 0.0 > eps: - raise ValueError("Invalid epsilon value: {}".format(eps)) + raise ValueError(f"Invalid epsilon value: {eps}") if not 0.0 <= betas[0] < 1.0: - raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) + raise ValueError(f"Invalid beta parameter at index 0: {betas[0]}") if not 0.0 <= betas[1] < 1.0: - raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) + raise ValueError(f"Invalid beta parameter at index 1: {betas[1]}") if 0.0 > weight_decay: - raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) + raise ValueError(f"Invalid weight_decay value: {weight_decay}") defaults = dict( lr=lr, betas=betas, @@ -63,10 +63,10 @@ def __init__( amsgrad=amsgrad, ) - super(Novograd, self).__init__(params, defaults) + super().__init__(params, defaults) def __setstate__(self, state): - super(Novograd, self).__setstate__(state) + super().__setstate__(state) for group in self.param_groups: group.setdefault("amsgrad", False) diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index 276ba6104d..1c3bbf6833 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -531,7 +531,7 @@ def randomize(self, img_size: Sequence[int]) -> None: max_size = img_size if self.max_roi_size is None else fall_back_tuple(self.max_roi_size, img_size) if any(i > j for i, j in zip(self._size, max_size)): raise ValueError(f"min ROI size: {self._size} is bigger than max ROI size: {max_size}.") - self._size = tuple((self.R.randint(low=self._size[i], high=max_size[i] + 1) for i in range(len(img_size)))) + self._size = tuple(self.R.randint(low=self._size[i], high=max_size[i] + 1) for i in range(len(img_size))) if self.random_center: valid_size = get_valid_patch_size(img_size, self._size) self._slices = (slice(None),) + get_random_patch(img_size, valid_size, self.R) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 7b73aa63b1..1985399a2e 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1142,10 +1142,10 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: img_t: torch.Tensor img_t, *_ = convert_data_type(img, torch.Tensor, dtype=torch.float32) # type: ignore - gf1, gf2 = [ + gf1, gf2 = ( GaussianFilter(img_t.ndim - 1, sigma, approx=self.approx).to(img_t.device) for sigma in (self.sigma1, self.sigma2) - ] + ) blurred_f = gf1(img_t.unsqueeze(0)) filter_blurred_f = gf2(blurred_f) out_t: torch.Tensor = (blurred_f + self.alpha * (blurred_f - filter_blurred_f)).squeeze(0) diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index fbd4a6b12b..5301b6ac09 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -561,7 +561,7 @@ def create_grid( return _create_grid_numpy(spatial_size, spacing, homogeneous, dtype) if _backend == TransformBackends.TORCH: return _create_grid_torch(spatial_size, spacing, homogeneous, dtype, device) - raise ValueError("backend {} is not supported".format(backend)) + raise ValueError(f"backend {backend} is not supported") def _create_grid_numpy( @@ -662,7 +662,7 @@ def create_rotate( cos_func=lambda th: torch.cos(torch.as_tensor(th, dtype=torch.float32, device=device)), eye_func=lambda rank: torch.eye(rank, device=device), ) - raise ValueError("backend {} is not supported".format(backend)) + raise ValueError(f"backend {backend} is not supported") def _create_rotate( @@ -747,7 +747,7 @@ def create_shear( return _create_shear( spatial_dims=spatial_dims, coefs=coefs, eye_func=lambda rank: torch.eye(rank, device=device) ) - raise ValueError("backend {} is not supported".format(backend)) + raise ValueError(f"backend {backend} is not supported") def _create_shear(spatial_dims: int, coefs: Union[Sequence[float], float], eye_func=np.eye) -> NdarrayOrTensor: @@ -790,7 +790,7 @@ def create_scale( scaling_factor=scaling_factor, array_func=lambda x: torch.diag(torch.as_tensor(x, device=device)), ) - raise ValueError("backend {} is not supported".format(backend)) + raise ValueError(f"backend {backend} is not supported") def _create_scale( @@ -825,7 +825,7 @@ def create_translate( eye_func=lambda x: torch.eye(torch.as_tensor(x), device=device), # type: ignore array_func=lambda x: torch.as_tensor(x, device=device), # type: ignore ) - raise ValueError("backend {} is not supported".format(backend)) + raise ValueError(f"backend {backend} is not supported") def _create_translate( @@ -1390,7 +1390,7 @@ def print_color(t, color): print(f"\033[{color}m{t}\033[00m") def print_table_column(name, torch, numpy, color=Colors.none): - print_color("{:<50} {:<8} {:<8}".format(name, torch, numpy), color) + print_color(f"{name:<50} {torch:<8} {numpy:<8}", color) backends = get_transform_backends() n_total = len(backends) diff --git a/monai/utils/jupyter_utils.py b/monai/utils/jupyter_utils.py index ed109393f9..d6d127b52f 100644 --- a/monai/utils/jupyter_utils.py +++ b/monai/utils/jupyter_utils.py @@ -128,7 +128,7 @@ def plot_metric_images( else: im.imshow(np.squeeze(imagemap[n]), cmap="gray") - im.set_title("%s\n%.3g -> %.3g" % (n, imagemap[n].min(), imagemap[n].max())) + im.set_title(f"{n}\n{imagemap[n].min():.3g} -> {imagemap[n].max():.3g}") im.axis("off") axes.append(im) diff --git a/monai/utils/module.py b/monai/utils/module.py index 33314fb0e3..6a1f365504 100644 --- a/monai/utils/module.py +++ b/monai/utils/module.py @@ -364,7 +364,7 @@ def get_torch_version_tuple(): Returns: tuple of ints represents the pytorch major/minor version. """ - return tuple((int(x) for x in torch.__version__.split(".")[:2])) + return tuple(int(x) for x in torch.__version__.split(".")[:2]) def version_leq(lhs, rhs): diff --git a/monai/utils/profiling.py b/monai/utils/profiling.py index 695653e897..d7459885fb 100644 --- a/monai/utils/profiling.py +++ b/monai/utils/profiling.py @@ -56,7 +56,7 @@ def wrapper(*args, **kwargs): cpu_time = torch.autograd.profiler.format_time(cpu_time) gpu_time = torch.autograd.profiler.format_time(gpu_time) - print("cpu time: {}, gpu time: {}".format(cpu_time, gpu_time), flush=True) + print(f"cpu time: {cpu_time}, gpu time: {gpu_time}", flush=True) return result @@ -83,7 +83,7 @@ def wrapper(*args, **kwargs): total_time = (end - start) * 1e6 total_time_str = torch.autograd.profiler.format_time(total_time) - print("end to end time: {}".format(total_time_str), flush=True) + print(f"end to end time: {total_time_str}", flush=True) return result diff --git a/monai/visualize/img2tensorboard.py b/monai/visualize/img2tensorboard.py index ccdbdc2396..fd6dc9483b 100644 --- a/monai/visualize/img2tensorboard.py +++ b/monai/visualize/img2tensorboard.py @@ -44,7 +44,7 @@ def _image3_animated_gif(tag: str, image: Union[np.ndarray, torch.Tensor], scale if len(image.shape) != 3: raise AssertionError("3D image tensors expected to be in `HWD` format, len(image.shape) != 3") - ims = [(np.asarray((image[:, :, i])) * scale_factor).astype(np.uint8) for i in range(image.shape[2])] + ims = [(np.asarray(image[:, :, i]) * scale_factor).astype(np.uint8) for i in range(image.shape[2])] ims = [GifImage.fromarray(im) for im in ims] img_str = b"" for b_data in PIL.GifImagePlugin.getheader(ims[0])[0]: diff --git a/tests/clang_format_utils.py b/tests/clang_format_utils.py index 41902eb272..1391fdcd47 100644 --- a/tests/clang_format_utils.py +++ b/tests/clang_format_utils.py @@ -50,10 +50,10 @@ def get_and_check_clang_format(): """ # If the host platform is not in PLATFORM_TO_HASH, it is unsupported. if HOST_PLATFORM not in PLATFORM_TO_HASH: - print("Unsupported platform: {}".format(HOST_PLATFORM)) + print(f"Unsupported platform: {HOST_PLATFORM}") return False if HOST_PLATFORM not in PLATFORM_TO_CF_URL: - print("Unsupported platform: {}".format(HOST_PLATFORM)) + print(f"Unsupported platform: {HOST_PLATFORM}") return False try: @@ -69,7 +69,7 @@ def get_and_check_clang_format(): mode = os.stat(CLANG_FORMAT_PATH).st_mode mode |= stat.S_IXUSR os.chmod(CLANG_FORMAT_PATH, mode) - print("Using clang-format located at {}".format(CLANG_FORMAT_PATH)) + print(f"Using clang-format located at {CLANG_FORMAT_PATH}") return True diff --git a/tests/test_copy_model_state.py b/tests/test_copy_model_state.py index 6330a1918a..438c521479 100644 --- a/tests/test_copy_model_state.py +++ b/tests/test_copy_model_state.py @@ -21,7 +21,7 @@ class _TestModelOne(torch.nn.Module): def __init__(self, n_n, n_m, n_class): - super(_TestModelOne, self).__init__() + super().__init__() self.layer = torch.nn.Linear(n_n, n_m) self.class_layer = torch.nn.Linear(n_m, n_class) @@ -33,7 +33,7 @@ def forward(self, x): class _TestModelTwo(torch.nn.Module): def __init__(self, n_n, n_m, n_d, n_class): - super(_TestModelTwo, self).__init__() + super().__init__() self.layer = torch.nn.Linear(n_n, n_m) self.layer_1 = torch.nn.Linear(n_m, n_d) self.class_layer = torch.nn.Linear(n_d, n_class) diff --git a/tests/test_csv_saver.py b/tests/test_csv_saver.py index 6dd0159322..a279599463 100644 --- a/tests/test_csv_saver.py +++ b/tests/test_csv_saver.py @@ -29,7 +29,7 @@ def test_saved_content(self): saver.finalize() filepath = os.path.join(tempdir, "predictions.csv") self.assertTrue(os.path.exists(filepath)) - with open(filepath, "r") as f: + with open(filepath) as f: reader = csv.reader(f) i = 0 for row in reader: diff --git a/tests/test_data_stats.py b/tests/test_data_stats.py index 50536f2a5c..a924fc0c48 100644 --- a/tests/test_data_stats.py +++ b/tests/test_data_stats.py @@ -159,7 +159,7 @@ def test_file(self, input_data, expected_print): for h in _logger.handlers[:]: h.close() _logger.removeHandler(h) - with open(filename, "r") as f: + with open(filename) as f: content = f.read() self.assertEqual(content, expected_print) diff --git a/tests/test_data_statsd.py b/tests/test_data_statsd.py index aea0f1e721..f2220f353f 100644 --- a/tests/test_data_statsd.py +++ b/tests/test_data_statsd.py @@ -192,7 +192,7 @@ def test_file(self, input_data, expected_print): h.close() _logger.removeHandler(h) del handler - with open(filename, "r") as f: + with open(filename) as f: content = f.read() self.assertEqual(content, expected_print) diff --git a/tests/test_efficientnet.py b/tests/test_efficientnet.py index 6befba108a..20c7123d7f 100644 --- a/tests/test_efficientnet.py +++ b/tests/test_efficientnet.py @@ -44,7 +44,7 @@ def get_model_names(): - return ["efficientnet-b{}".format(d) for d in range(8)] + return [f"efficientnet-b{d}" for d in range(8)] def get_expected_model_shape(model_name): diff --git a/tests/test_generalized_wasserstein_dice_loss.py b/tests/test_generalized_wasserstein_dice_loss.py index 295a4a6d70..5ad946d20d 100644 --- a/tests/test_generalized_wasserstein_dice_loss.py +++ b/tests/test_generalized_wasserstein_dice_loss.py @@ -159,7 +159,7 @@ def test_convergence(self): # define a model with one layer class OnelayerNet(nn.Module): def __init__(self): - super(OnelayerNet, self).__init__() + super().__init__() self.layer = nn.Linear(num_voxels, num_voxels * num_classes) def forward(self, x): diff --git a/tests/test_grid_pull.py b/tests/test_grid_pull.py index 9e4d2e8237..cbfd8a9590 100644 --- a/tests/test_grid_pull.py +++ b/tests/test_grid_pull.py @@ -85,7 +85,7 @@ def test_grid_pull(self, input_param, expected): grads = grads[0] else: grads = torch.cat(grads, dim=0) - self.assertTrue("{}".format(result.device).startswith(expected["device"])) + self.assertTrue(f"{result.device}".startswith(expected["device"])) np.testing.assert_allclose(result.detach().cpu().numpy(), expected["val"].cpu().numpy(), rtol=1e-4, atol=1e-4) np.testing.assert_allclose(grads.detach().cpu().numpy(), expected["grad"].cpu().numpy(), rtol=1e-4, atol=1e-4) diff --git a/tests/test_handler_classification_saver.py b/tests/test_handler_classification_saver.py index 87ce5ca3f8..e06c6e95f0 100644 --- a/tests/test_handler_classification_saver.py +++ b/tests/test_handler_classification_saver.py @@ -45,7 +45,7 @@ def _train_func(engine, batch): def _test_file(filename): filepath = os.path.join(tempdir, filename) self.assertTrue(os.path.exists(filepath)) - with open(filepath, "r") as f: + with open(filepath) as f: reader = csv.reader(f) i = 0 for row in reader: diff --git a/tests/test_handler_classification_saver_dist.py b/tests/test_handler_classification_saver_dist.py index 70cc0ca42f..d9bbe67ecd 100644 --- a/tests/test_handler_classification_saver_dist.py +++ b/tests/test_handler_classification_saver_dist.py @@ -61,7 +61,7 @@ def _train_func(engine, batch): filepath = os.path.join(tempdir, "predictions.csv") if rank == 1: self.assertTrue(os.path.exists(filepath)) - with open(filepath, "r") as f: + with open(filepath) as f: reader = csv.reader(f) i = 0 for row in reader: diff --git a/tests/test_handler_parameter_scheduler.py b/tests/test_handler_parameter_scheduler.py index 5b3e845ace..55ea6a4af2 100644 --- a/tests/test_handler_parameter_scheduler.py +++ b/tests/test_handler_parameter_scheduler.py @@ -9,7 +9,7 @@ class ToyNet(Module): def __init__(self, value): - super(ToyNet, self).__init__() + super().__init__() self.value = value def forward(self, input): diff --git a/tests/test_handler_stats.py b/tests/test_handler_stats.py index 84cdef59a8..9b7ad19dcc 100644 --- a/tests/test_handler_stats.py +++ b/tests/test_handler_stats.py @@ -140,7 +140,7 @@ def _train_func(engine, batch): engine.run(range(3), max_epochs=2) handler.close() stats_handler.logger.removeHandler(handler) - with open(filename, "r") as f: + with open(filename) as f: output_str = f.read() grep = re.compile(f".*{key_to_handler}.*") has_key_word = re.compile(f".*{key_to_print}.*") diff --git a/tests/test_integration_classification_2d.py b/tests/test_integration_classification_2d.py index 03b5571973..7a94780f82 100644 --- a/tests/test_integration_classification_2d.py +++ b/tests/test_integration_classification_2d.py @@ -197,7 +197,7 @@ def setUp(self): assert os.path.exists(data_dir) - class_names = sorted((x for x in os.listdir(data_dir) if os.path.isdir(os.path.join(data_dir, x)))) + class_names = sorted(x for x in os.listdir(data_dir) if os.path.isdir(os.path.join(data_dir, x))) image_files = [ [os.path.join(data_dir, class_name, x) for x in sorted(os.listdir(os.path.join(data_dir, class_name)))] for class_name in class_names diff --git a/tests/test_integration_stn.py b/tests/test_integration_stn.py index c1fcfe7a89..998eacbf41 100644 --- a/tests/test_integration_stn.py +++ b/tests/test_integration_stn.py @@ -9,7 +9,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import print_function import unittest diff --git a/tests/test_inverse.py b/tests/test_inverse.py index 9535a40c05..b09f532fd1 100644 --- a/tests/test_inverse.py +++ b/tests/test_inverse.py @@ -566,8 +566,8 @@ def setUp(self): "other": np.array(im_1d, copy=True), } - im_2d_fname, seg_2d_fname = [make_nifti_image(i) for i in create_test_image_2d(101, 100)] - im_3d_fname, seg_3d_fname = [make_nifti_image(i, affine) for i in create_test_image_3d(100, 101, 107)] + im_2d_fname, seg_2d_fname = (make_nifti_image(i) for i in create_test_image_2d(101, 100)) + im_3d_fname, seg_3d_fname = (make_nifti_image(i, affine) for i in create_test_image_3d(100, 101, 107)) load_ims = Compose([LoadImaged(KEYS), AddChanneld(KEYS)]) self.all_data["2D"] = load_ims({"image": im_2d_fname, "label": seg_2d_fname}) diff --git a/tests/test_inverse_collation.py b/tests/test_inverse_collation.py index bc0fc3ff1b..b986f21bce 100644 --- a/tests/test_inverse_collation.py +++ b/tests/test_inverse_collation.py @@ -99,12 +99,12 @@ def setUp(self): set_determinism(seed=0) b_size = 11 - im_fname, seg_fname = [make_nifti_image(i) for i in create_test_image_3d(101, 100, 107)] + im_fname, seg_fname = (make_nifti_image(i) for i in create_test_image_3d(101, 100, 107)) load_ims = Compose([LoadImaged(KEYS), AddChanneld(KEYS)]) self.data_3d = [load_ims({"image": im_fname, "label": seg_fname}) for _ in range(b_size)] b_size = 8 - im_fname, seg_fname = [make_nifti_image(i) for i in create_test_image_2d(62, 37, rad_max=10)] + im_fname, seg_fname = (make_nifti_image(i) for i in create_test_image_2d(62, 37, rad_max=10)) load_ims = Compose([LoadImaged(KEYS), AddChanneld(KEYS)]) self.data_2d = [load_ims({"image": im_fname, "label": seg_fname}) for _ in range(b_size)] diff --git a/tests/test_invertd.py b/tests/test_invertd.py index eda900bf2d..8c2066a167 100644 --- a/tests/test_invertd.py +++ b/tests/test_invertd.py @@ -45,7 +45,7 @@ class TestInvertd(unittest.TestCase): def test_invert(self): set_determinism(seed=0) - im_fname, seg_fname = [make_nifti_image(i) for i in create_test_image_3d(101, 100, 107, noise_max=100)] + im_fname, seg_fname = (make_nifti_image(i) for i in create_test_image_3d(101, 100, 107, noise_max=100)) transform = Compose( [ LoadImaged(KEYS), diff --git a/tests/test_lr_scheduler.py b/tests/test_lr_scheduler.py index aa126f7848..20fd7ca8cf 100644 --- a/tests/test_lr_scheduler.py +++ b/tests/test_lr_scheduler.py @@ -19,7 +19,7 @@ class SchedulerTestNet(torch.nn.Module): def __init__(self): - super(SchedulerTestNet, self).__init__() + super().__init__() self.conv1 = torch.nn.Conv2d(1, 1, 1) self.conv2 = torch.nn.Conv2d(1, 1, 1) @@ -47,11 +47,11 @@ def test_shape(self, input_param, expected_lr): self.assertEqual(len([scheduler.get_last_lr()[0]]), 1) lrs_1 = [] for _ in range(input_param["t_total"]): - lrs_1.append(float("{:.3f}".format(scheduler.get_last_lr()[0]))) + lrs_1.append(float(f"{scheduler.get_last_lr()[0]:.3f}")) optimizer.step() scheduler.step() for a, b in zip(lrs_1, expected_lr): - self.assertEqual(a, b, msg="LR is wrong ! expected {}, got {}".format(b, a)) + self.assertEqual(a, b, msg=f"LR is wrong ! expected {b}, got {a}") if __name__ == "__main__": diff --git a/tests/test_mmar_download.py b/tests/test_mmar_download.py index 6952e62c3c..725a6a8823 100644 --- a/tests/test_mmar_download.py +++ b/tests/test_mmar_download.py @@ -138,7 +138,7 @@ def test_load_ckpt(self, input_args, expected_name, expected_val): def test_unique(self): # model ids are unique - keys = sorted([m["id"] for m in MODEL_DESC]) + keys = sorted(m["id"] for m in MODEL_DESC) self.assertTrue(keys == sorted(set(keys))) @SkipIfAtLeastPyTorchVersion((1, 6)) diff --git a/tests/test_reg_loss_integration.py b/tests/test_reg_loss_integration.py index b864a64647..36e3a460a5 100644 --- a/tests/test_reg_loss_integration.py +++ b/tests/test_reg_loss_integration.py @@ -69,7 +69,7 @@ def test_convergence(self, loss_type, loss_args, forward_args): # define a one layer model class OnelayerNet(nn.Module): def __init__(self): - super(OnelayerNet, self).__init__() + super().__init__() self.layer = nn.Sequential( nn.Conv3d(in_channels=1, out_channels=1, kernel_size=3, padding=1), nn.ReLU(), diff --git a/tests/test_save_classificationd.py b/tests/test_save_classificationd.py index 67dc0320a6..26ce3176e8 100644 --- a/tests/test_save_classificationd.py +++ b/tests/test_save_classificationd.py @@ -83,7 +83,7 @@ def test_saved_content(self): def _test_file(filename, count): filepath = os.path.join(tempdir, filename) self.assertTrue(os.path.exists(filepath)) - with open(filepath, "r") as f: + with open(filepath) as f: reader = csv.reader(f) i = 0 for row in reader: diff --git a/tests/test_seg_loss_integration.py b/tests/test_seg_loss_integration.py index d2f991f160..98d840afea 100644 --- a/tests/test_seg_loss_integration.py +++ b/tests/test_seg_loss_integration.py @@ -91,7 +91,7 @@ def test_convergence(self, loss_type, loss_args, forward_args): # define a one layer model class OnelayerNet(nn.Module): def __init__(self): - super(OnelayerNet, self).__init__() + super().__init__() self.layer_1 = nn.Linear(num_voxels, 200) self.acti = nn.ReLU() self.layer_2 = nn.Linear(200, num_voxels * num_classes) diff --git a/tests/testing_data/cpp_resample_answers.py b/tests/testing_data/cpp_resample_answers.py index 51ac6ccda9..67af152059 100644 --- a/tests/testing_data/cpp_resample_answers.py +++ b/tests/testing_data/cpp_resample_answers.py @@ -23,7 +23,7 @@ def _read_testing_data_answers(fname: Optional[str] = None, delimiter=",") -> Li pwd = os.path.dirname(os.path.abspath(__file__)) filename = os.path.join(pwd, fname) if not os.path.isfile(filename): - warnings.warn("test data {} not found.".format(filename)) + warnings.warn(f"test data {filename} not found.") return answers with open(filename) as f: res_reader = csv.reader(f, delimiter=delimiter) From a0130d1a7540872ea0cd972e00e8f32e8d774a47 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Mon, 27 Sep 2021 09:38:08 +0100 Subject: [PATCH 54/89] 3018 enhance version string check (#3022) * enhance the release version string check Signed-off-by: GitHub * update the releasing steps Signed-off-by: GitHub Co-authored-by: Nic Ma --- .github/workflows/release.yml | 11 +++++++++++ CONTRIBUTING.md | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bfdc639788..0214ae4cf6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -144,6 +144,17 @@ jobs: run: | # get tag info for versioning mv _version.py monai/ + # version checks + target="\"version\": \"$RELEASE_VERSION\"" + echo $target + local=`grep "\"version\"" monai/_version.py + echo $local + if [ "$local" = "$target" ]; then + echo "matched version string" + else + echo "unmatched version string, please check the main branch" + exit 1 + fi # remove flake package as it is not needed on hub.docker.com sed -i '/flake/d' requirements-dev.txt docker build -t projectmonai/monai:"$RELEASE_VERSION" -f Dockerfile . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0dce26582a..954549581a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -289,9 +289,9 @@ When major features are ready for a milestone, to prepare for a new release: repository's artifacts (e.g. the file at https://github.com/Project-MONAI/MONAI/actions/runs/66570977). - Check the release test at [TestPyPI](https://test.pypi.org/project/monai/), download the artifacts when the CI finishes. - Optionally run [the cron testing jobs](https://github.com/Project-MONAI/MONAI/blob/dev/.github/workflows/cron.yml) on `releasing/[version number]`. +- Rebase `releasing/[version number]` to `main`, make sure all the test pipelines succeed. - Once the release candidate is verified, tag and push a milestone, for example, `git push origin 0.1.0`. The tag must be with the latest commit of `releasing/[version number]`. -- Rebase `releasing/[version number]` to `main`, make sure all the test pipelines succeed. - Upload the packages to [PyPI](https://pypi.org/project/monai/). This could be done manually by ``twine upload dist/*``, given the artifacts are unzipped to the folder ``dist/``. - Merge `releasing/[version number]` to `dev`, this step must make sure that the tagging commit unchanged on `dev`. From fe93596e8232da986af640f6242b62331875f722 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Tue, 28 Sep 2021 01:20:37 +0800 Subject: [PATCH 55/89] 3028 update ignite CI tests to 0.4.6 (#3029) * [DLMED] update ignite 0.4.6 Signed-off-by: Nic Ma * [DLMED] fix flake8 issues Signed-off-by: Nic Ma --- docs/requirements.txt | 2 +- .../pathology/handlers/prob_map_producer.py | 7 ++++-- monai/engines/evaluator.py | 24 ++++++++++-------- monai/engines/multi_gpu_supervised_trainer.py | 4 +-- monai/engines/trainer.py | 24 ++++++++++++------ monai/engines/workflow.py | 25 +++++++++++-------- monai/handlers/checkpoint_loader.py | 2 +- monai/handlers/checkpoint_saver.py | 8 +++--- monai/handlers/decollate_batch.py | 4 +-- monai/handlers/garbage_collector.py | 1 + monai/handlers/ignite_metric.py | 4 +-- monai/handlers/metrics_saver.py | 10 +++++--- monai/handlers/nvtx_handlers.py | 22 ++++++---------- monai/handlers/stats_handler.py | 9 ++++--- monai/handlers/utils.py | 2 +- monai/utils/jupyter_utils.py | 18 ++++++------- requirements-dev.txt | 2 +- setup.cfg | 4 +-- 18 files changed, 95 insertions(+), 77 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 47176c58a2..53eb6d3c0d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,6 @@ -f https://download.pytorch.org/whl/cpu/torch-1.6.0%2Bcpu-cp37-cp37m-linux_x86_64.whl torch>=1.5 -pytorch-ignite==0.4.5 +pytorch-ignite==0.4.6 numpy>=1.17 itk>=5.2 nibabel diff --git a/monai/apps/pathology/handlers/prob_map_producer.py b/monai/apps/pathology/handlers/prob_map_producer.py index 7ac4a0e45b..469e9d3c25 100644 --- a/monai/apps/pathology/handlers/prob_map_producer.py +++ b/monai/apps/pathology/handlers/prob_map_producer.py @@ -62,9 +62,10 @@ def attach(self, engine: Engine) -> None: engine: Ignite Engine, it can be a trainer, validator or evaluator. """ - self.num_images = len(engine.data_loader.dataset.data) + data_loader = engine.data_loader # type: ignore + self.num_images = len(data_loader.dataset.data) - for sample in engine.data_loader.dataset.data: + for sample in data_loader.dataset.data: name = sample["name"] self.prob_map[name] = np.zeros(sample["mask_shape"], dtype=self.dtype) self.counter[name] = len(sample["mask_locations"]) @@ -84,6 +85,8 @@ def __call__(self, engine: Engine) -> None: Args: engine: Ignite Engine, it can be a trainer, validator or evaluator. """ + if not isinstance(engine.state.batch, dict) or not isinstance(engine.state.output, dict): + raise ValueError("engine.state.batch and engine.state.output must be dictionaries.") names = engine.state.batch["name"] locs = engine.state.batch["mask_location"] pred = engine.state.output["pred"] diff --git a/monai/engines/evaluator.py b/monai/engines/evaluator.py index 1c37da71d4..bfe9d01e1f 100644 --- a/monai/engines/evaluator.py +++ b/monai/engines/evaluator.py @@ -219,7 +219,7 @@ def __init__( self.network = network self.inferer = SimpleInferer() if inferer is None else inferer - def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]: + def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]): """ callback function for the Supervised Evaluation processing logic of 1 iteration in Ignite Engine. Return below items in a dictionary: @@ -237,7 +237,7 @@ def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict """ if batchdata is None: raise ValueError("Must provide batch data for current iteration.") - batch = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) + batch = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) # type: ignore if len(batch) == 2: inputs, targets = batch args: Tuple = () @@ -246,15 +246,15 @@ def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict inputs, targets, args, kwargs = batch # put iteration outputs into engine.state - engine.state.output = {Keys.IMAGE: inputs, Keys.LABEL: targets} + engine.state.output = {Keys.IMAGE: inputs, Keys.LABEL: targets} # type: ignore # execute forward computation with self.mode(self.network): if self.amp: with torch.cuda.amp.autocast(): - engine.state.output[Keys.PRED] = self.inferer(inputs, self.network, *args, **kwargs) + engine.state.output[Keys.PRED] = self.inferer(inputs, self.network, *args, **kwargs) # type: ignore else: - engine.state.output[Keys.PRED] = self.inferer(inputs, self.network, *args, **kwargs) + engine.state.output[Keys.PRED] = self.inferer(inputs, self.network, *args, **kwargs) # type: ignore engine.fire_event(IterationEvents.FORWARD_COMPLETED) engine.fire_event(IterationEvents.MODEL_COMPLETED) @@ -349,7 +349,7 @@ def __init__( self.pred_keys = ensure_tuple(pred_keys) self.inferer = SimpleInferer() if inferer is None else inferer - def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict[str, torch.Tensor]: + def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]): """ callback function for the Supervised Evaluation processing logic of 1 iteration in Ignite Engine. Return below items in a dictionary: @@ -370,7 +370,7 @@ def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict """ if batchdata is None: raise ValueError("Must provide batch data for current iteration.") - batch = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) + batch = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) # type: ignore if len(batch) == 2: inputs, targets = batch args: Tuple = () @@ -379,17 +379,21 @@ def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]) -> Dict inputs, targets, args, kwargs = batch # put iteration outputs into engine.state - engine.state.output = {Keys.IMAGE: inputs, Keys.LABEL: targets} + engine.state.output = {Keys.IMAGE: inputs, Keys.LABEL: targets} # type: ignore for idx, network in enumerate(self.networks): with self.mode(network): if self.amp: with torch.cuda.amp.autocast(): + if isinstance(engine.state.output, dict): + engine.state.output.update( + {self.pred_keys[idx]: self.inferer(inputs, network, *args, **kwargs)} + ) + else: + if isinstance(engine.state.output, dict): engine.state.output.update( {self.pred_keys[idx]: self.inferer(inputs, network, *args, **kwargs)} ) - else: - engine.state.output.update({self.pred_keys[idx]: self.inferer(inputs, network, *args, **kwargs)}) engine.fire_event(IterationEvents.FORWARD_COMPLETED) engine.fire_event(IterationEvents.MODEL_COMPLETED) diff --git a/monai/engines/multi_gpu_supervised_trainer.py b/monai/engines/multi_gpu_supervised_trainer.py index 3671dbcfd1..b6f516ff99 100644 --- a/monai/engines/multi_gpu_supervised_trainer.py +++ b/monai/engines/multi_gpu_supervised_trainer.py @@ -59,7 +59,7 @@ def create_multigpu_supervised_trainer( prepare_batch: Callable = _prepare_batch, output_transform: Callable = _default_transform, distributed: bool = False, -) -> Engine: +): """ Derived from `create_supervised_trainer` in Ignite. @@ -107,7 +107,7 @@ def create_multigpu_supervised_evaluator( prepare_batch: Callable = _prepare_batch, output_transform: Callable = _default_eval_transform, distributed: bool = False, -) -> Engine: +): """ Derived from `create_supervised_evaluator` in Ignite. diff --git a/monai/engines/trainer.py b/monai/engines/trainer.py index 44e265be1f..eeda143def 100644 --- a/monai/engines/trainer.py +++ b/monai/engines/trainer.py @@ -172,7 +172,7 @@ def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]): """ if batchdata is None: raise ValueError("Must provide batch data for current iteration.") - batch = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) + batch = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) # type: ignore if len(batch) == 2: inputs, targets = batch args: Tuple = () @@ -180,7 +180,7 @@ def _iteration(self, engine: Engine, batchdata: Dict[str, torch.Tensor]): else: inputs, targets, args, kwargs = batch # put iteration outputs into engine.state - engine.state.output = {Keys.IMAGE: inputs, Keys.LABEL: targets} + engine.state.output = {Keys.IMAGE: inputs, Keys.LABEL: targets} # type: ignore def _compute_pred_loss(): engine.state.output[Keys.PRED] = self.inferer(inputs, self.network, *args, **kwargs) @@ -198,13 +198,13 @@ def _compute_pred_loss(): if self.amp and self.scaler is not None: with torch.cuda.amp.autocast(): _compute_pred_loss() - self.scaler.scale(engine.state.output[Keys.LOSS]).backward() + self.scaler.scale(engine.state.output[Keys.LOSS]).backward() # type: ignore engine.fire_event(IterationEvents.BACKWARD_COMPLETED) self.scaler.step(self.optimizer) self.scaler.update() else: _compute_pred_loss() - engine.state.output[Keys.LOSS].backward() + engine.state.output[Keys.LOSS].backward() # type: ignore engine.fire_event(IterationEvents.BACKWARD_COMPLETED) self.optimizer.step() engine.fire_event(IterationEvents.MODEL_COMPLETED) @@ -345,9 +345,14 @@ def _iteration( if batchdata is None: raise ValueError("must provide batch data for current iteration.") - d_input = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) + d_input = self.prepare_batch(batchdata, engine.state.device, engine.non_blocking) # type: ignore batch_size = self.data_loader.batch_size # type: ignore - g_input = self.g_prepare_batch(batch_size, self.latent_shape, engine.state.device, engine.non_blocking) + g_input = self.g_prepare_batch( + num_latents=batch_size, + latent_size=self.latent_shape, + device=engine.state.device, # type: ignore + non_blocking=engine.non_blocking, # type: ignore + ) g_output = self.g_inferer(g_input, self.g_network) # Train Discriminator @@ -367,7 +372,12 @@ def _iteration( # Train Generator if self.g_update_latents: - g_input = self.g_prepare_batch(batch_size, self.latent_shape, engine.state.device, engine.non_blocking) + g_input = self.g_prepare_batch( + num_latents=batch_size, + latent_size=self.latent_shape, + device=engine.state.device, # type: ignore + non_blocking=engine.non_blocking, # type: ignore + ) g_output = self.g_inferer(g_input, self.g_network) if PT_BEFORE_1_7: self.g_optimizer.zero_grad() diff --git a/monai/engines/workflow.py b/monai/engines/workflow.py index ffb8ce05b3..3454095a02 100644 --- a/monai/engines/workflow.py +++ b/monai/engines/workflow.py @@ -152,15 +152,15 @@ def set_sampler_epoch(engine: Engine): self.scaler: Optional[torch.cuda.amp.GradScaler] = None if event_names is None: - event_names = [IterationEvents] + event_names = [IterationEvents] # type: ignore else: if not isinstance(event_names, list): raise ValueError("event_names must be a list or string or EventEnum.") - event_names += [IterationEvents] + event_names += [IterationEvents] # type: ignore for name in event_names: if isinstance(name, str): self.register_events(name, event_to_attr=event_to_attr) - elif issubclass(name, EventEnum): + elif issubclass(name, EventEnum): # type: ignore self.register_events(*name, event_to_attr=event_to_attr) else: raise ValueError("event_names must be a list or string or EventEnum.") @@ -187,8 +187,10 @@ def _register_decollate(self): def _decollate_data(engine: Engine) -> None: # replicate the scalar values to make sure all the items have batch dimension, then decollate transform = Decollated(keys=None, detach=True) - engine.state.batch = transform(engine.state.batch) - engine.state.output = transform(engine.state.output) + if isinstance(engine.state.batch, (list, dict)): + engine.state.batch = transform(engine.state.batch) + if isinstance(engine.state.output, (list, dict)): + engine.state.output = transform(engine.state.output) def _register_postprocessing(self, posttrans: Callable): """ @@ -226,12 +228,13 @@ def _register_metrics(self, k_metric: Dict, add_metrics: Optional[Dict] = None): @self.on(Events.EPOCH_COMPLETED) def _compare_metrics(engine: Engine) -> None: - if engine.state.key_metric_name is not None: - current_val_metric = engine.state.metrics[engine.state.key_metric_name] - if self.metric_cmp_fn(current_val_metric, engine.state.best_metric): - self.logger.info(f"Got new best metric of {engine.state.key_metric_name}: {current_val_metric}") - engine.state.best_metric = current_val_metric - engine.state.best_metric_epoch = engine.state.epoch + key_metric_name = engine.state.key_metric_name # type: ignore + if key_metric_name is not None: + current_val_metric = engine.state.metrics[key_metric_name] + if self.metric_cmp_fn(current_val_metric, engine.state.best_metric): # type: ignore + self.logger.info(f"Got new best metric of {key_metric_name}: {current_val_metric}") + engine.state.best_metric = current_val_metric # type: ignore + engine.state.best_metric_epoch = engine.state.epoch # type: ignore def _register_handlers(self, handlers: Sequence): """ diff --git a/monai/handlers/checkpoint_loader.py b/monai/handlers/checkpoint_loader.py index f1f60abf63..7c30584b13 100644 --- a/monai/handlers/checkpoint_loader.py +++ b/monai/handlers/checkpoint_loader.py @@ -126,7 +126,7 @@ def __call__(self, engine: Engine) -> None: # save current max epochs setting in the engine, don't overwrite it if larger than max_epochs in checkpoint prior_max_epochs = engine.state.max_epochs Checkpoint.load_objects(to_load=self.load_dict, checkpoint=checkpoint, strict=self.strict) - if engine.state.epoch > prior_max_epochs: + if prior_max_epochs is not None and engine.state.epoch > prior_max_epochs: raise ValueError( f"Epoch count ({engine.state.epoch}) in checkpoint is larger than " f"the `engine.state.max_epochs` ({prior_max_epochs}) of engine. To further train from checkpoint, " diff --git a/monai/handlers/checkpoint_saver.py b/monai/handlers/checkpoint_saver.py index f365ff73c4..d5aadadfed 100644 --- a/monai/handlers/checkpoint_saver.py +++ b/monai/handlers/checkpoint_saver.py @@ -11,7 +11,7 @@ import logging import warnings -from typing import TYPE_CHECKING, Dict, Optional +from typing import TYPE_CHECKING, Dict, Mapping, Optional from monai.config import IgniteInfo from monai.utils import min_version, optional_import @@ -126,7 +126,7 @@ def __init__(self, dirname: str, filename: Optional[str] = None): super().__init__(dirname=dirname, require_empty=False, atomic=False) self.filename = filename - def __call__(self, checkpoint: Dict, filename: str, metadata: Optional[Dict] = None) -> None: + def __call__(self, checkpoint: Mapping, filename: str, metadata: Optional[Mapping] = None) -> None: if self.filename is not None: filename = self.filename super().__call__(checkpoint=checkpoint, filename=filename, metadata=metadata) @@ -154,8 +154,8 @@ def _final_func(engine: Engine): def _score_func(engine: Engine): if isinstance(key_metric_name, str): metric_name = key_metric_name - elif hasattr(engine.state, "key_metric_name") and isinstance(engine.state.key_metric_name, str): - metric_name = engine.state.key_metric_name + elif hasattr(engine.state, "key_metric_name"): + metric_name = engine.state.key_metric_name # type: ignore else: raise ValueError( f"Incompatible values: save_key_metric=True and key_metric_name={key_metric_name}." diff --git a/monai/handlers/decollate_batch.py b/monai/handlers/decollate_batch.py index 4e99fc6f04..0905ee6ebc 100644 --- a/monai/handlers/decollate_batch.py +++ b/monai/handlers/decollate_batch.py @@ -88,7 +88,7 @@ def __call__(self, engine: Engine) -> None: Args: engine: Ignite Engine, it can be a trainer, validator or evaluator. """ - if self.batch_transform is not None: + if self.batch_transform is not None and isinstance(engine.state.batch, (list, dict)): engine.state.batch = self.batch_transform(engine.state.batch) - if self.output_transform is not None: + if self.output_transform is not None and isinstance(engine.state.output, (list, dict)): engine.state.output = self.output_transform(engine.state.output) diff --git a/monai/handlers/garbage_collector.py b/monai/handlers/garbage_collector.py index fffca2a740..1eb970e795 100644 --- a/monai/handlers/garbage_collector.py +++ b/monai/handlers/garbage_collector.py @@ -42,6 +42,7 @@ class GarbageCollector: """ def __init__(self, trigger_event: str = "epoch", log_level: int = 10): + self.trigger_event: Events if isinstance(trigger_event, Events): self.trigger_event = trigger_event elif trigger_event.lower() == "epoch": diff --git a/monai/handlers/ignite_metric.py b/monai/handlers/ignite_metric.py index cbf84e4626..ea7bcd8eee 100644 --- a/monai/handlers/ignite_metric.py +++ b/monai/handlers/ignite_metric.py @@ -101,7 +101,7 @@ def compute(self) -> Any: if self.save_details: if self._engine is None or self._name is None: raise RuntimeError("please call the attach() function to connect expected engine first.") - self._engine.state.metric_details[self._name] = self.metric_fn.get_buffer() + self._engine.state.metric_details[self._name] = self.metric_fn.get_buffer() # type: ignore return result.item() if isinstance(result, torch.Tensor) else result @@ -120,4 +120,4 @@ def attach(self, engine: Engine, name: str) -> None: self._engine = engine self._name = name if self.save_details and not hasattr(engine.state, "metric_details"): - engine.state.metric_details = {} + engine.state.metric_details = {} # type: ignore diff --git a/monai/handlers/metrics_saver.py b/monai/handlers/metrics_saver.py index 97b080b244..4c722eb35b 100644 --- a/monai/handlers/metrics_saver.py +++ b/monai/handlers/metrics_saver.py @@ -132,10 +132,12 @@ def __call__(self, engine: Engine) -> None: if self.metrics is not None and len(engine.state.metrics) > 0: _metrics = {k: v for k, v in engine.state.metrics.items() if k in self.metrics or "*" in self.metrics} _metric_details = {} - if self.metric_details is not None and len(engine.state.metric_details) > 0: - for k, v in engine.state.metric_details.items(): - if k in self.metric_details or "*" in self.metric_details: - _metric_details[k] = v + if hasattr(engine.state, "metric_details"): + details = engine.state.metric_details # type: ignore + if self.metric_details is not None and len(details) > 0: + for k, v in details.items(): + if k in self.metric_details or "*" in self.metric_details: + _metric_details[k] = v write_metrics_reports( save_dir=self.save_dir, diff --git a/monai/handlers/nvtx_handlers.py b/monai/handlers/nvtx_handlers.py index aba7a7ec0e..847a3c0c47 100644 --- a/monai/handlers/nvtx_handlers.py +++ b/monai/handlers/nvtx_handlers.py @@ -97,9 +97,7 @@ def create_paired_events(self, event: str) -> Tuple[Events, Events]: ) def get_event(self, event: Union[str, Events]) -> Events: - if isinstance(event, str): - event = event.upper() - return Events[event] + return Events[event.upper()] if isinstance(event, str) else event def attach(self, engine: Engine) -> None: """ @@ -126,10 +124,8 @@ class RangePushHandler: msg: ASCII message to associate with range """ - def __init__(self, event: Events, msg: Optional[str] = None) -> None: - if isinstance(event, str): - event = event.upper() - self.event = Events[event] + def __init__(self, event: Union[str, Events], msg: Optional[str] = None) -> None: + self.event = Events[event.upper()] if isinstance(event, str) else event if msg is None: msg = self.event.name self.msg = msg @@ -156,10 +152,8 @@ class RangePopHandler: msg: ASCII message to associate with range """ - def __init__(self, event: Events) -> None: - if isinstance(event, str): - event = event.upper() - self.event = Events[event] + def __init__(self, event: Union[str, Events]) -> None: + self.event = Events[event.upper()] if isinstance(event, str) else event def attach(self, engine: Engine) -> None: """ @@ -181,10 +175,8 @@ class MarkHandler: msg: ASCII message to associate with range """ - def __init__(self, event: Events, msg: Optional[str] = None) -> None: - if isinstance(event, str): - event = event.upper() - self.event = Events[event] + def __init__(self, event: Union[str, Events], msg: Optional[str] = None) -> None: + self.event = Events[event.upper()] if isinstance(event, str) else event if msg is None: msg = self.event.name self.msg = msg diff --git a/monai/handlers/stats_handler.py b/monai/handlers/stats_handler.py index d5756074fc..c15abac542 100644 --- a/monai/handlers/stats_handler.py +++ b/monai/handlers/stats_handler.py @@ -172,8 +172,9 @@ def _default_epoch_print(self, engine: Engine) -> None: and hasattr(engine.state, "best_metric") and hasattr(engine.state, "best_metric_epoch") ): - out_str = f"Key metric: {engine.state.key_metric_name} " - out_str += f"best value: {engine.state.best_metric} at epoch: {engine.state.best_metric_epoch}" + out_str = f"Key metric: {engine.state.key_metric_name} " # type: ignore + out_str += f"best value: {engine.state.best_metric} " # type: ignore + out_str += f"at epoch: {engine.state.best_metric_epoch}" # type: ignore self.logger.info(out_str) def _default_iteration_print(self, engine: Engine) -> None: @@ -220,7 +221,9 @@ def _default_iteration_print(self, engine: Engine) -> None: return # no value to print num_iterations = engine.state.epoch_length - current_iteration = (engine.state.iteration - 1) % num_iterations + 1 + current_iteration = engine.state.iteration - 1 + if num_iterations is not None: + current_iteration %= num_iterations + 1 current_epoch = engine.state.epoch num_epochs = engine.state.max_epochs diff --git a/monai/handlers/utils.py b/monai/handlers/utils.py index 60f95d458e..5d72c028f9 100644 --- a/monai/handlers/utils.py +++ b/monai/handlers/utils.py @@ -50,7 +50,7 @@ def stopping_fn_from_loss(): """ def stopping_fn(engine: Engine): - return -engine.state.output + return -engine.state.output # type:ignore return stopping_fn diff --git a/monai/utils/jupyter_utils.py b/monai/utils/jupyter_utils.py index d6d127b52f..f862452fb1 100644 --- a/monai/utils/jupyter_utils.py +++ b/monai/utils/jupyter_utils.py @@ -16,11 +16,14 @@ from enum import Enum from threading import RLock, Thread -from typing import Any, Callable, Dict, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union import numpy as np import torch +from monai.config import IgniteInfo +from monai.utils.module import min_version, optional_import + try: import matplotlib.pyplot as plt @@ -28,14 +31,11 @@ except ImportError: has_matplotlib = False -try: +if TYPE_CHECKING: from ignite.engine import Engine, Events - - has_ignite = True -except ImportError: - Engine = object - Events = object - has_ignite = False +else: + Engine, _ = optional_import("ignite.engine", IgniteInfo.OPT_IMPORT_VERSION, min_version, "Engine") + Events, _ = optional_import("ignite.engine", IgniteInfo.OPT_IMPORT_VERSION, min_version, "Events") LOSS_NAME = "loss" @@ -190,7 +190,7 @@ def plot_engine_status( graphmap = {LOSS_NAME: logger.loss} graphmap.update(logger.metrics) - imagemap = {} + imagemap: Dict = {} if image_fn is not None and engine.state is not None and engine.state.batch is not None: for src in (engine.state.batch, engine.state.output): label = "Batch" if src is engine.state.batch else "Output" diff --git a/requirements-dev.txt b/requirements-dev.txt index e28f85b244..254cb06d27 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,6 @@ # Full requirements for developments -r requirements-min.txt -pytorch-ignite==0.4.5 +pytorch-ignite==0.4.6 gdown>=3.6.4 scipy itk>=5.2 diff --git a/setup.cfg b/setup.cfg index eddb898b0d..309169ebe8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,7 +34,7 @@ all = pillow tensorboard gdown>=3.6.4 - pytorch-ignite==0.4.5 + pytorch-ignite==0.4.6 torchvision itk>=5.2 tqdm>=4.47.0 @@ -56,7 +56,7 @@ tensorboard = gdown = gdown>=3.6.4 ignite = - pytorch-ignite==0.4.5 + pytorch-ignite==0.4.6 torchvision = torchvision itk = From 28fb7d6af1a74aac1576637403603de1c3d8a59a Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Tue, 28 Sep 2021 21:58:22 +0100 Subject: [PATCH 56/89] enhance DataStats to include dtype (#3043) * print dtype along with type Signed-off-by: Wenqi Li * update tests Signed-off-by: Wenqi Li --- monai/transforms/utility/array.py | 2 +- tests/test_data_stats.py | 6 ++++-- tests/test_data_statsd.py | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 3df53f8850..272c9963a8 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -577,7 +577,7 @@ def __call__( lines = [f"{prefix or self.prefix} statistics:"] if self.data_type if data_type is None else data_type: - lines.append(f"Type: {type(img)}") + lines.append(f"Type: {type(img)} {img.dtype if hasattr(img, 'dtype') else None}") if self.data_shape if data_shape is None else data_shape: lines.append(f"Shape: {img.shape}") if self.value_range if value_range is None else value_range: diff --git a/tests/test_data_stats.py b/tests/test_data_stats.py index a924fc0c48..535b28bcf1 100644 --- a/tests/test_data_stats.py +++ b/tests/test_data_stats.py @@ -11,6 +11,7 @@ import logging import os +import sys import tempfile import unittest @@ -126,7 +127,7 @@ TEST_CASE_8 = [ np.array([[0, 1], [1, 2]]), - "test data statistics:\nType: \nShape: (2, 2)\nValue range: (0, 2)\n" + "test data statistics:\nType: int64\nShape: (2, 2)\nValue range: (0, 2)\n" "Value: [[0 1]\n [1 2]]\nAdditional info: 1.0\n", ] @@ -161,7 +162,8 @@ def test_file(self, input_data, expected_print): _logger.removeHandler(h) with open(filename) as f: content = f.read() - self.assertEqual(content, expected_print) + if sys.platform != "win32": + self.assertEqual(content, expected_print) if __name__ == "__main__": diff --git a/tests/test_data_statsd.py b/tests/test_data_statsd.py index f2220f353f..686d23c4f9 100644 --- a/tests/test_data_statsd.py +++ b/tests/test_data_statsd.py @@ -11,6 +11,7 @@ import logging import os +import sys import tempfile import unittest @@ -147,7 +148,7 @@ TEST_CASE_9 = [ {"img": np.array([[0, 1], [1, 2]])}, - "test data statistics:\nType: \nShape: (2, 2)\nValue range: (0, 2)\n" + "test data statistics:\nType: int64\nShape: (2, 2)\nValue range: (0, 2)\n" "Value: [[0 1]\n [1 2]]\nAdditional info: 1.0\n", ] @@ -194,7 +195,8 @@ def test_file(self, input_data, expected_print): del handler with open(filename) as f: content = f.read() - self.assertEqual(content, expected_print) + if sys.platform != "win32": + self.assertEqual(content, expected_print) if __name__ == "__main__": From e4dd504cad220255ec1a8ab30fb50642d5369780 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Wed, 29 Sep 2021 00:02:20 +0100 Subject: [PATCH 57/89] enhance error handling (#3042) Signed-off-by: Wenqi Li --- monai/visualize/class_activation_maps.py | 9 +++++++++ tests/test_vis_gradcam.py | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/monai/visualize/class_activation_maps.py b/monai/visualize/class_activation_maps.py index 992eaecdac..6109d76a8a 100644 --- a/monai/visualize/class_activation_maps.py +++ b/monai/visualize/class_activation_maps.py @@ -137,6 +137,11 @@ def __call__(self, x, class_idx=None, retain_graph=False): self.score = self.class_score(logits, self.class_idx) self.model.zero_grad() self.score.sum().backward(retain_graph=retain_graph) + for layer in self.target_layers: + if layer not in self.gradients: + raise RuntimeError( + f"Backward hook for {layer} is not triggered; `requires_grad` of {layer} should be `True`." + ) grad = tuple(self.gradients[layer] for layer in self.target_layers) if train: self.model.train() @@ -221,6 +226,8 @@ class CAM(CAMBase): .. code-block:: python + import torch + # densenet 2d from monai.networks.nets import DenseNet121 from monai.visualize import CAM @@ -319,6 +326,8 @@ class GradCAM(CAMBase): .. code-block:: python + import torch + # densenet 2d from monai.networks.nets import DenseNet121 from monai.visualize import GradCAM diff --git a/tests/test_vis_gradcam.py b/tests/test_vis_gradcam.py index eebf32d70b..ecd62badcc 100644 --- a/tests/test_vis_gradcam.py +++ b/tests/test_vis_gradcam.py @@ -88,6 +88,16 @@ def test_shape(self, input_data, expected_shape): result2 = cam(x=image, layer_idx=-1, class_idx=model(image).max(1)[-1].cpu()) torch.testing.assert_allclose(result, result2) + def test_ill(self): + model = DenseNet121(spatial_dims=2, in_channels=1, out_channels=3) + for name, x in model.named_parameters(): + if "features" in name: + x.requires_grad = False + cam = GradCAM(nn_module=model, target_layers="class_layers.relu") + image = torch.rand((2, 1, 48, 64)) + with self.assertRaises(RuntimeError): + cam(x=image) + if __name__ == "__main__": unittest.main() From fc478b0a2ae8f8df2d157d362fc5aad34de53fb2 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Wed, 29 Sep 2021 11:56:23 +0100 Subject: [PATCH 58/89] 2792 - Torch GibbsNoise, RandGibbsNoise, KSpaceSpikeNoise, RandKSpaceSpikeNoise (#2974) GibbsNoise, RandGibbsNoise, KSpaceSpikeNoise, RandKSpaceSpikeNoise --- monai/transforms/intensity/array.py | 201 ++++++++++++----------- monai/transforms/intensity/dictionary.py | 72 +++----- monai/transforms/utils.py | 34 ++-- tests/test_gibbs_noise.py | 41 ++--- tests/test_gibbs_noised.py | 52 +++--- tests/test_k_space_spike_noise.py | 43 +++-- tests/test_k_space_spike_noised.py | 59 ++++--- tests/test_rand_gibbs_noise.py | 50 +++--- tests/test_rand_gibbs_noised.py | 66 ++++---- tests/test_rand_k_space_spike_noise.py | 62 ++++--- tests/test_rand_k_space_spike_noised.py | 66 ++++---- 11 files changed, 397 insertions(+), 349 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 1985399a2e..f9fc1ad6ab 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -39,7 +39,9 @@ ensure_tuple_size, fall_back_tuple, ) +from monai.utils.deprecated import deprecated_arg from monai.utils.enums import TransformBackends +from monai.utils.misc import is_module_ver_at_least from monai.utils.type_conversion import convert_to_tensor, get_equivalent_dtype __all__ = [ @@ -1271,68 +1273,6 @@ def __call__(self, img: np.ndarray) -> np.ndarray: ) -class RandGibbsNoise(RandomizableTransform): - """ - Naturalistic image augmentation via Gibbs artifacts. The transform - randomly applies Gibbs noise to 2D/3D MRI images. Gibbs artifacts - are one of the common type of type artifacts appearing in MRI scans. - - The transform is applied to all the channels in the data. - - For general information on Gibbs artifacts, please refer to: - https://pubs.rsna.org/doi/full/10.1148/rg.313105115 - https://pubs.rsna.org/doi/full/10.1148/radiographics.22.4.g02jl14949 - - - Args: - prob (float): probability of applying the transform. - alpha (float, Sequence(float)): Parametrizes the intensity of the Gibbs noise filter applied. Takes - values in the interval [0,1] with alpha = 0 acting as the identity mapping. - If a length-2 list is given as [a,b] then the value of alpha will be - sampled uniformly from the interval [a,b]. 0 <= a <= b <= 1. - as_tensor_output: if true return torch.Tensor, else return np.array. default: True. - """ - - def __init__(self, prob: float = 0.1, alpha: Sequence[float] = (0.0, 1.0), as_tensor_output: bool = True) -> None: - - if len(alpha) != 2: - raise ValueError("alpha length must be 2.") - if alpha[1] > 1 or alpha[0] < 0: - raise ValueError("alpha must take values in the interval [0,1]") - if alpha[0] > alpha[1]: - raise ValueError("When alpha = [a,b] we need a < b.") - - self.alpha = alpha - self.sampled_alpha = -1.0 # stores last alpha sampled by randomize() - self.as_tensor_output = as_tensor_output - - RandomizableTransform.__init__(self, prob=prob) - - def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, np.ndarray]: - - # randomize application and possibly alpha - self._randomize(None) - - if self._do_transform: - # apply transform - transform = GibbsNoise(self.sampled_alpha, self.as_tensor_output) - img = transform(img) - else: - if isinstance(img, np.ndarray) and self.as_tensor_output: - img = torch.Tensor(img) - elif isinstance(img, torch.Tensor) and not self.as_tensor_output: - img = img.detach().cpu().numpy() - return img - - def _randomize(self, _: Any) -> None: - """ - (1) Set random variable to apply the transform. - (2) Get alpha from uniform distribution. - """ - super().randomize(None) - self.sampled_alpha = self.R.uniform(self.alpha[0], self.alpha[1]) - - class GibbsNoise(Transform, Fourier): """ The transform applies Gibbs noise to 2D/3D MRI images. Gibbs artifacts @@ -1351,21 +1291,20 @@ class GibbsNoise(Transform, Fourier): Args: alpha: Parametrizes the intensity of the Gibbs noise filter applied. Takes values in the interval [0,1] with alpha = 0 acting as the identity mapping. - as_tensor_output: if true return torch.Tensor, else return np.array. Default: True. """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__(self, alpha: float = 0.5, as_tensor_output: bool = True) -> None: if alpha > 1 or alpha < 0: raise ValueError("alpha must take values in the interval [0,1].") self.alpha = alpha - self.as_tensor_output = as_tensor_output - def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, np.ndarray]: + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: n_dims = len(img.shape[1:]) - if isinstance(img, np.ndarray): - img = torch.Tensor(img) # FT k = self.shift_fourier(img, n_dims) # build and apply mask @@ -1373,13 +1312,13 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, # map back img = self.inv_shift_fourier(k, n_dims) - return img if self.as_tensor_output else img.cpu().detach().numpy() # type: ignore + return img - def _apply_mask(self, k: torch.Tensor) -> torch.Tensor: + def _apply_mask(self, k: NdarrayOrTensor) -> NdarrayOrTensor: """Builds and applies a mask on the spatial dimensions. Args: - k (np.ndarray): k-space version of the image. + k: k-space version of the image. Returns: masked version of the k-space image. """ @@ -1400,11 +1339,73 @@ def _apply_mask(self, k: torch.Tensor) -> torch.Tensor: # add channel dimension into mask mask = np.repeat(mask[None], k.shape[0], axis=0) + if isinstance(k, torch.Tensor): + mask, *_ = convert_data_type(mask, torch.Tensor, device=k.device) + # apply binary mask - k_masked = k * torch.tensor(mask, device=k.device) + k_masked: NdarrayOrTensor + k_masked = k * mask return k_masked +class RandGibbsNoise(RandomizableTransform): + """ + Naturalistic image augmentation via Gibbs artifacts. The transform + randomly applies Gibbs noise to 2D/3D MRI images. Gibbs artifacts + are one of the common type of type artifacts appearing in MRI scans. + + The transform is applied to all the channels in the data. + + For general information on Gibbs artifacts, please refer to: + https://pubs.rsna.org/doi/full/10.1148/rg.313105115 + https://pubs.rsna.org/doi/full/10.1148/radiographics.22.4.g02jl14949 + + + Args: + prob (float): probability of applying the transform. + alpha (float, Sequence(float)): Parametrizes the intensity of the Gibbs noise filter applied. Takes + values in the interval [0,1] with alpha = 0 acting as the identity mapping. + If a length-2 list is given as [a,b] then the value of alpha will be + sampled uniformly from the interval [a,b]. 0 <= a <= b <= 1. + """ + + backend = GibbsNoise.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") + def __init__(self, prob: float = 0.1, alpha: Sequence[float] = (0.0, 1.0), as_tensor_output: bool = True) -> None: + + if len(alpha) != 2: + raise ValueError("alpha length must be 2.") + if alpha[1] > 1 or alpha[0] < 0: + raise ValueError("alpha must take values in the interval [0,1]") + if alpha[0] > alpha[1]: + raise ValueError("When alpha = [a,b] we need a < b.") + + self.alpha = alpha + self.sampled_alpha = -1.0 # stores last alpha sampled by randomize() + + RandomizableTransform.__init__(self, prob=prob) + + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: + + # randomize application and possibly alpha + self._randomize(None) + + if self._do_transform: + # apply transform + transform = GibbsNoise(self.sampled_alpha) + img = transform(img) + return img + + def _randomize(self, _: Any) -> None: + """ + (1) Set random variable to apply the transform. + (2) Get alpha from uniform distribution. + """ + super().randomize(None) + self.sampled_alpha = self.R.uniform(self.alpha[0], self.alpha[1]) + + class KSpaceSpikeNoise(Transform, Fourier): """ Apply localized spikes in `k`-space at the given locations and intensities. @@ -1432,8 +1433,6 @@ class KSpaceSpikeNoise(Transform, Fourier): receive a sequence of intensities. This value should be tested as it is data-dependent. The default values are the 2.5 the mean of the log-intensity for each channel. - as_tensor_output: if ``True`` return torch.Tensor, else return np.array. - Default: ``True``. Example: When working with 4D data, ``KSpaceSpikeNoise(loc = ((3,60,64,32), (64,60,32)), k_intensity = (13,14))`` @@ -1442,6 +1441,9 @@ class KSpaceSpikeNoise(Transform, Fourier): with `log-intensity = 14`. """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, loc: Union[Tuple, Sequence[Tuple]], @@ -1450,7 +1452,6 @@ def __init__( ): self.loc = ensure_tuple(loc) - self.as_tensor_output = as_tensor_output self.k_intensity = k_intensity # assert one-to-one relationship between factors and locations @@ -1464,7 +1465,7 @@ def __init__( if isinstance(self.loc[0], Sequence) and k_intensity is not None and not isinstance(self.k_intensity, Sequence): raise ValueError("There must be one intensity_factor value for each tuple of indices in loc.") - def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, np.ndarray]: + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Args: img: image with dimensions (C, H, W) or (C, H, W, D) @@ -1481,17 +1482,17 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, n_dims = len(img.shape[1:]) - if isinstance(img, np.ndarray): - img = torch.Tensor(img) + lib = np if isinstance(img, np.ndarray) else torch + # FT k = self.shift_fourier(img, n_dims) - log_abs = torch.log(torch.absolute(k) + 1e-10) - phase = torch.angle(k) + log_abs = lib.log(lib.absolute(k) + 1e-10) # type: ignore + phase = lib.angle(k) # type: ignore k_intensity = self.k_intensity # default log intensity if k_intensity is None: - k_intensity = tuple(torch.mean(log_abs, dim=tuple(range(-n_dims, 0))) * 2.5) + k_intensity = tuple(lib.mean(log_abs, axis=tuple(range(-n_dims, 0))) * 2.5) # type: ignore # highlight if isinstance(self.loc[0], Sequence): @@ -1500,10 +1501,15 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, else: self._set_spike(log_abs, self.loc, k_intensity) # map back - k = torch.exp(log_abs) * torch.exp(1j * phase) + # complex exponential not implemented for older pytorch + if isinstance(phase, torch.Tensor) and not is_module_ver_at_least(torch, (1, 6, 0)): + phase = phase.cpu() + k = torch.exp(log_abs) * torch.exp(1j * phase.cpu()).to(log_abs.device) + else: + k = lib.exp(log_abs) * lib.exp(1j * phase) # type: ignore img = self.inv_shift_fourier(k, n_dims) - return img if self.as_tensor_output else img.cpu().detach().numpy() # type: ignore + return img def _check_indices(self, img) -> None: """Helper method to check consistency of self.loc and input image. @@ -1523,7 +1529,7 @@ def _check_indices(self, img) -> None: f"The index value at position {i} of one of the tuples in loc = {self.loc} is out of bounds for current image." ) - def _set_spike(self, k: torch.Tensor, idx: Tuple, val: Union[Sequence[float], float]): + def _set_spike(self, k: NdarrayOrTensor, idx: Tuple, val: Union[Sequence[float], float]): """ Helper function to introduce a given intensity at given location. @@ -1569,8 +1575,6 @@ class RandKSpaceSpikeNoise(RandomizableTransform, Fourier): log-intensity for each channel. channel_wise: treat each channel independently. True by default. - as_tensor_output: if True return torch.Tensor, else - return np.array. default: True. Example: To apply `k`-space spikes randomly with probability 0.5, and @@ -1579,6 +1583,9 @@ class RandKSpaceSpikeNoise(RandomizableTransform, Fourier): ``RandKSpaceSpikeNoise(prob=0.5, intensity_range=(11, 12), channel_wise=True)`` """ + backend = KSpaceSpikeNoise.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, prob: float = 0.1, @@ -1589,7 +1596,6 @@ def __init__( self.intensity_range = intensity_range self.channel_wise = channel_wise - self.as_tensor_output = as_tensor_output self.sampled_k_intensity: List = [] self.sampled_locs: List[Tuple] = [] @@ -1598,7 +1604,7 @@ def __init__( super().__init__(prob) - def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, np.ndarray]: + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply transform to `img`. Assumes data is in channel-first form. @@ -1617,20 +1623,18 @@ def __call__(self, img: Union[np.ndarray, torch.Tensor]) -> Union[torch.Tensor, self.sampled_k_intensity = [] self.sampled_locs = [] - if not isinstance(img, torch.Tensor): - img = torch.Tensor(img) - intensity_range = self._make_sequence(img) self._randomize(img, intensity_range) # build/appy transform only if there are spike locations if self.sampled_locs: - transform = KSpaceSpikeNoise(self.sampled_locs, self.sampled_k_intensity, self.as_tensor_output) - return transform(img) + transform = KSpaceSpikeNoise(self.sampled_locs, self.sampled_k_intensity) + out: NdarrayOrTensor = transform(img) + return out - return img if self.as_tensor_output else img.detach().numpy() + return img - def _randomize(self, img: torch.Tensor, intensity_range: Sequence[Sequence[float]]) -> None: + def _randomize(self, img: NdarrayOrTensor, intensity_range: Sequence[Sequence[float]]) -> None: """ Helper method to sample both the location and intensity of the spikes. When not working channel wise (channel_wise=False) it use the random @@ -1658,7 +1662,7 @@ def _randomize(self, img: torch.Tensor, intensity_range: Sequence[Sequence[float else: self.sampled_k_intensity = [self.R.uniform(intensity_range[0], intensity_range[1])] * len(img) - def _make_sequence(self, x: torch.Tensor) -> Sequence[Sequence[float]]: + def _make_sequence(self, x: NdarrayOrTensor) -> Sequence[Sequence[float]]: """ Formats the sequence of intensities ranges to Sequence[Sequence[float]]. """ @@ -1670,7 +1674,7 @@ def _make_sequence(self, x: torch.Tensor) -> Sequence[Sequence[float]]: return (ensure_tuple(self.intensity_range),) * x.shape[0] return ensure_tuple(self.intensity_range) - def _set_default_range(self, img: torch.Tensor) -> Sequence[Sequence[float]]: + def _set_default_range(self, img: NdarrayOrTensor) -> Sequence[Sequence[float]]: """ Sets default intensity ranges to be sampled. @@ -1680,8 +1684,9 @@ def _set_default_range(self, img: torch.Tensor) -> Sequence[Sequence[float]]: n_dims = len(img.shape[1:]) k = self.shift_fourier(img, n_dims) - log_abs = torch.log(torch.absolute(k) + 1e-10) - shifted_means = torch.mean(log_abs, dim=tuple(range(-n_dims, 0))) * 2.5 + mod = torch if isinstance(img, torch.Tensor) else np + log_abs = mod.log(mod.absolute(k) + 1e-10) # type: ignore + shifted_means = mod.mean(log_abs, dim=tuple(range(-n_dims, 0))) * 2.5 # type: ignore return tuple((i * 0.95, i * 1.1) for i in shifted_means) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index e95e00880e..204b3d7c37 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -48,6 +48,7 @@ from monai.transforms.transform import MapTransform, Randomizable, RandomizableTransform from monai.transforms.utils import is_positive from monai.utils import convert_to_dst_type, ensure_tuple, ensure_tuple_rep, ensure_tuple_size +from monai.utils.deprecated import deprecated_arg from monai.utils.type_conversion import convert_data_type __all__ = [ @@ -1171,28 +1172,27 @@ class RandGibbsNoised(RandomizableTransform, MapTransform): values in the interval [0,1] with alpha = 0 acting as the identity mapping. If a length-2 list is given as [a,b] then the value of alpha will be sampled uniformly from the interval [a,b]. - as_tensor_output: if true return torch.Tensor, else return np.array. default: True. allow_missing_keys: do not raise exception if key is missing. """ + backend = GibbsNoise.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, keys: KeysCollection, prob: float = 0.1, alpha: Sequence[float] = (0.0, 1.0), - as_tensor_output: bool = True, allow_missing_keys: bool = False, + as_tensor_output: bool = True, ) -> None: MapTransform.__init__(self, keys, allow_missing_keys) RandomizableTransform.__init__(self, prob=prob) self.alpha = alpha self.sampled_alpha = -1.0 # stores last alpha sampled by randomize() - self.as_tensor_output = as_tensor_output - def __call__( - self, data: Mapping[Hashable, Union[torch.Tensor, np.ndarray]] - ) -> Dict[Hashable, Union[torch.Tensor, np.ndarray]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) self._randomize(None) @@ -1200,13 +1200,8 @@ def __call__( for i, key in enumerate(self.key_iterator(d)): if self._do_transform: if i == 0: - transform = GibbsNoise(self.sampled_alpha, self.as_tensor_output) + transform = GibbsNoise(self.sampled_alpha) d[key] = transform(d[key]) - else: - if isinstance(d[key], np.ndarray) and self.as_tensor_output: - d[key] = torch.Tensor(d[key]) - elif isinstance(d[key], torch.Tensor) and not self.as_tensor_output: - d[key] = self._to_numpy(d[key]) return d def _randomize(self, _: Any) -> None: @@ -1217,11 +1212,6 @@ def _randomize(self, _: Any) -> None: super().randomize(None) self.sampled_alpha = self.R.uniform(self.alpha[0], self.alpha[1]) - def _to_numpy(self, d: Union[torch.Tensor, np.ndarray]) -> np.ndarray: - if isinstance(d, torch.Tensor): - d_numpy: np.ndarray = d.cpu().detach().numpy() - return d_numpy - class GibbsNoised(MapTransform): """ @@ -1239,20 +1229,20 @@ class GibbsNoised(MapTransform): you need to transform. alpha (float): Parametrizes the intensity of the Gibbs noise filter applied. Takes values in the interval [0,1] with alpha = 0 acting as the identity mapping. - as_tensor_output: if true return torch.Tensor, else return np.array. default: True. allow_missing_keys: do not raise exception if key is missing. """ + backend = GibbsNoise.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( - self, keys: KeysCollection, alpha: float = 0.5, as_tensor_output: bool = True, allow_missing_keys: bool = False + self, keys: KeysCollection, alpha: float = 0.5, allow_missing_keys: bool = False, as_tensor_output: bool = True ) -> None: MapTransform.__init__(self, keys, allow_missing_keys) - self.transform = GibbsNoise(alpha, as_tensor_output) + self.transform = GibbsNoise(alpha) - def __call__( - self, data: Mapping[Hashable, Union[torch.Tensor, np.ndarray]] - ) -> Dict[Hashable, Union[torch.Tensor, np.ndarray]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): @@ -1291,8 +1281,6 @@ class KSpaceSpikeNoised(MapTransform): receive a sequence of intensities. This value should be tested as it is data-dependent. The default values are the 2.5 the mean of the log-intensity for each channel. - as_tensor_output: if ``True`` return torch.Tensor, else return np.array. - Default: ``True``. allow_missing_keys: do not raise exception if key is missing. Example: @@ -1303,21 +1291,22 @@ class KSpaceSpikeNoised(MapTransform): with `log-intensity = 14`. """ + backend = KSpaceSpikeNoise.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, keys: KeysCollection, loc: Union[Tuple, Sequence[Tuple]], k_intensity: Optional[Union[Sequence[float], float]] = None, - as_tensor_output: bool = True, allow_missing_keys: bool = False, + as_tensor_output: bool = True, ) -> None: super().__init__(keys, allow_missing_keys) - self.transform = KSpaceSpikeNoise(loc, k_intensity, as_tensor_output) + self.transform = KSpaceSpikeNoise(loc, k_intensity) - def __call__( - self, data: Mapping[Hashable, Union[torch.Tensor, np.ndarray]] - ) -> Dict[Hashable, Union[torch.Tensor, np.ndarray]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: """ Args: data: Expects image/label to have dimensions (C, H, W) or @@ -1364,8 +1353,6 @@ class RandKSpaceSpikeNoised(RandomizableTransform, MapTransform): common_sampling: If ``True`` same values for location and log-intensity will be sampled for the image and label. common_seed: Seed to be used in case ``common_sampling = True``. - as_tensor_output: if ``True`` return torch.Tensor, else return - np.array. Default: ``True``. allow_missing_keys: do not raise exception if key is missing. Example: @@ -1375,6 +1362,9 @@ class RandKSpaceSpikeNoised(RandomizableTransform, MapTransform): ``RandKSpaceSpikeNoised("image", prob=0.5, intensity_ranges={"image":(13,15)}, channel_wise=True)``. """ + backend = KSpaceSpikeNoise.backend + + @deprecated_arg(name="as_tensor_output", since="0.6") def __init__( self, keys: KeysCollection, @@ -1384,8 +1374,8 @@ def __init__( channel_wise: bool = True, common_sampling: bool = False, common_seed: int = 42, - as_tensor_output: bool = True, allow_missing_keys: bool = False, + as_tensor_output: bool = True, ): MapTransform.__init__(self, keys, allow_missing_keys) @@ -1393,21 +1383,16 @@ def __init__( self.common_sampling = common_sampling self.common_seed = common_seed - self.as_tensor_output = as_tensor_output # the spikes artifact is amplitude dependent so we instantiate one per key self.transforms = {} if isinstance(intensity_ranges, Mapping): for k in self.keys: - self.transforms[k] = RandKSpaceSpikeNoise( - prob, intensity_ranges[k], channel_wise, self.as_tensor_output - ) + self.transforms[k] = RandKSpaceSpikeNoise(prob, intensity_ranges[k], channel_wise) else: for k in self.keys: - self.transforms[k] = RandKSpaceSpikeNoise(prob, None, channel_wise, self.as_tensor_output) + self.transforms[k] = RandKSpaceSpikeNoise(prob, None, channel_wise) - def __call__( - self, data: Mapping[Hashable, Union[torch.Tensor, np.ndarray]] - ) -> Dict[Hashable, Union[torch.Tensor, np.ndarray]]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: """ Args: data: Expects image/label to have dimensions (C, H, W) or @@ -1424,11 +1409,6 @@ def __call__( for key, t in self.key_iterator(d, self.transforms): if self._do_transform: d[key] = self.transforms[t](d[key]) - else: - if isinstance(d[key], np.ndarray) and self.as_tensor_output: - d[key] = torch.Tensor(d[key]) - elif isinstance(d[key], torch.Tensor) and not self.as_tensor_output: - d[key] = self._to_numpy(d[key]) return d def set_rand_state(self, seed: Optional[int] = None, state: Optional[np.random.RandomState] = None) -> None: diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 5301b6ac09..4927f9a478 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -43,7 +43,7 @@ optional_import, ) from monai.utils.enums import TransformBackends -from monai.utils.type_conversion import convert_data_type +from monai.utils.type_conversion import convert_data_type, convert_to_dst_type measure, _ = optional_import("skimage.measure", "0.14.2", min_version) ndimage, _ = optional_import("scipy.ndimage") @@ -1253,7 +1253,7 @@ class Fourier: @deprecated_arg( name="n_dims", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." ) - def shift_fourier(x: torch.Tensor, spatial_dims: int, n_dims: Optional[int] = None) -> torch.Tensor: + def shift_fourier(x: NdarrayOrTensor, spatial_dims: int, n_dims: Optional[int] = None) -> NdarrayOrTensor: """ Applies fourier transform and shifts the zero-frequency component to the center of the spectrum. Only the spatial dimensions get transformed. @@ -1270,16 +1270,23 @@ def shift_fourier(x: torch.Tensor, spatial_dims: int, n_dims: Optional[int] = No """ if n_dims is not None: spatial_dims = n_dims - k: torch.Tensor = torch.fft.fftshift( - torch.fft.fftn(x, dim=tuple(range(-spatial_dims, 0))), dim=tuple(range(-spatial_dims, 0)) - ) + dims = tuple(range(-spatial_dims, 0)) + k: NdarrayOrTensor + if isinstance(x, torch.Tensor): + if hasattr(torch.fft, "fftshift"): + k = torch.fft.fftshift(torch.fft.fftn(x, dim=dims), dim=dims) + else: + k = np.fft.fftshift(np.fft.fftn(x.cpu().numpy(), axes=dims), axes=dims) + k, *_ = convert_to_dst_type(k, x) + else: + k = np.fft.fftshift(np.fft.fftn(x, axes=dims), axes=dims) return k @staticmethod @deprecated_arg( name="n_dims", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." ) - def inv_shift_fourier(k: torch.Tensor, spatial_dims: int, n_dims: Optional[int] = None) -> torch.Tensor: + def inv_shift_fourier(k: NdarrayOrTensor, spatial_dims: int, n_dims: Optional[int] = None) -> NdarrayOrTensor: """ Applies inverse shift and fourier transform. Only the spatial dimensions are transformed. @@ -1296,10 +1303,17 @@ def inv_shift_fourier(k: torch.Tensor, spatial_dims: int, n_dims: Optional[int] """ if n_dims is not None: spatial_dims = n_dims - x: torch.Tensor = torch.fft.ifftn( - torch.fft.ifftshift(k, dim=tuple(range(-spatial_dims, 0))), dim=tuple(range(-spatial_dims, 0)) - ).real - return x + dims = tuple(range(-spatial_dims, 0)) + out: NdarrayOrTensor + if isinstance(k, torch.Tensor): + if hasattr(torch.fft, "ifftshift"): + out = torch.fft.ifftn(torch.fft.ifftshift(k, dim=dims), dim=dims, norm="backward").real + else: + out = np.fft.ifftn(np.fft.ifftshift(k.cpu().numpy(), axes=dims), axes=dims).real + out, *_ = convert_to_dst_type(out, k) + else: + out = np.fft.ifftn(np.fft.ifftshift(k, axes=dims), axes=dims).real + return out def get_number_image_type_conversions(transform: Compose, test_data: Any, key: Optional[Hashable] = None) -> int: diff --git a/tests/test_gibbs_noise.py b/tests/test_gibbs_noise.py index 264e2e630a..2c5e117eaf 100644 --- a/tests/test_gibbs_noise.py +++ b/tests/test_gibbs_noise.py @@ -19,17 +19,17 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import GibbsNoise from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from monai.utils.module import optional_import +from tests.utils import TEST_NDARRAYS + +_, has_torch_fft = optional_import("torch.fft", name="fftshift") TEST_CASES = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input)) + for input_type in TEST_NDARRAYS if has_torch_fft else [np.array]: + TEST_CASES.append((shape, input_type)) -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestGibbsNoise(unittest.TestCase): def setUp(self): set_determinism(0) @@ -39,36 +39,39 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, input_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d im = create_test_image(*im_shape, num_objs=4, rad_max=20, noise_max=0.0, num_seg_classes=5)[0][None] - return torch.Tensor(im) if as_tensor_input else im + return input_type(im) @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_same_result(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = 0.8 - t = GibbsNoise(alpha, as_tensor_output) + t = GibbsNoise(alpha) out1 = t(deepcopy(im)) out2 = t(deepcopy(im)) - np.testing.assert_allclose(out1, out2) - self.assertIsInstance(out1, torch.Tensor if as_tensor_output else np.ndarray) + self.assertEqual(type(out1), type(im)) + if isinstance(out1, torch.Tensor): + self.assertEqual(out1.device, im.device) + torch.testing.assert_allclose(out1, out2, rtol=1e-7, atol=0) + self.assertIsInstance(out1, type(im)) @parameterized.expand(TEST_CASES) - def test_identity(self, im_shape, _, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_identity(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = 0.0 t = GibbsNoise(alpha) out = t(deepcopy(im)) - np.testing.assert_allclose(im, out, atol=1e-2) + torch.testing.assert_allclose(im, out, atol=1e-2, rtol=1e-7) @parameterized.expand(TEST_CASES) - def test_alpha_1(self, im_shape, _, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_alpha_1(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = 1.0 t = GibbsNoise(alpha) out = t(deepcopy(im)) - np.testing.assert_allclose(0 * im, out) + torch.testing.assert_allclose(0 * im, out, rtol=1e-7, atol=0) if __name__ == "__main__": diff --git a/tests/test_gibbs_noised.py b/tests/test_gibbs_noised.py index 558556489a..f02052818f 100644 --- a/tests/test_gibbs_noised.py +++ b/tests/test_gibbs_noised.py @@ -19,19 +19,18 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import GibbsNoised from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from monai.utils.module import optional_import +from tests.utils import TEST_NDARRAYS + +_, has_torch_fft = optional_import("torch.fft", name="fftshift") TEST_CASES = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input)) - + for input_type in TEST_NDARRAYS if has_torch_fft else [np.array]: + TEST_CASES.append((shape, input_type)) KEYS = ["im", "label"] -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestGibbsNoised(unittest.TestCase): def setUp(self): set_determinism(0) @@ -41,49 +40,56 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, input_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d ims = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5) - ims = [torch.Tensor(im) for im in ims] if as_tensor_input else ims - return dict(zip(KEYS, ims)) + return {k: input_type(deepcopy(v)) for k, v in zip(KEYS, ims)} @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_same_result(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = 0.8 - t = GibbsNoised(KEYS, alpha, as_tensor_output) + t = GibbsNoised(KEYS, alpha) out1 = t(deepcopy(data)) out2 = t(deepcopy(data)) for k in KEYS: - np.testing.assert_allclose(out1[k], out2[k]) - self.assertIsInstance(out1[k], torch.Tensor if as_tensor_output else np.ndarray) + torch.testing.assert_allclose(out1[k], out2[k], rtol=1e-7, atol=0) + self.assertIsInstance(out1[k], type(data[k])) @parameterized.expand(TEST_CASES) - def test_identity(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_identity(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = 0.0 t = GibbsNoised(KEYS, alpha) out = t(deepcopy(data)) for k in KEYS: + self.assertEqual(type(out[k]), type(data[k])) + if isinstance(out[k], torch.Tensor): + self.assertEqual(out[k].device, data[k].device) + out[k], data[k] = out[k].cpu(), data[k].cpu() np.testing.assert_allclose(data[k], out[k], atol=1e-2) @parameterized.expand(TEST_CASES) - def test_alpha_1(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_alpha_1(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = 1.0 t = GibbsNoised(KEYS, alpha) out = t(deepcopy(data)) for k in KEYS: - np.testing.assert_allclose(0 * data[k], out[k]) + self.assertEqual(type(out[k]), type(data[k])) + if isinstance(out[k], torch.Tensor): + self.assertEqual(out[k].device, data[k].device) + out[k], data[k] = out[k].cpu(), data[k].cpu() + np.testing.assert_allclose(0.0 * data[k], out[k], atol=1e-2) @parameterized.expand(TEST_CASES) - def test_dict_matches(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_dict_matches(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) data = {KEYS[0]: deepcopy(data[KEYS[0]]), KEYS[1]: deepcopy(data[KEYS[0]])} alpha = 1.0 t = GibbsNoised(KEYS, alpha) out = t(deepcopy(data)) - np.testing.assert_allclose(out[KEYS[0]], out[KEYS[1]]) + torch.testing.assert_allclose(out[KEYS[0]], out[KEYS[1]], rtol=1e-7, atol=0) if __name__ == "__main__": diff --git a/tests/test_k_space_spike_noise.py b/tests/test_k_space_spike_noise.py index bb6d05e676..66763f286f 100644 --- a/tests/test_k_space_spike_noise.py +++ b/tests/test_k_space_spike_noise.py @@ -20,17 +20,14 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import KSpaceSpikeNoise from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from tests.utils import TEST_NDARRAYS -TEST_CASES = [] +TESTS = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input)) + for p in TEST_NDARRAYS: + TESTS.append((shape, p)) -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestKSpaceSpikeNoise(unittest.TestCase): def setUp(self): set_determinism(0) @@ -40,34 +37,44 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, im_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d - im = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5)[0][None] - return torch.Tensor(im) if as_tensor_input else im + im, _ = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5) + return im_type(im[None]) - @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): + @parameterized.expand(TESTS) + def test_same_result(self, im_shape, im_type): - im = self.get_data(im_shape, as_tensor_input) + im = self.get_data(im_shape, im_type) loc = [0, int(im.shape[1] / 2), 0] if len(im_shape) == 2 else [0, int(im.shape[1] / 2), 0, 0] k_intensity = 10 - t = KSpaceSpikeNoise(loc, k_intensity, as_tensor_output) + t = KSpaceSpikeNoise(loc, k_intensity) out1 = t(deepcopy(im)) out2 = t(deepcopy(im)) + self.assertEqual(type(im), type(out1)) + if isinstance(out1, torch.Tensor): + self.assertEqual(im.device, out1.device) + out1 = out1.cpu() + out2 = out2.cpu() + np.testing.assert_allclose(out1, out2) - self.assertIsInstance(out1, torch.Tensor if as_tensor_output else np.ndarray) - @parameterized.expand(TEST_CASES) - def test_highlighted_kspace_pixel(self, im_shape, as_tensor_output, as_tensor_input): + @parameterized.expand(TESTS) + def test_highlighted_kspace_pixel(self, im_shape, as_tensor_input): im = self.get_data(im_shape, as_tensor_input) loc = [0, int(im.shape[1] / 2), 0] if len(im_shape) == 2 else [0, int(im.shape[1] / 2), 0, 0] k_intensity = 10 - t = KSpaceSpikeNoise(loc, k_intensity, as_tensor_output) + t = KSpaceSpikeNoise(loc, k_intensity) out = t(im) + self.assertEqual(type(im), type(out)) + if isinstance(out, torch.Tensor): + self.assertEqual(im.device, out.device) + out = out.cpu() + n_dims = len(im_shape) out_k = fftshift(fftn(out, axes=tuple(range(-n_dims, 0))), axes=tuple(range(-n_dims, 0))) log_mag = np.log(np.absolute(out_k)) diff --git a/tests/test_k_space_spike_noised.py b/tests/test_k_space_spike_noised.py index 616662b3cd..3fa6a394f3 100644 --- a/tests/test_k_space_spike_noised.py +++ b/tests/test_k_space_spike_noised.py @@ -20,19 +20,16 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import KSpaceSpikeNoised from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from tests.utils import TEST_NDARRAYS -TEST_CASES = [] +TESTS = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input)) + for p in TEST_NDARRAYS: + TESTS.append((shape, p)) KEYS = ["image", "label"] -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestKSpaceSpikeNoised(unittest.TestCase): def setUp(self): set_determinism(0) @@ -42,55 +39,69 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, im_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d ims = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5) - ims = [im[None] for im in ims] - ims = [torch.Tensor(im) for im in ims] if as_tensor_input else ims - return dict(zip(KEYS, ims)) + ims = [im_type(im[None]) for im in ims] + return {k: v for k, v in zip(KEYS, ims)} - @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): + @parameterized.expand(TESTS) + def test_same_result(self, im_shape, im_type): - data = self.get_data(im_shape, as_tensor_input) + data = self.get_data(im_shape, im_type) loc = [0] + [int(im_shape[i] / 2) for i in range(len(im_shape))] k_intensity = 10 - t = KSpaceSpikeNoised(KEYS, loc, k_intensity, as_tensor_output) + t = KSpaceSpikeNoised(KEYS, loc, k_intensity) out1 = t(deepcopy(data)) out2 = t(deepcopy(data)) for k in KEYS: + self.assertEqual(type(out1[k]), type(data[k])) + if isinstance(out1[k], torch.Tensor): + self.assertEqual(out1[k].device, data[k].device) + out1[k] = out1[k].cpu() + out2[k] = out2[k].cpu() np.testing.assert_allclose(out1[k], out2[k]) - self.assertIsInstance(out1[k], torch.Tensor if as_tensor_output else np.ndarray) - @parameterized.expand(TEST_CASES) - def test_highlighted_kspace_pixel(self, im_shape, as_tensor_output, as_tensor_input): + @parameterized.expand(TESTS) + def test_highlighted_kspace_pixel(self, im_shape, im_type): - data = self.get_data(im_shape, as_tensor_input) + data = self.get_data(im_shape, im_type) loc = [0] + [int(im_shape[i] / 2) for i in range(len(im_shape))] k_intensity = 10 - t = KSpaceSpikeNoised(KEYS, loc, k_intensity, as_tensor_output) + t = KSpaceSpikeNoised(KEYS, loc, k_intensity) out = t(data) for k in KEYS: + self.assertEqual(type(out[k]), type(data[k])) + if isinstance(out[k], torch.Tensor): + self.assertEqual(out[k].device, data[k].device) + out[k] = out[k].cpu() + n_dims = len(im_shape) out_k = fftshift(fftn(out[k], axes=tuple(range(-n_dims, 0))), axes=tuple(range(-n_dims, 0))) log_mag = np.log(np.absolute(out_k)) np.testing.assert_allclose(k_intensity, log_mag[tuple(loc)], 1e-1) - @parameterized.expand(TEST_CASES) - def test_dict_matches(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + @parameterized.expand(TESTS) + def test_dict_matches(self, im_shape, im_type): + data = self.get_data(im_shape, im_type) # use same image for both dictionary entries to check same trans is applied to them data = {KEYS[0]: deepcopy(data[KEYS[0]]), KEYS[1]: deepcopy(data[KEYS[0]])} loc = [0] + [int(im_shape[i] / 2) for i in range(len(im_shape))] k_intensity = 10 - t = KSpaceSpikeNoised(KEYS, loc, k_intensity, as_tensor_output) + t = KSpaceSpikeNoised(KEYS, loc, k_intensity) out = t(deepcopy(data)) + for k in KEYS: + self.assertEqual(type(out[k]), type(data[k])) + if isinstance(out[k], torch.Tensor): + self.assertEqual(out[k].device, data[k].device) + out[k] = out[k].cpu() + np.testing.assert_allclose(out[KEYS[0]], out[KEYS[1]]) diff --git a/tests/test_rand_gibbs_noise.py b/tests/test_rand_gibbs_noise.py index a0701d09c3..15cadea0e2 100644 --- a/tests/test_rand_gibbs_noise.py +++ b/tests/test_rand_gibbs_noise.py @@ -19,17 +19,17 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import RandGibbsNoise from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from monai.utils.module import optional_import +from tests.utils import TEST_NDARRAYS + +_, has_torch_fft = optional_import("torch.fft", name="fftshift") TEST_CASES = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input)) + for input_type in TEST_NDARRAYS if has_torch_fft else [np.array]: + TEST_CASES.append((shape, input_type)) -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestRandGibbsNoise(unittest.TestCase): def setUp(self): set_determinism(0) @@ -39,50 +39,50 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, input_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d im = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5)[0][None] - return torch.Tensor(im) if as_tensor_input else im + return input_type(im) @parameterized.expand(TEST_CASES) - def test_0_prob(self, im_shape, as_tensor_output, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_0_prob(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = [0.5, 1.0] - t = RandGibbsNoise(0.0, alpha, as_tensor_output) + t = RandGibbsNoise(0.0, alpha) out = t(im) - np.testing.assert_allclose(im, out) + torch.testing.assert_allclose(im, out, rtol=1e-7, atol=0) @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_same_result(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = [0.5, 0.8] - t = RandGibbsNoise(1.0, alpha, as_tensor_output) + t = RandGibbsNoise(1.0, alpha) t.set_random_state(42) out1 = t(deepcopy(im)) t.set_random_state(42) out2 = t(deepcopy(im)) - np.testing.assert_allclose(out1, out2) - self.assertIsInstance(out1, torch.Tensor if as_tensor_output else np.ndarray) + torch.testing.assert_allclose(out1, out2, rtol=1e-7, atol=0) + self.assertIsInstance(out1, type(im)) @parameterized.expand(TEST_CASES) - def test_identity(self, im_shape, _, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_identity(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = [0.0, 0.0] t = RandGibbsNoise(1.0, alpha) out = t(deepcopy(im)) - np.testing.assert_allclose(im, out, atol=1e-2) + torch.testing.assert_allclose(im, out, atol=1e-2, rtol=1e-7) @parameterized.expand(TEST_CASES) - def test_alpha_1(self, im_shape, _, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_alpha_1(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = [1.0, 1.0] t = RandGibbsNoise(1.0, alpha) out = t(deepcopy(im)) - np.testing.assert_allclose(0 * im, out) + torch.testing.assert_allclose(0 * im, out, rtol=1e-7, atol=0) @parameterized.expand(TEST_CASES) - def test_alpha(self, im_shape, _, as_tensor_input): - im = self.get_data(im_shape, as_tensor_input) + def test_alpha(self, im_shape, input_type): + im = self.get_data(im_shape, input_type) alpha = [0.5, 0.51] t = RandGibbsNoise(1.0, alpha) _ = t(deepcopy(im)) diff --git a/tests/test_rand_gibbs_noised.py b/tests/test_rand_gibbs_noised.py index b778bffdda..b8bac67b81 100644 --- a/tests/test_rand_gibbs_noised.py +++ b/tests/test_rand_gibbs_noised.py @@ -19,19 +19,19 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import RandGibbsNoised from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from monai.utils.module import optional_import +from tests.utils import TEST_NDARRAYS + +_, has_torch_fft = optional_import("torch.fft", name="fftshift") TEST_CASES = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input)) + for input_type in TEST_NDARRAYS if has_torch_fft else [np.array]: + TEST_CASES.append((shape, input_type)) KEYS = ["im", "label"] -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestRandGibbsNoised(unittest.TestCase): def setUp(self): set_determinism(0) @@ -41,70 +41,76 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, input_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d ims = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5) - ims = [torch.Tensor(im) for im in ims] if as_tensor_input else ims - return dict(zip(KEYS, ims)) + return {k: input_type(v) for k, v in zip(KEYS, ims)} @parameterized.expand(TEST_CASES) - def test_0_prob(self, im_shape, as_tensor_output, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_0_prob(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = [0.5, 1.0] - t = RandGibbsNoised(KEYS, 0.0, alpha, as_tensor_output) + t = RandGibbsNoised(KEYS, 0.0, alpha) out = t(data) for k in KEYS: - np.testing.assert_allclose(data[k], out[k]) + torch.testing.assert_allclose(data[k], out[k], rtol=1e-7, atol=0) @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_same_result(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = [0.5, 0.8] - t = RandGibbsNoised(KEYS, 1.0, alpha, as_tensor_output) + t = RandGibbsNoised(KEYS, 1.0, alpha) t.set_random_state(42) out1 = t(deepcopy(data)) t.set_random_state(42) out2 = t(deepcopy(data)) for k in KEYS: - np.testing.assert_allclose(out1[k], out2[k]) - self.assertIsInstance(out1[k], torch.Tensor if as_tensor_output else np.ndarray) + torch.testing.assert_allclose(out1[k], out2[k], rtol=1e-7, atol=0) + self.assertIsInstance(out1[k], type(data[k])) @parameterized.expand(TEST_CASES) - def test_identity(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_identity(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = [0.0, 0.0] t = RandGibbsNoised(KEYS, 1.0, alpha) out = t(deepcopy(data)) for k in KEYS: + self.assertEqual(type(out[k]), type(data[k])) + if isinstance(out[k], torch.Tensor): + self.assertEqual(out[k].device, data[k].device) + out[k], data[k] = out[k].cpu(), data[k].cpu() np.testing.assert_allclose(data[k], out[k], atol=1e-2) @parameterized.expand(TEST_CASES) - def test_alpha_1(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_alpha_1(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = [1.0, 1.0] t = RandGibbsNoised(KEYS, 1.0, alpha) out = t(deepcopy(data)) for k in KEYS: - np.testing.assert_allclose(0 * data[k], out[k]) + self.assertEqual(type(out[k]), type(data[k])) + if isinstance(out[k], torch.Tensor): + self.assertEqual(out[k].device, data[k].device) + out[k], data[k] = out[k].cpu(), data[k].cpu() + np.testing.assert_allclose(0.0 * data[k], out[k], atol=1e-2) @parameterized.expand(TEST_CASES) - def test_dict_matches(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_dict_matches(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) # use same image for both dictionary entries to check same trans is applied to them data = {KEYS[0]: deepcopy(data[KEYS[0]]), KEYS[1]: deepcopy(data[KEYS[0]])} alpha = [0.5, 1.0] t = RandGibbsNoised(KEYS, 1.0, alpha) out = t(deepcopy(data)) - np.testing.assert_allclose(out[KEYS[0]], out[KEYS[1]]) + torch.testing.assert_allclose(out[KEYS[0]], out[KEYS[1]], rtol=1e-7, atol=0) @parameterized.expand(TEST_CASES) - def test_alpha(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + def test_alpha(self, im_shape, input_type): + data = self.get_data(im_shape, input_type) alpha = [0.5, 0.51] t = RandGibbsNoised(KEYS, 1.0, alpha) _ = t(deepcopy(data)) - self.assertGreaterEqual(t.sampled_alpha, 0.5) - self.assertLessEqual(t.sampled_alpha, 0.51) + self.assertTrue(0.5 <= t.sampled_alpha <= 0.51) if __name__ == "__main__": diff --git a/tests/test_rand_k_space_spike_noise.py b/tests/test_rand_k_space_spike_noise.py index 71f7e36d9b..1c9ca9c1d5 100644 --- a/tests/test_rand_k_space_spike_noise.py +++ b/tests/test_rand_k_space_spike_noise.py @@ -19,18 +19,15 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import KSpaceSpikeNoise, RandKSpaceSpikeNoise from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from tests.utils import TEST_NDARRAYS -TEST_CASES = [] +TESTS = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - for channel_wise in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input, channel_wise)) + for p in TEST_NDARRAYS: + for channel_wise in (True, False): + TESTS.append((shape, p, channel_wise)) -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestRandKSpaceSpikeNoise(unittest.TestCase): def setUp(self): set_determinism(0) @@ -40,44 +37,55 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, im_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d im = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5)[0][None] - return torch.Tensor(im) if as_tensor_input else im + return im_type(im) - @parameterized.expand(TEST_CASES) - def test_0_prob(self, im_shape, as_tensor_output, as_tensor_input, channel_wise): - im = self.get_data(im_shape, as_tensor_input) + @parameterized.expand(TESTS) + def test_0_prob(self, im_shape, im_type, channel_wise): + im = self.get_data(im_shape, im_type) intensity_range = [14, 15] - t = RandKSpaceSpikeNoise(0.0, intensity_range, channel_wise, as_tensor_output) + t = RandKSpaceSpikeNoise(0.0, intensity_range, channel_wise) out = t(im) + self.assertEqual(type(im), type(out)) + if isinstance(out, torch.Tensor): + self.assertEqual(out.device, im.device) + im, out = im.cpu(), out.cpu() np.testing.assert_allclose(im, out) - @parameterized.expand(TEST_CASES) - def test_1_prob(self, im_shape, as_tensor_output, as_tensor_input, channel_wise): - im = self.get_data(im_shape, as_tensor_input) + @parameterized.expand(TESTS) + def test_1_prob(self, im_shape, im_type, channel_wise): + im = self.get_data(im_shape, im_type) intensity_range = [14, 14] - t = RandKSpaceSpikeNoise(1.0, intensity_range, channel_wise, as_tensor_output) + t = RandKSpaceSpikeNoise(1.0, intensity_range, channel_wise) out = t(im) - base_t = KSpaceSpikeNoise(t.sampled_locs, [14], as_tensor_output) + base_t = KSpaceSpikeNoise(t.sampled_locs, [14]) out = out - base_t(im) + self.assertEqual(type(im), type(out)) + if isinstance(out, torch.Tensor): + self.assertEqual(out.device, im.device) + im, out = im.cpu(), out.cpu() np.testing.assert_allclose(out, im * 0) - @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input, channel_wise): - im = self.get_data(im_shape, as_tensor_input) + @parameterized.expand(TESTS) + def test_same_result(self, im_shape, im_type, channel_wise): + im = self.get_data(im_shape, im_type) intensity_range = [14, 15] - t = RandKSpaceSpikeNoise(0.0, intensity_range, channel_wise, as_tensor_output) + t = RandKSpaceSpikeNoise(0.0, intensity_range, channel_wise) t.set_random_state(42) out1 = t(deepcopy(im)) t.set_random_state(42) out2 = t(deepcopy(im)) + self.assertEqual(type(im), type(out1)) + if isinstance(out1, torch.Tensor): + self.assertEqual(out1.device, im.device) + out1, out2 = out1.cpu(), out2.cpu() np.testing.assert_allclose(out1, out2) - self.assertIsInstance(out1, torch.Tensor if as_tensor_output else np.ndarray) - @parameterized.expand(TEST_CASES) - def test_intensity(self, im_shape, _, as_tensor_input, channel_wise): - im = self.get_data(im_shape, as_tensor_input) + @parameterized.expand(TESTS) + def test_intensity(self, im_shape, im_type, channel_wise): + im = self.get_data(im_shape, im_type) intensity_range = [14, 14.1] t = RandKSpaceSpikeNoise(1.0, intensity_range, channel_wise) _ = t(deepcopy(im)) diff --git a/tests/test_rand_k_space_spike_noised.py b/tests/test_rand_k_space_spike_noised.py index 1056ebf163..869aa50872 100644 --- a/tests/test_rand_k_space_spike_noised.py +++ b/tests/test_rand_k_space_spike_noised.py @@ -19,19 +19,16 @@ from monai.data.synthetic import create_test_image_2d, create_test_image_3d from monai.transforms import RandKSpaceSpikeNoised from monai.utils.misc import set_determinism -from tests.utils import SkipIfBeforePyTorchVersion, SkipIfNoModule +from tests.utils import TEST_NDARRAYS -TEST_CASES = [] +TESTS = [] for shape in ((128, 64), (64, 48, 80)): - for as_tensor_output in (True, False): - for as_tensor_input in (True, False): - TEST_CASES.append((shape, as_tensor_output, as_tensor_input)) + for p in TEST_NDARRAYS: + TESTS.append((shape, p)) KEYS = ["image", "label"] -@SkipIfBeforePyTorchVersion((1, 8)) -@SkipIfNoModule("torch.fft") class TestKSpaceSpikeNoised(unittest.TestCase): def setUp(self): set_determinism(0) @@ -41,17 +38,16 @@ def tearDown(self): set_determinism(None) @staticmethod - def get_data(im_shape, as_tensor_input): + def get_data(im_shape, im_type): create_test_image = create_test_image_2d if len(im_shape) == 2 else create_test_image_3d ims = create_test_image(*im_shape, rad_max=20, noise_max=0.0, num_seg_classes=5) - ims = [im[None] for im in ims] - ims = [torch.Tensor(im) for im in ims] if as_tensor_input else ims - return dict(zip(KEYS, ims)) + ims = [im_type(im[None]) for im in ims] + return {k: v for k, v in zip(KEYS, ims)} - @parameterized.expand(TEST_CASES) - def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): + @parameterized.expand(TESTS) + def test_same_result(self, im_shape, im_type): - data = self.get_data(im_shape, as_tensor_input) + data = self.get_data(im_shape, im_type) intensity_ranges = {"image": (13, 15), "label": (13, 15)} t = RandKSpaceSpikeNoised( @@ -60,7 +56,6 @@ def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): prob=1.0, intensity_ranges=intensity_ranges, channel_wise=True, - as_tensor_output=as_tensor_output, ) t.set_rand_state(42) out1 = t(deepcopy(data)) @@ -69,12 +64,16 @@ def test_same_result(self, im_shape, as_tensor_output, as_tensor_input): out2 = t(deepcopy(data)) for k in KEYS: + self.assertEqual(type(out1[k]), type(data[k])) + if isinstance(out1[k], torch.Tensor): + self.assertEqual(out1[k].device, data[k].device) + out1[k] = out1[k].cpu() + out2[k] = out2[k].cpu() np.testing.assert_allclose(out1[k], out2[k], atol=1e-10) - self.assertIsInstance(out1[k], torch.Tensor if as_tensor_output else np.ndarray) - @parameterized.expand(TEST_CASES) - def test_0_prob(self, im_shape, as_tensor_output, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + @parameterized.expand(TESTS) + def test_0_prob(self, im_shape, im_type): + data = self.get_data(im_shape, im_type) intensity_ranges = {"image": (13, 15), "label": (13, 15)} t1 = RandKSpaceSpikeNoised( KEYS, @@ -82,7 +81,6 @@ def test_0_prob(self, im_shape, as_tensor_output, as_tensor_input): prob=1.0, intensity_ranges=intensity_ranges, channel_wise=True, - as_tensor_output=as_tensor_output, ) t2 = RandKSpaceSpikeNoised( @@ -91,19 +89,25 @@ def test_0_prob(self, im_shape, as_tensor_output, as_tensor_input): prob=1.0, intensity_ranges=intensity_ranges, channel_wise=True, - as_tensor_output=as_tensor_output, ) out1 = t1(data) out2 = t2(data) for k in KEYS: + self.assertEqual(type(out1[k]), type(data[k])) + if isinstance(out1[k], torch.Tensor): + self.assertEqual(out1[k].device, data[k].device) + out1[k] = out1[k].cpu() + out2[k] = out2[k].cpu() + data[k] = data[k].cpu() + np.testing.assert_allclose(data[k], out1[k]) np.testing.assert_allclose(data[k], out2[k]) - @parameterized.expand(TEST_CASES) - def test_intensity(self, im_shape, as_tensor_output, as_tensor_input): + @parameterized.expand(TESTS) + def test_intensity(self, im_shape, im_type): - data = self.get_data(im_shape, as_tensor_input) + data = self.get_data(im_shape, im_type) intensity_ranges = {"image": (13, 13.1), "label": (13, 13.1)} t = RandKSpaceSpikeNoised( KEYS, @@ -111,7 +115,6 @@ def test_intensity(self, im_shape, as_tensor_output, as_tensor_input): prob=1.0, intensity_ranges=intensity_ranges, channel_wise=True, - as_tensor_output=True, ) _ = t(data) @@ -120,9 +123,9 @@ def test_intensity(self, im_shape, as_tensor_output, as_tensor_input): self.assertGreaterEqual(t.transforms["label"].sampled_k_intensity[0], 13) self.assertLessEqual(t.transforms["label"].sampled_k_intensity[0], 13.1) - @parameterized.expand(TEST_CASES) - def test_same_transformation(self, im_shape, _, as_tensor_input): - data = self.get_data(im_shape, as_tensor_input) + @parameterized.expand(TESTS) + def test_same_transformation(self, im_shape, im_type): + data = self.get_data(im_shape, im_type) # use same image for both dictionary entries to check same trans is applied to them data = {KEYS[0]: deepcopy(data[KEYS[0]]), KEYS[1]: deepcopy(data[KEYS[0]])} @@ -135,11 +138,16 @@ def test_same_transformation(self, im_shape, _, as_tensor_input): intensity_ranges=intensity_ranges, channel_wise=True, common_sampling=True, - as_tensor_output=True, ) out = t(deepcopy(data)) + for k in KEYS: + self.assertEqual(type(out[k]), type(data[k])) + if isinstance(out[k], torch.Tensor): + self.assertEqual(out[k].device, data[k].device) + out[k] = out[k].cpu() + np.testing.assert_allclose(out[KEYS[0]], out[KEYS[1]]) From 0c033762e149fac2b8fe629f445e8d57bd1084f9 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Wed, 29 Sep 2021 13:23:49 +0100 Subject: [PATCH 59/89] AdjustContrast, AdjustContrastd, RandAdjustContrast, RandAdjustContrastd (#3044) Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/intensity/array.py | 12 +++++++----- monai/transforms/intensity/dictionary.py | 8 ++++++-- tests/test_adjust_contrast.py | 21 +++++++++++---------- tests/test_adjust_contrastd.py | 21 +++++++++++---------- tests/test_rand_adjust_contrast.py | 20 +++++++++++--------- tests/test_rand_adjust_contrastd.py | 20 +++++++++++--------- 6 files changed, 57 insertions(+), 45 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index f9fc1ad6ab..0e9f922888 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -725,20 +725,21 @@ class AdjustContrast(Transform): gamma: gamma value to adjust the contrast as function. """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__(self, gamma: float) -> None: if not isinstance(gamma, (int, float)): raise ValueError("gamma must be a float or int number.") self.gamma = gamma - def __call__(self, img: np.ndarray): + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore epsilon = 1e-7 img_min = img.min() img_range = img.max() - img_min - return np.power(((img - img_min) / float(img_range + epsilon)), self.gamma) * img_range + img_min + return ((img - img_min) / float(img_range + epsilon)) ** self.gamma * img_range + img_min class RandAdjustContrast(RandomizableTransform): @@ -753,6 +754,8 @@ class RandAdjustContrast(RandomizableTransform): If single number, value is picked from (0.5, gamma), default is (0.5, 4.5). """ + backend = AdjustContrast.backend + def __init__(self, prob: float = 0.1, gamma: Union[Sequence[float], float] = (0.5, 4.5)) -> None: RandomizableTransform.__init__(self, prob) @@ -773,11 +776,10 @@ def randomize(self, data: Optional[Any] = None) -> None: super().randomize(None) self.gamma_value = self.R.uniform(low=self.gamma[0], high=self.gamma[1]) - def __call__(self, img: np.ndarray): + def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize() if self.gamma_value is None: raise ValueError("gamma_value is not set.") diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index 204b3d7c37..a99bd59473 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -737,11 +737,13 @@ class AdjustContrastd(MapTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = AdjustContrast.backend + def __init__(self, keys: KeysCollection, gamma: float, allow_missing_keys: bool = False) -> None: super().__init__(keys, allow_missing_keys) self.adjuster = AdjustContrast(gamma) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): d[key] = self.adjuster(d[key]) @@ -764,6 +766,8 @@ class RandAdjustContrastd(RandomizableTransform, MapTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = AdjustContrast.backend + def __init__( self, keys: KeysCollection, @@ -791,7 +795,7 @@ def randomize(self, data: Optional[Any] = None) -> None: super().randomize(None) self.gamma_value = self.R.uniform(low=self.gamma[0], high=self.gamma[1]) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) self.randomize() if self.gamma_value is None: diff --git a/tests/test_adjust_contrast.py b/tests/test_adjust_contrast.py index 8e78698360..80ac61cfea 100644 --- a/tests/test_adjust_contrast.py +++ b/tests/test_adjust_contrast.py @@ -15,7 +15,7 @@ from parameterized import parameterized from monai.transforms import AdjustContrast -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose TEST_CASE_1 = [1.0] @@ -28,15 +28,16 @@ class TestAdjustContrast(NumpyImageTestCase2D): @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) def test_correct_results(self, gamma): adjuster = AdjustContrast(gamma=gamma) - result = adjuster(self.imt) - if gamma == 1.0: - expected = self.imt - else: - epsilon = 1e-7 - img_min = self.imt.min() - img_range = self.imt.max() - img_min - expected = np.power(((self.imt - img_min) / float(img_range + epsilon)), gamma) * img_range + img_min - np.testing.assert_allclose(expected, result, rtol=1e-05) + for p in TEST_NDARRAYS: + result = adjuster(p(self.imt)) + if gamma == 1.0: + expected = self.imt + else: + epsilon = 1e-7 + img_min = self.imt.min() + img_range = self.imt.max() - img_min + expected = np.power(((self.imt - img_min) / float(img_range + epsilon)), gamma) * img_range + img_min + assert_allclose(expected, result, rtol=1e-05, type_test=False) if __name__ == "__main__": diff --git a/tests/test_adjust_contrastd.py b/tests/test_adjust_contrastd.py index 65647607e4..1e1c2cf8bc 100644 --- a/tests/test_adjust_contrastd.py +++ b/tests/test_adjust_contrastd.py @@ -15,7 +15,7 @@ from parameterized import parameterized from monai.transforms import AdjustContrastd -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose TEST_CASE_1 = [1.0] @@ -28,15 +28,16 @@ class TestAdjustContrastd(NumpyImageTestCase2D): @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) def test_correct_results(self, gamma): adjuster = AdjustContrastd("img", gamma=gamma) - result = adjuster({"img": self.imt}) - if gamma == 1.0: - expected = self.imt - else: - epsilon = 1e-7 - img_min = self.imt.min() - img_range = self.imt.max() - img_min - expected = np.power(((self.imt - img_min) / float(img_range + epsilon)), gamma) * img_range + img_min - np.testing.assert_allclose(expected, result["img"], rtol=1e-05) + for p in TEST_NDARRAYS: + result = adjuster({"img": p(self.imt)}) + if gamma == 1.0: + expected = self.imt + else: + epsilon = 1e-7 + img_min = self.imt.min() + img_range = self.imt.max() - img_min + expected = np.power(((self.imt - img_min) / float(img_range + epsilon)), gamma) * img_range + img_min + assert_allclose(expected, result["img"], rtol=1e-05, type_test=False) if __name__ == "__main__": diff --git a/tests/test_rand_adjust_contrast.py b/tests/test_rand_adjust_contrast.py index d7d750957d..db408dda42 100644 --- a/tests/test_rand_adjust_contrast.py +++ b/tests/test_rand_adjust_contrast.py @@ -15,7 +15,7 @@ from parameterized import parameterized from monai.transforms import RandAdjustContrast -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose TEST_CASE_1 = [(0.5, 4.5)] @@ -26,14 +26,16 @@ class TestRandAdjustContrast(NumpyImageTestCase2D): @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) def test_correct_results(self, gamma): adjuster = RandAdjustContrast(prob=1.0, gamma=gamma) - result = adjuster(self.imt) - epsilon = 1e-7 - img_min = self.imt.min() - img_range = self.imt.max() - img_min - expected = ( - np.power(((self.imt - img_min) / float(img_range + epsilon)), adjuster.gamma_value) * img_range + img_min - ) - np.testing.assert_allclose(expected, result, rtol=1e-05) + for p in TEST_NDARRAYS: + result = adjuster(p(self.imt)) + epsilon = 1e-7 + img_min = self.imt.min() + img_range = self.imt.max() - img_min + expected = ( + np.power(((self.imt - img_min) / float(img_range + epsilon)), adjuster.gamma_value) * img_range + + img_min + ) + assert_allclose(expected, result, rtol=1e-05, type_test=False) if __name__ == "__main__": diff --git a/tests/test_rand_adjust_contrastd.py b/tests/test_rand_adjust_contrastd.py index e4b61293bb..026828a9a3 100644 --- a/tests/test_rand_adjust_contrastd.py +++ b/tests/test_rand_adjust_contrastd.py @@ -15,7 +15,7 @@ from parameterized import parameterized from monai.transforms import RandAdjustContrastd -from tests.utils import NumpyImageTestCase2D +from tests.utils import TEST_NDARRAYS, NumpyImageTestCase2D, assert_allclose TEST_CASE_1 = [(0.5, 4.5)] @@ -26,14 +26,16 @@ class TestRandAdjustContrastd(NumpyImageTestCase2D): @parameterized.expand([TEST_CASE_1, TEST_CASE_2]) def test_correct_results(self, gamma): adjuster = RandAdjustContrastd("img", prob=1.0, gamma=gamma) - result = adjuster({"img": self.imt}) - epsilon = 1e-7 - img_min = self.imt.min() - img_range = self.imt.max() - img_min - expected = ( - np.power(((self.imt - img_min) / float(img_range + epsilon)), adjuster.gamma_value) * img_range + img_min - ) - np.testing.assert_allclose(expected, result["img"], rtol=1e-05) + for p in TEST_NDARRAYS: + result = adjuster({"img": p(self.imt)}) + epsilon = 1e-7 + img_min = self.imt.min() + img_range = self.imt.max() - img_min + expected = ( + np.power(((self.imt - img_min) / float(img_range + epsilon)), adjuster.gamma_value) * img_range + + img_min + ) + assert_allclose(expected, result["img"], rtol=1e-05, type_test=False) if __name__ == "__main__": From f85ad48276827651ee5dde1b9820f0e661f96861 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Wed, 29 Sep 2021 15:35:01 +0100 Subject: [PATCH 60/89] remove false positive tests (#3046) Signed-off-by: Wenqi Li --- tests/test_savitzky_golay_smooth.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_savitzky_golay_smooth.py b/tests/test_savitzky_golay_smooth.py index 71405466c4..0f398bc48f 100644 --- a/tests/test_savitzky_golay_smooth.py +++ b/tests/test_savitzky_golay_smooth.py @@ -25,14 +25,14 @@ np.expand_dims(np.array([1.0]), 0), # Input data: Single value np.expand_dims(np.array([1 / 3]), 0), # Expected output: With a window length of 3 and polyorder 1 # output should be equal to mean of 0, 1 and 0 = 1/3 (because input will be zero-padded and a linear fit performed) - 1e-15, # absolute tolerance + 1e-5, # absolute tolerance ] TEST_CASE_2D_AXIS_2 = [ {"window_length": 3, "order": 1, "axis": 2}, # along axis 2 (second spatial dim) np.expand_dims(np.ones((2, 3)), 0), np.expand_dims(np.array([[2 / 3, 1.0, 2 / 3], [2 / 3, 1.0, 2 / 3]]), 0), - 1e-15, # absolute tolerance + 1e-5, # absolute tolerance ] # Replicated-padding trivial tests @@ -42,7 +42,7 @@ np.expand_dims(np.array([1.0]), 0), # Input data: Single value np.expand_dims(np.array([1.0]), 0), # Expected output: With a window length of 3 and polyorder 1 # output will be equal to mean of [1, 1, 1] = 1 (input will be nearest-neighbour-padded and a linear fit performed) - 1e-15, # absolute tolerance + 1e-5, # absolute tolerance ] # Sine smoothing @@ -63,7 +63,7 @@ class TestSavitzkyGolaySmooth(unittest.TestCase): def test_value(self, arguments, image, expected_data, atol): for p in TEST_NDARRAYS: result = SavitzkyGolaySmooth(**arguments)(p(image.astype(np.float32))) - torch.testing.assert_allclose(result, p(expected_data.astype(np.float32)), rtol=1e-7, atol=atol) + torch.testing.assert_allclose(result, p(expected_data.astype(np.float32)), rtol=1e-4, atol=atol) class TestSavitzkyGolaySmoothREP(unittest.TestCase): @@ -71,7 +71,7 @@ class TestSavitzkyGolaySmoothREP(unittest.TestCase): def test_value(self, arguments, image, expected_data, atol): for p in TEST_NDARRAYS: result = SavitzkyGolaySmooth(**arguments)(p(image.astype(np.float32))) - torch.testing.assert_allclose(result, p(expected_data.astype(np.float32)), rtol=1e-7, atol=atol) + torch.testing.assert_allclose(result, p(expected_data.astype(np.float32)), rtol=1e-4, atol=atol) if __name__ == "__main__": From bf561bba9bb402b84fe74ed46c00725fe0d8a3db Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Wed, 29 Sep 2021 17:03:34 +0100 Subject: [PATCH 61/89] Torch `Spacing`, `Spacingd` (#3045) Torch `Spacing`, `Spacingd` --- monai/data/nifti_writer.py | 18 +- monai/transforms/spatial/array.py | 55 +++-- monai/transforms/spatial/dictionary.py | 16 +- tests/test_nifti_rw.py | 216 +++++++++-------- tests/test_spacing.py | 311 ++++++++++++++----------- tests/test_spacingd.py | 143 ++++++------ tests/utils.py | 7 +- 7 files changed, 435 insertions(+), 331 deletions(-) diff --git a/monai/data/nifti_writer.py b/monai/data/nifti_writer.py index c56d4c1e8d..210321daca 100644 --- a/monai/data/nifti_writer.py +++ b/monai/data/nifti_writer.py @@ -15,17 +15,19 @@ import torch from monai.config import DtypeLike +from monai.config.type_definitions import NdarrayOrTensor from monai.data.utils import compute_shape_offset, to_affine_nd from monai.networks.layers import AffineTransform from monai.utils import GridSampleMode, GridSamplePadMode, optional_import +from monai.utils.type_conversion import convert_data_type nib, _ = optional_import("nibabel") def write_nifti( - data: np.ndarray, + data: NdarrayOrTensor, file_name: str, - affine: Optional[np.ndarray] = None, + affine: Optional[NdarrayOrTensor] = None, target_affine: Optional[np.ndarray] = None, resample: bool = True, output_spatial_shape: Union[Sequence[int], np.ndarray, None] = None, @@ -96,13 +98,17 @@ def write_nifti( If None, use the data type of input data. output_dtype: data type for saving data. Defaults to ``np.float32``. """ + if isinstance(data, torch.Tensor): + data, *_ = convert_data_type(data, np.ndarray) + if isinstance(affine, torch.Tensor): + affine, *_ = convert_data_type(affine, np.ndarray) if not isinstance(data, np.ndarray): - raise AssertionError("input data must be numpy array.") + raise AssertionError("input data must be numpy array or torch tensor.") dtype = dtype or data.dtype sr = min(data.ndim, 3) if affine is None: affine = np.eye(4, dtype=np.float64) - affine = to_affine_nd(sr, affine) + affine = to_affine_nd(sr, affine) # type: ignore if target_affine is None: target_affine = affine @@ -122,7 +128,7 @@ def write_nifti( data = nib.orientations.apply_orientation(data, ornt_transform) _affine = affine @ nib.orientations.inv_ornt_aff(ornt_transform, data_shape) if np.allclose(_affine, target_affine, atol=1e-3) or not resample: - results_img = nib.Nifti1Image(data.astype(output_dtype), to_affine_nd(3, _affine)) + results_img = nib.Nifti1Image(data.astype(output_dtype), to_affine_nd(3, _affine)) # type: ignore nib.save(results_img, file_name) return @@ -138,7 +144,7 @@ def write_nifti( while len(output_spatial_shape_) < 3: output_spatial_shape_ = output_spatial_shape_ + [1] spatial_shape, channel_shape = data.shape[:3], data.shape[3:] - data_np = data.reshape(list(spatial_shape) + [-1]) + data_np: np.ndarray = data.reshape(list(spatial_shape) + [-1]) # type: ignore data_np = np.moveaxis(data_np, -1, 0) # channel first for pytorch data_torch = affine_xform( torch.as_tensor(np.ascontiguousarray(data_np).astype(dtype)).unsqueeze(0), diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index cb4e69a509..62ac5d2c3e 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -13,6 +13,7 @@ https://github.com/Project-MONAI/MONAI/wiki/MONAI_Design """ import warnings +from copy import deepcopy from typing import Any, List, Optional, Sequence, Tuple, Union import numpy as np @@ -85,6 +86,8 @@ class Spacing(Transform): Resample input image into the specified `pixdim`. """ + backend = [TransformBackends.TORCH] + def __init__( self, pixdim: Union[Sequence[float], float], @@ -136,14 +139,14 @@ def __init__( def __call__( self, - data_array: np.ndarray, - affine: Optional[np.ndarray] = None, + data_array: NdarrayOrTensor, + affine: Optional[NdarrayOrTensor] = None, mode: Optional[Union[GridSampleMode, str]] = None, padding_mode: Optional[Union[GridSamplePadMode, str]] = None, align_corners: Optional[bool] = None, dtype: DtypeLike = None, output_spatial_shape: Optional[np.ndarray] = None, - ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + ) -> Tuple[NdarrayOrTensor, NdarrayOrTensor, NdarrayOrTensor]: """ Args: data_array: in shape (num_channels, H[, W, ...]). @@ -171,9 +174,8 @@ def __call__( data_array (resampled into `self.pixdim`), original affine, current affine. """ - data_array, *_ = convert_data_type(data_array, np.ndarray) # type: ignore _dtype = dtype or self.dtype or data_array.dtype - sr = data_array.ndim - 1 + sr = int(data_array.ndim - 1) if sr <= 0: raise ValueError("data_array must have at least one spatial dimension.") if affine is None: @@ -181,7 +183,8 @@ def __call__( affine = np.eye(sr + 1, dtype=np.float64) affine_ = np.eye(sr + 1, dtype=np.float64) else: - affine_ = to_affine_nd(sr, affine) + affine, *_ = convert_data_type(affine, np.ndarray) + affine_ = to_affine_nd(sr, affine) # type: ignore out_d = self.pixdim[:sr] if out_d.size < sr: @@ -197,26 +200,28 @@ def __call__( # no resampling if it's identity transform if np.allclose(transform, np.diag(np.ones(len(transform))), atol=1e-3): - output_data = data_array.copy().astype(np.float32) - new_affine = to_affine_nd(affine, new_affine) - return output_data, affine, new_affine + output_data, *_ = convert_data_type(deepcopy(data_array), dtype=_dtype) + new_affine = to_affine_nd(affine, new_affine) # type: ignore - # resample - affine_xform = AffineTransform( - normalized=False, - mode=look_up_option(mode or self.mode, GridSampleMode), - padding_mode=look_up_option(padding_mode or self.padding_mode, GridSamplePadMode), - align_corners=self.align_corners if align_corners is None else align_corners, - reverse_indexing=True, - ) - output_data = affine_xform( - # AffineTransform requires a batch dim - torch.as_tensor(np.ascontiguousarray(data_array).astype(_dtype)).unsqueeze(0), - torch.as_tensor(np.ascontiguousarray(transform).astype(_dtype)), - spatial_size=output_shape if output_spatial_shape is None else output_spatial_shape, - ) - output_data = np.asarray(output_data.squeeze(0).detach().cpu().numpy(), dtype=np.float32) # type: ignore - new_affine = to_affine_nd(affine, new_affine) + else: + # resample + affine_xform = AffineTransform( + normalized=False, + mode=look_up_option(mode or self.mode, GridSampleMode), + padding_mode=look_up_option(padding_mode or self.padding_mode, GridSamplePadMode), + align_corners=self.align_corners if align_corners is None else align_corners, + reverse_indexing=True, + ) + data_array_t: torch.Tensor + data_array_t, *_ = convert_data_type(data_array, torch.Tensor, dtype=_dtype) # type: ignore + output_data = affine_xform( + # AffineTransform requires a batch dim + data_array_t.unsqueeze(0), + convert_data_type(transform, torch.Tensor, data_array_t.device, dtype=_dtype)[0], + spatial_size=output_shape if output_spatial_shape is None else output_spatial_shape, + ).squeeze(0) + output_data, *_ = convert_to_dst_type(output_data, data_array, dtype=_dtype) + new_affine = to_affine_nd(affine, new_affine) # type: ignore return output_data, affine, new_affine diff --git a/monai/transforms/spatial/dictionary.py b/monai/transforms/spatial/dictionary.py index 0b6473a22c..bd10aad8f7 100644 --- a/monai/transforms/spatial/dictionary.py +++ b/monai/transforms/spatial/dictionary.py @@ -135,6 +135,8 @@ class Spacingd(MapTransform, InvertibleTransform): :py:class:`monai.transforms.Spacing` """ + backend = Spacing.backend + def __init__( self, keys: KeysCollection, @@ -211,8 +213,8 @@ def __init__( self.meta_key_postfix = ensure_tuple_rep(meta_key_postfix, len(self.keys)) def __call__( - self, data: Mapping[Union[Hashable, str], Dict[str, np.ndarray]] - ) -> Dict[Union[Hashable, str], Union[np.ndarray, Dict[str, np.ndarray]]]: + self, data: Mapping[Union[Hashable, str], Dict[str, NdarrayOrTensor]] + ) -> Dict[Union[Hashable, str], Union[NdarrayOrTensor, Dict[str, NdarrayOrTensor]]]: d: Dict = dict(data) for key, mode, padding_mode, align_corners, dtype, meta_key, meta_key_postfix in self.key_iterator( d, self.mode, self.padding_mode, self.align_corners, self.dtype, self.meta_keys, self.meta_key_postfix @@ -226,7 +228,7 @@ def __call__( # using affine fetched from d[affine_key] original_spatial_shape = d[key].shape[1:] d[key], old_affine, new_affine = self.spacing_transform( - data_array=np.asarray(d[key]), + data_array=d[key], affine=meta_data["affine"], mode=mode, padding_mode=padding_mode, @@ -249,7 +251,7 @@ def __call__( meta_data["affine"] = new_affine return d - def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def inverse(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = deepcopy(dict(data)) for key, dtype in self.key_iterator(d, self.dtype): transform = self.get_most_recent_transform(d, key) @@ -269,15 +271,15 @@ def inverse(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndar inverse_transform = Spacing(orig_pixdim, diagonal=self.spacing_transform.diagonal) # Apply inverse d[key], _, new_affine = inverse_transform( - data_array=np.asarray(d[key]), - affine=meta_data["affine"], + data_array=d[key], + affine=meta_data["affine"], # type: ignore mode=mode, padding_mode=padding_mode, align_corners=False if align_corners == "none" else align_corners, dtype=dtype, output_spatial_shape=orig_size, ) - meta_data["affine"] = new_affine + meta_data["affine"] = new_affine # type: ignore # Remove the applied transform self.pop_transform(d, key) diff --git a/tests/test_nifti_rw.py b/tests/test_nifti_rw.py index f16d80659c..ff7f11e47f 100644 --- a/tests/test_nifti_rw.py +++ b/tests/test_nifti_rw.py @@ -19,54 +19,66 @@ from monai.data import write_nifti from monai.transforms import LoadImage, Orientation, Spacing -from tests.utils import make_nifti_image - -TEST_IMAGE = np.arange(24).reshape((2, 4, 3)) -TEST_AFFINE = np.array( - [[-5.3, 0.0, 0.0, 102.01], [0.0, 0.52, 2.17, -7.50], [-0.0, 1.98, -0.26, -23.12], [0.0, 0.0, 0.0, 1.0]] -) - -TEST_CASES = [ - [ - TEST_IMAGE, - TEST_AFFINE, - dict(reader="NibabelReader", image_only=False, as_closest_canonical=True), - np.arange(24).reshape((2, 4, 3)), - ], - [ - TEST_IMAGE, - TEST_AFFINE, - dict(reader="NibabelReader", image_only=True, as_closest_canonical=True), - np.array( +from tests.utils import TEST_NDARRAYS, assert_allclose, make_nifti_image + +TESTS = [] +for p in TEST_NDARRAYS: + for q in TEST_NDARRAYS: + TEST_IMAGE = p(np.arange(24).reshape((2, 4, 3))) + TEST_AFFINE = q( + np.array( + [[-5.3, 0.0, 0.0, 102.01], [0.0, 0.52, 2.17, -7.50], [-0.0, 1.98, -0.26, -23.12], [0.0, 0.0, 0.0, 1.0]] + ) + ) + TESTS.append( + [ + TEST_IMAGE, + TEST_AFFINE, + dict(reader="NibabelReader", image_only=False, as_closest_canonical=True), + np.arange(24).reshape((2, 4, 3)), + ] + ) + TESTS.append( + [ + TEST_IMAGE, + TEST_AFFINE, + dict(reader="NibabelReader", image_only=True, as_closest_canonical=True), + np.array( + [ + [[12.0, 15.0, 18.0, 21.0], [13.0, 16.0, 19.0, 22.0], [14.0, 17.0, 20.0, 23.0]], + [[0.0, 3.0, 6.0, 9.0], [1.0, 4.0, 7.0, 10.0], [2.0, 5.0, 8.0, 11.0]], + ] + ), + ] + ) + TESTS.append( [ - [[12.0, 15.0, 18.0, 21.0], [13.0, 16.0, 19.0, 22.0], [14.0, 17.0, 20.0, 23.0]], - [[0.0, 3.0, 6.0, 9.0], [1.0, 4.0, 7.0, 10.0], [2.0, 5.0, 8.0, 11.0]], + TEST_IMAGE, + TEST_AFFINE, + dict(reader="NibabelReader", image_only=True, as_closest_canonical=False), + np.arange(24).reshape((2, 4, 3)), ] - ), - ], - [ - TEST_IMAGE, - TEST_AFFINE, - dict(reader="NibabelReader", image_only=True, as_closest_canonical=False), - np.arange(24).reshape((2, 4, 3)), - ], - [ - TEST_IMAGE, - TEST_AFFINE, - dict(reader="NibabelReader", image_only=False, as_closest_canonical=False), - np.arange(24).reshape((2, 4, 3)), - ], - [ - TEST_IMAGE, - None, - dict(reader="NibabelReader", image_only=False, as_closest_canonical=False), - np.arange(24).reshape((2, 4, 3)), - ], -] + ) + TESTS.append( + [ + TEST_IMAGE, + TEST_AFFINE, + dict(reader="NibabelReader", image_only=False, as_closest_canonical=False), + np.arange(24).reshape((2, 4, 3)), + ] + ) + TESTS.append( + [ + TEST_IMAGE, + None, + dict(reader="NibabelReader", image_only=False, as_closest_canonical=False), + np.arange(24).reshape((2, 4, 3)), + ] + ) class TestNiftiLoadRead(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_orientation(self, array, affine, reader_param, expected): test_image = make_nifti_image(array, affine) @@ -93,8 +105,8 @@ def test_orientation(self, array, affine, reader_param, expected): os.remove(test_image) if affine is not None: - np.testing.assert_allclose(saved_affine, affine) - np.testing.assert_allclose(saved_data, expected) + assert_allclose(saved_affine, affine, type_test=False) + assert_allclose(saved_data, expected, type_test=False) def test_consistency(self): np.set_printoptions(suppress=True, precision=3) @@ -140,69 +152,81 @@ def test_consistency(self): def test_write_2d(self): with tempfile.TemporaryDirectory() as out_dir: image_name = os.path.join(out_dir, "test.nii.gz") - img = np.arange(6).reshape((2, 3)) - write_nifti(img, image_name, affine=np.diag([1]), target_affine=np.diag([1.4])) - out = nib.load(image_name) - np.testing.assert_allclose(out.get_fdata(), [[0, 1, 2], [3.0, 4, 5]]) - np.testing.assert_allclose(out.affine, np.diag([1.4, 1, 1, 1])) - - image_name = os.path.join(out_dir, "test1.nii.gz") - img = np.arange(5).reshape((1, 5)) - write_nifti(img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 1, 3, 5])) - out = nib.load(image_name) - np.testing.assert_allclose(out.get_fdata(), [[0, 2, 4]]) - np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 1, 1])) + for p in TEST_NDARRAYS: + img = p(np.arange(6).reshape((2, 3))) + write_nifti(img, image_name, affine=np.diag([1]), target_affine=np.diag([1.4])) + out = nib.load(image_name) + np.testing.assert_allclose(out.get_fdata(), [[0, 1, 2], [3.0, 4, 5]]) + np.testing.assert_allclose(out.affine, np.diag([1.4, 1, 1, 1])) + + image_name = os.path.join(out_dir, "test1.nii.gz") + img = np.arange(5).reshape((1, 5)) + write_nifti( + img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 1, 3, 5]) + ) + out = nib.load(image_name) + np.testing.assert_allclose(out.get_fdata(), [[0, 2, 4]]) + np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 1, 1])) def test_write_3d(self): with tempfile.TemporaryDirectory() as out_dir: image_name = os.path.join(out_dir, "test.nii.gz") - img = np.arange(6).reshape((1, 2, 3)) - write_nifti(img, image_name, affine=np.diag([1]), target_affine=np.diag([1.4])) - out = nib.load(image_name) - np.testing.assert_allclose(out.get_fdata(), [[[0, 1, 2], [3, 4, 5]]]) - np.testing.assert_allclose(out.affine, np.diag([1.4, 1, 1, 1])) - - image_name = os.path.join(out_dir, "test1.nii.gz") - img = np.arange(5).reshape((1, 1, 5)) - write_nifti(img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 2, 3, 5])) - out = nib.load(image_name) - np.testing.assert_allclose(out.get_fdata(), [[[0, 2, 4]]]) - np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 2, 1])) + for p in TEST_NDARRAYS: + img = p(np.arange(6).reshape((1, 2, 3))) + write_nifti(img, image_name, affine=np.diag([1]), target_affine=np.diag([1.4])) + out = nib.load(image_name) + np.testing.assert_allclose(out.get_fdata(), [[[0, 1, 2], [3, 4, 5]]]) + np.testing.assert_allclose(out.affine, np.diag([1.4, 1, 1, 1])) + + image_name = os.path.join(out_dir, "test1.nii.gz") + img = p(np.arange(5).reshape((1, 1, 5))) + write_nifti( + img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 2, 3, 5]) + ) + out = nib.load(image_name) + np.testing.assert_allclose(out.get_fdata(), [[[0, 2, 4]]]) + np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 2, 1])) def test_write_4d(self): with tempfile.TemporaryDirectory() as out_dir: image_name = os.path.join(out_dir, "test.nii.gz") - img = np.arange(6).reshape((1, 1, 3, 2)) - write_nifti(img, image_name, affine=np.diag([1.4, 1]), target_affine=np.diag([1, 1.4, 1])) - out = nib.load(image_name) - np.testing.assert_allclose(out.get_fdata(), [[[[0, 1], [2, 3], [4, 5]]]]) - np.testing.assert_allclose(out.affine, np.diag([1, 1.4, 1, 1])) - - image_name = os.path.join(out_dir, "test1.nii.gz") - img = np.arange(5).reshape((1, 1, 5, 1)) - write_nifti(img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 2, 3, 5])) - out = nib.load(image_name) - np.testing.assert_allclose(out.get_fdata(), [[[[0], [2], [4]]]]) - np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 2, 1])) + for p in TEST_NDARRAYS: + img = p(np.arange(6).reshape((1, 1, 3, 2))) + write_nifti(img, image_name, affine=np.diag([1.4, 1]), target_affine=np.diag([1, 1.4, 1])) + out = nib.load(image_name) + np.testing.assert_allclose(out.get_fdata(), [[[[0, 1], [2, 3], [4, 5]]]]) + np.testing.assert_allclose(out.affine, np.diag([1, 1.4, 1, 1])) + + image_name = os.path.join(out_dir, "test1.nii.gz") + img = p(np.arange(5).reshape((1, 1, 5, 1))) + write_nifti( + img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 2, 3, 5]) + ) + out = nib.load(image_name) + np.testing.assert_allclose(out.get_fdata(), [[[[0], [2], [4]]]]) + np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 2, 1])) def test_write_5d(self): with tempfile.TemporaryDirectory() as out_dir: image_name = os.path.join(out_dir, "test.nii.gz") - img = np.arange(12).reshape((1, 1, 3, 2, 2)) - write_nifti(img, image_name, affine=np.diag([1]), target_affine=np.diag([1.4])) - out = nib.load(image_name) - np.testing.assert_allclose( - out.get_fdata(), - np.array([[[[[0.0, 1.0], [2.0, 3.0]], [[4.0, 5.0], [6.0, 7.0]], [[8.0, 9.0], [10.0, 11.0]]]]]), - ) - np.testing.assert_allclose(out.affine, np.diag([1.4, 1, 1, 1])) - - image_name = os.path.join(out_dir, "test1.nii.gz") - img = np.arange(10).reshape((1, 1, 5, 1, 2)) - write_nifti(img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 2, 3, 5])) - out = nib.load(image_name) - np.testing.assert_allclose(out.get_fdata(), np.array([[[[[0.0, 1.0]], [[4.0, 5.0]], [[8.0, 9.0]]]]])) - np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 2, 1])) + for p in TEST_NDARRAYS: + img = p(np.arange(12).reshape((1, 1, 3, 2, 2))) + write_nifti(img, image_name, affine=np.diag([1]), target_affine=np.diag([1.4])) + out = nib.load(image_name) + np.testing.assert_allclose( + out.get_fdata(), + np.array([[[[[0.0, 1.0], [2.0, 3.0]], [[4.0, 5.0], [6.0, 7.0]], [[8.0, 9.0], [10.0, 11.0]]]]]), + ) + np.testing.assert_allclose(out.affine, np.diag([1.4, 1, 1, 1])) + + image_name = os.path.join(out_dir, "test1.nii.gz") + img = p(np.arange(10).reshape((1, 1, 5, 1, 2))) + write_nifti( + img, image_name, affine=np.diag([1, 1, 1, 3, 3]), target_affine=np.diag([1.4, 2.0, 2, 3, 5]) + ) + out = nib.load(image_name) + np.testing.assert_allclose(out.get_fdata(), np.array([[[[[0.0, 1.0]], [[4.0, 5.0]], [[8.0, 9.0]]]]])) + np.testing.assert_allclose(out.affine, np.diag([1.4, 2, 2, 1])) if __name__ == "__main__": diff --git a/tests/test_spacing.py b/tests/test_spacing.py index 6be6730c5a..cd362bccea 100644 --- a/tests/test_spacing.py +++ b/tests/test_spacing.py @@ -12,155 +12,204 @@ import unittest import numpy as np +import torch from parameterized import parameterized from monai.transforms import Spacing from monai.utils import ensure_tuple, fall_back_tuple +from tests.utils import TEST_NDARRAYS -TEST_CASES = [ - [ - {"pixdim": (1.0, 1.5), "padding_mode": "zeros", "dtype": float}, - np.arange(4).reshape((1, 2, 2)) + 1.0, # data - {"affine": np.eye(4)}, - np.array([[[1.0, 1.0], [3.0, 2.0]]]), - ], - [ - {"pixdim": 1.0, "padding_mode": "zeros", "dtype": float}, - np.ones((1, 2, 1, 2)), # data - {"affine": np.eye(4)}, - np.array([[[[1.0, 1.0]], [[1.0, 1.0]]]]), - ], - [ - {"pixdim": (1.0, 1.0, 1.0), "padding_mode": "zeros", "dtype": float}, - np.ones((1, 2, 1, 2)), # data - {"affine": np.eye(4)}, - np.array([[[[1.0, 1.0]], [[1.0, 1.0]]]]), - ], - [ - {"pixdim": (1.0, 0.2, 1.5), "diagonal": False, "padding_mode": "zeros", "align_corners": True}, - np.ones((1, 2, 1, 2)), # data - {"affine": np.array([[2, 1, 0, 4], [-1, -3, 0, 5], [0, 0, 2.0, 5], [0, 0, 0, 1]])}, - np.array([[[[0.95527864, 0.95527864]], [[1.0, 1.0]], [[1.0, 1.0]]]]), - ], - [ - {"pixdim": (3.0, 1.0), "padding_mode": "zeros"}, - np.arange(24).reshape((2, 3, 4)), # data - {"affine": np.diag([-3.0, 0.2, 1.5, 1])}, - np.array([[[0, 0], [4, 0], [8, 0]], [[12, 0], [16, 0], [20, 0]]]), - ], - [ - {"pixdim": (3.0, 1.0), "padding_mode": "zeros"}, - np.arange(24).reshape((2, 3, 4)), # data - {}, - np.array([[[0, 1, 2, 3], [0, 0, 0, 0]], [[12, 13, 14, 15], [0, 0, 0, 0]]]), - ], - [ - {"pixdim": (1.0, 1.0)}, - np.arange(24).reshape((2, 3, 4)), # data - {}, - np.array( - [[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]] - ), - ], - [ - {"pixdim": (4.0, 5.0, 6.0)}, - np.arange(24).reshape((1, 2, 3, 4)), # data - {"affine": np.array([[-4, 0, 0, 4], [0, 5, 0, -5], [0, 0, 6, -6], [0, 0, 0, 1]])}, - np.arange(24).reshape((1, 2, 3, 4)), # data - ], - [ - {"pixdim": (4.0, 5.0, 6.0), "diagonal": True}, - np.arange(24).reshape((1, 2, 3, 4)), # data - {"affine": np.array([[-4, 0, 0, 4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]])}, - np.array( - [[[[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]]] - ), - ], - [ - {"pixdim": (4.0, 5.0, 6.0), "padding_mode": "border", "diagonal": True}, - np.arange(24).reshape((1, 2, 3, 4)), # data - {"affine": np.array([[-4, 0, 0, -4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]])}, - np.array( - [[[[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]]] - ), - ], - [ - {"pixdim": (4.0, 5.0, 6.0), "padding_mode": "border", "diagonal": True}, - np.arange(24).reshape((1, 2, 3, 4)), # data - {"affine": np.array([[-4, 0, 0, -4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "nearest"}, - np.array( - [[[[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]]] - ), - ], - [ - {"pixdim": (1.9, 4.0), "padding_mode": "zeros", "diagonal": True}, - np.arange(24).reshape((1, 4, 6)), # data - {"affine": np.array([[-4, 0, 0, -4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "nearest"}, - np.array( - [ +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + p, + {"pixdim": (1.0, 1.5), "padding_mode": "zeros", "dtype": float}, + np.arange(4).reshape((1, 2, 2)) + 1.0, # data + {"affine": np.eye(4)}, + np.array([[[1.0, 1.0], [3.0, 2.0]]]), + ] + ) + TESTS.append( + [ + p, + {"pixdim": 1.0, "padding_mode": "zeros", "dtype": float}, + np.ones((1, 2, 1, 2)), # data + {"affine": np.eye(4)}, + np.array([[[[1.0, 1.0]], [[1.0, 1.0]]]]), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (1.0, 1.0, 1.0), "padding_mode": "zeros", "dtype": float}, + np.ones((1, 2, 1, 2)), # data + {"affine": np.eye(4)}, + np.array([[[[1.0, 1.0]], [[1.0, 1.0]]]]), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (1.0, 0.2, 1.5), "diagonal": False, "padding_mode": "zeros", "align_corners": True}, + np.ones((1, 2, 1, 2)), # data + {"affine": np.array([[2, 1, 0, 4], [-1, -3, 0, 5], [0, 0, 2.0, 5], [0, 0, 0, 1]])}, + np.array([[[[0.95527864, 0.95527864]], [[1.0, 1.0]], [[1.0, 1.0]]]]), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (3.0, 1.0), "padding_mode": "zeros"}, + np.arange(24).reshape((2, 3, 4)), # data + {"affine": np.diag([-3.0, 0.2, 1.5, 1])}, + np.array([[[0, 0], [4, 0], [8, 0]], [[12, 0], [16, 0], [20, 0]]]), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (3.0, 1.0), "padding_mode": "zeros"}, + np.arange(24).reshape((2, 3, 4)), # data + {}, + np.array([[[0, 1, 2, 3], [0, 0, 0, 0]], [[12, 13, 14, 15], [0, 0, 0, 0]]]), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (1.0, 1.0)}, + np.arange(24).reshape((2, 3, 4)), # data + {}, + np.array( + [[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]] + ), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (4.0, 5.0, 6.0)}, + np.arange(24).reshape((1, 2, 3, 4)), # data + {"affine": np.array([[-4, 0, 0, 4], [0, 5, 0, -5], [0, 0, 6, -6], [0, 0, 0, 1]])}, + np.arange(24).reshape((1, 2, 3, 4)), # data + ] + ) + TESTS.append( + [ + p, + {"pixdim": (4.0, 5.0, 6.0), "diagonal": True}, + np.arange(24).reshape((1, 2, 3, 4)), # data + {"affine": np.array([[-4, 0, 0, 4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]])}, + np.array( + [[[[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]]] + ), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (4.0, 5.0, 6.0), "padding_mode": "border", "diagonal": True}, + np.arange(24).reshape((1, 2, 3, 4)), # data + {"affine": np.array([[-4, 0, 0, -4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]])}, + np.array( + [[[[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]]] + ), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (4.0, 5.0, 6.0), "padding_mode": "border", "diagonal": True}, + np.arange(24).reshape((1, 2, 3, 4)), # data + {"affine": np.array([[-4, 0, 0, -4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "nearest"}, + np.array( + [[[[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]]] + ), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (1.9, 4.0), "padding_mode": "zeros", "diagonal": True}, + np.arange(24).reshape((1, 4, 6)), # data + {"affine": np.array([[-4, 0, 0, -4], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "nearest"}, + np.array( [ - [18.0, 19.0, 20.0, 20.0, 21.0, 22.0, 23.0], - [18.0, 19.0, 20.0, 20.0, 21.0, 22.0, 23.0], - [12.0, 13.0, 14.0, 14.0, 15.0, 16.0, 17.0], - [12.0, 13.0, 14.0, 14.0, 15.0, 16.0, 17.0], - [6.0, 7.0, 8.0, 8.0, 9.0, 10.0, 11.0], - [6.0, 7.0, 8.0, 8.0, 9.0, 10.0, 11.0], - [0.0, 1.0, 2.0, 2.0, 3.0, 4.0, 5.0], + [ + [18.0, 19.0, 20.0, 20.0, 21.0, 22.0, 23.0], + [18.0, 19.0, 20.0, 20.0, 21.0, 22.0, 23.0], + [12.0, 13.0, 14.0, 14.0, 15.0, 16.0, 17.0], + [12.0, 13.0, 14.0, 14.0, 15.0, 16.0, 17.0], + [6.0, 7.0, 8.0, 8.0, 9.0, 10.0, 11.0], + [6.0, 7.0, 8.0, 8.0, 9.0, 10.0, 11.0], + [0.0, 1.0, 2.0, 2.0, 3.0, 4.0, 5.0], + ] ] - ] - ), - ], - [ - {"pixdim": (5.0, 3.0), "padding_mode": "border", "diagonal": True, "dtype": np.float32}, - np.arange(24).reshape((1, 4, 6)), # data - {"affine": np.array([[-4, 0, 0, 0], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "bilinear"}, - np.array( - [ + ), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (5.0, 3.0), "padding_mode": "border", "diagonal": True, "dtype": np.float32}, + np.arange(24).reshape((1, 4, 6)), # data + {"affine": np.array([[-4, 0, 0, 0], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "bilinear"}, + np.array( [ - [18.0, 18.6, 19.2, 19.8, 20.400002, 21.0, 21.6, 22.2, 22.8], - [10.5, 11.1, 11.700001, 12.299999, 12.900001, 13.5, 14.1, 14.700001, 15.3], - [3.0, 3.6000001, 4.2000003, 4.8, 5.4000006, 6.0, 6.6000004, 7.200001, 7.8], + [ + [18.0, 18.6, 19.2, 19.8, 20.400002, 21.0, 21.6, 22.2, 22.8], + [10.5, 11.1, 11.700001, 12.299999, 12.900001, 13.5, 14.1, 14.700001, 15.3], + [3.0, 3.6000001, 4.2000003, 4.8, 5.4000006, 6.0, 6.6000004, 7.200001, 7.8], + ] ] - ] - ), - ], - [ - {"pixdim": (5.0, 3.0), "padding_mode": "zeros", "diagonal": True, "dtype": np.float32}, - np.arange(24).reshape((1, 4, 6)), # data - {"affine": np.array([[-4, 0, 0, 0], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "bilinear"}, - np.array( - [ + ), + ] + ) + TESTS.append( + [ + p, + {"pixdim": (5.0, 3.0), "padding_mode": "zeros", "diagonal": True, "dtype": np.float32}, + np.arange(24).reshape((1, 4, 6)), # data + {"affine": np.array([[-4, 0, 0, 0], [0, 5, 0, 0], [0, 0, 6, 0], [0, 0, 0, 1]]), "mode": "bilinear"}, + np.array( [ - [18.0000, 18.6000, 19.2000, 19.8000, 20.4000, 21.0000, 21.6000, 22.2000, 22.8000], - [10.5000, 11.1000, 11.7000, 12.3000, 12.9000, 13.5000, 14.1000, 14.7000, 15.3000], - [3.0000, 3.6000, 4.2000, 4.8000, 5.4000, 6.0000, 6.6000, 7.2000, 7.8000], + [ + [18.0000, 18.6000, 19.2000, 19.8000, 20.4000, 21.0000, 21.6000, 22.2000, 22.8000], + [10.5000, 11.1000, 11.7000, 12.3000, 12.9000, 13.5000, 14.1000, 14.7000, 15.3000], + [3.0000, 3.6000, 4.2000, 4.8000, 5.4000, 6.0000, 6.6000, 7.2000, 7.8000], + ] ] - ] - ), - ], - [ - {"pixdim": [-1, -1, 0.5], "padding_mode": "zeros", "dtype": float}, - np.ones((1, 2, 1, 2)), # data - {"affine": np.eye(4)}, - np.array([[[[1.0, 1.0, 1.0]], [[1.0, 1.0, 1.0]]]]), - ], -] + ), + ] + ) + TESTS.append( + [ + p, + {"pixdim": [-1, -1, 0.5], "padding_mode": "zeros", "dtype": float}, + np.ones((1, 2, 1, 2)), # data + {"affine": np.eye(4)}, + np.array([[[[1.0, 1.0, 1.0]], [[1.0, 1.0, 1.0]]]]), + ] + ) class TestSpacingCase(unittest.TestCase): - @parameterized.expand(TEST_CASES) - def test_spacing(self, init_param, img, data_param, expected_output): - res = Spacing(**init_param)(img, **data_param) - if not isinstance(res, tuple): - np.testing.assert_allclose(res, expected_output, atol=1e-6) - return - np.testing.assert_allclose(res[0], expected_output, atol=1e-6) - sr = len(res[0].shape) - 1 + @parameterized.expand(TESTS) + def test_spacing(self, in_type, init_param, img, data_param, expected_output): + _img = in_type(img) + output_data, _, new_affine = Spacing(**init_param)(_img, **data_param) + if isinstance(_img, torch.Tensor): + self.assertEqual(_img.device, output_data.device) + output_data = output_data.cpu() + + np.testing.assert_allclose(output_data, expected_output, atol=1e-3, rtol=1e-3) + sr = len(output_data.shape) - 1 if isinstance(init_param["pixdim"], float): init_param["pixdim"] = [init_param["pixdim"]] * sr init_pixdim = ensure_tuple(init_param["pixdim"]) init_pixdim = init_param["pixdim"][:sr] - norm = np.sqrt(np.sum(np.square(res[2]), axis=0))[:sr] + norm = np.sqrt(np.sum(np.square(new_affine), axis=0))[:sr] np.testing.assert_allclose(fall_back_tuple(init_pixdim, norm), norm) diff --git a/tests/test_spacingd.py b/tests/test_spacingd.py index 61a4a4c38b..fd1ee7fd54 100644 --- a/tests/test_spacingd.py +++ b/tests/test_spacingd.py @@ -10,82 +10,95 @@ # limitations under the License. import unittest +from typing import List, Tuple import numpy as np +import torch +from parameterized import parameterized from monai.transforms import Spacingd +from tests.utils import TEST_NDARRAYS - -class TestSpacingDCase(unittest.TestCase): - def test_spacingd_3d(self): - data = {"image": np.ones((2, 10, 15, 20)), "image_meta_dict": {"affine": np.eye(4)}} - spacing = Spacingd(keys="image", pixdim=(1, 2, 1.4)) - res = spacing(data) - self.assertEqual(("image", "image_meta_dict", "image_transforms"), tuple(sorted(res))) - np.testing.assert_allclose(res["image"].shape, (2, 10, 8, 15)) - np.testing.assert_allclose(res["image_meta_dict"]["affine"], np.diag([1, 2, 1.4, 1.0])) - - def test_spacingd_2d(self): - data = {"image": np.ones((2, 10, 20)), "image_meta_dict": {"affine": np.eye(3)}} - spacing = Spacingd(keys="image", pixdim=(1, 2)) - res = spacing(data) - self.assertEqual(("image", "image_meta_dict", "image_transforms"), tuple(sorted(res))) - np.testing.assert_allclose(res["image"].shape, (2, 10, 10)) - np.testing.assert_allclose(res["image_meta_dict"]["affine"], np.diag((1, 2, 1))) - - def test_spacingd_2d_no_metadata(self): - data = {"image": np.ones((2, 10, 20))} - spacing = Spacingd(keys="image", pixdim=(1, 2)) - res = spacing(data) - self.assertEqual(("image", "image_meta_dict", "image_transforms"), tuple(sorted(res))) - np.testing.assert_allclose(res["image"].shape, (2, 10, 10)) - np.testing.assert_allclose(res["image_meta_dict"]["affine"], np.diag((1, 2, 1))) - - def test_interp_all(self): - data = { - "image": np.arange(20).reshape((2, 1, 10)), - "seg": np.ones((2, 1, 10)), - "image_meta_dict": {"affine": np.eye(4)}, - "seg_meta_dict": {"affine": np.eye(4)}, - } - spacing = Spacingd( - keys=("image", "seg"), - mode="nearest", - pixdim=( - 1, - 0.2, - ), +TESTS: List[Tuple] = [] +for p in TEST_NDARRAYS: + TESTS.append( + ( + "spacing 3d", + {"image": p(np.ones((2, 10, 15, 20))), "image_meta_dict": {"affine": p(np.eye(4))}}, + dict(keys="image", pixdim=(1, 2, 1.4)), + ("image", "image_meta_dict", "image_transforms"), + (2, 10, 8, 15), + np.diag([1, 2, 1.4, 1.0]), ) - res = spacing(data) - self.assertEqual( - ("image", "image_meta_dict", "image_transforms", "seg", "seg_meta_dict", "seg_transforms"), - tuple(sorted(res)), + ) + TESTS.append( + ( + "spacing 2d", + {"image": np.ones((2, 10, 20)), "image_meta_dict": {"affine": np.eye(3)}}, + dict(keys="image", pixdim=(1, 2)), + ("image", "image_meta_dict", "image_transforms"), + (2, 10, 10), + np.diag((1, 2, 1)), ) - np.testing.assert_allclose(res["image"].shape, (2, 1, 46)) - np.testing.assert_allclose(res["image_meta_dict"]["affine"], np.diag((1, 0.2, 1, 1))) - - def test_interp_sep(self): - data = { - "image": np.ones((2, 1, 10)), - "seg": np.ones((2, 1, 10)), - "image_meta_dict": {"affine": np.eye(4)}, - "seg_meta_dict": {"affine": np.eye(4)}, - } - spacing = Spacingd( - keys=("image", "seg"), - mode=("bilinear", "nearest"), - pixdim=( - 1, - 0.2, + ) + TESTS.append( + ( + "spacing 2d no metadata", + {"image": np.ones((2, 10, 20))}, + dict(keys="image", pixdim=(1, 2)), + ("image", "image_meta_dict", "image_transforms"), + (2, 10, 10), + np.diag((1, 2, 1)), + ) + ) + TESTS.append( + ( + "interp all", + { + "image": np.arange(20).reshape((2, 1, 10)), + "seg": np.ones((2, 1, 10)), + "image_meta_dict": {"affine": np.eye(4)}, + "seg_meta_dict": {"affine": np.eye(4)}, + }, + dict( + keys=("image", "seg"), + mode="nearest", + pixdim=( + 1, + 0.2, + ), ), + ("image", "image_meta_dict", "image_transforms", "seg", "seg_meta_dict", "seg_transforms"), + (2, 1, 46), + np.diag((1, 0.2, 1, 1)), ) - res = spacing(data) - self.assertEqual( + ) + TESTS.append( + ( + "interp sep", + { + "image": np.ones((2, 1, 10)), + "seg": np.ones((2, 1, 10)), + "image_meta_dict": {"affine": np.eye(4)}, + "seg_meta_dict": {"affine": np.eye(4)}, + }, + dict(keys=("image", "seg"), mode=("bilinear", "nearest"), pixdim=(1, 0.2)), ("image", "image_meta_dict", "image_transforms", "seg", "seg_meta_dict", "seg_transforms"), - tuple(sorted(res)), + (2, 1, 46), + np.diag((1, 0.2, 1, 1)), ) - np.testing.assert_allclose(res["image"].shape, (2, 1, 46)) - np.testing.assert_allclose(res["image_meta_dict"]["affine"], np.diag((1, 0.2, 1, 1))) + ) + + +class TestSpacingDCase(unittest.TestCase): + @parameterized.expand(TESTS) + def test_spacingd(self, _, data, kw_args, expected_keys, expected_shape, expected_affine): + res = Spacingd(**kw_args)(data) + if isinstance(data["image"], torch.Tensor): + self.assertEqual(data["image"].device, res["image"].device) + self.assertEqual(expected_keys, tuple(sorted(res))) + np.testing.assert_allclose(res["image"].shape, expected_shape) + np.testing.assert_allclose(res["image_meta_dict"]["affine"], expected_affine) if __name__ == "__main__": diff --git a/tests/utils.py b/tests/utils.py index 6b7f6c4c16..b7e32068c3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -38,6 +38,7 @@ from monai.utils import ensure_tuple, optional_import, set_determinism from monai.utils.misc import is_module_ver_at_least from monai.utils.module import version_leq +from monai.utils.type_conversion import convert_data_type nib, _ = optional_import("nibabel") @@ -187,11 +188,15 @@ def __call__(self, obj): )(obj) -def make_nifti_image(array, affine=None): +def make_nifti_image(array: NdarrayOrTensor, affine=None): """ Create a temporary nifti image on the disk and return the image name. User is responsible for deleting the temporary file when done with it. """ + if isinstance(array, torch.Tensor): + array, *_ = convert_data_type(array, np.ndarray) + if isinstance(affine, torch.Tensor): + affine, *_ = convert_data_type(affine, np.ndarray) if affine is None: affine = np.eye(4) test_image = nib.Nifti1Image(array, affine) From f909a6bb82c32b447f208a4e5bf259c398270438 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Thu, 30 Sep 2021 02:44:45 +0100 Subject: [PATCH 62/89] 2975 torch fgbgtoindices (#3038) * torch fgbgtoindices Signed-off-by: Wenqi Li * unravel indices Signed-off-by: Wenqi Li * simplified Signed-off-by: Wenqi Li Co-authored-by: Nic Ma --- docs/source/transforms.rst | 3 + monai/transforms/utility/array.py | 22 ++--- monai/transforms/utility/dictionary.py | 4 +- monai/transforms/utils.py | 4 +- .../utils_pytorch_numpy_unification.py | 26 ++++-- monai/utils/type_conversion.py | 5 +- tests/test_fg_bg_to_indices.py | 90 +++++++++++-------- tests/test_fg_bg_to_indicesd.py | 81 ++++++++++------- 8 files changed, 135 insertions(+), 100 deletions(-) diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index 0b0f9f0792..4c3bff363d 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -1418,3 +1418,6 @@ Utilities --------- .. automodule:: monai.transforms.utils :members: + +.. automodule:: monai.transforms.utils_pytorch_numpy_unification + :members: diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 272c9963a8..8c15d0c148 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -31,7 +31,7 @@ map_binary_to_indices, map_classes_to_indices, ) -from monai.transforms.utils_pytorch_numpy_unification import in1d, moveaxis +from monai.transforms.utils_pytorch_numpy_unification import in1d, moveaxis, unravel_indices from monai.utils import ( convert_data_type, convert_to_cupy, @@ -789,16 +789,18 @@ class FgBgToIndices(Transform): """ + backend = [TransformBackends.NUMPY, TransformBackends.TORCH] + def __init__(self, image_threshold: float = 0.0, output_shape: Optional[Sequence[int]] = None) -> None: self.image_threshold = image_threshold self.output_shape = output_shape def __call__( self, - label: np.ndarray, - image: Optional[np.ndarray] = None, + label: NdarrayOrTensor, + image: Optional[NdarrayOrTensor] = None, output_shape: Optional[Sequence[int]] = None, - ) -> Tuple[np.ndarray, np.ndarray]: + ) -> Tuple[NdarrayOrTensor, NdarrayOrTensor]: """ Args: label: input data to compute foreground and background indices. @@ -807,18 +809,12 @@ def __call__( output_shape: expected shape of output indices. if None, use `self.output_shape` instead. """ - fg_indices: np.ndarray - bg_indices: np.ndarray - label, *_ = convert_data_type(label, np.ndarray) # type: ignore - if image is not None: - image, *_ = convert_data_type(image, np.ndarray) # type: ignore if output_shape is None: output_shape = self.output_shape - fg_indices, bg_indices = map_binary_to_indices(label, image, self.image_threshold) # type: ignore + fg_indices, bg_indices = map_binary_to_indices(label, image, self.image_threshold) if output_shape is not None: - fg_indices = np.stack([np.unravel_index(i, output_shape) for i in fg_indices]) - bg_indices = np.stack([np.unravel_index(i, output_shape) for i in bg_indices]) - + fg_indices = unravel_indices(fg_indices, output_shape) + bg_indices = unravel_indices(bg_indices, output_shape) return fg_indices, bg_indices diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 4fb07644a9..0be46fd02b 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -1119,6 +1119,8 @@ class FgBgToIndicesd(MapTransform): """ + backend = FgBgToIndices.backend + def __init__( self, keys: KeysCollection, @@ -1135,7 +1137,7 @@ def __init__( self.image_key = image_key self.converter = FgBgToIndices(image_threshold, output_shape) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) image = d[self.image_key] if self.image_key else None for key in self.key_iterator(d): diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 4927f9a478..01a62e36ff 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -286,9 +286,7 @@ def map_binary_to_indices( fg_indices = nonzero(label_flat) if image is not None: img_flat = ravel(any_np_pt(image > image_threshold, 0)) - img_flat, *_ = convert_data_type( - img_flat, type(label), device=label.device if isinstance(label, torch.Tensor) else None - ) + img_flat, *_ = convert_to_dst_type(img_flat, label, dtype=img_flat.dtype) bg_indices = nonzero(img_flat & ~label_flat) else: bg_indices = nonzero(~label_flat) diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 4283c4a81f..3fe2402504 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -26,6 +26,7 @@ "nonzero", "floor_divide", "unravel_index", + "unravel_indices", "ravel", "any_np_pt", "maximum", @@ -91,9 +92,8 @@ def percentile(x: NdarrayOrTensor, q) -> Union[NdarrayOrTensor, float, int]: if np.isscalar(q): if not 0 <= q <= 100: raise ValueError - else: - if any(q < 0) or any(q > 100): - raise ValueError + elif any(q < 0) or any(q > 100): + raise ValueError result: Union[NdarrayOrTensor, float, int] if isinstance(x, np.ndarray): result = np.percentile(x, q) @@ -167,7 +167,7 @@ def unravel_index(idx, shape): Args: idx: index to unravel - b: shape of array/tensor + shape: shape of array/tensor Returns: Index unravelled for given shape @@ -175,12 +175,26 @@ def unravel_index(idx, shape): if isinstance(idx, torch.Tensor): coord = [] for dim in reversed(shape): - coord.insert(0, idx % dim) + coord.append(idx % dim) idx = floor_divide(idx, dim) - return torch.stack(coord) + return torch.stack(coord[::-1]) return np.unravel_index(np.asarray(idx, dtype=int), shape) +def unravel_indices(idx, shape): + """Computing unravel cooridnates from indices. + + Args: + idx: a sequence of indices to unravel + shape: shape of array/tensor + + Returns: + Stacked indices unravelled for given shape + """ + lib_stack = torch.stack if isinstance(idx[0], torch.Tensor) else np.stack + return lib_stack([unravel_index(i, shape) for i in idx]) + + def ravel(x: NdarrayOrTensor): """`np.ravel` with equivalent implementation for torch. diff --git a/monai/utils/type_conversion.py b/monai/utils/type_conversion.py index 87095fef99..648e68440e 100644 --- a/monai/utils/type_conversion.py +++ b/monai/utils/type_conversion.py @@ -270,10 +270,7 @@ def convert_to_dst_type( See Also: :func:`convert_data_type` """ - device = None - if isinstance(dst, torch.Tensor): - device = dst.device - + device = dst.device if isinstance(dst, torch.Tensor) else None if dtype is None: dtype = dst.dtype diff --git a/tests/test_fg_bg_to_indices.py b/tests/test_fg_bg_to_indices.py index 98626c7028..0d35dd23f8 100644 --- a/tests/test_fg_bg_to_indices.py +++ b/tests/test_fg_bg_to_indices.py @@ -11,58 +11,70 @@ import unittest -import numpy as np from parameterized import parameterized from monai.transforms import FgBgToIndices +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"image_threshold": 0.0, "output_shape": None}, - np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), - None, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 4, 8]), -] +TESTS_CASES = [] +for p in TEST_NDARRAYS: + TESTS_CASES.append( + [ + {"image_threshold": 0.0, "output_shape": None}, + p([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), + None, + p([1, 2, 3, 5, 6, 7]), + p([0, 4, 8]), + ] + ) -TEST_CASE_2 = [ - {"image_threshold": 0.0, "output_shape": None}, - np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), - np.array([[[1, 1, 1], [1, 0, 1], [1, 1, 1]]]), - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] + TESTS_CASES.append( + [ + {"image_threshold": 0.0, "output_shape": None}, + p([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), + p([[[1, 1, 1], [1, 0, 1], [1, 1, 1]]]), + p([1, 2, 3, 5, 6, 7]), + p([0, 8]), + ] + ) -TEST_CASE_3 = [ - {"image_threshold": 1.0, "output_shape": None}, - np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), - np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] + TESTS_CASES.append( + [ + {"image_threshold": 1.0, "output_shape": None}, + p([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), + p([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), + p([1, 2, 3, 5, 6, 7]), + p([0, 8]), + ] + ) -TEST_CASE_4 = [ - {"image_threshold": 1.0, "output_shape": None}, - np.array([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), - np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] + TESTS_CASES.append( + [ + {"image_threshold": 1.0, "output_shape": None}, + p([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), + p([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), + p([1, 2, 3, 5, 6, 7]), + p([0, 8]), + ] + ) -TEST_CASE_5 = [ - {"image_threshold": 1.0, "output_shape": [3, 3]}, - np.array([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), - np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), - np.array([[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]]), - np.array([[0, 0], [2, 2]]), -] + TESTS_CASES.append( + [ + {"image_threshold": 1.0, "output_shape": [3, 3]}, + p([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), + p([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]]), + p([[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]]), + p([[0, 0], [2, 2]]), + ] + ) class TestFgBgToIndices(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5]) + @parameterized.expand(TESTS_CASES) def test_type_shape(self, input_data, label, image, expected_fg, expected_bg): fg_indices, bg_indices = FgBgToIndices(**input_data)(label, image) - np.testing.assert_allclose(fg_indices, expected_fg) - np.testing.assert_allclose(bg_indices, expected_bg) + assert_allclose(fg_indices, expected_fg) + assert_allclose(bg_indices, expected_bg) if __name__ == "__main__": diff --git a/tests/test_fg_bg_to_indicesd.py b/tests/test_fg_bg_to_indicesd.py index ce6ca30f1b..4691526d94 100644 --- a/tests/test_fg_bg_to_indicesd.py +++ b/tests/test_fg_bg_to_indicesd.py @@ -11,53 +11,66 @@ import unittest -import numpy as np from parameterized import parameterized from monai.transforms import FgBgToIndicesd +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - {"keys": "label", "image_key": None, "image_threshold": 0.0, "output_shape": None}, - {"label": np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]])}, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 4, 8]), -] +TEST_CASES = [] +for p in TEST_NDARRAYS: -TEST_CASE_2 = [ - {"keys": "label", "image_key": "image", "image_threshold": 0.0, "output_shape": None}, - {"label": np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), "image": np.array([[[1, 1, 1], [1, 0, 1], [1, 1, 1]]])}, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] + TEST_CASES.append( + [ + {"keys": "label", "image_key": None, "image_threshold": 0.0, "output_shape": None}, + {"label": p([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]])}, + p([1, 2, 3, 5, 6, 7]), + p([0, 4, 8]), + ] + ) -TEST_CASE_3 = [ - {"keys": "label", "image_key": "image", "image_threshold": 1.0, "output_shape": None}, - {"label": np.array([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), "image": np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])}, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] + TEST_CASES.append( + [ + {"keys": "label", "image_key": "image", "image_threshold": 0.0, "output_shape": None}, + {"label": p([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), "image": p([[[1, 1, 1], [1, 0, 1], [1, 1, 1]]])}, + p([1, 2, 3, 5, 6, 7]), + p([0, 8]), + ] + ) -TEST_CASE_4 = [ - {"keys": "label", "image_key": "image", "image_threshold": 1.0, "output_shape": None}, - {"label": np.array([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), "image": np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])}, - np.array([1, 2, 3, 5, 6, 7]), - np.array([0, 8]), -] + TEST_CASES.append( + [ + {"keys": "label", "image_key": "image", "image_threshold": 1.0, "output_shape": None}, + {"label": p([[[0, 1, 1], [1, 0, 1], [1, 1, 0]]]), "image": p([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])}, + p([1, 2, 3, 5, 6, 7]), + p([0, 8]), + ] + ) -TEST_CASE_5 = [ - {"keys": "label", "image_key": "image", "image_threshold": 1.0, "output_shape": [3, 3]}, - {"label": np.array([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), "image": np.array([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])}, - np.array([[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]]), - np.array([[0, 0], [2, 2]]), -] + TEST_CASES.append( + [ + {"keys": "label", "image_key": "image", "image_threshold": 1.0, "output_shape": None}, + {"label": p([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), "image": p([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])}, + p([1, 2, 3, 5, 6, 7]), + p([0, 8]), + ] + ) + + TEST_CASES.append( + [ + {"keys": "label", "image_key": "image", "image_threshold": 1.0, "output_shape": [3, 3]}, + {"label": p([[[0, 1, 2], [3, 0, 4], [5, 6, 0]]]), "image": p([[[3, 3, 3], [3, 1, 3], [3, 3, 3]]])}, + p([[0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]]), + p([[0, 0], [2, 2]]), + ] + ) class TestFgBgToIndicesd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5]) + @parameterized.expand(TEST_CASES) def test_type_shape(self, input_data, data, expected_fg, expected_bg): result = FgBgToIndicesd(**input_data)(data) - np.testing.assert_allclose(result["label_fg_indices"], expected_fg) - np.testing.assert_allclose(result["label_bg_indices"], expected_bg) + assert_allclose(result["label_fg_indices"], expected_fg) + assert_allclose(result["label_bg_indices"], expected_bg) if __name__ == "__main__": From d15cedd9d5466365f476c61e79a52141dbc13f2e Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Thu, 30 Sep 2021 22:50:25 +0800 Subject: [PATCH 63/89] 3051 Fix dtype issue in Spacing transform (#3052) * [DLMED] fix spacing dtype Signed-off-by: Nic Ma * [DLMED] fix dtype Signed-off-by: Nic Ma --- monai/transforms/intensity/array.py | 3 ++- monai/transforms/spatial/array.py | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 0e9f922888..2dc1ed1a94 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -739,7 +739,8 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: epsilon = 1e-7 img_min = img.min() img_range = img.max() - img_min - return ((img - img_min) / float(img_range + epsilon)) ** self.gamma * img_range + img_min + ret: NdarrayOrTensor = ((img - img_min) / float(img_range + epsilon)) ** self.gamma * img_range + img_min + return ret class RandAdjustContrast(RandomizableTransform): diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 62ac5d2c3e..27d25cf2bc 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -13,7 +13,6 @@ https://github.com/Project-MONAI/MONAI/wiki/MONAI_Design """ import warnings -from copy import deepcopy from typing import Any, List, Optional, Sequence, Tuple, Union import numpy as np @@ -200,9 +199,8 @@ def __call__( # no resampling if it's identity transform if np.allclose(transform, np.diag(np.ones(len(transform))), atol=1e-3): - output_data, *_ = convert_data_type(deepcopy(data_array), dtype=_dtype) + output_data, *_ = convert_data_type(data_array, dtype=torch.float32) new_affine = to_affine_nd(affine, new_affine) # type: ignore - else: # resample affine_xform = AffineTransform( @@ -220,7 +218,7 @@ def __call__( convert_data_type(transform, torch.Tensor, data_array_t.device, dtype=_dtype)[0], spatial_size=output_shape if output_spatial_shape is None else output_spatial_shape, ).squeeze(0) - output_data, *_ = convert_to_dst_type(output_data, data_array, dtype=_dtype) + output_data, *_ = convert_to_dst_type(output_data, data_array, dtype=torch.float32) new_affine = to_affine_nd(affine, new_affine) # type: ignore return output_data, affine, new_affine From a589c82503c46bb446cf6bea03a0675c33778bf4 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Thu, 30 Sep 2021 19:36:45 +0100 Subject: [PATCH 64/89] Create transform images (#3039) create example transform images --- docs/source/transforms.rst | 4 + .../transforms/utils_create_transform_ims.py | 220 ++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 monai/transforms/utils_create_transform_ims.py diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index 4c3bff363d..b94121cbe2 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -461,6 +461,8 @@ Spatial `RandFlip` """""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandFlip.png + :alt: example of RandFlip .. autoclass:: RandFlip :members: :special-members: __call__ @@ -1115,6 +1117,8 @@ Spatial (Dict) `RandFlipd` """"""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandFlipd.png + :alt: example of RandFlipd .. autoclass:: RandFlipd :members: :special-members: __call__ diff --git a/monai/transforms/utils_create_transform_ims.py b/monai/transforms/utils_create_transform_ims.py new file mode 100644 index 0000000000..8eb0c6b945 --- /dev/null +++ b/monai/transforms/utils_create_transform_ims.py @@ -0,0 +1,220 @@ +# Copyright 2020 - 2021 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 os +import pathlib +import tempfile +from copy import deepcopy +from glob import glob +from typing import TYPE_CHECKING + +import numpy as np + +from monai.apps import download_and_extract +from monai.transforms import ( + AddChanneld, + Compose, + LoadImaged, + MapTransform, + RandFlip, + RandFlipd, + Randomizable, + Rotate90d, + ScaleIntensityd, + SpatialPadd, +) +from monai.utils.enums import CommonKeys +from monai.utils.module import optional_import + +if TYPE_CHECKING: + import matplotlib.pyplot as plt + + has_matplotlib = True + +else: + plt, has_matplotlib = optional_import("matplotlib.pyplot") + + +KEYS = [CommonKeys.IMAGE, CommonKeys.LABEL] + + +def get_data(): + """Get the example data to be used. + + Use MarsAtlas as it only contains 1 image for quick download and + that image is parcellated. + """ + cache_dir = os.environ.get("MONAI_DATA_DIRECTORY") or tempfile.mkdtemp() + fname = "MarsAtlas-MNI-Colin27.zip" + url = "https://www.dropbox.com/s/ndz8qtqblkciole/" + fname + "?dl=1" + out_path = os.path.join(cache_dir, "MarsAtlas-MNI-Colin27") + zip_path = os.path.join(cache_dir, fname) + + download_and_extract(url, zip_path, out_path) + + image, label = sorted(glob(os.path.join(out_path, "*.nii"))) + + data = {CommonKeys.IMAGE: image, CommonKeys.LABEL: label} + + transforms = Compose( + [ + LoadImaged(KEYS), + AddChanneld(KEYS), + ScaleIntensityd(CommonKeys.IMAGE), + Rotate90d(KEYS, spatial_axes=[0, 2]), + ] + ) + data = transforms(data) + im = data[CommonKeys.IMAGE] + max_size = max(im.shape) + data = SpatialPadd(KEYS, (max_size, max_size, max_size))(data) + return {k: data[k] for k in KEYS} + + +def update_docstring(code_path, transform_name): + """ + Find the documentation for a given transform and if it's missing, + add a pointer to the transform's example image. + """ + with open(code_path) as f: + contents = f.readlines() + doc_start = None + for i, line in enumerate(contents): + # find the line containing start of the transform documentation + if "`" + transform_name + "`" in line: + doc_start = i + break + if doc_start is None: + raise RuntimeError("Couldn't find transform documentation") + + # if image is already in docs, nothing to do + image_line = doc_start + 2 + if ".. image" in contents[image_line]: + return + + # add the line for the image and the alt text + contents_orig = deepcopy(contents) + contents.insert( + image_line, + ".. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/" + transform_name + ".png\n", + ) + contents.insert(image_line + 1, " :alt: example of " + transform_name + "\n") + + # check that we've only added two lines + assert len(contents) == len(contents_orig) + 2 + + # write the updated doc to overwrite the original + with open(code_path, "w") as f: + f.writelines(contents) + + +def pre_process_data(data, ndim, is_map): + """If transform requires 2D data, then convert to 2D""" + if ndim == 2: + for k in KEYS: + data[k] = data[k][..., data[k].shape[-1] // 2] + + return data if is_map else data[CommonKeys.IMAGE] + + +def get_2d_slice(image, view): + """Get the central slice of a 3D volume""" + shape = image.shape + slices = [slice(0, s) for s in shape] + _slice = shape[view] // 2 + slices[view] = slice(_slice, _slice + 1) + slices = tuple(slices) + return np.squeeze(image[slices], view) + + +def get_stacked_2d_ims(im): + """Get the 3 orthogonal views and stack them into 1 image. + Requires that all images be same size, but this is taken care + of by the `SpatialPadd` earlier. + """ + return np.hstack([get_2d_slice(im, view) for view in range(3)]) + + +def get_stacked_before_after(before, after): + """Stack before and after images into 1 image. + Requires that before and after images be the same size. + """ + return np.vstack([get_stacked_2d_ims(d[0]) for d in (before, after)]) + + +def save_image(images, labels, filename): + """Save image to file, ensuring there's no whitespace around the edge.""" + sizes = images.shape + fig = plt.figure() + fig.set_size_inches(1.0 * sizes[1] / sizes[0], 1, forward=False) + ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0]) + ax.set_axis_off() + fig.add_axes(ax) + ax.imshow(images, cmap="gray") + if labels is not None: + ax.imshow(labels, cmap="hsv", alpha=0.9) + fig.savefig(filename, dpi=images.shape[0]) + plt.close(fig) + + +def create_transform_im(transform, data, ndim, update_doc=True, out_dir=None, seed=0): + """Create an image with the before and after of the transform. + Also update the transform's documentation to point to this image.""" + + if not has_matplotlib: + raise RuntimeError + + if isinstance(transform, Randomizable): + transform.set_random_state(seed) + + out_dir = os.environ.get("MONAI_DOC_IMAGES") + if out_dir is None: + raise RuntimeError( + "Please git clone https://github.com/Project-MONAI/DocImages" + + " and then set the environmental variable `MONAI_DOC_IMAGES`" + ) + out_dir = os.path.join(out_dir, "transforms") + + # Path is transform name + transform_name = transform.__class__.__name__ + out_fname = transform_name + ".png" + out_file = os.path.join(out_dir, out_fname) + + is_map = isinstance(transform, MapTransform) + data_in = pre_process_data(data, ndim, is_map) + + data_tr = transform(data_in) + + if ndim != 3: + raise NotImplementedError + + image_before = data_in[CommonKeys.IMAGE] if is_map else data_in + image_after = data_tr[CommonKeys.IMAGE] if is_map else data_tr + stacked_images = get_stacked_before_after(image_before, image_after) + stacked_labels = None + if is_map: + label_before = data_in[CommonKeys.LABEL] + label_after = data_tr[CommonKeys.LABEL] + stacked_labels = get_stacked_before_after(label_before, label_after) + stacked_labels[stacked_labels == 0] = np.nan + + save_image(stacked_images, stacked_labels, out_file) + + if update_doc: + base_dir = pathlib.Path(__file__).parent.parent.parent + rst_path = os.path.join(base_dir, "docs", "source", "transforms.rst") + update_docstring(rst_path, transform_name) + + +if __name__ == "__main__": + data = get_data() + create_transform_im(RandFlip(prob=1, spatial_axis=2), data, 3) + create_transform_im(RandFlipd(KEYS, prob=1, spatial_axis=2), data, 3) From 7c46f8e9b0969ebb119c59af9dd256e2949464d2 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Fri, 1 Oct 2021 21:29:18 +0800 Subject: [PATCH 65/89] 2975 Fix the perf issue of RandCropByPosNegLabel (#3050) * [DLMED] fix crop performance issue Signed-off-by: Nic Ma * [DLMED] fix CI test Signed-off-by: Nic Ma * [DLMED] use default to avoid overflow Signed-off-by: Nic Ma * [DLMED] fix CI error Signed-off-by: Nic Ma --- monai/transforms/croppad/array.py | 4 ++-- monai/transforms/utils.py | 14 +++++++------- .../transforms/utils_pytorch_numpy_unification.py | 2 +- tests/test_generate_label_classes_crop_centers.py | 3 ++- tests/test_generate_pos_neg_label_crop_centers.py | 4 +++- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index 1c3bbf6833..c904631bed 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -419,7 +419,7 @@ def __init__( if roi_start_torch.numel() == 1: self.slices = [slice(int(roi_start_torch.item()), int(roi_end_torch.item()))] else: - self.slices = [slice(int(s.item()), int(e.item())) for s, e in zip(roi_start_torch, roi_end_torch)] + self.slices = [slice(int(s), int(e)) for s, e in zip(roi_start_torch.tolist(), roi_end_torch.tolist())] def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ @@ -966,7 +966,7 @@ def __call__( results: List[NdarrayOrTensor] = [] if self.centers is not None: for center in self.centers: - cropper = SpatialCrop(roi_center=tuple(center), roi_size=self.spatial_size) + cropper = SpatialCrop(roi_center=center, roi_size=self.spatial_size) results.append(cropper(img)) return results diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 01a62e36ff..26110081bb 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -291,6 +291,9 @@ def map_binary_to_indices( else: bg_indices = nonzero(~label_flat) + # no need to save the indices in GPU, otherwise, still need to move to CPU at runtime when crop by indices + fg_indices, *_ = convert_data_type(fg_indices, device=torch.device("cpu")) + bg_indices, *_ = convert_data_type(bg_indices, device=torch.device("cpu")) return fg_indices, bg_indices @@ -389,12 +392,12 @@ def correct_crop_centers( centers: List[Union[int, torch.Tensor]], spatial_size: Union[Sequence[int], int], label_spatial_shape: Sequence[int], -) -> List[int]: +): """ Utility to correct the crop center if the crop size is bigger than the image size. Args: - ceters: pre-computed crop centers, will correct based on the valid region. + centers: pre-computed crop centers of every dim, will correct based on the valid region. spatial_size: spatial size of the ROIs to be sampled. label_spatial_shape: spatial shape of the original label data to compare with ROI. @@ -422,9 +425,7 @@ def correct_crop_centers( center_i = valid_end[i] - 1 centers[i] = center_i - corrected_centers: List[int] = [c.item() if isinstance(c, torch.Tensor) else c for c in centers] # type: ignore - - return corrected_centers + return centers def generate_pos_neg_label_crop_centers( @@ -476,8 +477,7 @@ def generate_pos_neg_label_crop_centers( idx = indices_to_use[random_int] center = unravel_index(idx, label_spatial_shape) # shift center to range of valid centers - center_ori = list(center) - centers.append(correct_crop_centers(center_ori, spatial_size, label_spatial_shape)) + centers.append(correct_crop_centers(center, spatial_size, label_spatial_shape)) return centers diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 3fe2402504..2c370a4707 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -178,7 +178,7 @@ def unravel_index(idx, shape): coord.append(idx % dim) idx = floor_divide(idx, dim) return torch.stack(coord[::-1]) - return np.unravel_index(np.asarray(idx, dtype=int), shape) + return np.asarray(np.unravel_index(idx, shape)) def unravel_indices(idx, shape): diff --git a/tests/test_generate_label_classes_crop_centers.py b/tests/test_generate_label_classes_crop_centers.py index cc068504bf..0e40750276 100644 --- a/tests/test_generate_label_classes_crop_centers.py +++ b/tests/test_generate_label_classes_crop_centers.py @@ -61,7 +61,8 @@ def test_type_shape(self, input_data, expected_type, expected_count, expected_sh # check for consistency between numpy, torch and torch.cuda results.append(result) if len(results) > 1: - assert_allclose(results[0], results[-1]) + for x, y in zip(result[0], result[-1]): + assert_allclose(x, y, type_test=False) if __name__ == "__main__": diff --git a/tests/test_generate_pos_neg_label_crop_centers.py b/tests/test_generate_pos_neg_label_crop_centers.py index b263f10e55..b8f2840757 100644 --- a/tests/test_generate_pos_neg_label_crop_centers.py +++ b/tests/test_generate_pos_neg_label_crop_centers.py @@ -53,7 +53,9 @@ def test_type_shape(self, input_data, expected_type, expected_count, expected_sh # check for consistency between numpy, torch and torch.cuda results.append(result) if len(results) > 1: - assert_allclose(results[0], results[-1]) + # compare every crop center + for x, y in zip(results[0], results[-1]): + assert_allclose(x, y, type_test=False) if __name__ == "__main__": From 3b5af505b726aa58f1e2e74801da212159900916 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Sat, 2 Oct 2021 17:56:52 +0800 Subject: [PATCH 66/89] [DLMED] fix broken link (#3059) Signed-off-by: Nic Ma --- docs/source/highlights.md | 2 +- docs/source/whatsnew_0_7.md | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/source/highlights.md b/docs/source/highlights.md index 44ab949a95..2db79b4821 100644 --- a/docs/source/highlights.md +++ b/docs/source/highlights.md @@ -387,7 +387,7 @@ Wentao Zhu, Can Zhao, Wenqi Li, Holger Roth, Ziyue Xu, and Daguang Xu (2020) "LA ![LAMP UNet](../images/unet-pipe.png) ## Performance optimization and GPU acceleration -Typically, model training is a time-consuming step during deep learning development, especially in medical imaging applications. Volumetric medical images are usually large (as multi-dimensional arrays) and the model training process can be complex. Even with powerful hardware (e.g. CPU/GPU with large RAM), it is not easy to fully leverage them to achieve high performance. MONAI provides a [fast training guide](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_model_training_guide.md) to achieve the best performance. +Typically, model training is a time-consuming step during deep learning development, especially in medical imaging applications. Volumetric medical images are usually large (as multi-dimensional arrays) and the model training process can be complex. Even with powerful hardware (e.g. CPU/GPU with large RAM), it is not easy to fully leverage them to achieve high performance. MONAI provides a fast training guide to achieve the best performance: https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_model_training_guide.md. NVIDIA GPUs have been widely applied in many areas of deep learning training and evaluation, and the CUDA parallel computation shows obvious acceleration when comparing to traditional computation methods. To fully leverage GPU features, many popular mechanisms raised, like automatic mixed precision (AMP), distributed data parallel, etc. MONAI can support these features and provides rich examples. diff --git a/docs/source/whatsnew_0_7.md b/docs/source/whatsnew_0_7.md index 010a62824b..748729e94d 100644 --- a/docs/source/whatsnew_0_7.md +++ b/docs/source/whatsnew_0_7.md @@ -11,12 +11,13 @@ Model training is often a time-consuming step during deep learning development, especially for medical imaging applications. Even with powerful hardware (e.g. CPU/GPU with large RAM), the workflows often require careful profiling and tuning to achieve high performance. MONAI has been focusing on performance -enhancements, and in this version, [a fast model training -guide](https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_model_training_guide.md) -is provided to help build highly performant workflows, with a comprehensive -overview of the profiling tools and practical strategies. The following figure -shows the use of [Nvidia Nsight™ Systems](https://developer.nvidia.com/nsight-systems) for system-wide performance analysis during -a performance enhancement study. +enhancements, and in this version, a fast model training guide is provided +to help build highly performant workflows, with a comprehensive overview of +the profiling tools and practical strategies: +https://github.com/Project-MONAI/tutorials/blob/master/acceleration/fast_model_training_guide.md. + +The following figure shows the use of [Nvidia Nsight™ Systems](https://developer.nvidia.com/nsight-systems) for system-wide +performance analysis during a performance enhancement study. ![nsight_vis](../images/nsight_comparison.png) With the performance profiling and enhancements, several typical use cases were studied to From 8271d8e1b26a319fda997c1fd1a6ac5aabc0ff7c Mon Sep 17 00:00:00 2001 From: Jirka Borovec Date: Sun, 3 Oct 2021 21:49:17 +0200 Subject: [PATCH 67/89] remove redundant noqa (#3027) * apply yesqa Signed-off-by: Jirka * rev Signed-off-by: Jirka * expand Signed-off-by: Jirka * plugins Signed-off-by: Jirka --- .pre-commit-config.yaml | 17 ++++++++++++----- docs/source/conf.py | 2 +- monai/__init__.py | 2 +- setup.cfg | 19 ++++++++++++++++--- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 71f9ac71ef..980a562610 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,11 +34,18 @@ repos: monai/_version.py )$ - #- repo: https://github.com/asottile/yesqa - # rev: v1.2.3 - # hooks: - # - id: yesqa - # name: Unused noqa + - repo: https://github.com/asottile/yesqa + rev: v1.2.3 + hooks: + - id: yesqa + name: Unused noqa + additional_dependencies: + - flake8>=3.8.1 + - flake8-bugbear + - flake8-comprehensions + - flake8-executable + - flake8-pyi + - pep8-naming #- repo: https://github.com/PyCQA/isort # rev: 5.9.3 diff --git a/docs/source/conf.py b/docs/source/conf.py index 324be8a0fd..46c905f99c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -18,7 +18,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) print(sys.path) -import monai # noqa: E402 +import monai # -- Project information ----------------------------------------------------- project = "MONAI" diff --git a/monai/__init__.py b/monai/__init__.py index 2c7c920162..7ab30bcae7 100644 --- a/monai/__init__.py +++ b/monai/__init__.py @@ -33,7 +33,7 @@ ), ) -from .utils.module import load_submodules # noqa: E402 +from .utils.module import load_submodules # handlers_* have some external decorators the users may not have installed # *.so files and folder "_C" may not exist when the cpp extensions are not compiled diff --git a/setup.cfg b/setup.cfg index 309169ebe8..19f04de526 100644 --- a/setup.cfg +++ b/setup.cfg @@ -83,9 +83,22 @@ max_line_length = 120 # C408 ignored because we like the dict keyword argument syntax # E501 is not flexible enough, we're using B950 instead ignore = - E203,E305,E402,E501,E721,E741,F821,F841,F999,W503,W504,C408,E302,W291,E303, - # N812 lowercase 'torch.nn.functional' imported as non lowercase 'F' - N812 + E203 + E305 + E402 + E501 + E721 + E741 + F821 + F841 + F999 + W503 + W504 + C408 + E302 + W291 + E303 + N812 # lowercase 'torch.nn.functional' imported as non lowercase 'F' per_file_ignores = __init__.py: F401 exclude = *.pyi,.git,.eggs,monai/_version.py,versioneer.py,venv,.venv,_version.py From 87e2ecdcfc77c9f41d4fb10626d8c6e3e302be57 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Mon, 4 Oct 2021 08:38:35 +0800 Subject: [PATCH 68/89] [DLMED] enhance label classes (#3061) Signed-off-by: Nic Ma --- monai/transforms/utility/array.py | 18 ++-- monai/transforms/utility/dictionary.py | 2 +- monai/transforms/utils.py | 4 +- tests/test_classes_to_indices.py | 100 ++++++++++++--------- tests/test_classes_to_indicesd.py | 120 ++++++++++++++----------- 5 files changed, 138 insertions(+), 106 deletions(-) diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index 8c15d0c148..ef20cf6f3a 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -819,6 +819,9 @@ def __call__( class ClassesToIndices(Transform): + + backend = [TransformBackends.NUMPY, TransformBackends.TORCH] + def __init__( self, num_classes: Optional[int] = None, @@ -845,10 +848,10 @@ def __init__( def __call__( self, - label: np.ndarray, - image: Optional[np.ndarray] = None, + label: NdarrayOrTensor, + image: Optional[NdarrayOrTensor] = None, output_shape: Optional[Sequence[int]] = None, - ) -> List[np.ndarray]: + ) -> List[NdarrayOrTensor]: """ Args: label: input data to compute the indices of every class. @@ -857,16 +860,13 @@ def __call__( output_shape: expected shape of output indices. if None, use `self.output_shape` instead. """ - label, *_ = convert_data_type(label, np.ndarray) # type: ignore - if image is not None: - image, *_ = convert_data_type(image, np.ndarray) # type: ignore if output_shape is None: output_shape = self.output_shape - indices: List[np.ndarray] - indices = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) # type: ignore + indices: List[NdarrayOrTensor] + indices = map_classes_to_indices(label, self.num_classes, image, self.image_threshold) if output_shape is not None: - indices = [np.stack([np.unravel_index(i, output_shape) for i in array]) for array in indices] + indices = [unravel_indices(cls_indices, output_shape) for cls_indices in indices] return indices diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 0be46fd02b..7333484d13 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -1180,7 +1180,7 @@ def __init__( self.image_key = image_key self.converter = ClassesToIndices(num_classes, image_threshold, output_shape) - def __call__(self, data: Mapping[Hashable, Any]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, Any]): d = dict(data) image = d[self.image_key] if self.image_key else None for key in self.key_iterator(d): diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 26110081bb..3682a74e8f 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -339,7 +339,9 @@ def map_classes_to_indices( for c in range(num_classes_): label_flat = ravel(any_np_pt(label[c : c + 1] if channels > 1 else label == c, 0)) label_flat = img_flat & label_flat if img_flat is not None else label_flat - indices.append(nonzero(label_flat)) + # no need to save the indices in GPU, otherwise, still need to move to CPU at runtime when crop by indices + cls_indices, *_ = convert_data_type(nonzero(label_flat), device=torch.device("cpu")) + indices.append(cls_indices) return indices diff --git a/tests/test_classes_to_indices.py b/tests/test_classes_to_indices.py index 0ba3dd094a..7c89e3179d 100644 --- a/tests/test_classes_to_indices.py +++ b/tests/test_classes_to_indices.py @@ -11,68 +11,80 @@ import unittest -import numpy as np from parameterized import parameterized from monai.transforms import ClassesToIndices +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - # test Argmax data - {"num_classes": 3, "image_threshold": 0.0}, - np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), - None, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7])], -] +TESTS_CASES = [] +for p in TEST_NDARRAYS: + TESTS_CASES.append( + [ + # test Argmax data + {"num_classes": 3, "image_threshold": 0.0}, + p([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), + None, + [p([0, 4, 8]), p([1, 5, 6]), p([2, 3, 7])], + ] + ) -TEST_CASE_2 = [ - {"num_classes": 3, "image_threshold": 60}, - np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), - np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), - [np.array([0, 8]), np.array([1, 5, 6]), np.array([3])], -] + TESTS_CASES.append( + [ + {"num_classes": 3, "image_threshold": 60}, + p([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), + p([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), + [p([0, 8]), p([1, 5, 6]), p([3])], + ] + ) -TEST_CASE_3 = [ - # test One-Hot data - {"image_threshold": 0.0}, - np.array( + TESTS_CASES.append( [ - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 1, 0], [0, 0, 1], [1, 0, 0]], - [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + # test One-Hot data + {"image_threshold": 0.0}, + p( + [ + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + [[0, 1, 0], [0, 0, 1], [1, 0, 0]], + [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + ] + ), + None, + [p([0, 4, 8]), p([1, 5, 6]), p([2, 3, 7])], ] - ), - None, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7])], -] + ) -TEST_CASE_4 = [ - {"num_classes": None, "image_threshold": 60}, - np.array( + TESTS_CASES.append( [ - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 1, 0], [0, 0, 1], [1, 0, 0]], - [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + {"num_classes": None, "image_threshold": 60}, + p( + [ + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + [[0, 1, 0], [0, 0, 1], [1, 0, 0]], + [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + ] + ), + p([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), + [p([0, 8]), p([1, 5, 6]), p([3])], ] - ), - np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), - [np.array([0, 8]), np.array([1, 5, 6]), np.array([3])], -] + ) -TEST_CASE_5 = [ - # test output_shape - {"num_classes": 3, "image_threshold": 0.0, "output_shape": [3, 3]}, - np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), - None, - [np.array([[0, 0], [1, 1], [2, 2]]), np.array([[0, 1], [1, 2], [2, 0]]), np.array([[0, 2], [1, 0], [2, 1]])], -] + TESTS_CASES.append( + [ + # test output_shape + {"num_classes": 3, "image_threshold": 0.0, "output_shape": [3, 3]}, + p([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), + None, + [p([[0, 0], [1, 1], [2, 2]]), p([[0, 1], [1, 2], [2, 0]]), p([[0, 2], [1, 0], [2, 1]])], + ] + ) class TestClassesToIndices(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5]) + @parameterized.expand(TESTS_CASES) def test_value(self, input_args, label, image, expected_indices): indices = ClassesToIndices(**input_args)(label, image) for i, e in zip(indices, expected_indices): - np.testing.assert_allclose(i, e) + assert_allclose(i, e) if __name__ == "__main__": diff --git a/tests/test_classes_to_indicesd.py b/tests/test_classes_to_indicesd.py index 67fac95c8c..0df7490ec5 100644 --- a/tests/test_classes_to_indicesd.py +++ b/tests/test_classes_to_indicesd.py @@ -11,73 +11,91 @@ import unittest -import numpy as np from parameterized import parameterized from monai.transforms import ClassesToIndicesd +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - # test Argmax data - {"keys": "label", "num_classes": 3, "image_threshold": 0.0}, - {"label": np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])}, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7])], -] +TESTS_CASES = [] +for p in TEST_NDARRAYS: + TESTS_CASES.append( + [ + # test Argmax data + {"keys": "label", "num_classes": 3, "image_threshold": 0.0}, + {"label": p([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])}, + [p([0, 4, 8]), p([1, 5, 6]), p([2, 3, 7])], + ] + ) -TEST_CASE_2 = [ - {"keys": "label", "image_key": "image", "num_classes": 3, "image_threshold": 60}, - { - "label": np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), - "image": np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), - }, - [np.array([0, 8]), np.array([1, 5, 6]), np.array([3])], -] + TESTS_CASES.append( + [ + {"keys": "label", "image_key": "image", "num_classes": 3, "image_threshold": 60}, + { + "label": p([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]]), + "image": p([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), + }, + [p([0, 8]), p([1, 5, 6]), p([3])], + ] + ) -TEST_CASE_3 = [ - # test One-Hot data - {"keys": "label", "image_threshold": 0.0}, - { - "label": np.array( - [ - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 1, 0], [0, 0, 1], [1, 0, 0]], - [[0, 0, 1], [1, 0, 0], [0, 1, 0]], - ] - ) - }, - [np.array([0, 4, 8]), np.array([1, 5, 6]), np.array([2, 3, 7])], -] + TESTS_CASES.append( + [ + # test One-Hot data + {"keys": "label", "image_threshold": 0.0}, + { + "label": p( + [ + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + [[0, 1, 0], [0, 0, 1], [1, 0, 0]], + [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + ] + ) + }, + [p([0, 4, 8]), p([1, 5, 6]), p([2, 3, 7])], + ] + ) -TEST_CASE_4 = [ - {"keys": "label", "image_key": "image", "num_classes": None, "image_threshold": 60}, - { - "label": np.array( - [ - [[1, 0, 0], [0, 1, 0], [0, 0, 1]], - [[0, 1, 0], [0, 0, 1], [1, 0, 0]], - [[0, 0, 1], [1, 0, 0], [0, 1, 0]], - ] - ), - "image": np.array([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), - }, - [np.array([0, 8]), np.array([1, 5, 6]), np.array([3])], -] + TESTS_CASES.append( + [ + {"keys": "label", "image_key": "image", "num_classes": None, "image_threshold": 60}, + { + "label": p( + [ + [[1, 0, 0], [0, 1, 0], [0, 0, 1]], + [[0, 1, 0], [0, 0, 1], [1, 0, 0]], + [[0, 0, 1], [1, 0, 0], [0, 1, 0]], + ] + ), + "image": p([[[132, 1434, 51], [61, 0, 133], [523, 44, 232]]]), + }, + [p([0, 8]), p([1, 5, 6]), p([3])], + ] + ) -TEST_CASE_5 = [ - # test output_shape - {"keys": "label", "indices_postfix": "cls", "num_classes": 3, "image_threshold": 0.0, "output_shape": [3, 3]}, - {"label": np.array([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])}, - [np.array([[0, 0], [1, 1], [2, 2]]), np.array([[0, 1], [1, 2], [2, 0]]), np.array([[0, 2], [1, 0], [2, 1]])], -] + TESTS_CASES.append( + [ + # test output_shape + { + "keys": "label", + "indices_postfix": "cls", + "num_classes": 3, + "image_threshold": 0.0, + "output_shape": [3, 3], + }, + {"label": p([[[0, 1, 2], [2, 0, 1], [1, 2, 0]]])}, + [p([[0, 0], [1, 1], [2, 2]]), p([[0, 1], [1, 2], [2, 0]]), p([[0, 2], [1, 0], [2, 1]])], + ] + ) class TestClassesToIndicesd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5]) + @parameterized.expand(TESTS_CASES) def test_value(self, input_args, input_data, expected_indices): result = ClassesToIndicesd(**input_args)(input_data) key_postfix = input_args.get("indices_postfix") key_postfix = "_cls_indices" if key_postfix is None else key_postfix for i, e in zip(result["label" + key_postfix], expected_indices): - np.testing.assert_allclose(i, e) + assert_allclose(i, e) if __name__ == "__main__": From 15c1f779c6fad1412b42e329d2509ec1c653c016 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Mon, 4 Oct 2021 09:52:56 +0800 Subject: [PATCH 69/89] [DLMED] enhance ScaleIntensity (#3062) Signed-off-by: Nic Ma --- monai/transforms/intensity/array.py | 16 ++++++++++++---- monai/transforms/intensity/dictionary.py | 5 ++++- tests/test_scale_intensity.py | 12 ++++++++++++ tests/test_scale_intensityd.py | 13 +++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 2dc1ed1a94..4029c9b78e 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -386,6 +386,7 @@ def __init__( minv: Optional[float] = 0.0, maxv: Optional[float] = 1.0, factor: Optional[float] = None, + channel_wise: bool = False, dtype: DtypeLike = np.float32, ) -> None: """ @@ -394,11 +395,14 @@ def __init__( maxv: maximum value of output data. factor: factor scale by ``v = v * (1 + factor)``. In order to use this parameter, please set `minv` and `maxv` into None. + channel_wise: if True, scale on each channel separately. Please ensure + that the first dimension represents the channel of the image if True. dtype: output data type, defaults to float32. """ self.minv = minv self.maxv = maxv self.factor = factor + self.channel_wise = channel_wise self.dtype = dtype def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: @@ -410,11 +414,15 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ if self.minv is not None and self.maxv is not None: - return rescale_array(img, self.minv, self.maxv, dtype=self.dtype) + if self.channel_wise: + out = [rescale_array(d, self.minv, self.maxv, dtype=self.dtype) for d in img] + return torch.stack(out) if isinstance(img, torch.Tensor) else np.stack(out) # type: ignore + else: + return rescale_array(img, self.minv, self.maxv, dtype=self.dtype) if self.factor is not None: - out = img * (1 + self.factor) - out, *_ = convert_data_type(out, dtype=self.dtype) - return out + ret = img * (1 + self.factor) + ret, *_ = convert_data_type(ret, dtype=self.dtype) + return ret raise ValueError("Incompatible values: minv=None or maxv=None and factor=None.") diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index a99bd59473..d921aaeb36 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -490,6 +490,7 @@ def __init__( minv: Optional[float] = 0.0, maxv: Optional[float] = 1.0, factor: Optional[float] = None, + channel_wise: bool = False, dtype: DtypeLike = np.float32, allow_missing_keys: bool = False, ) -> None: @@ -501,12 +502,14 @@ def __init__( maxv: maximum value of output data. factor: factor scale by ``v = v * (1 + factor)``. In order to use this parameter, please set `minv` and `maxv` into None. + channel_wise: if True, scale on each channel separately. Please ensure + that the first dimension represents the channel of the image if True. dtype: output data type, defaults to float32. allow_missing_keys: don't raise exception if key is missing. """ super().__init__(keys, allow_missing_keys) - self.scaler = ScaleIntensity(minv, maxv, factor, dtype) + self.scaler = ScaleIntensity(minv, maxv, factor, channel_wise, dtype) def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) diff --git a/tests/test_scale_intensity.py b/tests/test_scale_intensity.py index 24c6900ba5..ddc2fb08e1 100644 --- a/tests/test_scale_intensity.py +++ b/tests/test_scale_intensity.py @@ -35,6 +35,18 @@ def test_factor_scale(self): expected = p((self.imt * (1 + 0.1)).astype(np.float32)) assert_allclose(result, p(expected), rtol=1e-7, atol=0) + def test_channel_wise(self): + for p in TEST_NDARRAYS: + scaler = ScaleIntensity(minv=1.0, maxv=2.0, channel_wise=True) + data = p(self.imt) + result = scaler(data) + mina = self.imt.min() + maxa = self.imt.max() + for i, c in enumerate(data): + norm = (c - mina) / (maxa - mina) + expected = p((norm * (2.0 - 1.0)) + 1.0) + assert_allclose(result[i], expected, type_test=False, rtol=1e-7, atol=0) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_scale_intensityd.py b/tests/test_scale_intensityd.py index ce298f20af..93449b15e2 100644 --- a/tests/test_scale_intensityd.py +++ b/tests/test_scale_intensityd.py @@ -37,6 +37,19 @@ def test_factor_scale(self): expected = (self.imt * (1 + 0.1)).astype(np.float32) assert_allclose(result[key], p(expected)) + def test_channel_wise(self): + key = "img" + for p in TEST_NDARRAYS: + scaler = ScaleIntensityd(keys=[key], minv=1.0, maxv=2.0, channel_wise=True) + data = p(self.imt) + result = scaler({key: data}) + mina = self.imt.min() + maxa = self.imt.max() + for i, c in enumerate(data): + norm = (c - mina) / (maxa - mina) + expected = p((norm * (2.0 - 1.0)) + 1.0) + assert_allclose(result[key][i], expected, type_test=False, rtol=1e-7, atol=0) + if __name__ == "__main__": unittest.main() From a0aac6a0ce7642718daee9d8a5c86c0c1c2c2d14 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Mon, 4 Oct 2021 08:04:58 +0100 Subject: [PATCH 70/89] Extra transform examples (#3056) * create images Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * use brats Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * update Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * working Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * rename file Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * optional import matplotlib Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * docstrings Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * store images in https://github.com/Project-MONAI/DocImages Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * extra transform example images Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * most transforms Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> --- docs/source/transforms.rst | 236 ++++++++ monai/transforms/intensity/array.py | 2 +- monai/transforms/spatial/array.py | 17 +- monai/transforms/utils.py | 2 +- .../transforms/utils_create_transform_ims.py | 531 ++++++++++++++++-- 5 files changed, 726 insertions(+), 62 deletions(-) diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index b94121cbe2..5300ea758e 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -67,72 +67,96 @@ Crop and Pad `SpatialPad` """""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/SpatialPad.png + :alt: example of SpatialPad .. autoclass:: SpatialPad :members: :special-members: __call__ `BorderPad` """"""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/BorderPad.png + :alt: example of BorderPad .. autoclass:: BorderPad :members: :special-members: __call__ `DivisiblePad` """""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/DivisiblePad.png + :alt: example of DivisiblePad .. autoclass:: DivisiblePad :members: :special-members: __call__ `SpatialCrop` """"""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/SpatialCrop.png + :alt: example of SpatialCrop .. autoclass:: SpatialCrop :members: :special-members: __call__ `CenterSpatialCrop` """"""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/CenterSpatialCrop.png + :alt: example of CenterSpatialCrop .. autoclass:: CenterSpatialCrop :members: :special-members: __call__ `RandSpatialCrop` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandSpatialCrop.png + :alt: example of RandSpatialCrop .. autoclass:: RandSpatialCrop :members: :special-members: __call__ `RandSpatialCropSamples` """""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandSpatialCropSamples.png + :alt: example of RandSpatialCropSamples .. autoclass:: RandSpatialCropSamples :members: :special-members: __call__ `CropForeground` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/CropForeground.png + :alt: example of CropForeground .. autoclass:: CropForeground :members: :special-members: __call__ `RandWeightedCrop` """""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandWeightedCrop.png + :alt: example of RandWeightedCrop .. autoclass:: RandWeightedCrop :members: :special-members: __call__ `RandCropByPosNegLabel` """"""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCropByPosNegLabel.png + :alt: example of RandCropByPosNegLabel .. autoclass:: RandCropByPosNegLabel :members: :special-members: __call__ `RandCropByLabelClasses` """""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCropByLabelClasses.png + :alt: example of RandCropByLabelClasses .. autoclass:: RandCropByLabelClasses :members: :special-members: __call__ `ResizeWithPadOrCrop` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ResizeWithPadOrCrop.png + :alt: example of ResizeWithPadOrCrop .. autoclass:: ResizeWithPadOrCrop :members: :special-members: __call__ @@ -145,12 +169,16 @@ Crop and Pad `RandScaleCrop` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandScaleCrop.png + :alt: example of RandScaleCrop .. autoclass:: RandScaleCrop :members: :special-members: __call__ `CenterScaleCrop` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/CenterScaleCrop.png + :alt: example of CenterScaleCrop .. autoclass:: CenterScaleCrop :members: :special-members: __call__ @@ -160,90 +188,120 @@ Intensity `RandGaussianNoise` """"""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGaussianNoise.png + :alt: example of RandGaussianNoise .. autoclass:: RandGaussianNoise :members: :special-members: __call__ `ShiftIntensity` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ShiftIntensity.png + :alt: example of ShiftIntensity .. autoclass:: ShiftIntensity :members: :special-members: __call__ `RandShiftIntensity` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandShiftIntensity.png + :alt: example of RandShiftIntensity .. autoclass:: RandShiftIntensity :members: :special-members: __call__ `StdShiftIntensity` """"""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/StdShiftIntensity.png + :alt: example of StdShiftIntensity .. autoclass:: StdShiftIntensity :members: :special-members: __call__ `RandStdShiftIntensity` """"""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandStdShiftIntensity.png + :alt: example of RandStdShiftIntensity .. autoclass:: RandStdShiftIntensity :members: :special-members: __call__ `RandBiasField` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandBiasField.png + :alt: example of RandBiasField .. autoclass:: RandBiasField :members: :special-members: __call__ `ScaleIntensity` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ScaleIntensity.png + :alt: example of ScaleIntensity .. autoclass:: ScaleIntensity :members: :special-members: __call__ `RandScaleIntensity` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandScaleIntensity.png + :alt: example of RandScaleIntensity .. autoclass:: RandScaleIntensity :members: :special-members: __call__ `NormalizeIntensity` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/NormalizeIntensity.png + :alt: example of NormalizeIntensity .. autoclass:: NormalizeIntensity :members: :special-members: __call__ `ThresholdIntensity` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ThresholdIntensity.png + :alt: example of ThresholdIntensity .. autoclass:: ThresholdIntensity :members: :special-members: __call__ `ScaleIntensityRange` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ScaleIntensityRange.png + :alt: example of ScaleIntensityRange .. autoclass:: ScaleIntensityRange :members: :special-members: __call__ `ScaleIntensityRangePercentiles` """""""""""""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ScaleIntensityRangePercentiles.png + :alt: example of ScaleIntensityRangePercentiles .. autoclass:: ScaleIntensityRangePercentiles :members: :special-members: __call__ `AdjustContrast` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/AdjustContrast.png + :alt: example of AdjustContrast .. autoclass:: AdjustContrast :members: :special-members: __call__ `RandAdjustContrast` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandAdjustContrast.png + :alt: example of RandAdjustContrast .. autoclass:: RandAdjustContrast :members: :special-members: __call__ `MaskIntensity` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/MaskIntensity.png + :alt: example of MaskIntensity .. autoclass:: MaskIntensity :members: :special-members: __call__ @@ -256,30 +314,40 @@ Intensity `GaussianSmooth` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/GaussianSmooth.png + :alt: example of GaussianSmooth .. autoclass:: GaussianSmooth :members: :special-members: __call__ `RandGaussianSmooth` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGaussianSmooth.png + :alt: example of RandGaussianSmooth .. autoclass:: RandGaussianSmooth :members: :special-members: __call__ `GaussianSharpen` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/GaussianSharpen.png + :alt: example of GaussianSharpen .. autoclass:: GaussianSharpen :members: :special-members: __call__ `RandGaussianSharpen` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGaussianSharpen.png + :alt: example of RandGaussianSharpen .. autoclass:: RandGaussianSharpen :members: :special-members: __call__ `RandHistogramShift` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandHistogramShift.png + :alt: example of RandHistogramShift .. autoclass:: RandHistogramShift :members: :special-members: __call__ @@ -292,24 +360,32 @@ Intensity `GibbsNoise` """""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/GibbsNoise.png + :alt: example of GibbsNoise .. autoclass:: GibbsNoise :members: :special-members: __call__ `RandGibbsNoise` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGibbsNoise.png + :alt: example of RandGibbsNoise .. autoclass:: RandGibbsNoise :members: :special-members: __call__ `KSpaceSpikeNoise` """""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/KSpaceSpikeNoise.png + :alt: example of KSpaceSpikeNoise .. autoclass:: KSpaceSpikeNoise :members: :special-members: __call__ `RandKSpaceSpikeNoise` """""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandKSpaceSpikeNoise.png + :alt: example of RandKSpaceSpikeNoise .. autoclass:: RandKSpaceSpikeNoise :members: :special-members: __call__ @@ -322,18 +398,24 @@ Intensity `RandCoarseDropout` """"""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCoarseDropout.png + :alt: example of RandCoarseDropout .. autoclass:: RandCoarseDropout :members: :special-members: __call__ `RandCoarseShuffle` """"""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCoarseShuffle.png + :alt: example of RandCoarseShuffle .. autoclass:: RandCoarseShuffle :members: :special-members: __call__ `HistogramNormalize` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/HistogramNormalize.png + :alt: example of HistogramNormalize .. autoclass:: HistogramNormalize :members: :special-members: __call__ @@ -393,6 +475,8 @@ Post-processing `AsDiscrete` """""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/AsDiscrete.png + :alt: example of AsDiscrete .. autoclass:: AsDiscrete :members: :special-members: __call__ @@ -405,6 +489,8 @@ Post-processing `LabelFilter` """"""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/LabelFilter.png + :alt: example of LabelFilter .. autoclass:: LabelFilter :members: :special-members: __call__ @@ -417,6 +503,8 @@ Post-processing `LabelToContour` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/LabelToContour.png + :alt: example of LabelToContour .. autoclass:: LabelToContour :members: :special-members: __call__ @@ -443,18 +531,24 @@ Spatial `Spacing` """"""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Spacing.png + :alt: example of Spacing .. autoclass:: Spacing :members: :special-members: __call__ `Orientation` """"""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Orientation.png + :alt: example of Orientation .. autoclass:: Orientation :members: :special-members: __call__ `RandRotate` """""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandRotate.png + :alt: example of RandRotate .. autoclass:: RandRotate :members: :special-members: __call__ @@ -469,18 +563,24 @@ Spatial `RandAxisFlip` """""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandAxisFlip.png + :alt: example of RandAxisFlip .. autoclass:: RandAxisFlip :members: :special-members: __call__ `RandZoom` """""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandZoom.png + :alt: example of RandZoom .. autoclass:: RandZoom :members: :special-members: __call__ `Affine` """""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Affine.png + :alt: example of Affine .. autoclass:: Affine :members: :special-members: __call__ @@ -493,6 +593,8 @@ Spatial `RandAffine` """""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandAffine.png + :alt: example of RandAffine .. autoclass:: RandAffine :members: :special-members: __call__ @@ -517,48 +619,64 @@ Spatial `Rand2DElastic` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rand2DElastic.png + :alt: example of Rand2DElastic .. autoclass:: Rand2DElastic :members: :special-members: __call__ `Rand3DElastic` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rand3DElastic.png + :alt: example of Rand3DElastic .. autoclass:: Rand3DElastic :members: :special-members: __call__ `Rotate90` """""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rotate90.png + :alt: example of Rotate90 .. autoclass:: Rotate90 :members: :special-members: __call__ `RandRotate90` """""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandRotate90.png + :alt: example of RandRotate90 .. autoclass:: RandRotate90 :members: :special-members: __call__ `Flip` """""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Flip.png + :alt: example of Flip .. autoclass:: Flip :members: :special-members: __call__ `Resize` """""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Resize.png + :alt: example of Resize .. autoclass:: Resize :members: :special-members: __call__ `Rotate` """""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rotate.png + :alt: example of Rotate .. autoclass:: Rotate :members: :special-members: __call__ `Zoom` """""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Zoom.png + :alt: example of Zoom .. autoclass:: Zoom :members: :special-members: __call__ @@ -756,72 +874,96 @@ Crop and Pad (Dict) `SpatialPadd` """"""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/SpatialPadd.png + :alt: example of SpatialPadd .. autoclass:: SpatialPadd :members: :special-members: __call__ `BorderPadd` """""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/BorderPadd.png + :alt: example of BorderPadd .. autoclass:: BorderPadd :members: :special-members: __call__ `DivisiblePadd` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/DivisiblePadd.png + :alt: example of DivisiblePadd .. autoclass:: DivisiblePadd :members: :special-members: __call__ `SpatialCropd` """""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/SpatialCropd.png + :alt: example of SpatialCropd .. autoclass:: SpatialCropd :members: :special-members: __call__ `CenterSpatialCropd` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/CenterSpatialCropd.png + :alt: example of CenterSpatialCropd .. autoclass:: CenterSpatialCropd :members: :special-members: __call__ `RandSpatialCropd` """""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandSpatialCropd.png + :alt: example of RandSpatialCropd .. autoclass:: RandSpatialCropd :members: :special-members: __call__ `RandSpatialCropSamplesd` """"""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandSpatialCropSamplesd.png + :alt: example of RandSpatialCropSamplesd .. autoclass:: RandSpatialCropSamplesd :members: :special-members: __call__ `CropForegroundd` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/CropForegroundd.png + :alt: example of CropForegroundd .. autoclass:: CropForegroundd :members: :special-members: __call__ `RandWeightedCropd` """"""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandWeightedCropd.png + :alt: example of RandWeightedCropd .. autoclass:: RandWeightedCropd :members: :special-members: __call__ `RandCropByPosNegLabeld` """""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCropByPosNegLabeld.png + :alt: example of RandCropByPosNegLabeld .. autoclass:: RandCropByPosNegLabeld :members: :special-members: __call__ `RandCropByLabelClassesd` """"""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCropByLabelClassesd.png + :alt: example of RandCropByLabelClassesd .. autoclass:: RandCropByLabelClassesd :members: :special-members: __call__ `ResizeWithPadOrCropd` """""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ResizeWithPadOrCropd.png + :alt: example of ResizeWithPadOrCropd .. autoclass:: ResizeWithPadOrCropd :members: :special-members: __call__ @@ -834,12 +976,16 @@ Crop and Pad (Dict) `RandScaleCropd` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandScaleCropd.png + :alt: example of RandScaleCropd .. autoclass:: RandScaleCropd :members: :special-members: __call__ `CenterScaleCropd` """""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/CenterScaleCropd.png + :alt: example of CenterScaleCropd .. autoclass:: CenterScaleCropd :members: :special-members: __call__ @@ -849,162 +995,216 @@ Intensity (Dict) `RandGaussianNoised` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGaussianNoised.png + :alt: example of RandGaussianNoised .. autoclass:: RandGaussianNoised :members: :special-members: __call__ `ShiftIntensityd` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ShiftIntensityd.png + :alt: example of ShiftIntensityd .. autoclass:: ShiftIntensityd :members: :special-members: __call__ `RandShiftIntensityd` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandShiftIntensityd.png + :alt: example of RandShiftIntensityd .. autoclass:: RandShiftIntensityd :members: :special-members: __call__ `StdShiftIntensityd` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/StdShiftIntensityd.png + :alt: example of StdShiftIntensityd .. autoclass:: StdShiftIntensityd :members: :special-members: __call__ `RandStdShiftIntensityd` """""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandStdShiftIntensityd.png + :alt: example of RandStdShiftIntensityd .. autoclass:: RandStdShiftIntensityd :members: :special-members: __call__ `RandBiasFieldd` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandBiasFieldd.png + :alt: example of RandBiasFieldd .. autoclass:: RandBiasFieldd :members: :special-members: __call__ `ScaleIntensityd` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ScaleIntensityd.png + :alt: example of ScaleIntensityd .. autoclass:: ScaleIntensityd :members: :special-members: __call__ `RandScaleIntensityd` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandScaleIntensityd.png + :alt: example of RandScaleIntensityd .. autoclass:: RandScaleIntensityd :members: :special-members: __call__ `NormalizeIntensityd` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/NormalizeIntensityd.png + :alt: example of NormalizeIntensityd .. autoclass:: NormalizeIntensityd :members: :special-members: __call__ `ThresholdIntensityd` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ThresholdIntensityd.png + :alt: example of ThresholdIntensityd .. autoclass:: ThresholdIntensityd :members: :special-members: __call__ `ScaleIntensityRanged` """""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ScaleIntensityRanged.png + :alt: example of ScaleIntensityRanged .. autoclass:: ScaleIntensityRanged :members: :special-members: __call__ `GibbsNoised` """""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/GibbsNoised.png + :alt: example of GibbsNoised .. autoclass:: GibbsNoised :members: :special-members: __call__ `RandGibbsNoised` """""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGibbsNoised.png + :alt: example of RandGibbsNoised .. autoclass:: RandGibbsNoised :members: :special-members: __call__ `KSpaceSpikeNoised` """""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/KSpaceSpikeNoised.png + :alt: example of KSpaceSpikeNoised .. autoclass:: KSpaceSpikeNoised :members: :special-members: __call__ `RandKSpaceSpikeNoised` """"""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandKSpaceSpikeNoised.png + :alt: example of RandKSpaceSpikeNoised .. autoclass:: RandKSpaceSpikeNoised :members: :special-members: __call__ `ScaleIntensityRangePercentilesd` """"""""""""""""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/ScaleIntensityRangePercentilesd.png + :alt: example of ScaleIntensityRangePercentilesd .. autoclass:: ScaleIntensityRangePercentilesd :members: :special-members: __call__ `AdjustContrastd` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/AdjustContrastd.png + :alt: example of AdjustContrastd .. autoclass:: AdjustContrastd :members: :special-members: __call__ `RandAdjustContrastd` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandAdjustContrastd.png + :alt: example of RandAdjustContrastd .. autoclass:: RandAdjustContrastd :members: :special-members: __call__ `MaskIntensityd` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/MaskIntensityd.png + :alt: example of MaskIntensityd .. autoclass:: MaskIntensityd :members: :special-members: __call__ `GaussianSmoothd` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/GaussianSmoothd.png + :alt: example of GaussianSmoothd .. autoclass:: GaussianSmoothd :members: :special-members: __call__ `RandGaussianSmoothd` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGaussianSmoothd.png + :alt: example of RandGaussianSmoothd .. autoclass:: RandGaussianSmoothd :members: :special-members: __call__ `GaussianSharpend` """""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/GaussianSharpend.png + :alt: example of GaussianSharpend .. autoclass:: GaussianSharpend :members: :special-members: __call__ `RandGaussianSharpend` """""""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandGaussianSharpend.png + :alt: example of RandGaussianSharpend .. autoclass:: RandGaussianSharpend :members: :special-members: __call__ `RandHistogramShiftd` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandHistogramShiftd.png + :alt: example of RandHistogramShiftd .. autoclass:: RandHistogramShiftd :members: :special-members: __call__ `RandCoarseDropoutd` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCoarseDropoutd.png + :alt: example of RandCoarseDropoutd .. autoclass:: RandCoarseDropoutd :members: :special-members: __call__ `RandCoarseShuffled` """""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCoarseShuffled.png + :alt: example of RandCoarseShuffled .. autoclass:: RandCoarseShuffled :members: :special-members: __call__ `HistogramNormalized` """"""""""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/HistogramNormalized.png + :alt: example of HistogramNormalized .. autoclass:: HistogramNormalized :members: :special-members: __call__ @@ -1036,6 +1236,8 @@ Post-processing (Dict) `AsDiscreted` """"""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/AsDiscreted.png + :alt: example of AsDiscreted .. autoclass:: AsDiscreted :members: :special-members: __call__ @@ -1048,6 +1250,8 @@ Post-processing (Dict) `LabelFilterd` """""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/LabelFilterd.png + :alt: example of LabelFilterd .. autoclass:: LabelFilterd :members: :special-members: __call__ @@ -1060,6 +1264,8 @@ Post-processing (Dict) `LabelToContourd` """"""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/LabelToContourd.png + :alt: example of LabelToContourd .. autoclass:: LabelToContourd :members: :special-members: __call__ @@ -1099,18 +1305,24 @@ Spatial (Dict) `Spacingd` """""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Spacingd.png + :alt: example of Spacingd .. autoclass:: Spacingd :members: :special-members: __call__ `Orientationd` """""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Orientationd.png + :alt: example of Orientationd .. autoclass:: Orientationd :members: :special-members: __call__ `Flipd` """"""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Flipd.png + :alt: example of Flipd .. autoclass:: Flipd :members: :special-members: __call__ @@ -1125,72 +1337,96 @@ Spatial (Dict) `RandAxisFlipd` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandAxisFlipd.png + :alt: example of RandAxisFlipd .. autoclass:: RandAxisFlipd :members: :special-members: __call__ `Rotated` """"""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rotated.png + :alt: example of Rotated .. autoclass:: Rotated :members: :special-members: __call__ `RandRotated` """"""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandRotated.png + :alt: example of RandRotated .. autoclass:: RandRotated :members: :special-members: __call__ `Zoomd` """"""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Zoomd.png + :alt: example of Zoomd .. autoclass:: Zoomd :members: :special-members: __call__ `RandZoomd` """"""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandZoomd.png + :alt: example of RandZoomd .. autoclass:: RandZoomd :members: :special-members: __call__ `RandRotate90d` """"""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandRotate90d.png + :alt: example of RandRotate90d .. autoclass:: RandRotate90d :members: :special-members: __call__ `Rotate90d` """"""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rotate90d.png + :alt: example of Rotate90d .. autoclass:: Rotate90d :members: :special-members: __call__ `Resized` """"""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Resized.png + :alt: example of Resized .. autoclass:: Resized :members: :special-members: __call__ `Affined` """"""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Affined.png + :alt: example of Affined .. autoclass:: Affined :members: :special-members: __call__ `RandAffined` """"""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandAffined.png + :alt: example of RandAffined .. autoclass:: RandAffined :members: :special-members: __call__ `Rand2DElasticd` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rand2DElasticd.png + :alt: example of Rand2DElasticd .. autoclass:: Rand2DElasticd :members: :special-members: __call__ `Rand3DElasticd` """""""""""""""" +.. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/Rand3DElasticd.png + :alt: example of Rand3DElasticd .. autoclass:: Rand3DElasticd :members: :special-members: __call__ diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 4029c9b78e..7a554cbf69 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1374,7 +1374,7 @@ class RandGibbsNoise(RandomizableTransform): Args: prob (float): probability of applying the transform. - alpha (float, Sequence(float)): Parametrizes the intensity of the Gibbs noise filter applied. Takes + alpha (Sequence(float)): Parametrizes the intensity of the Gibbs noise filter applied. Takes values in the interval [0,1] with alpha = 0 acting as the identity mapping. If a length-2 list is given as [a,b] then the value of alpha will be sampled uniformly from the interval [a,b]. 0 <= a <= b <= 1. diff --git a/monai/transforms/spatial/array.py b/monai/transforms/spatial/array.py index 27d25cf2bc..9ccd315354 100644 --- a/monai/transforms/spatial/array.py +++ b/monai/transforms/spatial/array.py @@ -95,6 +95,7 @@ def __init__( padding_mode: Union[GridSamplePadMode, str] = GridSamplePadMode.BORDER, align_corners: bool = False, dtype: DtypeLike = np.float64, + image_only: bool = False, ) -> None: """ Args: @@ -127,6 +128,7 @@ def __init__( dtype: data type for resampling computation. Defaults to ``np.float64`` for best precision. If None, use the data type of input data. To be compatible with other modules, the output data type is always ``np.float32``. + image_only: return just the image or the image, the old affine and new affine. Default is `False`. """ self.pixdim = np.array(ensure_tuple(pixdim), dtype=np.float64) @@ -135,6 +137,7 @@ def __init__( self.padding_mode: GridSamplePadMode = look_up_option(padding_mode, GridSamplePadMode) self.align_corners = align_corners self.dtype = dtype + self.image_only = image_only def __call__( self, @@ -145,7 +148,7 @@ def __call__( align_corners: Optional[bool] = None, dtype: DtypeLike = None, output_spatial_shape: Optional[np.ndarray] = None, - ) -> Tuple[NdarrayOrTensor, NdarrayOrTensor, NdarrayOrTensor]: + ) -> Union[NdarrayOrTensor, Tuple[NdarrayOrTensor, NdarrayOrTensor, NdarrayOrTensor]]: """ Args: data_array: in shape (num_channels, H[, W, ...]). @@ -221,6 +224,8 @@ def __call__( output_data, *_ = convert_to_dst_type(output_data, data_array, dtype=torch.float32) new_affine = to_affine_nd(affine, new_affine) # type: ignore + if self.image_only: + return output_data return output_data, affine, new_affine @@ -234,6 +239,7 @@ def __init__( axcodes: Optional[str] = None, as_closest_canonical: bool = False, labels: Optional[Sequence[Tuple[str, str]]] = tuple(zip("LPI", "RAS")), + image_only: bool = False, ) -> None: """ Args: @@ -246,6 +252,7 @@ def __init__( labels: optional, None or sequence of (2,) sequences (2,) sequences are labels for (beginning, end) of output axis. Defaults to ``(('L', 'R'), ('P', 'A'), ('I', 'S'))``. + image_only: if True return only the image volume, otherwise return (image, affine, new_affine). Raises: ValueError: When ``axcodes=None`` and ``as_closest_canonical=True``. Incompatible values. @@ -260,10 +267,11 @@ def __init__( self.axcodes = axcodes self.as_closest_canonical = as_closest_canonical self.labels = labels + self.image_only = image_only def __call__( self, data_array: np.ndarray, affine: Optional[np.ndarray] = None - ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray, np.ndarray]]: """ original orientation of `data_array` is defined by `affine`. @@ -276,7 +284,8 @@ def __call__( ValueError: When ``axcodes`` spatiality differs from ``data_array``. Returns: - data_array (reoriented in `self.axcodes`), original axcodes, current axcodes. + data_array [reoriented in `self.axcodes`] if `self.image_only`, else + (data_array [reoriented in `self.axcodes`], original axcodes, current axcodes). """ data_array, *_ = convert_data_type(data_array, np.ndarray) # type: ignore @@ -308,6 +317,8 @@ def __call__( new_affine = affine_ @ nib.orientations.inv_ornt_aff(spatial_ornt, shape) new_affine = to_affine_nd(affine, new_affine) + if self.image_only: + return data_array return data_array, affine, new_affine diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 3682a74e8f..690b2d095d 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -513,7 +513,7 @@ def generate_label_classes_crop_centers( raise ValueError("num_samples must be an int number and greater than 0.") ratios_: List[Union[float, int]] = ([1] * len(indices)) if ratios is None else ratios if len(ratios_) != len(indices): - raise ValueError("random crop radios must match the number of indices of classes.") + raise ValueError("random crop ratios must match the number of indices of classes.") if any(i < 0 for i in ratios_): raise ValueError("ratios should not contain negative number.") diff --git a/monai/transforms/utils_create_transform_ims.py b/monai/transforms/utils_create_transform_ims.py index 8eb0c6b945..daf93f8226 100644 --- a/monai/transforms/utils_create_transform_ims.py +++ b/monai/transforms/utils_create_transform_ims.py @@ -12,24 +12,143 @@ import os import pathlib import tempfile +import textwrap from copy import deepcopy from glob import glob -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Callable import numpy as np +import torch from monai.apps import download_and_extract from monai.transforms import ( AddChanneld, + Affine, + Affined, + AsDiscrete, Compose, + Flip, + Flipd, LoadImaged, MapTransform, + Orientation, + Orientationd, + Rand3DElastic, + Rand3DElasticd, RandFlip, RandFlipd, Randomizable, + RandRotate, + RandRotated, + RandZoom, + RandZoomd, + Rotate, + Rotate90, Rotate90d, + Rotated, + ScaleIntensity, ScaleIntensityd, SpatialPadd, + Zoom, + Zoomd, +) +from monai.transforms.croppad.array import ( + BorderPad, + CenterScaleCrop, + CenterSpatialCrop, + CropForeground, + DivisiblePad, + RandCropByLabelClasses, + RandCropByPosNegLabel, + RandScaleCrop, + RandSpatialCrop, + RandSpatialCropSamples, + RandWeightedCrop, + ResizeWithPadOrCrop, + SpatialCrop, + SpatialPad, +) +from monai.transforms.croppad.dictionary import ( + BorderPadd, + CenterScaleCropd, + CenterSpatialCropd, + CropForegroundd, + DivisiblePadd, + RandCropByLabelClassesd, + RandCropByPosNegLabeld, + RandScaleCropd, + RandSpatialCropd, + RandSpatialCropSamplesd, + RandWeightedCropd, + ResizeWithPadOrCropd, + SpatialCropd, +) +from monai.transforms.intensity.array import ( + AdjustContrast, + GaussianSharpen, + GaussianSmooth, + GibbsNoise, + HistogramNormalize, + KSpaceSpikeNoise, + MaskIntensity, + NormalizeIntensity, + RandAdjustContrast, + RandBiasField, + RandCoarseDropout, + RandCoarseShuffle, + RandGaussianNoise, + RandGaussianSharpen, + RandGaussianSmooth, + RandGibbsNoise, + RandHistogramShift, + RandKSpaceSpikeNoise, + RandScaleIntensity, + RandShiftIntensity, + RandStdShiftIntensity, + ScaleIntensityRange, + ScaleIntensityRangePercentiles, + ShiftIntensity, + StdShiftIntensity, + ThresholdIntensity, +) +from monai.transforms.intensity.dictionary import ( + AdjustContrastd, + GaussianSharpend, + GaussianSmoothd, + GibbsNoised, + HistogramNormalized, + KSpaceSpikeNoised, + MaskIntensityd, + NormalizeIntensityd, + RandAdjustContrastd, + RandBiasFieldd, + RandCoarseDropoutd, + RandCoarseShuffled, + RandGaussianNoised, + RandGaussianSharpend, + RandGaussianSmoothd, + RandGibbsNoised, + RandHistogramShiftd, + RandKSpaceSpikeNoised, + RandScaleIntensityd, + RandShiftIntensityd, + RandStdShiftIntensityd, + ScaleIntensityRanged, + ScaleIntensityRangePercentilesd, + ShiftIntensityd, + StdShiftIntensityd, + ThresholdIntensityd, +) +from monai.transforms.post.array import LabelFilter, LabelToContour +from monai.transforms.post.dictionary import AsDiscreted, LabelFilterd, LabelToContourd +from monai.transforms.spatial.array import Rand2DElastic, RandAffine, RandAxisFlip, RandRotate90, Resize, Spacing +from monai.transforms.spatial.dictionary import ( + Rand2DElasticd, + RandAffined, + RandAxisFlipd, + RandRotate90d, + Resized, + Spacingd, ) from monai.utils.enums import CommonKeys from monai.utils.module import optional_import @@ -43,10 +162,7 @@ plt, has_matplotlib = optional_import("matplotlib.pyplot") -KEYS = [CommonKeys.IMAGE, CommonKeys.LABEL] - - -def get_data(): +def get_data(keys): """Get the example data to be used. Use MarsAtlas as it only contains 1 image for quick download and @@ -66,17 +182,16 @@ def get_data(): transforms = Compose( [ - LoadImaged(KEYS), - AddChanneld(KEYS), + LoadImaged(keys), + AddChanneld(keys), ScaleIntensityd(CommonKeys.IMAGE), - Rotate90d(KEYS, spatial_axes=[0, 2]), + Rotate90d(keys, spatial_axes=[0, 2]), ] ) data = transforms(data) - im = data[CommonKeys.IMAGE] - max_size = max(im.shape) - data = SpatialPadd(KEYS, (max_size, max_size, max_size))(data) - return {k: data[k] for k in KEYS} + max_size = max(data[keys[0]].shape) + padder = SpatialPadd(keys, (max_size, max_size, max_size)) + return padder(data) def update_docstring(code_path, transform_name): @@ -116,70 +231,146 @@ def update_docstring(code_path, transform_name): f.writelines(contents) -def pre_process_data(data, ndim, is_map): +def pre_process_data(data, ndim, is_map, is_post): """If transform requires 2D data, then convert to 2D""" if ndim == 2: - for k in KEYS: + for k in keys: data[k] = data[k][..., data[k].shape[-1] // 2] + if is_post: + for k in keys: + data[k] = torch.as_tensor(data[k]) - return data if is_map else data[CommonKeys.IMAGE] - - -def get_2d_slice(image, view): - """Get the central slice of a 3D volume""" - shape = image.shape - slices = [slice(0, s) for s in shape] - _slice = shape[view] // 2 - slices[view] = slice(_slice, _slice + 1) - slices = tuple(slices) - return np.squeeze(image[slices], view) + if is_map: + return data + return data[CommonKeys.LABEL] if is_post else data[CommonKeys.IMAGE] -def get_stacked_2d_ims(im): +def get_2d_slice(image, view, is_label): + """Remove channel and get the central slice of a 3D volume. If is already 2d, only remove channel. + If image is label, set 0 to np.nan. + """ + image = image[0] # remove channel + if image.ndim == 2: + out = image + else: + shape = image.shape + slices = [slice(0, s) for s in shape] + _slice = shape[view] // 2 + slices[view] = slice(_slice, _slice + 1) + slices = tuple(slices) + out = np.squeeze(image[slices], view) + if is_label: + out[out == 0] = np.nan + return out + + +def get_stacked_2d_ims(im, is_label): """Get the 3 orthogonal views and stack them into 1 image. Requires that all images be same size, but this is taken care of by the `SpatialPadd` earlier. """ - return np.hstack([get_2d_slice(im, view) for view in range(3)]) + out = [get_2d_slice(im, i, is_label) for i in range(3)] + return out -def get_stacked_before_after(before, after): - """Stack before and after images into 1 image. +def get_stacked_before_after(before, after, is_label=False): + """Stack before and after images into 1 image if 3d. Requires that before and after images be the same size. """ - return np.vstack([get_stacked_2d_ims(d[0]) for d in (before, after)]) + return [get_stacked_2d_ims(d, is_label) for d in (before, after)] -def save_image(images, labels, filename): +def save_image(images, labels, filename, transform_name, transform_args, im_sizes, colorbar=False): """Save image to file, ensuring there's no whitespace around the edge.""" - sizes = images.shape - fig = plt.figure() - fig.set_size_inches(1.0 * sizes[1] / sizes[0], 1, forward=False) - ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0]) - ax.set_axis_off() - fig.add_axes(ax) - ax.imshow(images, cmap="gray") - if labels is not None: - ax.imshow(labels, cmap="hsv", alpha=0.9) - fig.savefig(filename, dpi=images.shape[0]) + plt.rcParams.update({"font.family": "monospace"}) + plt.style.use("dark_background") + fig, axes = plt.subplots(len(images), len(images[0])) + for row in range(len(images)): + vmin = min(i.min() for i in images[row]) + vmax = max(i.max() for i in images[row]) + for col in range(len(images[0])): + ax = axes[row][col] + imshow = ax.imshow(images[row][col], cmap="gray", vmin=vmin, vmax=vmax) + if colorbar and col == len(images[0]) - 1: + plt.colorbar(imshow, ax=ax) + if col == 0: + y_label = "After" if row else "Before" + y_label += ("\n" + im_sizes[row]) if im_sizes[0] != im_sizes[1] else "" + ax.set_ylabel(y_label) + ax.set_xticks([]) + ax.set_yticks([]) + ax.set_frame_on(False) + if labels is not None: + ax.imshow(labels[row][col], cmap="hsv", alpha=0.9) + # title is e.g., Flipd(keys=keys, spatial_axis=0) + title = transform_name + "(" + for k, v in transform_args.items(): + title += k + "=" + if isinstance(v, str): + title += "'" + v + "'" + elif isinstance(v, (np.ndarray, torch.Tensor)): + title += "[array]" + elif isinstance(v, Callable): + title += "[callable]" + else: + title += str(v) + title += ", " + if len(transform_args) > 0: + title = title[:-2] + title += ")" + # shorten the lines + title = textwrap.fill(title, 50, break_long_words=False, subsequent_indent=" " * (len(transform_name) + 1)) + fig.suptitle(title, x=0.1, horizontalalignment="left") + plt.tight_layout() + fig.savefig(filename) plt.close(fig) -def create_transform_im(transform, data, ndim, update_doc=True, out_dir=None, seed=0): +def get_image(data, is_map, key): + """Get image. If is dictionary, extract key. If is list, stack. If both dictionary and list, do both. + Also return the image size as string to be used im the imshow. If it's a list, return `N x (H,W,D)`. + """ + # if list, extract. + if not isinstance(data, list): + data = data[key] if is_map else data + im_size = str(data.shape[1:]) + + # output is sometimes a list (e.g., RandSpatialCropSamples) + if isinstance(data, list): + data = [d[key] if is_map else d for d in data] + im_size = str(len(data)) + " x " + str(data[0].shape[1:]) + # if we can stack in square or cube (e.g., there are 4 or 8 examples), then do that + log2 = np.log2(len(data)) + if log2 % 1 == 0: + for i in range(int(log2)): + data = [np.concatenate(data[j : j + 2], axis=i + 1) for j in range(0, len(data), 2)] + data = data[0] + else: + data = np.hstack(data) + return data, im_size + + +def create_transform_im( + transform, transform_args, data, ndim=3, colorbar=False, update_doc=True, out_dir=None, seed=0, is_post=False +): """Create an image with the before and after of the transform. Also update the transform's documentation to point to this image.""" + transform = transform(**transform_args) + if not has_matplotlib: raise RuntimeError if isinstance(transform, Randomizable): + # increment the seed for map transforms so they're different to the array versions. + seed = seed + 1 if isinstance(transform, MapTransform) else seed transform.set_random_state(seed) out_dir = os.environ.get("MONAI_DOC_IMAGES") if out_dir is None: raise RuntimeError( "Please git clone https://github.com/Project-MONAI/DocImages" - + " and then set the environmental variable `MONAI_DOC_IMAGES`" + + " and then set the environment variable `MONAI_DOC_IMAGES`" ) out_dir = os.path.join(out_dir, "transforms") @@ -189,24 +380,22 @@ def create_transform_im(transform, data, ndim, update_doc=True, out_dir=None, se out_file = os.path.join(out_dir, out_fname) is_map = isinstance(transform, MapTransform) - data_in = pre_process_data(data, ndim, is_map) + data_in = pre_process_data(deepcopy(data), ndim, is_map, is_post) - data_tr = transform(data_in) + data_tr = transform(deepcopy(data_in)) - if ndim != 3: - raise NotImplementedError + image_before, im_before_shape = get_image(data_in, is_map, CommonKeys.IMAGE) + image_after, im_after_shape = get_image(data_tr, is_map, CommonKeys.IMAGE) - image_before = data_in[CommonKeys.IMAGE] if is_map else data_in - image_after = data_tr[CommonKeys.IMAGE] if is_map else data_tr + im_sizes = (im_before_shape, im_after_shape) stacked_images = get_stacked_before_after(image_before, image_after) stacked_labels = None if is_map: - label_before = data_in[CommonKeys.LABEL] - label_after = data_tr[CommonKeys.LABEL] - stacked_labels = get_stacked_before_after(label_before, label_after) - stacked_labels[stacked_labels == 0] = np.nan + label_before, _ = get_image(data_in, is_map, CommonKeys.LABEL) + label_after, _ = get_image(data_tr, is_map, CommonKeys.LABEL) + stacked_labels = get_stacked_before_after(label_before, label_after, is_label=True) - save_image(stacked_images, stacked_labels, out_file) + save_image(stacked_images, stacked_labels, out_file, transform_name, transform_args, im_sizes, colorbar) if update_doc: base_dir = pathlib.Path(__file__).parent.parent.parent @@ -215,6 +404,234 @@ def create_transform_im(transform, data, ndim, update_doc=True, out_dir=None, se if __name__ == "__main__": - data = get_data() - create_transform_im(RandFlip(prob=1, spatial_axis=2), data, 3) - create_transform_im(RandFlipd(KEYS, prob=1, spatial_axis=2), data, 3) + + keys = [CommonKeys.IMAGE, CommonKeys.LABEL] + data = get_data(keys) + create_transform_im(RandFlip, dict(prob=1, spatial_axis=1), data) + create_transform_im(RandFlipd, dict(keys=keys, prob=1, spatial_axis=2), data) + create_transform_im(Flip, dict(spatial_axis=1), data) + create_transform_im(Flipd, dict(keys=keys, spatial_axis=2), data) + create_transform_im(Flipd, dict(keys=keys, spatial_axis=2), data) + create_transform_im(Orientation, dict(axcodes="RPI", image_only=True), data) + create_transform_im(Orientationd, dict(keys=keys, axcodes="RPI"), data) + create_transform_im( + Rand3DElastic, dict(prob=1.0, sigma_range=(1, 2), magnitude_range=(0.5, 0.5), shear_range=(1, 1, 1)), data + ) + create_transform_im(Affine, dict(shear_params=(0, 0.5, 0), image_only=True, padding_mode="zeros"), data) + create_transform_im( + Affined, dict(keys=keys, shear_params=(0, 0.5, 0), mode=["bilinear", "nearest"], padding_mode="zeros"), data + ) + create_transform_im(RandAffine, dict(prob=1, shear_range=(0.5, 0.5), padding_mode="zeros"), data) + create_transform_im( + RandAffined, + dict(keys=keys, prob=1, shear_range=(0.5, 0.5), mode=["bilinear", "nearest"], padding_mode="zeros"), + data, + ) + create_transform_im( + Rand3DElastic, dict(sigma_range=(5, 7), magnitude_range=(50, 150), prob=1, padding_mode="zeros"), data + ) + create_transform_im( + Rand2DElastic, dict(prob=1, spacing=(20, 20), magnitude_range=(1, 2), padding_mode="zeros"), data, 2 + ) + create_transform_im( + Rand2DElasticd, + dict( + keys=keys, + prob=1, + spacing=(20, 20), + magnitude_range=(1, 2), + padding_mode="zeros", + mode=["bilinear", "nearest"], + ), + data, + 2, + ) + create_transform_im( + Rand3DElasticd, + dict( + keys=keys, + sigma_range=(5, 7), + magnitude_range=(50, 150), + prob=1, + padding_mode="zeros", + mode=["bilinear", "nearest"], + ), + data, + ) + create_transform_im(Rotate90, dict(spatial_axes=(1, 2)), data) + create_transform_im(Rotate90d, dict(keys=keys, spatial_axes=(1, 2)), data) + create_transform_im(RandRotate90, dict(prob=1), data) + create_transform_im(RandRotate90d, dict(keys=keys, prob=1), data) + create_transform_im(Rotate, dict(angle=0.1), data) + create_transform_im(Rotated, dict(keys=keys, angle=0.1, mode=["bilinear", "nearest"]), data) + create_transform_im(RandRotate, dict(prob=1, range_x=[0.4, 0.4]), data) + create_transform_im(RandRotated, dict(keys=keys, prob=1, range_x=[0.4, 0.4], mode=["bilinear", "nearest"]), data) + create_transform_im(Zoom, dict(zoom=0.6), data) + create_transform_im(Zoomd, dict(keys=keys, zoom=1.3, mode=["area", "nearest"]), data) + create_transform_im(RandZoom, dict(prob=1, min_zoom=0.6, max_zoom=0.8), data) + create_transform_im(RandZoomd, dict(keys=keys, prob=1, min_zoom=1.3, max_zoom=1.5, mode=["area", "nearest"]), data) + create_transform_im(ScaleIntensity, dict(minv=0, maxv=10), data, colorbar=True) + create_transform_im(ScaleIntensityd, dict(keys=CommonKeys.IMAGE, minv=0, maxv=10), data, colorbar=True) + create_transform_im(RandScaleIntensity, dict(prob=1.0, factors=(5, 10)), data, colorbar=True) + create_transform_im( + RandScaleIntensityd, dict(keys=CommonKeys.IMAGE, prob=1.0, factors=(5, 10)), data, colorbar=True + ) + create_transform_im(DivisiblePad, dict(k=64), data) + create_transform_im(DivisiblePadd, dict(keys=keys, k=64), data) + create_transform_im(CropForeground, dict(), data) + create_transform_im(CropForegroundd, dict(keys=keys, source_key=CommonKeys.IMAGE), data) + create_transform_im(RandGaussianNoise, dict(prob=1, mean=0, std=0.1), data) + create_transform_im(RandGaussianNoised, dict(keys=CommonKeys.IMAGE, prob=1, mean=0, std=0.1), data) + create_transform_im(KSpaceSpikeNoise, dict(loc=(100, 100, 100), k_intensity=13), data) + create_transform_im(KSpaceSpikeNoised, dict(keys=CommonKeys.IMAGE, loc=(100, 100, 100), k_intensity=13), data) + create_transform_im(RandKSpaceSpikeNoise, dict(prob=1, intensity_range=(10, 13)), data) + create_transform_im( + RandKSpaceSpikeNoised, + dict( + keys=CommonKeys.IMAGE, + global_prob=1, + prob=1, + common_sampling=True, + intensity_ranges={CommonKeys.IMAGE: (13, 15)}, + ), + data, + ) + create_transform_im(GibbsNoise, dict(alpha=0.8), data) + create_transform_im(GibbsNoised, dict(keys=CommonKeys.IMAGE, alpha=0.8), data) + create_transform_im(RandGibbsNoise, dict(prob=1.0, alpha=(0.6, 0.8)), data) + create_transform_im(RandGibbsNoised, dict(keys=CommonKeys.IMAGE, prob=1.0, alpha=(0.6, 0.8)), data) + create_transform_im(ShiftIntensity, dict(offset=1), data, colorbar=True) + create_transform_im(ShiftIntensityd, dict(keys=CommonKeys.IMAGE, offset=1), data, colorbar=True) + create_transform_im(RandShiftIntensity, dict(prob=1.0, offsets=(10, 20)), data, colorbar=True) + create_transform_im( + RandShiftIntensityd, dict(keys=CommonKeys.IMAGE, prob=1.0, offsets=(10, 20)), data, colorbar=True + ) + create_transform_im(StdShiftIntensity, dict(factor=10), data, colorbar=True) + create_transform_im(StdShiftIntensityd, dict(keys=CommonKeys.IMAGE, factor=10), data, colorbar=True) + create_transform_im(RandStdShiftIntensity, dict(prob=1.0, factors=(5, 10)), data, colorbar=True) + create_transform_im( + RandStdShiftIntensityd, dict(keys=CommonKeys.IMAGE, prob=1.0, factors=(5, 10)), data, colorbar=True + ) + create_transform_im(RandBiasField, dict(prob=1, coeff_range=(0.2, 0.3)), data) + create_transform_im(RandBiasFieldd, dict(keys=CommonKeys.IMAGE, prob=1, coeff_range=(0.2, 0.3)), data) + create_transform_im(NormalizeIntensity, dict(subtrahend=0, divisor=10), data, colorbar=True) + create_transform_im(NormalizeIntensityd, dict(keys=CommonKeys.IMAGE, subtrahend=0, divisor=10), data, colorbar=True) + create_transform_im(ThresholdIntensity, dict(threshold=0.4, above=False, cval=0.9), data, colorbar=True) + create_transform_im( + ThresholdIntensityd, dict(keys=CommonKeys.IMAGE, threshold=0.4, above=False, cval=0.9), data, colorbar=True + ) + create_transform_im(ScaleIntensityRange, dict(a_min=0, a_max=1, b_min=1, b_max=10), data, colorbar=True) + create_transform_im( + ScaleIntensityRanged, dict(keys=CommonKeys.IMAGE, a_min=0, a_max=1, b_min=1, b_max=10), data, colorbar=True + ) + create_transform_im(ScaleIntensityRangePercentiles, dict(lower=5, upper=95, b_min=1, b_max=10), data, colorbar=True) + create_transform_im( + ScaleIntensityRangePercentilesd, + dict(keys=CommonKeys.IMAGE, lower=5, upper=95, b_min=1, b_max=10), + data, + colorbar=True, + ) + create_transform_im(AdjustContrast, dict(gamma=2), data, colorbar=True) + create_transform_im(AdjustContrastd, dict(keys=CommonKeys.IMAGE, gamma=2), data, colorbar=True) + create_transform_im(RandAdjustContrast, dict(prob=1, gamma=(1.5, 2)), data, colorbar=True) + create_transform_im(RandAdjustContrastd, dict(keys=CommonKeys.IMAGE, prob=1, gamma=(1.5, 2)), data, colorbar=True) + create_transform_im(MaskIntensity, dict(mask_data=data[CommonKeys.IMAGE], select_fn=lambda x: x > 0.3), data) + create_transform_im( + MaskIntensityd, dict(keys=CommonKeys.IMAGE, mask_key=CommonKeys.IMAGE, select_fn=lambda x: x > 0.3), data + ) + create_transform_im(GaussianSmooth, dict(sigma=2), data) + create_transform_im(GaussianSmoothd, dict(keys=CommonKeys.IMAGE, sigma=2), data) + create_transform_im(RandGaussianSmooth, dict(prob=1.0, sigma_x=(1, 2)), data) + create_transform_im(RandGaussianSmoothd, dict(keys=CommonKeys.IMAGE, prob=1.0, sigma_x=(1, 2)), data) + create_transform_im(GaussianSharpen, dict(), GaussianSmoothd(CommonKeys.IMAGE, 2)(data)) + create_transform_im(GaussianSharpend, dict(keys=CommonKeys.IMAGE), GaussianSmoothd(CommonKeys.IMAGE, 2)(data)) + create_transform_im(RandGaussianSharpen, dict(prob=1), GaussianSmoothd(CommonKeys.IMAGE, 2)(data)) + create_transform_im( + RandGaussianSharpend, dict(keys=CommonKeys.IMAGE, prob=1), GaussianSmoothd(CommonKeys.IMAGE, 2)(data) + ) + create_transform_im(RandHistogramShift, dict(prob=1, num_control_points=3), data, colorbar=True) + create_transform_im( + RandHistogramShiftd, dict(keys=CommonKeys.IMAGE, prob=1, num_control_points=3), data, colorbar=True + ) + create_transform_im(RandCoarseDropout, dict(prob=1, holes=200, spatial_size=20, fill_value=0), data) + create_transform_im( + RandCoarseDropoutd, dict(keys=CommonKeys.IMAGE, prob=1, holes=200, spatial_size=20, fill_value=0), data + ) + create_transform_im(RandCoarseShuffle, dict(prob=1, holes=200, spatial_size=20), data) + create_transform_im(RandCoarseShuffled, dict(keys=CommonKeys.IMAGE, prob=1, holes=200, spatial_size=20), data) + create_transform_im(HistogramNormalize, dict(num_bins=10), data) + create_transform_im(HistogramNormalized, dict(keys=CommonKeys.IMAGE, num_bins=10), data) + create_transform_im(SpatialPad, dict(spatial_size=(300, 300, 300)), data) + create_transform_im(SpatialPadd, dict(keys=keys, spatial_size=(300, 300, 300)), data) + create_transform_im(BorderPad, dict(spatial_border=10), data) + create_transform_im(BorderPadd, dict(keys=keys, spatial_border=10), data) + create_transform_im(SpatialCrop, dict(roi_center=(75, 75, 75), roi_size=(100, 100, 100)), data) + create_transform_im(SpatialCropd, dict(keys=keys, roi_center=(75, 75, 75), roi_size=(100, 100, 100)), data) + create_transform_im(CenterSpatialCrop, dict(roi_size=(100, 100, 100)), data) + create_transform_im(CenterSpatialCropd, dict(keys=keys, roi_size=(100, 100, 100)), data) + create_transform_im(RandSpatialCrop, dict(roi_size=(100, 100, 100), random_size=False), data) + create_transform_im(RandSpatialCropd, dict(keys=keys, roi_size=(100, 100, 100), random_size=False), data) + create_transform_im(RandSpatialCropSamples, dict(num_samples=8, roi_size=(100, 100, 100), random_size=False), data) + create_transform_im( + RandSpatialCropSamplesd, dict(keys=keys, num_samples=8, roi_size=(100, 100, 100), random_size=False), data + ) + create_transform_im( + RandWeightedCrop, dict(spatial_size=(100, 100, 100), num_samples=8, weight_map=data[CommonKeys.IMAGE] > 0), data + ) + create_transform_im( + RandWeightedCropd, dict(keys=keys, spatial_size=(100, 100, 100), num_samples=8, w_key=CommonKeys.IMAGE), data + ) + create_transform_im( + RandCropByPosNegLabel, + dict(spatial_size=(100, 100, 100), label=data[CommonKeys.LABEL], neg=0, num_samples=8), + data, + ) + create_transform_im( + RandCropByPosNegLabeld, + dict(keys=keys, spatial_size=(100, 100, 100), label_key=CommonKeys.LABEL, neg=0, num_samples=8), + data, + ) + create_transform_im( + RandCropByLabelClasses, + dict(spatial_size=(100, 100, 100), label=data[CommonKeys.LABEL], num_classes=2, ratios=[0, 1], num_samples=8), + data, + ) + create_transform_im( + RandCropByLabelClassesd, + dict( + keys=keys, + spatial_size=(100, 100, 100), + label_key=CommonKeys.LABEL, + num_classes=2, + ratios=[0, 1], + num_samples=8, + ), + data, + ) + create_transform_im(ResizeWithPadOrCrop, dict(spatial_size=(100, 100, 100)), data) + create_transform_im(ResizeWithPadOrCropd, dict(keys=keys, spatial_size=(100, 100, 100)), data) + create_transform_im(RandScaleCrop, dict(roi_scale=0.4), data) + create_transform_im(RandScaleCropd, dict(keys=keys, roi_scale=0.4), data) + create_transform_im(CenterScaleCrop, dict(roi_scale=0.4), data) + create_transform_im(CenterScaleCropd, dict(keys=keys, roi_scale=0.4), data) + create_transform_im( + AsDiscrete, dict(num_classes=2, threshold_values=True, logit_thresh=10), data, is_post=True, colorbar=True + ) + create_transform_im( + AsDiscreted, + dict(keys=CommonKeys.LABEL, num_classes=2, threshold_values=True, logit_thresh=10), + data, + is_post=True, + ) + create_transform_im(LabelFilter, dict(applied_labels=(1, 2, 3, 4, 5, 6)), data, is_post=True) + create_transform_im( + LabelFilterd, dict(keys=CommonKeys.LABEL, applied_labels=(1, 2, 3, 4, 5, 6)), data, is_post=True + ) + create_transform_im(LabelToContour, dict(), data, is_post=True) + create_transform_im(LabelToContourd, dict(keys=CommonKeys.LABEL), data, is_post=True) + create_transform_im(Spacing, dict(pixdim=(5, 5, 5), image_only=True), data) + create_transform_im(Spacingd, dict(keys=keys, pixdim=(5, 5, 5), mode=["bilinear", "nearest"]), data) + create_transform_im(RandAxisFlip, dict(prob=1), data) + create_transform_im(RandAxisFlipd, dict(keys=keys, prob=1), data) + create_transform_im(Resize, dict(spatial_size=(100, 100, 100)), data) + create_transform_im(Resized, dict(keys=keys, spatial_size=(100, 100, 100), mode=["area", "nearest"]), data) From 26f20f45fdbe58a2aa665612f68b77c524fd0f36 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Mon, 4 Oct 2021 13:33:11 +0100 Subject: [PATCH 71/89] update backend (#3065) Signed-off-by: Wenqi Li --- monai/transforms/utility/dictionary.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 7333484d13..0a4df58647 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -1165,6 +1165,8 @@ class ClassesToIndicesd(MapTransform): """ + backend = ClassesToIndices.backend + def __init__( self, keys: KeysCollection, From 7ad0f6ebca5852b708ad98665c22e6f9b03a1048 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Mon, 4 Oct 2021 21:39:58 +0800 Subject: [PATCH 72/89] 3063 Fix the complex Tensor issue in type conversion (#3064) * [DLMED] fix complex array issue Signed-off-by: Nic Ma * [DLMED] fix test issue Signed-off-by: Nic Ma --- monai/transforms/intensity/array.py | 17 +++++------------ monai/transforms/utils.py | 4 ++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 7a554cbf69..d2d8cac1ad 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -41,7 +41,6 @@ ) from monai.utils.deprecated import deprecated_arg from monai.utils.enums import TransformBackends -from monai.utils.misc import is_module_ver_at_least from monai.utils.type_conversion import convert_to_tensor, get_equivalent_dtype __all__ = [ @@ -1493,11 +1492,10 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: n_dims = len(img.shape[1:]) - lib = np if isinstance(img, np.ndarray) else torch - # FT k = self.shift_fourier(img, n_dims) - log_abs = lib.log(lib.absolute(k) + 1e-10) # type: ignore + lib = np if isinstance(k, np.ndarray) else torch + log_abs = lib.log(lib.abs(k) + 1e-10) # type: ignore phase = lib.angle(k) # type: ignore k_intensity = self.k_intensity @@ -1512,13 +1510,8 @@ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: else: self._set_spike(log_abs, self.loc, k_intensity) # map back - # complex exponential not implemented for older pytorch - if isinstance(phase, torch.Tensor) and not is_module_ver_at_least(torch, (1, 6, 0)): - phase = phase.cpu() - k = torch.exp(log_abs) * torch.exp(1j * phase.cpu()).to(log_abs.device) - else: - k = lib.exp(log_abs) * lib.exp(1j * phase) # type: ignore - img = self.inv_shift_fourier(k, n_dims) + k = lib.exp(log_abs) * lib.exp(1j * phase) # type: ignore + img, *_ = convert_to_dst_type(self.inv_shift_fourier(k, n_dims), dst=img) return img @@ -1695,7 +1688,7 @@ def _set_default_range(self, img: NdarrayOrTensor) -> Sequence[Sequence[float]]: n_dims = len(img.shape[1:]) k = self.shift_fourier(img, n_dims) - mod = torch if isinstance(img, torch.Tensor) else np + mod = torch if isinstance(k, torch.Tensor) else np log_abs = mod.log(mod.absolute(k) + 1e-10) # type: ignore shifted_means = mod.mean(log_abs, dim=tuple(range(-n_dims, 0))) * 2.5 # type: ignore return tuple((i * 0.95, i * 1.1) for i in shifted_means) diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 690b2d095d..18657d0122 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -1276,8 +1276,8 @@ def shift_fourier(x: NdarrayOrTensor, spatial_dims: int, n_dims: Optional[int] = if hasattr(torch.fft, "fftshift"): k = torch.fft.fftshift(torch.fft.fftn(x, dim=dims), dim=dims) else: + # if using old PyTorch, will convert to numpy array and return k = np.fft.fftshift(np.fft.fftn(x.cpu().numpy(), axes=dims), axes=dims) - k, *_ = convert_to_dst_type(k, x) else: k = np.fft.fftshift(np.fft.fftn(x, axes=dims), axes=dims) return k @@ -1309,8 +1309,8 @@ def inv_shift_fourier(k: NdarrayOrTensor, spatial_dims: int, n_dims: Optional[in if hasattr(torch.fft, "ifftshift"): out = torch.fft.ifftn(torch.fft.ifftshift(k, dim=dims), dim=dims, norm="backward").real else: + # if using old PyTorch, will convert to numpy array and return out = np.fft.ifftn(np.fft.ifftshift(k.cpu().numpy(), axes=dims), axes=dims).real - out, *_ = convert_to_dst_type(out, k) else: out = np.fft.ifftn(np.fft.ifftshift(k, axes=dims), axes=dims).real return out From 4618e858e520ddd6fba50813f5f87328939331fc Mon Sep 17 00:00:00 2001 From: Eric Kerfoot <17726042+ericspod@users.noreply.github.com> Date: Mon, 4 Oct 2021 18:21:03 +0100 Subject: [PATCH 73/89] Ae docs (#3067) * Adding documentation for AutoEncoder and VarAutoEncoder Signed-off-by: Eric Kerfoot --- monai/networks/nets/autoencoder.py | 89 ++++++++++++++++-- monai/networks/nets/classifier.py | 75 +++++++-------- monai/networks/nets/fullyconnectednet.py | 51 ++++++++-- monai/networks/nets/generator.py | 54 +++++------ monai/networks/nets/regressor.py | 41 ++++---- monai/networks/nets/unet.py | 114 ++++++++++++++++------- monai/networks/nets/varautoencoder.py | 32 ++++++- 7 files changed, 318 insertions(+), 138 deletions(-) diff --git a/monai/networks/nets/autoencoder.py b/monai/networks/nets/autoencoder.py index b7dc309b71..f4a0451dc7 100644 --- a/monai/networks/nets/autoencoder.py +++ b/monai/networks/nets/autoencoder.py @@ -23,7 +23,69 @@ class AutoEncoder(nn.Module): """ - Base class for the architecture implementing :py:class:`monai.networks.nets.VarAutoEncoder`. + Simple definition of an autoencoder and base class for the architecture implementing + :py:class:`monai.networks.nets.VarAutoEncoder`. The network is composed of an encode sequence of blocks, followed + by an intermediary sequence of blocks, and finally a decode sequence of blocks. The encode and decode blocks are + default :py:class:`monai.networks.blocks.Convolution` instances with the encode blocks having the given stride + and the decode blocks having transpose convolutions with the same stride. If `num_res_units` is given residual + blocks are used instead. + + By default the intermediary sequence is empty but if `inter_channels` is given to specify the output channels of + blocks then this will be become a sequence of Convolution blocks or of residual blocks if `num_inter_units` is + given. The optional parameter `inter_dilations` can be used to specify the dilation values of the convolutions in + these blocks, this allows a network to use dilated kernels in this middle section. Since the intermediary section + isn't meant to change the size of the output the strides for all these kernels is 1. + + Args: + spatial_dims: number of spatial dimensions. + in_channels: number of input channels. + out_channels: number of output channels. + channels: sequence of channels. Top block first. The length of `channels` should be no less than 2. + strides: sequence of convolution strides. The length of `stride` should equal to `len(channels) - 1`. + kernel_size: convolution kernel size, the value(s) should be odd. If sequence, + its length should equal to dimensions. Defaults to 3. + up_kernel_size: upsampling convolution kernel size, the value(s) should be odd. If sequence, + its length should equal to dimensions. Defaults to 3. + num_res_units: number of residual units. Defaults to 0. + inter_channels: sequence of channels defining the blocks in the intermediate layer between encode and decode. + inter_dilations: defines the dilation value for each block of the intermediate layer. Defaults to 1. + num_inter_units: number of residual units for each block of the intermediate layer. Defaults to 0. + act: activation type and arguments. Defaults to PReLU. + norm: feature normalization type and arguments. Defaults to instance norm. + dropout: dropout ratio. Defaults to no dropout. + bias: whether to have a bias term in convolution blocks. Defaults to True. + According to `Performance Tuning Guide `_, + if a conv layer is directly followed by a batch norm layer, bias should be False. + + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + + Examples:: + + from monai.networks.nets import AutoEncoder + + # 3 layers each down/up sampling their inputs by a factor 2 with no intermediate layer + net = AutoEncoder( + spatial_dims=2, + in_channels=1, + out_channels=1, + channels=(2, 4, 8), + strides=(2, 2, 2) + ) + + # 1 layer downsampling by 2, followed by a sequence of residual units with 2 convolutions defined by + # progressively increasing dilations, then final upsample layer + net = AutoEncoder( + spatial_dims=2, + in_channels=1, + out_channels=1, + channels=(4,), + strides=(2,), + inter_channels=(8, 8, 8), + inter_dilations=(1, 2, 4), + num_inter_units=2 + ) + """ @deprecated_arg( @@ -48,13 +110,6 @@ def __init__( bias: bool = True, dimensions: Optional[int] = None, ) -> None: - """ - Initialize the AutoEncoder. - - .. deprecated:: 0.6.0 - ``dimensions`` is deprecated, use ``spatial_dims`` instead. - - """ super().__init__() self.dimensions = spatial_dims if dimensions is None else dimensions @@ -87,6 +142,9 @@ def __init__( def _get_encode_module( self, in_channels: int, channels: Sequence[int], strides: Sequence[int] ) -> Tuple[nn.Sequential, int]: + """ + Returns the encode part of the network by building up a sequence of layers returned by `_get_encode_layer`. + """ encode = nn.Sequential() layer_channels = in_channels @@ -98,6 +156,10 @@ def _get_encode_module( return encode, layer_channels def _get_intermediate_module(self, in_channels: int, num_inter_units: int) -> Tuple[nn.Module, int]: + """ + Returns the intermediate block of the network which accepts input from the encoder and whose output goes + to the decoder. + """ # Define some types intermediate: nn.Module unit: nn.Module @@ -145,6 +207,9 @@ def _get_intermediate_module(self, in_channels: int, num_inter_units: int) -> Tu def _get_decode_module( self, in_channels: int, channels: Sequence[int], strides: Sequence[int] ) -> Tuple[nn.Sequential, int]: + """ + Returns the decode part of the network by building up a sequence of layers returned by `_get_decode_layer`. + """ decode = nn.Sequential() layer_channels = in_channels @@ -156,7 +221,9 @@ def _get_decode_module( return decode, layer_channels def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Module: - + """ + Returns a single layer of the encoder part of the network. + """ mod: nn.Module if self.num_res_units > 0: mod = ResidualUnit( @@ -187,7 +254,9 @@ def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, i return mod def _get_decode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Sequential: - + """ + Returns a single layer of the decoder part of the network. + """ decode = nn.Sequential() conv = Convolution( diff --git a/monai/networks/nets/classifier.py b/monai/networks/nets/classifier.py index 92fee4f566..a1f913ea23 100644 --- a/monai/networks/nets/classifier.py +++ b/monai/networks/nets/classifier.py @@ -25,6 +25,19 @@ class Classifier(Regressor): Defines a classification network from Regressor by specifying the output shape as a single dimensional tensor with size equal to the number of classes to predict. The final activation function can also be specified, eg. softmax or sigmoid. + + Args: + in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) + classes: integer stating the dimension of the final output tensor + channels: tuple of integers stating the output channels of each convolutional layer + strides: tuple of integers stating the stride (downscale factor) of each convolutional layer + kernel_size: integer or tuple of integers stating size of convolutional kernels + num_res_units: integer stating number of convolutions in residual units, 0 means no residual units + act: name or type defining activation layers + norm: name or type defining normalization layers + dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout + bias: boolean stating if convolution layers should have a bias component + last_act: name defining the last activation layer """ def __init__( @@ -41,20 +54,6 @@ def __init__( bias: bool = True, last_act: Optional[str] = None, ) -> None: - """ - Args: - in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) - classes: integer stating the dimension of the final output tensor - channels: tuple of integers stating the output channels of each convolutional layer - strides: tuple of integers stating the stride (downscale factor) of each convolutional layer - kernel_size: integer or tuple of integers stating size of convolutional kernels - num_res_units: integer stating number of convolutions in residual units, 0 means no residual units - act: name or type defining activation layers - norm: name or type defining normalization layers - dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout - bias: boolean stating if convolution layers should have a bias component - last_act: name defining the last activation layer - """ super().__init__(in_shape, (classes,), channels, strides, kernel_size, num_res_units, act, norm, dropout, bias) if last_act is not None: @@ -68,6 +67,18 @@ class Discriminator(Classifier): """ Defines a discriminator network from Classifier with a single output value and sigmoid activation by default. This is meant for use with GANs or other applications requiring a generic discriminator network. + + Args: + in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) + channels: tuple of integers stating the output channels of each convolutional layer + strides: tuple of integers stating the stride (downscale factor) of each convolutional layer + kernel_size: integer or tuple of integers stating size of convolutional kernels + num_res_units: integer stating number of convolutions in residual units, 0 means no residual units + act: name or type defining activation layers + norm: name or type defining normalization layers + dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout + bias: boolean stating if convolution layers should have a bias component + last_act: name defining the last activation layer """ def __init__( @@ -83,19 +94,6 @@ def __init__( bias: bool = True, last_act=Act.SIGMOID, ) -> None: - """ - Args: - in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) - channels: tuple of integers stating the output channels of each convolutional layer - strides: tuple of integers stating the stride (downscale factor) of each convolutional layer - kernel_size: integer or tuple of integers stating size of convolutional kernels - num_res_units: integer stating number of convolutions in residual units, 0 means no residual units - act: name or type defining activation layers - norm: name or type defining normalization layers - dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout - bias: boolean stating if convolution layers should have a bias component - last_act: name defining the last activation layer - """ super().__init__(in_shape, 1, channels, strides, kernel_size, num_res_units, act, norm, dropout, bias, last_act) @@ -104,6 +102,17 @@ class Critic(Classifier): Defines a critic network from Classifier with a single output value and no final activation. The final layer is `nn.Flatten` instead of `nn.Linear`, the final result is computed as the mean over the first dimension. This is meant to be used with Wasserstein GANs. + + Args: + in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) + channels: tuple of integers stating the output channels of each convolutional layer + strides: tuple of integers stating the stride (downscale factor) of each convolutional layer + kernel_size: integer or tuple of integers stating size of convolutional kernels + num_res_units: integer stating number of convolutions in residual units, 0 means no residual units + act: name or type defining activation layers + norm: name or type defining normalization layers + dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout + bias: boolean stating if convolution layers should have a bias component """ def __init__( @@ -118,18 +127,6 @@ def __init__( dropout: Optional[float] = 0.25, bias: bool = True, ) -> None: - """ - Args: - in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) - channels: tuple of integers stating the output channels of each convolutional layer - strides: tuple of integers stating the stride (downscale factor) of each convolutional layer - kernel_size: integer or tuple of integers stating size of convolutional kernels - num_res_units: integer stating number of convolutions in residual units, 0 means no residual units - act: name or type defining activation layers - norm: name or type defining normalization layers - dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout - bias: boolean stating if convolution layers should have a bias component - """ super().__init__(in_shape, 1, channels, strides, kernel_size, num_res_units, act, norm, dropout, bias, None) def _get_final_layer(self, in_shape: Sequence[int]): diff --git a/monai/networks/nets/fullyconnectednet.py b/monai/networks/nets/fullyconnectednet.py index b906bab015..19197bd58d 100644 --- a/monai/networks/nets/fullyconnectednet.py +++ b/monai/networks/nets/fullyconnectednet.py @@ -30,9 +30,24 @@ def _get_adn_layer( class FullyConnectedNet(nn.Sequential): """ - Plain full-connected layer neural network + Simple full-connected layer neural network composed of a sequence of linear layers with PReLU activation and + dropout. The network accepts input with `in_channels` channels, has output with `out_channels` channels, and + hidden layer output channels given in `hidden_channels`. If `bias` is True then linear units have a bias term. + + Args: + in_channels: number of input channels. + out_channels: number of output channels. + hidden_channels: number of output channels for each hidden layer. + dropout: dropout ratio. Defaults to no dropout. + act: activation type and arguments. Defaults to PReLU. + bias: whether to have a bias term in linear units. Defaults to True. + adn_ordering: order of operations in :py:class:`monai.networks.blocks.ADN`. + + Examples:: + + # accepts 4 values and infers 3 values as output, has 3 hidden layers with 10, 20, 10 values as output + net = FullyConnectedNet(4, 3, [10, 20, 10], dropout=0.2) - The network uses dropout and, by default, PReLU activation """ def __init__( @@ -53,8 +68,11 @@ def __init__( self.in_channels = in_channels self.out_channels = out_channels self.hidden_channels = list(hidden_channels) + self.act = act + self.dropout = dropout + self.adn_ordering = adn_ordering + self.add_module("flatten", nn.Flatten()) - self.adn_layer = _get_adn_layer(act, dropout, adn_ordering) prev_channels = self.in_channels for i, c in enumerate(hidden_channels): @@ -64,13 +82,34 @@ def __init__( self.add_module("output", nn.Linear(prev_channels, out_channels, bias)) def _get_layer(self, in_channels: int, out_channels: int, bias: bool) -> nn.Sequential: - seq = nn.Sequential(nn.Linear(in_channels, out_channels, bias)) - seq.add_module("ADN", self.adn_layer) + seq = nn.Sequential( + nn.Linear(in_channels, out_channels, bias), _get_adn_layer(self.act, self.dropout, self.adn_ordering) + ) return seq class VarFullyConnectedNet(nn.Module): - """Variational fully-connected network.""" + """ + Variational fully-connected network. This is composed of an encode layer, reparameterization layer, and then a + decode layer. + + Args: + in_channels: number of input channels. + out_channels: number of output channels. + latent_size: number of latent variables to use. + encode_channels: number of output channels for each hidden layer of the encode half. + decode_channels: number of output channels for each hidden layer of the decode half. + dropout: dropout ratio. Defaults to no dropout. + act: activation type and arguments. Defaults to PReLU. + bias: whether to have a bias term in linear units. Defaults to True. + adn_ordering: order of operations in :py:class:`monai.networks.blocks.ADN`. + + Examples:: + + # accepts inputs with 4 values, uses a latent space of 2 variables, and produces outputs of 3 values + net = VarFullyConnectedNet(4, 3, 2, [5, 10], [10, 5]) + + """ def __init__( self, diff --git a/monai/networks/nets/generator.py b/monai/networks/nets/generator.py index ea05787173..90aa26cd01 100644 --- a/monai/networks/nets/generator.py +++ b/monai/networks/nets/generator.py @@ -25,13 +25,35 @@ class Generator(nn.Module): """ Defines a simple generator network accepting a latent vector and through a sequence of convolution layers constructs an output tensor of greater size and high dimensionality. The method `_get_layer` is used to - create each of these layers, override this method to define layers beyond the default Convolution or - ResidualUnit layers. + create each of these layers, override this method to define layers beyond the default + :py:class:`monai.networks.blocks.Convolution` or :py:class:`monai.networks.blocks.ResidualUnit` layers. + + The layers are constructed using the values in the `channels` and `strides` arguments, the number being defined by + the length of these (which must match). Input is first passed through a :py:class:`torch.nn.Linear` layer to + convert the input vector to an image tensor with dimensions `start_shape`. This passes through the convolution + layers and is progressively upsampled if the `strides` valus are greater than 1 using transpose convolutions. The + size of the final output is defined by the `start_shape` dimension and the amount of upsampling done through + strides. In the default definition the size of the output's spatial dimensions will be that of `start_shape` + multiplied by the product of `strides`, thus the example network below upsamples an starting size of (64, 8, 8) + to (1, 64, 64) since its `strides` are (2, 2, 2). + + Args: + latent_shape: tuple of integers stating the dimension of the input latent vector (minus batch dimension) + start_shape: tuple of integers stating the dimension of the tensor to pass to convolution subnetwork + channels: tuple of integers stating the output channels of each convolutional layer + strides: tuple of integers stating the stride (upscale factor) of each convolutional layer + kernel_size: integer or tuple of integers stating size of convolutional kernels + num_res_units: integer stating number of convolutions in residual units, 0 means no residual units + act: name or type defining activation layers + norm: name or type defining normalization layers + dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout + bias: boolean stating if convolution layers should have a bias component + + Examples:: + + # 3 layers, latent input vector of shape (42, 24), output volume of shape (1, 64, 64) + net = Generator((42, 24), (64, 8, 8), (32, 16, 1), (2, 2, 2)) - For example, a generator accepting a latent vector if shape (42,24) and producing an output volume of - shape (1,64,64) can be constructed as: - - gen = Generator((42, 24), (64, 8, 8), (32, 16, 1), (2, 2, 2)) """ def __init__( @@ -47,26 +69,6 @@ def __init__( dropout: Optional[float] = None, bias: bool = True, ) -> None: - """ - Construct the generator network with the number of layers defined by `channels` and `strides`. In the - forward pass a `nn.Linear` layer relates the input latent vector to a tensor of dimensions `start_shape`, - this is then fed forward through the sequence of convolutional layers. The number of layers is defined by - the length of `channels` and `strides` which must match, each layer having the number of output channels - given in `channels` and an upsample factor given in `strides` (ie. a transpose convolution with that stride - size). - - Args: - latent_shape: tuple of integers stating the dimension of the input latent vector (minus batch dimension) - start_shape: tuple of integers stating the dimension of the tensor to pass to convolution subnetwork - channels: tuple of integers stating the output channels of each convolutional layer - strides: tuple of integers stating the stride (upscale factor) of each convolutional layer - kernel_size: integer or tuple of integers stating size of convolutional kernels - num_res_units: integer stating number of convolutions in residual units, 0 means no residual units - act: name or type defining activation layers - norm: name or type defining normalization layers - dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout - bias: boolean stating if convolution layers should have a bias component - """ super().__init__() self.in_channels, *self.start_shape = ensure_tuple(start_shape) diff --git a/monai/networks/nets/regressor.py b/monai/networks/nets/regressor.py index 0153014902..bc8feb7527 100644 --- a/monai/networks/nets/regressor.py +++ b/monai/networks/nets/regressor.py @@ -29,6 +29,30 @@ class Regressor(nn.Module): This defines a network for relating large-sized input tensors to small output tensors, ie. regressing large values to a prediction. An output of a single dimension can be used as value regression or multi-label classification prediction, an output of a single value can be used as a discriminator or critic prediction. + + The network is constructed as a sequence of layers, either :py:class:`monai.networks.blocks.Convolution` or + :py:class:`monai.networks.blocks.ResidualUnit`, with a final fully-connected layer resizing the output from the + blocks to the final size. Each block is defined with a stride value typically used to downsample the input using + strided convolutions. In this way each block progressively condenses information from the input into a deep + representation the final fully-connected layer relates to a final result. + + Args: + in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) + out_shape: tuple of integers stating the dimension of the final output tensor (minus batch dimension) + channels: tuple of integers stating the output channels of each convolutional layer + strides: tuple of integers stating the stride (downscale factor) of each convolutional layer + kernel_size: integer or tuple of integers stating size of convolutional kernels + num_res_units: integer stating number of convolutions in residual units, 0 means no residual units + act: name or type defining activation layers + norm: name or type defining normalization layers + dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout + bias: boolean stating if convolution layers should have a bias component + + Examples:: + + # infers a 2-value result (eg. a 2D cartesian coordinate) from a 64x64 image + net = Regressor((1, 64, 64), (2,), (2, 4, 8), (2, 2, 2)) + """ def __init__( @@ -44,23 +68,6 @@ def __init__( dropout: Optional[float] = None, bias: bool = True, ) -> None: - """ - Construct the regressor network with the number of layers defined by `channels` and `strides`. Inputs are - first passed through the convolutional layers in the forward pass, the output from this is then pass - through a fully connected layer to relate them to the final output tensor. - - Args: - in_shape: tuple of integers stating the dimension of the input tensor (minus batch dimension) - out_shape: tuple of integers stating the dimension of the final output tensor - channels: tuple of integers stating the output channels of each convolutional layer - strides: tuple of integers stating the stride (downscale factor) of each convolutional layer - kernel_size: integer or tuple of integers stating size of convolutional kernels - num_res_units: integer stating number of convolutions in residual units, 0 means no residual units - act: name or type defining activation layers - norm: name or type defining normalization layers - dropout: optional float value in range [0, 1] stating dropout probability for layers, None for no dropout - bias: boolean stating if convolution layers should have a bias component - """ super().__init__() self.in_channels, *self.in_shape = ensure_tuple(in_shape) diff --git a/monai/networks/nets/unet.py b/monai/networks/nets/unet.py index 1dd52455d9..7d5f979330 100644 --- a/monai/networks/nets/unet.py +++ b/monai/networks/nets/unet.py @@ -26,6 +26,85 @@ @export("monai.networks.nets") @alias("Unet") class UNet(nn.Module): + """ + Enhanced version of UNet which has residual units implemented with the ResidualUnit class. + The residual part uses a convolution to change the input dimensions to match the output dimensions + if this is necessary but will use nn.Identity if not. + Refer to: https://link.springer.com/chapter/10.1007/978-3-030-12029-0_40. + + Each layer of the network has a encode and decode path with a skip connection between them. Data in the encode path + is downsampled using strided convolutions (if `strides` is given values greater than 1) and in the decode path + upsampled using strided transpose convolutions. These down or up sampling operations occur at the beginning of each + block rather than afterwards as is typical in UNet implementations. + + To further explain this consider the first example network given below. This network has 3 layers with strides + of 2 for each of the middle layers (the last layer is the bottom connection which does not down/up sample). Input + data to this network is immediately reduced in the spatial dimensions by a factor of 2 by the first convolution of + the residual unit defining the first layer of the encode part. The last layer of the decode part will upsample its + input (data from the previous layer concatenated with data from the skip connection) in the first convolution. this + ensures the final output of the network has the same shape as the input. + + Padding values for the convolutions are chosen to ensure output sizes are even divisors/multiples of the input + sizes if the `strides` value for a layer is a factor of the input sizes. A typical case is to use `strides` values + of 2 and inputs that are multiples of powers of 2. An input can thus be downsampled evenly however many times its + dimensions can be divided by 2, so for the example network inputs would have to have dimensions that are mutliples + of 4. In the second example network given below the input to the bottom layer will have shape (1, 64, 15, 15) for + an input of shape (1, 1, 240, 240) demonstrating the input being reduced in size spatially by 2**4. + + Args: + spatial_dims: number of spatial dimensions. + in_channels: number of input channels. + out_channels: number of output channels. + channels: sequence of channels. Top block first. The length of `channels` should be no less than 2. + strides: sequence of convolution strides. The length of `stride` should equal to `len(channels) - 1`. + kernel_size: convolution kernel size, the value(s) should be odd. If sequence, + its length should equal to dimensions. Defaults to 3. + up_kernel_size: upsampling convolution kernel size, the value(s) should be odd. If sequence, + its length should equal to dimensions. Defaults to 3. + num_res_units: number of residual units. Defaults to 0. + act: activation type and arguments. Defaults to PReLU. + norm: feature normalization type and arguments. Defaults to instance norm. + dropout: dropout ratio. Defaults to no dropout. + bias: whether to have a bias term in convolution blocks. Defaults to True. + According to `Performance Tuning Guide `_, + if a conv layer is directly followed by a batch norm layer, bias should be False. + + Examples:: + + from monai.networks.nets import UNet + + # 3 layer network with down/upsampling by a factor of 2 at each layer with 2-convolution residual units + net = UNet( + spatial_dims=2, + in_channels=1, + out_channels=1, + channels=(4, 8, 16), + strides=(2, 2), + num_res_units=2 + ) + + # 5 layer network with simple convolution/normalization/dropout/activation blocks defining the layers + net=UNet( + spatial_dims=2, + in_channels=1, + out_channels=1, + channels=(4, 8, 16, 32, 64), + strides=(2, 2, 2, 2), + ) + + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + + Note: The acceptable spatial size of input data depends on the parameters of the network, + to set appropriate spatial size, please check the tutorial for more details: + https://github.com/Project-MONAI/tutorials/blob/master/modules/UNet_input_size_constrains.ipynb. + Typically, when using a stride of 2 in down / up sampling, the output dimensions are either half of the + input when downsampling, or twice when upsampling. In this case with N numbers of layers in the network, + the inputs must have spatial dimensions that are all multiples of 2^N. + Usually, applying `resize`, `pad` or `crop` transforms can help adjust the spatial size of input data. + + """ + @deprecated_arg( name="dimensions", new_name="spatial_dims", since="0.6", msg_suffix="Please use `spatial_dims` instead." ) @@ -45,42 +124,7 @@ def __init__( bias: bool = True, dimensions: Optional[int] = None, ) -> None: - """ - Enhanced version of UNet which has residual units implemented with the ResidualUnit class. - The residual part uses a convolution to change the input dimensions to match the output dimensions - if this is necessary but will use nn.Identity if not. - Refer to: https://link.springer.com/chapter/10.1007/978-3-030-12029-0_40. - Args: - spatial_dims: number of spatial dimensions. - in_channels: number of input channels. - out_channels: number of output channels. - channels: sequence of channels. Top block first. The length of `channels` should be no less than 2. - strides: sequence of convolution strides. The length of `stride` should equal to `len(channels) - 1`. - kernel_size: convolution kernel size, the value(s) should be odd. If sequence, - its length should equal to dimensions. Defaults to 3. - up_kernel_size: upsampling convolution kernel size, the value(s) should be odd. If sequence, - its length should equal to dimensions. Defaults to 3. - num_res_units: number of residual units. Defaults to 0. - act: activation type and arguments. Defaults to PReLU. - norm: feature normalization type and arguments. Defaults to instance norm. - dropout: dropout ratio. Defaults to no dropout. - bias: whether to have a bias term in convolution blocks. Defaults to True. - According to `Performance Tuning Guide `_, - if a conv layer is directly followed by a batch norm layer, bias should be False. - - .. deprecated:: 0.6.0 - ``dimensions`` is deprecated, use ``spatial_dims`` instead. - - Note: The acceptable spatial size of input data depends on the parameters of the network, - to set appropriate spatial size, please check the tutorial for more details: - https://github.com/Project-MONAI/tutorials/blob/master/modules/UNet_input_size_constrains.ipynb. - Typically, when using a stride of 2 in down / up sampling, the output dimensions are either half of the - input when downsampling, or twice when upsampling. In this case with N numbers of layers in the network, - the inputs must have spatial dimensions that are all multiples of 2^N. - Usually, applying `resize`, `pad` or `crop` transforms can help adjust the spatial size of input data. - - """ super().__init__() if len(channels) < 2: diff --git a/monai/networks/nets/varautoencoder.py b/monai/networks/nets/varautoencoder.py index a228efab07..b4ef8be93d 100644 --- a/monai/networks/nets/varautoencoder.py +++ b/monai/networks/nets/varautoencoder.py @@ -28,10 +28,36 @@ class VarAutoEncoder(AutoEncoder): """ Variational Autoencoder based on the paper - https://arxiv.org/abs/1312.6114 - .. code-block:: python + Args: + spatial_dims: number of spatial dimensions. + in_shape: shape of input data starting with channel dimension. + out_channels: number of output channels. + latent_size: size of the latent variable. + channels: sequence of channels. Top block first. The length of `channels` should be no less than 2. + strides: sequence of convolution strides. The length of `stride` should equal to `len(channels) - 1`. + kernel_size: convolution kernel size, the value(s) should be odd. If sequence, + its length should equal to dimensions. Defaults to 3. + up_kernel_size: upsampling convolution kernel size, the value(s) should be odd. If sequence, + its length should equal to dimensions. Defaults to 3. + num_res_units: number of residual units. Defaults to 0. + inter_channels: sequence of channels defining the blocks in the intermediate layer between encode and decode. + inter_dilations: defines the dilation value for each block of the intermediate layer. Defaults to 1. + num_inter_units: number of residual units for each block of the intermediate layer. Defaults to 0. + act: activation type and arguments. Defaults to PReLU. + norm: feature normalization type and arguments. Defaults to instance norm. + dropout: dropout ratio. Defaults to no dropout. + bias: whether to have a bias term in convolution blocks. Defaults to True. + According to `Performance Tuning Guide `_, + if a conv layer is directly followed by a batch norm layer, bias should be False. + + .. deprecated:: 0.6.0 + ``dimensions`` is deprecated, use ``spatial_dims`` instead. + + Examples:: from monai.networks.nets import VarAutoEncoder + # 3 layer network accepting images with dimensions (1, 32, 32) and using a latent vector with 2 values model = VarAutoEncoder( dimensions=2, in_shape=(32, 32), # image spatial shape @@ -44,10 +70,6 @@ class VarAutoEncoder(AutoEncoder): see also: - Variational autoencoder network with MedNIST Dataset https://github.com/Project-MONAI/tutorials/blob/master/modules/varautoencoder_mednist.ipynb - - .. deprecated:: 0.6.0 - ``dimensions`` is deprecated, use ``spatial_dims`` instead. - """ @deprecated_arg( From 04060ffeb527368c5057349cfe5c7c314a104561 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Oct 2021 11:02:33 +0000 Subject: [PATCH 74/89] [pre-commit.ci] pre-commit suggestions (#3069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit suggestions updates: - [github.com/asottile/pyupgrade: v2.27.0 → v2.29.0](https://github.com/asottile/pyupgrade/compare/v2.27.0...v2.29.0) * fixes #3071 Signed-off-by: Wenqi Li Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Wenqi Li --- .github/workflows/blossom-ci.yml | 4 ++-- .github/workflows/pythonapp-gpu.yml | 3 ++- .pre-commit-config.yaml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/blossom-ci.yml b/.github/workflows/blossom-ci.yml index 52bd4fddae..9c83e6fcf2 100644 --- a/.github/workflows/blossom-ci.yml +++ b/.github/workflows/blossom-ci.yml @@ -2,7 +2,7 @@ name: Blossom-CI on: issue_comment: - types: [created] + types: [created, edited] workflow_dispatch: inputs: platform: @@ -23,7 +23,7 @@ permissions: jobs: Authorization: - name: Authorization + name: Authorization (#${{ github.event.issue.number }}) runs-on: blossom outputs: args: ${{ env.args }} diff --git a/.github/workflows/pythonapp-gpu.yml b/.github/workflows/pythonapp-gpu.yml index 32d51e30e4..530ffdba2d 100644 --- a/.github/workflows/pythonapp-gpu.yml +++ b/.github/workflows/pythonapp-gpu.yml @@ -101,7 +101,8 @@ jobs: which python python -m pip install --upgrade pip wheel python -m pip install ${{ matrix.pytorch }} - python -m pip install -r requirements-dev.txt + # fixes preinstalled ruamel_yaml error from the docker image + python -m pip install -r requirements-dev.txt --ignore-installed ruamel_yaml python -m pip list - name: Run quick tests (GPU) run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 980a562610..970158194b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,7 +23,7 @@ repos: - id: detect-private-key - repo: https://github.com/asottile/pyupgrade - rev: v2.27.0 + rev: v2.29.0 hooks: - id: pyupgrade args: [--py36-plus] From 51b238019556f604632fb3e3490382058070720f Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Tue, 5 Oct 2021 17:56:10 +0100 Subject: [PATCH 75/89] update workflow (#3073) * update workflow Signed-off-by: Wenqi Li * fixes gpu tests Signed-off-by: Wenqi Li --- .github/workflows/blossom-ci.yml | 4 ++-- .github/workflows/pythonapp-gpu.yml | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/blossom-ci.yml b/.github/workflows/blossom-ci.yml index 9c83e6fcf2..52bd4fddae 100644 --- a/.github/workflows/blossom-ci.yml +++ b/.github/workflows/blossom-ci.yml @@ -2,7 +2,7 @@ name: Blossom-CI on: issue_comment: - types: [created, edited] + types: [created] workflow_dispatch: inputs: platform: @@ -23,7 +23,7 @@ permissions: jobs: Authorization: - name: Authorization (#${{ github.event.issue.number }}) + name: Authorization runs-on: blossom outputs: args: ${{ env.args }} diff --git a/.github/workflows/pythonapp-gpu.yml b/.github/workflows/pythonapp-gpu.yml index 530ffdba2d..edaa2487ce 100644 --- a/.github/workflows/pythonapp-gpu.yml +++ b/.github/workflows/pythonapp-gpu.yml @@ -100,9 +100,10 @@ jobs: run: | which python python -m pip install --upgrade pip wheel - python -m pip install ${{ matrix.pytorch }} # fixes preinstalled ruamel_yaml error from the docker image - python -m pip install -r requirements-dev.txt --ignore-installed ruamel_yaml + rm -rf $(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")/ruamel* + python -m pip install ${{ matrix.pytorch }} + python -m pip install -r requirements-dev.txt python -m pip list - name: Run quick tests (GPU) run: | From 57a26a0e85c1ab672a13dce9b3605c148420922c Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Tue, 5 Oct 2021 19:16:22 +0100 Subject: [PATCH 76/89] correct panelled example images (#3068) * correct panelled example images Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- .../transforms/utils_create_transform_ims.py | 110 +++++++++++------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/monai/transforms/utils_create_transform_ims.py b/monai/transforms/utils_create_transform_ims.py index daf93f8226..ca507b5c9c 100644 --- a/monai/transforms/utils_create_transform_ims.py +++ b/monai/transforms/utils_create_transform_ims.py @@ -246,10 +246,9 @@ def pre_process_data(data, ndim, is_map, is_post): def get_2d_slice(image, view, is_label): - """Remove channel and get the central slice of a 3D volume. If is already 2d, only remove channel. + """If image is 3d, get the central slice. If is already 2d, return as-is. If image is label, set 0 to np.nan. """ - image = image[0] # remove channel if image.ndim == 2: out = image else: @@ -280,28 +279,30 @@ def get_stacked_before_after(before, after, is_label=False): return [get_stacked_2d_ims(d, is_label) for d in (before, after)] -def save_image(images, labels, filename, transform_name, transform_args, im_sizes, colorbar=False): +def save_image(images, labels, filename, transform_name, transform_args, shapes, colorbar=False): """Save image to file, ensuring there's no whitespace around the edge.""" plt.rcParams.update({"font.family": "monospace"}) plt.style.use("dark_background") - fig, axes = plt.subplots(len(images), len(images[0])) - for row in range(len(images)): + nrow = len(images) # before and after (should always be 2) + ncol = len(images[0]) # num orthogonal views (either 1 or 3) + fig, axes = plt.subplots(nrow, ncol) + for row in range(nrow): vmin = min(i.min() for i in images[row]) vmax = max(i.max() for i in images[row]) - for col in range(len(images[0])): - ax = axes[row][col] + for col in range(ncol): + ax = axes[row][col] if ncol > 1 else axes[row] imshow = ax.imshow(images[row][col], cmap="gray", vmin=vmin, vmax=vmax) if colorbar and col == len(images[0]) - 1: plt.colorbar(imshow, ax=ax) if col == 0: y_label = "After" if row else "Before" - y_label += ("\n" + im_sizes[row]) if im_sizes[0] != im_sizes[1] else "" + y_label += ("\n" + shapes[row]) if shapes[0] != shapes[1] else "" ax.set_ylabel(y_label) ax.set_xticks([]) ax.set_yticks([]) ax.set_frame_on(False) if labels is not None: - ax.imshow(labels[row][col], cmap="hsv", alpha=0.9) + ax.imshow(labels[row][col], cmap="hsv", alpha=0.9, interpolation="nearest") # title is e.g., Flipd(keys=keys, spatial_axis=0) title = transform_name + "(" for k, v in transform_args.items(): @@ -326,28 +327,47 @@ def save_image(images, labels, filename, transform_name, transform_args, im_size plt.close(fig) -def get_image(data, is_map, key): +def get_images(data, is_label=False): """Get image. If is dictionary, extract key. If is list, stack. If both dictionary and list, do both. Also return the image size as string to be used im the imshow. If it's a list, return `N x (H,W,D)`. """ - # if list, extract. + # If not a list, convert if not isinstance(data, list): - data = data[key] if is_map else data - im_size = str(data.shape[1:]) - - # output is sometimes a list (e.g., RandSpatialCropSamples) - if isinstance(data, list): - data = [d[key] if is_map else d for d in data] - im_size = str(len(data)) + " x " + str(data[0].shape[1:]) - # if we can stack in square or cube (e.g., there are 4 or 8 examples), then do that - log2 = np.log2(len(data)) - if log2 % 1 == 0: - for i in range(int(log2)): - data = [np.concatenate(data[j : j + 2], axis=i + 1) for j in range(0, len(data), 2)] - data = data[0] - else: - data = np.hstack(data) - return data, im_size + data = [data] + key = CommonKeys.LABEL if is_label else CommonKeys.IMAGE + is_map = isinstance(data[0], dict) + # length of the list will be equal to number of samples produced. This will be 1 except for transforms that + # produce `num_samples`. + data = [d[key] if is_map else d for d in data] + data = [d[0] for d in data] # remove channel component + + # for each sample, create a list of the orthogonal views. If image is 2d, length will be 1. If 3d, there + # will be three orthogonal views + num_samples = len(data) + num_orthog_views = 3 if data[0].ndim == 3 else 1 + shape_str = (f"{num_samples} x " if num_samples > 1 else "") + str(data[0].shape) + for i in range(num_samples): + data[i] = [get_2d_slice(data[i], view, is_label) for view in range(num_orthog_views)] + + # we might need to panel the images. this happens if a transform produces e.g. 4 output images. In this case, we + # create a 2-by-2 grid from them. Output will be a list containing n_orthog_views, each element being either the image + # (if num_samples is 1) or the panelled image. + nrows = int(np.floor(num_samples ** 0.5)) + out = [] + if num_samples == 1: + out = data[0] + else: + for view in range(num_orthog_views): + result = np.asarray([d[view] for d in data]) + nindex, height, width = result.shape + ncols = nindex // nrows + # only implemented for square number of images (e.g. 4 images goes to a 2-by-2 panel) + if nindex != nrows * ncols: + raise NotImplementedError + # want result.shape = (height*nrows, width*ncols), have to be careful about striding + result = result.reshape(nrows, ncols, height, width).swapaxes(1, 2).reshape(height * nrows, width * ncols) + out.append(result) + return out, shape_str def create_transform_im( @@ -384,18 +404,18 @@ def create_transform_im( data_tr = transform(deepcopy(data_in)) - image_before, im_before_shape = get_image(data_in, is_map, CommonKeys.IMAGE) - image_after, im_after_shape = get_image(data_tr, is_map, CommonKeys.IMAGE) + images_before, before_shape = get_images(data_in) + images_after, after_shape = get_images(data_tr) + images = (images_before, images_after) + shapes = (before_shape, after_shape) - im_sizes = (im_before_shape, im_after_shape) - stacked_images = get_stacked_before_after(image_before, image_after) - stacked_labels = None + labels = None if is_map: - label_before, _ = get_image(data_in, is_map, CommonKeys.LABEL) - label_after, _ = get_image(data_tr, is_map, CommonKeys.LABEL) - stacked_labels = get_stacked_before_after(label_before, label_after, is_label=True) + labels_before, *_ = get_images(data_in, is_label=True) + labels_after, *_ = get_images(data_tr, is_label=True) + labels = (labels_before, labels_after) - save_image(stacked_images, stacked_labels, out_file, transform_name, transform_args, im_sizes, colorbar) + save_image(images, labels, out_file, transform_name, transform_args, shapes, colorbar) if update_doc: base_dir = pathlib.Path(__file__).parent.parent.parent @@ -571,29 +591,31 @@ def create_transform_im( create_transform_im(CenterSpatialCropd, dict(keys=keys, roi_size=(100, 100, 100)), data) create_transform_im(RandSpatialCrop, dict(roi_size=(100, 100, 100), random_size=False), data) create_transform_im(RandSpatialCropd, dict(keys=keys, roi_size=(100, 100, 100), random_size=False), data) - create_transform_im(RandSpatialCropSamples, dict(num_samples=8, roi_size=(100, 100, 100), random_size=False), data) + create_transform_im(RandSpatialCropSamples, dict(num_samples=4, roi_size=(100, 100, 100), random_size=False), data) create_transform_im( - RandSpatialCropSamplesd, dict(keys=keys, num_samples=8, roi_size=(100, 100, 100), random_size=False), data + RandSpatialCropSamplesd, dict(keys=keys, num_samples=4, roi_size=(100, 100, 100), random_size=False), data ) create_transform_im( - RandWeightedCrop, dict(spatial_size=(100, 100, 100), num_samples=8, weight_map=data[CommonKeys.IMAGE] > 0), data + RandWeightedCrop, dict(spatial_size=(100, 100, 100), num_samples=4, weight_map=data[CommonKeys.IMAGE] > 0), data ) create_transform_im( - RandWeightedCropd, dict(keys=keys, spatial_size=(100, 100, 100), num_samples=8, w_key=CommonKeys.IMAGE), data + RandWeightedCropd, dict(keys=keys, spatial_size=(100, 100, 100), num_samples=4, w_key=CommonKeys.IMAGE), data ) create_transform_im( RandCropByPosNegLabel, - dict(spatial_size=(100, 100, 100), label=data[CommonKeys.LABEL], neg=0, num_samples=8), + dict(spatial_size=(100, 100, 100), label=data[CommonKeys.LABEL], neg=0, num_samples=4), data, ) create_transform_im( RandCropByPosNegLabeld, - dict(keys=keys, spatial_size=(100, 100, 100), label_key=CommonKeys.LABEL, neg=0, num_samples=8), + dict(keys=keys, spatial_size=(100, 100, 100), label_key=CommonKeys.LABEL, neg=0, num_samples=4), data, ) create_transform_im( RandCropByLabelClasses, - dict(spatial_size=(100, 100, 100), label=data[CommonKeys.LABEL], num_classes=2, ratios=[0, 1], num_samples=8), + dict( + spatial_size=(100, 100, 100), label=data[CommonKeys.LABEL] > 0, num_classes=2, ratios=[0, 1], num_samples=4 + ), data, ) create_transform_im( @@ -604,7 +626,7 @@ def create_transform_im( label_key=CommonKeys.LABEL, num_classes=2, ratios=[0, 1], - num_samples=8, + num_samples=4, ), data, ) From 1651f1b003b0ffae8b615d191952ad65ad091277 Mon Sep 17 00:00:00 2001 From: Yiwen Li <44606435+kate-sann5100@users.noreply.github.com> Date: Tue, 5 Oct 2021 22:05:31 +0100 Subject: [PATCH 77/89] 2755 Add b-spline kernel option (#2847) * 2755 Add b-spline kernel option Signed-off-by: kate-sann5100 --- monai/losses/image_dissimilarity.py | 119 ++++++++++++++++--- tests/test_global_mutual_information_loss.py | 27 +++++ tests/test_reg_loss_integration.py | 3 + 3 files changed, 132 insertions(+), 17 deletions(-) diff --git a/monai/losses/image_dissimilarity.py b/monai/losses/image_dissimilarity.py index 9eb4540a6b..78f92303fc 100644 --- a/monai/losses/image_dissimilarity.py +++ b/monai/losses/image_dissimilarity.py @@ -16,6 +16,7 @@ from monai.networks.layers import gaussian_1d, separable_filtering from monai.utils import LossReduction, deprecated_arg +from monai.utils.module import look_up_option def make_rectangular_kernel(kernel_size: int) -> torch.Tensor: @@ -92,18 +93,15 @@ def __init__( if ndim is not None: spatial_dims = ndim self.ndim = spatial_dims - if self.ndim not in [1, 2, 3]: + if self.ndim not in {1, 2, 3}: raise ValueError(f"Unsupported ndim: {self.ndim}-d, only 1-d, 2-d, and 3-d inputs are supported") self.kernel_size = kernel_size if self.kernel_size % 2 == 0: raise ValueError(f"kernel_size must be odd, got {self.kernel_size}") - if kernel_type not in kernel_dict.keys(): - raise ValueError( - f'Unsupported kernel_type: {kernel_type}, available options are ["rectangular", "triangular", "gaussian"].' - ) - self.kernel = kernel_dict[kernel_type](self.kernel_size) + _kernel = look_up_option(kernel_type, kernel_dict) + self.kernel = _kernel(self.kernel_size) self.kernel_vol = self.get_kernel_vol() self.smooth_nr = float(smooth_nr) @@ -177,6 +175,7 @@ class GlobalMutualInformationLoss(_Loss): def __init__( self, + kernel_type: str = "gaussian", num_bins: int = 23, sigma_ratio: float = 0.5, reduction: Union[LossReduction, str] = LossReduction.MEAN, @@ -185,6 +184,19 @@ def __init__( ) -> None: """ Args: + kernel_type: {``"gaussian"``, ``"b-spline"``} + ``"gaussian"``: adapted from DeepReg + Reference: https://dspace.mit.edu/handle/1721.1/123142, Section 3.1, equation 3.1-3.5, Algorithm 1. + ``"b-spline"``: based on the method of Mattes et al [1,2] and adapted from ITK + References: + [1] "Nonrigid multimodality image registration" + D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank + Medical Imaging 2001: Image Processing, 2001, pp. 1609-1620. + [2] "PET-CT Image Registration in the Chest Using Free-form Deformations" + D. Mattes, D. R. Haynor, H. Vesselle, T. Lewellen and W. Eubank + IEEE Transactions in Medical Imaging. Vol.22, No.1, + January 2003. pp.120-128. + num_bins: number of bins for intensity sigma_ratio: a hyper param for gaussian function reduction: {``"none"``, ``"mean"``, ``"sum"``} @@ -201,20 +213,94 @@ def __init__( raise ValueError("num_bins must > 0, got {num_bins}") bin_centers = torch.linspace(0.0, 1.0, num_bins) # (num_bins,) sigma = torch.mean(bin_centers[1:] - bin_centers[:-1]) * sigma_ratio - self.preterm = 1 / (2 * sigma ** 2) - self.bin_centers = bin_centers[None, None, ...] + self.kernel_type = look_up_option(kernel_type, ["gaussian", "b-spline"]) + self.num_bins = num_bins + self.kernel_type = kernel_type + if self.kernel_type == "gaussian": + self.preterm = 1 / (2 * sigma ** 2) + self.bin_centers = bin_centers[None, None, ...] self.smooth_nr = float(smooth_nr) self.smooth_dr = float(smooth_dr) - def parzen_windowing(self, pred: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + def parzen_windowing( + self, pred: torch.Tensor, target: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: + if self.kernel_type == "gaussian": + pred_weight, pred_probability = self.parzen_windowing_gaussian(pred) + target_weight, target_probability = self.parzen_windowing_gaussian(target) + elif self.kernel_type == "b-spline": + # a third order BSpline kernel is used for the pred image intensity PDF. + pred_weight, pred_probability = self.parzen_windowing_b_spline(pred, order=3) + # a zero order (box car) BSpline kernel is used for the target image intensity PDF. + target_weight, target_probability = self.parzen_windowing_b_spline(target, order=0) + else: + raise ValueError + return pred_weight, pred_probability, target_weight, target_probability + + def parzen_windowing_b_spline(self, img: torch.Tensor, order: int) -> Tuple[torch.Tensor, torch.Tensor]: """ + Parzen windowing with b-spline kernel (adapted from ITK) + Args: - pred: the shape should be B[NDHW]. + img: the shape should be B[NDHW]. + order: int. + """ + + # Compute binsize for the histograms. + # + # The binsize for the image intensities needs to be adjusted so that + # we can avoid dealing with boundary conditions using the cubic + # spline as the Parzen window. We do this by increasing the size + # of the bins so that the joint histogram becomes "padded" at the + # borders. Because we are changing the binsize, + # we also need to shift the minimum by the padded amount in order to + # avoid minimum values filling in our padded region. + # + # Note that there can still be non-zero bin values in the padded region, + # it's just that these bins will never be a central bin for the Parzen + # window. + _max, _min = torch.max(img), torch.min(img) + padding = 2 + bin_size = (_max - _min) / (self.num_bins - 2 * padding) + norm_min = torch.div(_min, bin_size, rounding_mode="floor") - padding + + # assign bin/window index to each voxel + window_term = torch.div(img, bin_size) - norm_min # B[NDHW] + # make sure the extreme values are in valid (non-padded) bins + window_term = torch.clamp(window_term, padding, self.num_bins - padding - 1) # B[NDHW] + window_term = window_term.reshape(window_term.shape[0], -1, 1) # (batch, num_sample, 1) + bins = torch.arange(self.num_bins, device=window_term.device).reshape(1, 1, -1) # (1, 1, num_bins) + sample_bin_matrix = torch.abs(bins - window_term) # (batch, num_sample, num_bins) + + # b-spleen kernel + # (4 - 6 * abs ** 2 + 3 * abs ** 3) / 6 when 0 <= abs < 1 + # (2 - abs) ** 3 / 6 when 1 <= abs < 2 + weight = torch.zeros_like(sample_bin_matrix, dtype=torch.float) # (batch, num_sample, num_bins) + if order == 0: + weight = weight + (sample_bin_matrix < 0.5) + (sample_bin_matrix == 0.5) * 0.5 + elif order == 3: + weight = ( + weight + (4 - 6 * sample_bin_matrix ** 2 + 3 * sample_bin_matrix ** 3) * (sample_bin_matrix < 1) / 6 + ) + weight = weight + (2 - sample_bin_matrix) ** 3 * (sample_bin_matrix >= 1) * (sample_bin_matrix < 2) / 6 + else: + raise ValueError(f"Do not support b-spline {order}-order parzen windowing") + + weight = weight / torch.sum(weight, dim=-1, keepdim=True) # (batch, num_sample, num_bins) + probability = torch.mean(weight, dim=-2, keepdim=True) # (batch, 1, num_bins) + return weight, probability + + def parzen_windowing_gaussian(self, img: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: + """ + Parzen windowing with gaussian kernel (adapted from DeepReg implementation) + Note: the input is expected to range between 0 and 1 + Args: + img: the shape should be B[NDHW]. """ - pred = torch.clamp(pred, 0, 1) - pred = pred.reshape(pred.shape[0], -1, 1) # (batch, num_sample, 1) + img = torch.clamp(img, 0, 1) + img = img.reshape(img.shape[0], -1, 1) # (batch, num_sample, 1) weight = torch.exp( - -self.preterm.to(pred) * (pred - self.bin_centers.to(pred)) ** 2 + -self.preterm.to(img) * (img - self.bin_centers.to(img)) ** 2 ) # (batch, num_sample, num_bin) weight = weight / torch.sum(weight, dim=-1, keepdim=True) # (batch, num_sample, num_bin) probability = torch.mean(weight, dim=-2, keepdim=True) # (batch, 1, num_bin) @@ -230,11 +316,10 @@ def forward(self, pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor: """ if target.shape != pred.shape: raise ValueError(f"ground truth has differing shape ({target.shape}) from pred ({pred.shape})") - wa, pa = self.parzen_windowing(pred) # (batch, num_sample, num_bin), (batch, 1, num_bin) - wb, pb = self.parzen_windowing(target) # (batch, num_sample, num_bin), (batch, 1, num_bin) - pab = torch.bmm(wa.permute(0, 2, 1), wb).div(wa.shape[1]) # (batch, num_bins, num_bins) + wa, pa, wb, pb = self.parzen_windowing(pred, target) # (batch, num_sample, num_bin), (batch, 1, num_bin) - papb = torch.bmm(pa.permute(0, 2, 1), pb) # (batch, num_bins, num_bins) + pab = torch.bmm(wa.permute(0, 2, 1), wb.to(wa)).div(wa.shape[1]) # (batch, num_bins, num_bins) + papb = torch.bmm(pa.permute(0, 2, 1), pb.to(pa)) # (batch, num_bins, num_bins) mi = torch.sum( pab * torch.log((pab + self.smooth_nr) / (papb + self.smooth_dr) + self.smooth_dr), dim=(1, 2) ) # (batch) diff --git a/tests/test_global_mutual_information_loss.py b/tests/test_global_mutual_information_loss.py index 3373b59621..a688ea8394 100644 --- a/tests/test_global_mutual_information_loss.py +++ b/tests/test_global_mutual_information_loss.py @@ -16,6 +16,7 @@ from parameterized import parameterized from monai.losses.image_dissimilarity import GlobalMutualInformationLoss +from tests.utils import SkipIfBeforePyTorchVersion device = "cuda" if torch.cuda.is_available() else "cpu" @@ -45,6 +46,31 @@ }, -1.083999, ], + [ + {"kernel_type": "b-spline"}, + { + "pred": torch.arange(0, 3, dtype=torch.float, device=device)[None, :, None, None, None] + .expand(1, 3, 3, 3, 3) + .div(3), + "target": torch.arange(0, 3, dtype=torch.float, device=device)[None, :, None, None, None] + .expand(1, 3, 3, 3, 3) + .div(3), + }, + -1.0986018, + ], + [ + {"kernel_type": "b-spline"}, + { + "pred": torch.arange(0, 3, dtype=torch.float, device=device)[None, :, None, None, None] + .expand(1, 3, 3, 3, 3) + .div(3), + "target": torch.arange(0, 3, dtype=torch.float, device=device)[None, :, None, None, None] + .expand(1, 3, 3, 3, 3) + .div(3) + ** 2, + }, + -1.09861, + ], [ {}, { @@ -85,6 +111,7 @@ class TestGlobalMutualInformationLoss(unittest.TestCase): @parameterized.expand(TEST_CASES) + @SkipIfBeforePyTorchVersion((1, 9)) def test_shape(self, input_param, input_data, expected_val): result = GlobalMutualInformationLoss(**input_param).forward(**input_data) np.testing.assert_allclose(result.detach().cpu().numpy(), expected_val, rtol=1e-4) diff --git a/tests/test_reg_loss_integration.py b/tests/test_reg_loss_integration.py index 36e3a460a5..1578aa4888 100644 --- a/tests/test_reg_loss_integration.py +++ b/tests/test_reg_loss_integration.py @@ -17,6 +17,7 @@ from parameterized import parameterized from monai.losses import BendingEnergyLoss, GlobalMutualInformationLoss, LocalNormalizedCrossCorrelationLoss +from tests.utils import SkipIfBeforePyTorchVersion TEST_CASES = [ [BendingEnergyLoss, {}, ["pred"]], @@ -36,6 +37,7 @@ ["pred", "target"], ], [GlobalMutualInformationLoss, {"num_bins": 10}, ["pred", "target"]], + [GlobalMutualInformationLoss, {"kernel_type": "b-spline", "num_bins": 10}, ["pred", "target"]], ] @@ -51,6 +53,7 @@ def tearDown(self): torch.backends.cudnn.benchmark = True @parameterized.expand(TEST_CASES) + @SkipIfBeforePyTorchVersion((1, 9)) def test_convergence(self, loss_type, loss_args, forward_args): """ The goal of this test is to assess if the gradient of the loss function From 6cf6a8dabffca41eb1c2f97e29c60455f9268abf Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Wed, 6 Oct 2021 16:27:18 +0100 Subject: [PATCH 78/89] daily tests for mmar loading (#3066) * adds integration tests Signed-off-by: Wenqi Li * temp tests Signed-off-by: Wenqi Li * cache pip Signed-off-by: Wenqi Li * fixes conc Signed-off-by: Wenqi Li * Revert "temp tests" This reverts commit 5a931c6ce4b237f4269a7ca1317a5715845f1f20. Signed-off-by: Wenqi Li * print outcome Signed-off-by: Wenqi Li * fixes typo Signed-off-by: Wenqi Li * update based on comments Signed-off-by: Wenqi Li --- .github/workflows/cron-mmar.yml | 42 +++++++++++++++++++++++++++++++++ tests/ngc_mmar_loading.py | 37 +++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 .github/workflows/cron-mmar.yml create mode 100644 tests/ngc_mmar_loading.py diff --git a/.github/workflows/cron-mmar.yml b/.github/workflows/cron-mmar.yml new file mode 100644 index 0000000000..735c23117c --- /dev/null +++ b/.github/workflows/cron-mmar.yml @@ -0,0 +1,42 @@ +name: cron-mmar + +on: + schedule: + - cron: "0 2 * * *" # at 02:00 UTC + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +concurrency: + # automatically cancel the previously triggered workflows when there's a newer version + group: mmar-tests-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + cron-load: + if: github.repository == 'Project-MONAI/MONAI' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: cache weekly timestamp + id: pip-cache + run: echo "::set-output name=datew::$(date '+%Y-%V')" + - name: cache for pip + uses: actions/cache@v2 + id: cache + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ steps.pip-cache.outputs.datew }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip wheel + python -m pip install -r requirements-dev.txt + - name: Loading MMARs + run: | + # clean up temporary files + $(pwd)/runtests.sh --clean + # run tests + python -m tests.ngc_mmar_loading diff --git a/tests/ngc_mmar_loading.py b/tests/ngc_mmar_loading.py new file mode 100644 index 0000000000..8aa3859d87 --- /dev/null +++ b/tests/ngc_mmar_loading.py @@ -0,0 +1,37 @@ +# Copyright 2020 - 2021 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 os +import unittest + +import torch +from parameterized import parameterized + +from monai.apps.mmars import MODEL_DESC, load_from_mmar +from monai.config import print_debug_info + + +class TestAllDownloadingMMAR(unittest.TestCase): + def setUp(self): + print_debug_info() + self.test_dir = "./" + + @parameterized.expand((item,) for item in MODEL_DESC) + def test_loading_mmar(self, item): + pretrained_model = load_from_mmar(item=item, mmar_dir="./", map_location="cpu") + self.assertTrue(isinstance(pretrained_model, torch.nn.Modules)) + + def tearDown(self): + print(os.listdir(self.test_dir)) + + +if __name__ == "__main__": + unittest.main() From 07c5f53a93541142fcaab750e564b6c2d9494c72 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Thu, 7 Oct 2021 11:37:09 +0100 Subject: [PATCH 79/89] fixes mmar tests (#3077) Signed-off-by: Wenqi Li --- tests/ngc_mmar_loading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ngc_mmar_loading.py b/tests/ngc_mmar_loading.py index 8aa3859d87..c1ed22de5d 100644 --- a/tests/ngc_mmar_loading.py +++ b/tests/ngc_mmar_loading.py @@ -27,7 +27,7 @@ def setUp(self): @parameterized.expand((item,) for item in MODEL_DESC) def test_loading_mmar(self, item): pretrained_model = load_from_mmar(item=item, mmar_dir="./", map_location="cpu") - self.assertTrue(isinstance(pretrained_model, torch.nn.Modules)) + self.assertTrue(isinstance(pretrained_model, torch.nn.Module)) def tearDown(self): print(os.listdir(self.test_dir)) From af88eebe813e8576eca8f036731cf48012909457 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Thu, 7 Oct 2021 13:05:35 +0100 Subject: [PATCH 80/89] 2231 enhances a few transform backends (#3075) * fixes RandGaussianSmooth Signed-off-by: Wenqi Li * minor fixes Signed-off-by: Wenqi Li --- monai/transforms/intensity/array.py | 2 ++ monai/transforms/post/array.py | 11 ++++++---- monai/transforms/post/dictionary.py | 4 ++++ monai/transforms/utility/array.py | 6 +++--- monai/transforms/utility/dictionary.py | 5 +++-- monai/transforms/utils.py | 29 +++++++++++++++++--------- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index d2d8cac1ad..fd4aceb376 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1076,6 +1076,8 @@ class RandGaussianSmooth(RandomizableTransform): """ + backend = GaussianSmooth.backend + def __init__( self, sigma_x: Tuple[float, float] = (0.25, 1.5), diff --git a/monai/transforms/post/array.py b/monai/transforms/post/array.py index d20f368109..eb1860eed1 100644 --- a/monai/transforms/post/array.py +++ b/monai/transforms/post/array.py @@ -25,7 +25,7 @@ from monai.networks.layers import GaussianFilter from monai.transforms.transform import Transform from monai.transforms.utils import fill_holes, get_largest_connected_component_mask -from monai.utils import deprecated_arg, ensure_tuple, look_up_option +from monai.utils import TransformBackends, deprecated_arg, ensure_tuple, look_up_option __all__ = [ "Activations", @@ -57,6 +57,8 @@ class Activations(Transform): """ + backend = [TransformBackends.TORCH] + def __init__(self, sigmoid: bool = False, softmax: bool = False, other: Optional[Callable] = None) -> None: self.sigmoid = sigmoid self.softmax = softmax @@ -134,6 +136,8 @@ class AsDiscrete(Transform): """ + backend = [TransformBackends.TORCH] + @deprecated_arg("n_classes", since="0.6") def __init__( self, @@ -655,9 +659,8 @@ def __call__( prob_map = torch.as_tensor(prob_map, dtype=torch.float) self.filter.to(prob_map) prob_map = self.filter(prob_map) - else: - if not isinstance(prob_map, torch.Tensor): - prob_map = prob_map.copy() + elif not isinstance(prob_map, torch.Tensor): + prob_map = prob_map.copy() if isinstance(prob_map, torch.Tensor): prob_map = prob_map.detach().cpu().numpy() diff --git a/monai/transforms/post/dictionary.py b/monai/transforms/post/dictionary.py index 97ae4ec5a9..4ca07da949 100644 --- a/monai/transforms/post/dictionary.py +++ b/monai/transforms/post/dictionary.py @@ -86,6 +86,8 @@ class Activationsd(MapTransform): Add activation layers to the input data specified by `keys`. """ + backend = Activations.backend + def __init__( self, keys: KeysCollection, @@ -126,6 +128,8 @@ class AsDiscreted(MapTransform): Dictionary-based wrapper of :py:class:`monai.transforms.AsDiscrete`. """ + backend = AsDiscrete.backend + @deprecated_arg("n_classes", since="0.6") def __init__( self, diff --git a/monai/transforms/utility/array.py b/monai/transforms/utility/array.py index ef20cf6f3a..ffc3b99cb5 100644 --- a/monai/transforms/utility/array.py +++ b/monai/transforms/utility/array.py @@ -887,9 +887,7 @@ def __call__(self, img: np.ndarray) -> np.ndarray: if img.ndim == 4 and img.shape[0] == 1: img = np.squeeze(img, axis=0) - result = [] - # merge labels 1 (tumor non-enh) and 4 (tumor enh) to TC - result.append(np.logical_or(img == 1, img == 4)) + result = [np.logical_or(img == 1, img == 4)] # merge labels 1 (tumor non-enh) and 4 (tumor enh) and 2 (large edema) to WT result.append(np.logical_or(np.logical_or(img == 1, img == 4), img == 2)) # label 4 is ET @@ -1125,6 +1123,8 @@ class ToDevice(Transform): """ + backend = [TransformBackends.TORCH] + def __init__(self, device: Union[torch.device, str], **kwargs) -> None: """ Args: diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py index 0a4df58647..cefb654698 100644 --- a/monai/transforms/utility/dictionary.py +++ b/monai/transforms/utility/dictionary.py @@ -701,8 +701,7 @@ class SelectItemsd(MapTransform): """ def __call__(self, data): - result = {key: data[key] for key in self.key_iterator(data)} - return result + return {key: data[key] for key in self.key_iterator(data)} class SqueezeDimd(MapTransform): @@ -1465,6 +1464,8 @@ class ToDeviced(MapTransform): Dictionary-based wrapper of :py:class:`monai.transforms.ToDevice`. """ + backend = [TransformBackends.TORCH] + def __init__( self, keys: KeysCollection, diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 18657d0122..67fdb70a8c 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -1370,20 +1370,29 @@ def get_transform_backends(): continue unique_transforms.append(obj) - if isclass(obj) and issubclass(obj, Transform): - if n in [ - "Transform", + if ( + isclass(obj) + and issubclass(obj, Transform) + and n + not in [ + "BatchInverseTransform", + "Compose", + "Decollated", + "InvertD", "InvertibleTransform", "Lambda", "LambdaD", - "Compose", - "RandomizableTransform", + "MapTransform", "OneOf", - "BatchInverseTransform", - "InverteD", - ]: - continue - + "PadListDataCollate", + "RandLambda", + "RandLambdaD", + "RandTorchVisionD", + "RandomizableTransform", + "TorchVisionD", + "Transform", + ] + ): backends[n] = [ TransformBackends.TORCH in obj.backend, TransformBackends.NUMPY in obj.backend, From 8d07aad1a0727b12569f555db889a7e9243fc134 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Fri, 8 Oct 2021 00:07:56 +0800 Subject: [PATCH 81/89] [DLMED] add more tests (#3080) Signed-off-by: Nic Ma --- monai/utils/module.py | 20 ++++++++++++++------ tests/test_version_leq.py | 3 +++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/monai/utils/module.py b/monai/utils/module.py index 6a1f365504..ef019a8955 100644 --- a/monai/utils/module.py +++ b/monai/utils/module.py @@ -367,14 +367,22 @@ def get_torch_version_tuple(): return tuple(int(x) for x in torch.__version__.split(".")[:2]) -def version_leq(lhs, rhs): - """Returns True if version `lhs` is earlier or equal to `rhs`.""" +def version_leq(lhs: str, rhs: str): + """ + Returns True if version `lhs` is earlier or equal to `rhs`. + + Args: + lhs: version name to compare with `rhs`, return True if earlier or equal to `rhs`. + rhs: version name to compare with `lhs`, return True if later or equal to `lhs`. + + """ + lhs, rhs = str(lhs), str(rhs) ver, has_ver = optional_import("pkg_resources", name="parse_version") if has_ver: return ver(lhs) <= ver(rhs) - def _try_cast(val): + def _try_cast(val: str): val = val.strip() try: m = match("(\\d+)(.*)", val) @@ -390,10 +398,10 @@ def _try_cast(val): rhs = rhs.split("+", 1)[0] # parse the version strings in this basic way without `packaging` package - lhs = map(_try_cast, lhs.split(".")) - rhs = map(_try_cast, rhs.split(".")) + lhs_ = map(_try_cast, lhs.split(".")) + rhs_ = map(_try_cast, rhs.split(".")) - for l, r in zip(lhs, rhs): + for l, r in zip(lhs_, rhs_): if l != r: if isinstance(l, int) and isinstance(r, int): return l < r diff --git a/tests/test_version_leq.py b/tests/test_version_leq.py index a1913069d3..042a561a90 100644 --- a/tests/test_version_leq.py +++ b/tests/test_version_leq.py @@ -67,6 +67,9 @@ def _pairwise(iterable): ("0post1", "0.4post1"), ("2.1.0-rc1", "2.1.0"), ("2.1dev", "2.1a0"), + (1.6, "1.6.0"), + ("1.6.0", 1.6), + (1.6, 1.7), ) + tuple(_pairwise(reversed(torture.split()))) From 6a2086d21baf4b60c2ab3d400ed5c97cf24a0da9 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Thu, 7 Oct 2021 21:11:13 +0100 Subject: [PATCH 82/89] 2357 Fixes unit test cases to run on GA100 (#3072) * relax atol for a100 Signed-off-by: Wenqi Li * temp tests Signed-off-by: Wenqi Li * fixes #3071 Signed-off-by: Wenqi Li * remove temp tests Signed-off-by: Wenqi Li * fixes tests Signed-off-by: Wenqi Li * update tests Signed-off-by: Wenqi Li * add tf32 tests Signed-off-by: Wenqi Li * fixes rtol wit tf32 Signed-off-by: Wenqi Li * detect tf32 Signed-off-by: Wenqi Li * update flag Signed-off-by: Wenqi Li * fixes testing util Signed-off-by: Wenqi Li --- monai/__init__.py | 2 +- tests/test_affine_grid.py | 6 ++-- tests/test_affine_transform.py | 27 ++++++++------- tests/test_create_grid_and_affine.py | 4 +-- tests/test_global_mutual_information_loss.py | 2 +- tests/test_lltm.py | 8 +++-- tests/test_rand_affine.py | 6 ++-- tests/test_rand_affine_grid.py | 6 ++-- tests/test_rand_affined.py | 6 ++-- tests/test_rand_elastic_2d.py | 6 ++-- tests/test_rand_elasticd_2d.py | 6 ++-- tests/utils.py | 36 +++++++++++++++++--- 12 files changed, 80 insertions(+), 35 deletions(-) diff --git a/monai/__init__.py b/monai/__init__.py index 7ab30bcae7..5043208b9c 100644 --- a/monai/__init__.py +++ b/monai/__init__.py @@ -26,7 +26,7 @@ __basedir__ = os.path.dirname(__file__) -if not (sys.version_info.major == PY_REQUIRED_MAJOR and sys.version_info.minor >= PY_REQUIRED_MINOR): +if sys.version_info.major != PY_REQUIRED_MAJOR or sys.version_info.minor < PY_REQUIRED_MINOR: raise RuntimeError( "MONAI requires Python {}.{} or higher. But the current Python is: {}".format( PY_REQUIRED_MAJOR, PY_REQUIRED_MINOR, sys.version diff --git a/tests/test_affine_grid.py b/tests/test_affine_grid.py index 972cf20a1f..9bf2bcf90e 100644 --- a/tests/test_affine_grid.py +++ b/tests/test_affine_grid.py @@ -16,7 +16,7 @@ from parameterized import parameterized from monai.transforms import AffineGrid -from tests.utils import TEST_NDARRAYS, assert_allclose +from tests.utils import TEST_NDARRAYS, assert_allclose, is_tf32_env TESTS = [] for p in TEST_NDARRAYS: @@ -107,6 +107,8 @@ ] ) +_rtol = 5e-2 if is_tf32_env() else 1e-4 + class TestAffineGrid(unittest.TestCase): @parameterized.expand(TESTS) @@ -115,7 +117,7 @@ def test_affine_grid(self, input_param, input_data, expected_val): result, _ = g(**input_data) if "device" in input_data: self.assertEqual(result.device, input_data[device]) - assert_allclose(result, expected_val, type_test=False, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, type_test=False, rtol=_rtol) if __name__ == "__main__": diff --git a/tests/test_affine_transform.py b/tests/test_affine_transform.py index 42af58be73..ef39c297ce 100644 --- a/tests/test_affine_transform.py +++ b/tests/test_affine_transform.py @@ -17,6 +17,9 @@ from monai.networks import normalize_transform, to_norm_affine from monai.networks.layers import AffineTransform +from tests.utils import is_tf32_env + +_rtol = 1e-4 if not is_tf32_env() else 5e-3 TEST_NORM_CASES = [ [(4, 5), True, [[[0.666667, 0, -1], [0, 0.5, -1], [0, 0, 1]]]], @@ -95,7 +98,7 @@ def test_to_norm_affine(self, affine, src_size, dst_size, align_corners, expecte affine = torch.as_tensor(affine, device=torch.device("cuda:0"), dtype=torch.float32) new_affine = to_norm_affine(affine, src_size, dst_size, align_corners) new_affine = new_affine.detach().cpu().numpy() - np.testing.assert_allclose(new_affine, expected, atol=1e-4) + np.testing.assert_allclose(new_affine, expected, atol=1e-5, rtol=_rtol) @parameterized.expand(TEST_ILL_TO_NORM_AFFINE_CASES) def test_to_norm_affine_ill(self, affine, src_size, dst_size, align_corners): @@ -113,7 +116,7 @@ def test_affine_shift(self): out = AffineTransform()(image, affine) out = out.detach().cpu().numpy() expected = [[[[0, 4, 1, 3], [0, 7, 6, 8], [0, 3, 5, 3]]]] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=1e-5, rtol=_rtol) def test_affine_shift_1(self): affine = torch.as_tensor([[1.0, 0.0, -1.0], [0.0, 1.0, -1.0]]) @@ -121,7 +124,7 @@ def test_affine_shift_1(self): out = AffineTransform()(image, affine) out = out.detach().cpu().numpy() expected = [[[[0, 0, 0, 0], [0, 4, 1, 3], [0, 7, 6, 8]]]] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=1e-5, rtol=_rtol) def test_affine_shift_2(self): affine = torch.as_tensor([[1.0, 0.0, -1.0], [0.0, 1.0, 0.0]]) @@ -129,28 +132,28 @@ def test_affine_shift_2(self): out = AffineTransform()(image, affine) out = out.detach().cpu().numpy() expected = [[[[0, 0, 0, 0], [4, 1, 3, 2], [7, 6, 8, 5]]]] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=1e-5, rtol=_rtol) def test_zoom(self): affine = torch.as_tensor([[1.0, 0.0, 0.0], [0.0, 2.0, 0.0]]) image = torch.arange(1.0, 13.0).view(1, 1, 3, 4).to(device=torch.device("cpu:0")) out = AffineTransform((3, 2))(image, affine) expected = [[[[1, 3], [5, 7], [9, 11]]]] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=1e-5, rtol=_rtol) def test_zoom_1(self): affine = torch.as_tensor([[2.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) image = torch.arange(1.0, 13.0).view(1, 1, 3, 4).to(device=torch.device("cpu:0")) out = AffineTransform()(image, affine, (1, 4)) expected = [[[[1, 2, 3, 4]]]] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=_rtol) def test_zoom_2(self): affine = torch.as_tensor([[2.0, 0.0, 0.0], [0.0, 2.0, 0.0]], dtype=torch.float32) image = torch.arange(1.0, 13.0).view(1, 1, 3, 4).to(device=torch.device("cpu:0")) out = AffineTransform((1, 2))(image, affine) expected = [[[[1, 3]]]] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=1e-5, rtol=_rtol) def test_affine_transform_minimum(self): t = np.pi / 3 @@ -169,7 +172,7 @@ def test_affine_transform_minimum(self): ] ] ] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=1e-3, rtol=_rtol) def test_affine_transform_2d(self): t = np.pi / 3 @@ -188,7 +191,7 @@ def test_affine_transform_2d(self): ] ] ] - np.testing.assert_allclose(out, expected, atol=1e-5) + np.testing.assert_allclose(out, expected, atol=1e-3, rtol=_rtol) if torch.cuda.is_available(): affine = torch.as_tensor(affine, device=torch.device("cuda:0"), dtype=torch.float32) @@ -205,7 +208,7 @@ def test_affine_transform_2d(self): ] ] ] - np.testing.assert_allclose(out, expected, atol=1e-4) + np.testing.assert_allclose(out, expected, atol=5e-3) def test_affine_transform_3d(self): t = np.pi / 3 @@ -231,7 +234,7 @@ def test_affine_transform_3d(self): ] ], ] - np.testing.assert_allclose(out, expected, atol=1e-4) + np.testing.assert_allclose(out, expected, atol=1e-4, rtol=_rtol) if torch.cuda.is_available(): affine = torch.as_tensor(affine, device=torch.device("cuda:0"), dtype=torch.float32) @@ -255,7 +258,7 @@ def test_affine_transform_3d(self): ] ], ] - np.testing.assert_allclose(out, expected, atol=1e-4) + np.testing.assert_allclose(out, expected, atol=5e-3) def test_ill_affine_transform(self): with self.assertRaises(ValueError): # image too small diff --git a/tests/test_create_grid_and_affine.py b/tests/test_create_grid_and_affine.py index b53eaa5b9d..cd8d75f63e 100644 --- a/tests/test_create_grid_and_affine.py +++ b/tests/test_create_grid_and_affine.py @@ -22,7 +22,7 @@ create_shear, create_translate, ) -from tests.utils import assert_allclose +from tests.utils import assert_allclose, is_tf32_env class TestCreateGrid(unittest.TestCase): @@ -162,7 +162,7 @@ def test_assert(func, params, expected): m = func(*params, device="cuda:0", backend="torch") else: m = func(*params, backend=b) - assert_allclose(m, expected, type_test=False, atol=1e-7) + assert_allclose(m, expected, type_test=False, rtol=1e-2 if is_tf32_env() else 1e-5, atol=1e-5) class TestCreateAffine(unittest.TestCase): diff --git a/tests/test_global_mutual_information_loss.py b/tests/test_global_mutual_information_loss.py index a688ea8394..6a658563bc 100644 --- a/tests/test_global_mutual_information_loss.py +++ b/tests/test_global_mutual_information_loss.py @@ -114,7 +114,7 @@ class TestGlobalMutualInformationLoss(unittest.TestCase): @SkipIfBeforePyTorchVersion((1, 9)) def test_shape(self, input_param, input_data, expected_val): result = GlobalMutualInformationLoss(**input_param).forward(**input_data) - np.testing.assert_allclose(result.detach().cpu().numpy(), expected_val, rtol=1e-4) + np.testing.assert_allclose(result.detach().cpu().numpy(), expected_val, rtol=1e-3, atol=1e-3) def test_ill_shape(self): loss = GlobalMutualInformationLoss() diff --git a/tests/test_lltm.py b/tests/test_lltm.py index f1311379bc..4186c91246 100644 --- a/tests/test_lltm.py +++ b/tests/test_lltm.py @@ -15,7 +15,9 @@ from parameterized import parameterized from monai.networks.layers import LLTM -from tests.utils import SkipIfNoModule +from tests.utils import SkipIfNoModule, is_tf32_env + +_rtol = 0.001 if is_tf32_env() else 0.0001 TEST_CASE_1 = [ {"input_features": 32, "state_size": 2}, @@ -50,8 +52,8 @@ def test_value_cuda(self, input_param, expected_h, expected_c): new_h, new_c = lltm(x, (h, c)) (new_h.sum() + new_c.sum()).backward() - torch.testing.assert_allclose(new_h, expected_h.to(device), rtol=0.0001, atol=1e-04) - torch.testing.assert_allclose(new_c, expected_c.to(device), rtol=0.0001, atol=1e-04) + torch.testing.assert_allclose(new_h, expected_h.to(device), rtol=_rtol, atol=0.001) + torch.testing.assert_allclose(new_c, expected_c.to(device), rtol=_rtol, atol=0.001) if __name__ == "__main__": diff --git a/tests/test_rand_affine.py b/tests/test_rand_affine.py index c88aa538ed..96322813c9 100644 --- a/tests/test_rand_affine.py +++ b/tests/test_rand_affine.py @@ -17,7 +17,9 @@ from monai.transforms import RandAffine from monai.utils.type_conversion import convert_data_type -from tests.utils import TEST_NDARRAYS, assert_allclose +from tests.utils import TEST_NDARRAYS, assert_allclose, is_tf32_env + +_rtol = 1e-3 if is_tf32_env() else 1e-4 TESTS = [] for p in TEST_NDARRAYS: @@ -141,7 +143,7 @@ def test_rand_affine(self, input_param, input_data, expected_val): result = g(**input_data) if input_param.get("cache_grid", False): self.assertTrue(g._cached_grid is not None) - assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, rtol=_rtol, atol=1e-4) def test_ill_cache(self): with self.assertWarns(UserWarning): diff --git a/tests/test_rand_affine_grid.py b/tests/test_rand_affine_grid.py index 4fb534aba1..ade615cd65 100644 --- a/tests/test_rand_affine_grid.py +++ b/tests/test_rand_affine_grid.py @@ -16,7 +16,9 @@ from parameterized import parameterized from monai.transforms import RandAffineGrid -from tests.utils import TEST_NDARRAYS, assert_allclose +from tests.utils import TEST_NDARRAYS, assert_allclose, is_tf32_env + +_rtol = 1e-1 if is_tf32_env else 1e-4 TESTS = [] for p in TEST_NDARRAYS: @@ -201,7 +203,7 @@ def test_rand_affine_grid(self, input_param, input_data, expected_val): result = g(**input_data) if "device" in input_data: self.assertEqual(result.device, input_data[device]) - assert_allclose(result, expected_val, type_test=False, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, type_test=False, rtol=_rtol, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_rand_affined.py b/tests/test_rand_affined.py index 0109175b16..651452ab07 100644 --- a/tests/test_rand_affined.py +++ b/tests/test_rand_affined.py @@ -17,7 +17,9 @@ from monai.transforms import RandAffined from monai.utils import GridSampleMode -from tests.utils import TEST_NDARRAYS, assert_allclose +from tests.utils import TEST_NDARRAYS, assert_allclose, is_tf32_env + +_rtol = 1e-3 if is_tf32_env() else 1e-4 TESTS = [] for p in TEST_NDARRAYS: @@ -209,7 +211,7 @@ def test_rand_affined(self, input_param, input_data, expected_val): if "_transforms" in key: continue expected = expected_val[key] if isinstance(expected_val, dict) else expected_val - assert_allclose(result, expected, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected, rtol=_rtol, atol=1e-3) g.set_random_state(4) res = g(input_data) diff --git a/tests/test_rand_elastic_2d.py b/tests/test_rand_elastic_2d.py index c414eb1ffd..22920d0f35 100644 --- a/tests/test_rand_elastic_2d.py +++ b/tests/test_rand_elastic_2d.py @@ -16,7 +16,9 @@ from parameterized import parameterized from monai.transforms import Rand2DElastic -from tests.utils import TEST_NDARRAYS, assert_allclose +from tests.utils import TEST_NDARRAYS, assert_allclose, is_tf32_env + +_rtol = 5e-3 if is_tf32_env() else 1e-4 TESTS = [] for p in TEST_NDARRAYS: @@ -110,7 +112,7 @@ def test_rand_2d_elastic(self, input_param, input_data, expected_val): g = Rand2DElastic(**input_param) g.set_random_state(123) result = g(**input_data) - assert_allclose(result, expected_val, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected_val, rtol=_rtol, atol=1e-4) if __name__ == "__main__": diff --git a/tests/test_rand_elasticd_2d.py b/tests/test_rand_elasticd_2d.py index 84f18120e1..77e6489d50 100644 --- a/tests/test_rand_elasticd_2d.py +++ b/tests/test_rand_elasticd_2d.py @@ -16,7 +16,9 @@ from parameterized import parameterized from monai.transforms import Rand2DElasticd -from tests.utils import TEST_NDARRAYS, assert_allclose +from tests.utils import TEST_NDARRAYS, assert_allclose, is_tf32_env + +_rtol = 5e-3 if is_tf32_env() else 1e-4 TESTS = [] for p in TEST_NDARRAYS: @@ -164,7 +166,7 @@ def test_rand_2d_elasticd(self, input_param, input_data, expected_val): for key in res: result = res[key] expected = expected_val[key] if isinstance(expected_val, dict) else expected_val - assert_allclose(result, expected, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected, rtol=_rtol, atol=5e-3) if __name__ == "__main__": diff --git a/tests/utils.py b/tests/utils.py index b7e32068c3..a3d52ae2cb 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -25,7 +25,7 @@ from io import BytesIO from subprocess import PIPE, Popen from typing import Callable, Optional, Tuple -from urllib.error import ContentTooShortError, HTTPError, URLError +from urllib.error import HTTPError, URLError import numpy as np import torch @@ -43,6 +43,7 @@ nib, _ = optional_import("nibabel") quick_test_var = "QUICKTEST" +_tf32_enabled = None def clone(data: NdarrayTensor) -> NdarrayTensor: @@ -94,16 +95,43 @@ def assert_allclose( def test_pretrained_networks(network, input_param, device): try: - net = network(**input_param).to(device) - except (URLError, HTTPError, ContentTooShortError) as e: + return network(**input_param).to(device) + except (URLError, HTTPError) as e: raise unittest.SkipTest(e) from e - return net def test_is_quick(): return os.environ.get(quick_test_var, "").lower() == "true" +def is_tf32_env(): + """ + The environment variable NVIDIA_TF32_OVERRIDE=0 will override any defaults + or programmatic configuration of NVIDIA libraries, and consequently, + cuBLAS will not accelerate FP32 computations with TF32 tensor cores. + """ + global _tf32_enabled + if _tf32_enabled is None: + _tf32_enabled = False + if ( + torch.cuda.is_available() + and not version_leq(f"{torch.version.cuda}", "10.100") # at least 11.0 + and os.environ.get("NVIDIA_TF32_OVERRIDE", "1") != "0" + and torch.cuda.device_count() > 0 + ): + try: + # with TF32 enabled, the speed is ~8x faster, but the precision has ~2 digits less in the result + g_gpu = torch.Generator(device="cuda") + g_gpu.manual_seed(2147483647) + a_full = torch.randn(1024, 1024, dtype=torch.double, device="cuda", generator=g_gpu) + b_full = torch.randn(1024, 1024, dtype=torch.double, device="cuda", generator=g_gpu) + _tf32_enabled = (a_full.float() @ b_full.float() - a_full @ b_full).abs().max().item() > 0.001 # 0.1713 + except BaseException: + pass + print(f"tf32 enabled: {_tf32_enabled}") + return _tf32_enabled + + def skip_if_quick(obj): """ Skip the unit tests if environment variable `quick_test_var=true`. From 932abbebf77a03762ae4f9e3c2985e932d318538 Mon Sep 17 00:00:00 2001 From: Yiheng Wang <68361391+yiheng-wang-nv@users.noreply.github.com> Date: Fri, 8 Oct 2021 16:28:41 +0800 Subject: [PATCH 83/89] fix densenet264 error (#3081) Signed-off-by: Yiheng Wang --- monai/networks/nets/densenet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monai/networks/nets/densenet.py b/monai/networks/nets/densenet.py index 6a2c2fb4e1..e6d1cc68e6 100644 --- a/monai/networks/nets/densenet.py +++ b/monai/networks/nets/densenet.py @@ -375,7 +375,7 @@ def __init__( self, init_features: int = 64, growth_rate: int = 32, - block_config: Sequence[int] = (6, 12, 48, 32), + block_config: Sequence[int] = (6, 12, 64, 48), pretrained: bool = False, progress: bool = True, **kwargs, From 6169c5d9e6dace574c986a801cd6e2b47f2fa51b Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Fri, 8 Oct 2021 11:26:39 +0100 Subject: [PATCH 84/89] fixes figures (#3083) Signed-off-by: Wenqi Li --- .../transforms/utils_create_transform_ims.py | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/monai/transforms/utils_create_transform_ims.py b/monai/transforms/utils_create_transform_ims.py index ca507b5c9c..b842c41572 100644 --- a/monai/transforms/utils_create_transform_ims.py +++ b/monai/transforms/utils_create_transform_ims.py @@ -268,8 +268,7 @@ def get_stacked_2d_ims(im, is_label): Requires that all images be same size, but this is taken care of by the `SpatialPadd` earlier. """ - out = [get_2d_slice(im, i, is_label) for i in range(3)] - return out + return [get_2d_slice(im, i, is_label) for i in range(3)] def get_stacked_before_after(before, after, is_label=False): @@ -285,21 +284,32 @@ def save_image(images, labels, filename, transform_name, transform_args, shapes, plt.style.use("dark_background") nrow = len(images) # before and after (should always be 2) ncol = len(images[0]) # num orthogonal views (either 1 or 3) - fig, axes = plt.subplots(nrow, ncol) + # roughly estimate the height_ratios of the first:second row + hs = [float(r[0].shape[0]) for r in images] + fig = plt.figure(tight_layout=True) + spec = fig.add_gridspec(nrow, ncol, hspace=0, wspace=0, height_ratios=hs) for row in range(nrow): vmin = min(i.min() for i in images[row]) vmax = max(i.max() for i in images[row]) for col in range(ncol): - ax = axes[row][col] if ncol > 1 else axes[row] + ax = fig.add_subplot(spec[row, col]) imshow = ax.imshow(images[row][col], cmap="gray", vmin=vmin, vmax=vmax) - if colorbar and col == len(images[0]) - 1: + ax.set_aspect("equal") + if colorbar and col == ncol - 1: plt.colorbar(imshow, ax=ax) if col == 0: y_label = "After" if row else "Before" y_label += ("\n" + shapes[row]) if shapes[0] != shapes[1] else "" ax.set_ylabel(y_label) + # print yticks for the right most column + if col != ncol - 1 or colorbar: + ax.set_yticks([]) + else: + ax.yaxis.tick_right() + for n, label in enumerate(ax.yaxis.get_ticklabels()): + if n > 2: + label.set_visible(False) ax.set_xticks([]) - ax.set_yticks([]) ax.set_frame_on(False) if labels is not None: ax.imshow(labels[row][col], cmap="hsv", alpha=0.9, interpolation="nearest") @@ -322,7 +332,6 @@ def save_image(images, labels, filename, transform_name, transform_args, shapes, # shorten the lines title = textwrap.fill(title, 50, break_long_words=False, subsequent_indent=" " * (len(transform_name) + 1)) fig.suptitle(title, x=0.1, horizontalalignment="left") - plt.tight_layout() fig.savefig(filename) plt.close(fig) @@ -349,14 +358,14 @@ def get_images(data, is_label=False): for i in range(num_samples): data[i] = [get_2d_slice(data[i], view, is_label) for view in range(num_orthog_views)] - # we might need to panel the images. this happens if a transform produces e.g. 4 output images. In this case, we - # create a 2-by-2 grid from them. Output will be a list containing n_orthog_views, each element being either the image - # (if num_samples is 1) or the panelled image. - nrows = int(np.floor(num_samples ** 0.5)) out = [] if num_samples == 1: out = data[0] else: + # we might need to panel the images. this happens if a transform produces e.g. 4 output images. + # In this case, we create a 2-by-2 grid from them. Output will be a list containing n_orthog_views, + # each element being either the image (if num_samples is 1) or the panelled image. + nrows = int(np.floor(num_samples ** 0.5)) for view in range(num_orthog_views): result = np.asarray([d[view] for d in data]) nindex, height, width = result.shape From 54bd9db6a131602850bd9efba75a500a2d1c2984 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Fri, 8 Oct 2021 15:01:47 +0100 Subject: [PATCH 85/89] fixes rst format issues (#3088) Signed-off-by: Wenqi Li --- .gitignore | 1 + docs/source/transforms.rst | 50 +++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 7444d7f2f9..13155c3088 100644 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,4 @@ tests/testing_data/*.tiff # VSCode .vscode/ +*.zip diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index 5300ea758e..b0c25ddfdb 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -386,39 +386,39 @@ Intensity """""""""""""""""""""" .. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandKSpaceSpikeNoise.png :alt: example of RandKSpaceSpikeNoise - .. autoclass:: RandKSpaceSpikeNoise - :members: - :special-members: __call__ +.. autoclass:: RandKSpaceSpikeNoise + :members: + :special-members: __call__ `RandCoarseTransform` """"""""""""""""""""" - .. autoclass:: RandCoarseTransform - :members: - :special-members: __call__ +.. autoclass:: RandCoarseTransform + :members: + :special-members: __call__ `RandCoarseDropout` """"""""""""""""""" .. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCoarseDropout.png :alt: example of RandCoarseDropout - .. autoclass:: RandCoarseDropout - :members: - :special-members: __call__ +.. autoclass:: RandCoarseDropout + :members: + :special-members: __call__ `RandCoarseShuffle` """"""""""""""""""" .. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/RandCoarseShuffle.png :alt: example of RandCoarseShuffle - .. autoclass:: RandCoarseShuffle - :members: - :special-members: __call__ +.. autoclass:: RandCoarseShuffle + :members: + :special-members: __call__ `HistogramNormalize` """""""""""""""""""" .. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/HistogramNormalize.png :alt: example of HistogramNormalize - .. autoclass:: HistogramNormalize - :members: - :special-members: __call__ +.. autoclass:: HistogramNormalize + :members: + :special-members: __call__ IO ^^ @@ -843,13 +843,13 @@ Utility `IntensityStats` """""""""""""""" - .. autoclass:: IntensityStats - :members: - :special-members: __call__ +.. autoclass:: IntensityStats + :members: + :special-members: __call__ `ToDevice` """""""""" - .. autoclass:: ToDevice +.. autoclass:: ToDevice :members: :special-members: __call__ @@ -1205,9 +1205,9 @@ Intensity (Dict) """"""""""""""""""""" .. image:: https://github.com/Project-MONAI/DocImages/raw/main/transforms/HistogramNormalized.png :alt: example of HistogramNormalized - .. autoclass:: HistogramNormalized - :members: - :special-members: __call__ +.. autoclass:: HistogramNormalized + :members: + :special-members: __call__ IO (Dict) @@ -1622,9 +1622,9 @@ Utility (Dict) `ToDeviced` """"""""""" - .. autoclass:: ToDeviced - :members: - :special-members: __call__ +.. autoclass:: ToDeviced + :members: + :special-members: __call__ `CuCIMd` """""""" From 3b109f0be93bc205d38d04ce41788278eefd78e9 Mon Sep 17 00:00:00 2001 From: Wenqi Li Date: Fri, 8 Oct 2021 16:56:48 +0100 Subject: [PATCH 86/89] oneof doc (#3090) Signed-off-by: Wenqi Li --- docs/source/transforms.rst | 5 +++++ monai/transforms/compose.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index b0c25ddfdb..65c1f7efb6 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -53,6 +53,11 @@ Generic Interfaces .. autoclass:: Decollated :members: +`OneOf` +^^^^^^^ +.. autoclass:: OneOf + :members: + Vanilla Transforms ------------------ diff --git a/monai/transforms/compose.py b/monai/transforms/compose.py index 38aa2199c6..2405530ef3 100644 --- a/monai/transforms/compose.py +++ b/monai/transforms/compose.py @@ -181,7 +181,7 @@ class OneOf(Compose): weights: probabilities corresponding to each callable in transforms. Probabilities are normalized to sum to one. - OneOf inherits from Compose and uses args map_items and unpack_items in + ``OneOf`` inherits from ``Compose`` and uses args ``map_items`` and ``unpack_items`` in the same way. """ From 484bb5c0714fbcd30acb8c9da9aeb67d75fe32fd Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Sat, 9 Oct 2021 01:50:01 +0800 Subject: [PATCH 87/89] 3082 Enhance heavy random computation of transforms (#3086) * [DLMED] enhance random computation Signed-off-by: Nic Ma * [DLMED] update according to comments Signed-off-by: Nic Ma Co-authored-by: Wenqi Li --- monai/transforms/intensity/array.py | 19 ++++++++++--------- monai/transforms/intensity/dictionary.py | 21 ++++++++------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index fd4aceb376..86a865c237 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -90,27 +90,28 @@ class RandGaussianNoise(RandomizableTransform): backend = [TransformBackends.TORCH, TransformBackends.NUMPY] - def __init__(self, prob: float = 0.1, mean: Union[Sequence[float], float] = 0.0, std: float = 0.1) -> None: + def __init__(self, prob: float = 0.1, mean: float = 0.0, std: float = 0.1) -> None: RandomizableTransform.__init__(self, prob) self.mean = mean self.std = std - self._noise: np.ndarray - def randomize(self, im_shape: Sequence[int]) -> None: + def randomize(self, data: Any) -> None: super().randomize(None) - self._noise = self.R.normal(self.mean, self.R.uniform(0, self.std), size=im_shape) + self._rand_std = self.R.uniform(0, self.std) + + def _add_noise(self, img: NdarrayOrTensor) -> NdarrayOrTensor: + noise = self.R.normal(self.mean, self._rand_std, size=img.shape) + noise_, *_ = convert_to_dst_type(noise, img) + return img + noise_ def __call__(self, img: NdarrayOrTensor) -> NdarrayOrTensor: """ Apply the transform to `img`. """ - self.randomize(img.shape) - if self._noise is None: - raise RuntimeError("randomized factor should not be None.") + self.randomize(None) if not self._do_transform: return img - noise, *_ = convert_to_dst_type(self._noise, img) - return img + noise + return self._add_noise(img) class RandRicianNoise(RandomizableTransform): diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index d921aaeb36..dbbfe3cba0 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -168,24 +168,19 @@ def __init__( self.std = std self._noise: List[np.ndarray] = [] - def randomize(self, im_shape: Sequence[int]) -> None: - super().randomize(None) - self._noise.clear() - for m in self.mean: - self._noise.append(self.R.normal(m, self.R.uniform(0, self.std), size=im_shape)) + def _add_noise(self, img: NdarrayTensor, mean: float) -> NdarrayTensor: + noise = self.R.normal(mean, self.R.uniform(0, self.std), size=img.shape) + noise_, *_ = convert_to_dst_type(noise, img) + return img + noise_ def __call__(self, data: Mapping[Hashable, NdarrayTensor]) -> Dict[Hashable, NdarrayTensor]: d = dict(data) - - image_shape = d[self.keys[0]].shape # image shape from the first data key - self.randomize(image_shape) - if len(self._noise) != len(self.keys): - raise RuntimeError("inconsistent noise items and keys.") + super().randomize(None) if not self._do_transform: return d - for key, noise in self.key_iterator(d, self._noise): - noise, *_ = convert_to_dst_type(noise, d[key]) - d[key] = d[key] + noise + + for key, mean in self.key_iterator(d, self.mean): + d[key] = self._add_noise(img=d[key], mean=mean) return d From dc970c74fd33cf57cfb2c69a2b9e96839371d73f Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Fri, 8 Oct 2021 19:43:29 +0100 Subject: [PATCH 88/89] Torch `CropForeground`, `HistogramNormalize`, `RandHistogramShift` (#3079) * Torch `CropForeground`, `HistogramNormalize`, `RandHistogramShift` Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> * fix Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> Co-authored-by: Wenqi Li --- monai/transforms/croppad/array.py | 12 +- monai/transforms/intensity/array.py | 20 +- monai/transforms/intensity/dictionary.py | 27 ++- monai/transforms/utils.py | 37 ++-- .../utils_pytorch_numpy_unification.py | 33 ++-- tests/test_crop_foreground.py | 107 ++++++----- tests/test_crop_foregroundd.py | 173 +++++++++++------- tests/test_generate_spatial_bounding_box.py | 119 +++++++----- tests/test_histogram_normalize.py | 47 +++-- tests/test_histogram_normalized.py | 47 +++-- tests/test_rand_histogram_shift.py | 45 +++-- tests/test_rand_histogram_shiftd.py | 77 ++++---- 12 files changed, 449 insertions(+), 295 deletions(-) diff --git a/monai/transforms/croppad/array.py b/monai/transforms/croppad/array.py index c904631bed..c2cf03d6fe 100644 --- a/monai/transforms/croppad/array.py +++ b/monai/transforms/croppad/array.py @@ -693,6 +693,8 @@ def threshold_at_one(x): """ + backend = [TransformBackends.TORCH, TransformBackends.NUMPY] + def __init__( self, select_fn: Callable = is_positive, @@ -728,13 +730,15 @@ def __init__( self.mode: NumpyPadMode = look_up_option(mode, NumpyPadMode) self.np_kwargs = np_kwargs - def compute_bounding_box(self, img: np.ndarray): + def compute_bounding_box(self, img: NdarrayOrTensor) -> Tuple[np.ndarray, np.ndarray]: """ Compute the start points and end points of bounding box to crop. And adjust bounding box coords to be divisible by `k`. """ box_start, box_end = generate_spatial_bounding_box(img, self.select_fn, self.channel_indices, self.margin) + box_start = [i.cpu() if isinstance(i, torch.Tensor) else i for i in box_start] # type: ignore + box_end = [i.cpu() if isinstance(i, torch.Tensor) else i for i in box_end] # type: ignore box_start_ = np.asarray(box_start, dtype=np.int16) box_end_ = np.asarray(box_end, dtype=np.int16) orig_spatial_size = box_end_ - box_start_ @@ -747,7 +751,7 @@ def compute_bounding_box(self, img: np.ndarray): def crop_pad( self, - img: np.ndarray, + img: NdarrayOrTensor, box_start: np.ndarray, box_end: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = None, @@ -762,13 +766,11 @@ def crop_pad( pad = list(chain(*zip(pad_to_start.tolist(), pad_to_end.tolist()))) return BorderPad(spatial_border=pad, mode=mode or self.mode, **self.np_kwargs)(cropped) - def __call__(self, img: np.ndarray, mode: Optional[Union[NumpyPadMode, str]] = None): + def __call__(self, img: NdarrayOrTensor, mode: Optional[Union[NumpyPadMode, str]] = None): """ Apply the transform to `img`, assuming `img` is channel-first and slicing doesn't change the channel dim. """ - img, *_ = convert_data_type(img, np.ndarray) # type: ignore - box_start, box_end = self.compute_bounding_box(img) cropped = self.crop_pad(img, box_start, box_end, mode) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 86a865c237..376c2c811f 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -1249,6 +1249,8 @@ class RandHistogramShift(RandomizableTransform): prob: probability of histogram shift. """ + backend = [TransformBackends.NUMPY] + def __init__(self, num_control_points: Union[Tuple[int, int], int] = 10, prob: float = 0.1) -> None: RandomizableTransform.__init__(self, prob) @@ -1273,16 +1275,17 @@ def randomize(self, data: Optional[Any] = None) -> None: self.floating_control_points[i - 1], self.floating_control_points[i + 1] ) - def __call__(self, img: np.ndarray) -> np.ndarray: - img, *_ = convert_data_type(img, np.ndarray) # type: ignore + def __call__(self, img: NdarrayOrTensor) -> np.ndarray: + img_np: np.ndarray + img_np, *_ = convert_data_type(img, np.ndarray) # type: ignore self.randomize() if not self._do_transform: - return img - img_min, img_max = img.min(), img.max() + return img_np + img_min, img_max = img_np.min(), img_np.max() reference_control_points_scaled = self.reference_control_points * (img_max - img_min) + img_min floating_control_points_scaled = self.floating_control_points * (img_max - img_min) + img_min return np.asarray( - np.interp(img, reference_control_points_scaled, floating_control_points_scaled), dtype=img.dtype + np.interp(img_np, reference_control_points_scaled, floating_control_points_scaled), dtype=img_np.dtype ) @@ -1902,12 +1905,14 @@ class HistogramNormalize(Transform): """ + backend = [TransformBackends.NUMPY] + def __init__( self, num_bins: int = 256, min: int = 0, max: int = 255, - mask: Optional[np.ndarray] = None, + mask: Optional[NdarrayOrTensor] = None, dtype: DtypeLike = np.float32, ) -> None: self.num_bins = num_bins @@ -1916,8 +1921,7 @@ def __init__( self.mask = mask self.dtype = dtype - def __call__(self, img: np.ndarray, mask: Optional[np.ndarray] = None) -> np.ndarray: - img, *_ = convert_data_type(img, np.ndarray) # type: ignore + def __call__(self, img: NdarrayOrTensor, mask: Optional[NdarrayOrTensor] = None) -> np.ndarray: return equalize_hist( img=img, mask=mask if mask is not None else self.mask, diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index dbbfe3cba0..8681093168 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -49,6 +49,7 @@ from monai.transforms.utils import is_positive from monai.utils import convert_to_dst_type, ensure_tuple, ensure_tuple_rep, ensure_tuple_size from monai.utils.deprecated import deprecated_arg +from monai.utils.enums import TransformBackends from monai.utils.type_conversion import convert_data_type __all__ = [ @@ -1108,6 +1109,8 @@ class RandHistogramShiftd(RandomizableTransform, MapTransform): allow_missing_keys: don't raise exception if key is missing. """ + backend = [TransformBackends.NUMPY] + def __init__( self, keys: KeysCollection, @@ -1138,17 +1141,19 @@ def randomize(self, data: Optional[Any] = None) -> None: self.floating_control_points[i - 1], self.floating_control_points[i + 1] ) - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) self.randomize() - if not self._do_transform: - return d for key in self.key_iterator(d): - img_min, img_max = d[key].min(), d[key].max() - reference_control_points_scaled = self.reference_control_points * (img_max - img_min) + img_min - floating_control_points_scaled = self.floating_control_points * (img_max - img_min) + img_min - dtype = d[key].dtype - d[key] = np.interp(d[key], reference_control_points_scaled, floating_control_points_scaled).astype(dtype) + d[key] = convert_data_type(d[key], np.ndarray)[0] + if self._do_transform: + img_min, img_max = d[key].min(), d[key].max() + reference_control_points_scaled = self.reference_control_points * (img_max - img_min) + img_min + floating_control_points_scaled = self.floating_control_points * (img_max - img_min) + img_min + dtype = d[key].dtype + d[key] = np.interp(d[key], reference_control_points_scaled, floating_control_points_scaled).astype( + dtype + ) return d @@ -1594,13 +1599,15 @@ class HistogramNormalized(MapTransform): """ + backend = HistogramNormalize.backend + def __init__( self, keys: KeysCollection, num_bins: int = 256, min: int = 0, max: int = 255, - mask: Optional[np.ndarray] = None, + mask: Optional[NdarrayOrTensor] = None, mask_key: Optional[str] = None, dtype: DtypeLike = np.float32, allow_missing_keys: bool = False, @@ -1609,7 +1616,7 @@ def __init__( self.transform = HistogramNormalize(num_bins=num_bins, min=min, max=max, mask=mask, dtype=dtype) self.mask_key = mask_key if mask is None else None - def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: + def __call__(self, data: Mapping[Hashable, NdarrayOrTensor]) -> Dict[Hashable, NdarrayOrTensor]: d = dict(data) for key in self.key_iterator(d): d[key] = self.transform(d[key], d[self.mask_key]) if self.mask_key is not None else self.transform(d[key]) diff --git a/monai/transforms/utils.py b/monai/transforms/utils.py index 67fdb70a8c..15543e91ef 100644 --- a/monai/transforms/utils.py +++ b/monai/transforms/utils.py @@ -25,7 +25,7 @@ from monai.networks.layers import GaussianFilter from monai.transforms.compose import Compose, OneOf from monai.transforms.transform import MapTransform, Transform, apply_transform -from monai.transforms.utils_pytorch_numpy_unification import any_np_pt, nonzero, ravel, unravel_index +from monai.transforms.utils_pytorch_numpy_unification import any_np_pt, nonzero, ravel, unravel_index, where from monai.utils import ( GridSampleMode, InterpolateMode, @@ -839,7 +839,7 @@ def _create_translate( def generate_spatial_bounding_box( - img: np.ndarray, + img: NdarrayOrTensor, select_fn: Callable = is_positive, channel_indices: Optional[IndexSelection] = None, margin: Union[Sequence[int], int] = 0, @@ -864,7 +864,7 @@ def generate_spatial_bounding_box( margin: add margin value to spatial dims of the bounding box, if only 1 value provided, use it for all dims. """ data = img[list(ensure_tuple(channel_indices))] if channel_indices is not None else img - data = np.any(select_fn(data), axis=0) + data = select_fn(data).any(0) ndim = len(data.shape) margin = ensure_tuple_rep(margin, ndim) for m in margin: @@ -875,13 +875,18 @@ def generate_spatial_bounding_box( box_end = [0] * ndim for di, ax in enumerate(itertools.combinations(reversed(range(ndim)), ndim - 1)): - dt = data.any(axis=ax) - if not np.any(dt): + dt = data + if len(ax) != 0: + dt = any_np_pt(dt, ax) + + if not dt.any(): # if no foreground, return all zero bounding box coords return [0] * ndim, [0] * ndim - min_d = max(np.argmax(dt) - margin[di], 0) - max_d = max(data.shape[di] - max(np.argmax(dt[::-1]) - margin[di], 0), min_d + 1) + arg_max = where(dt == dt.max())[0] + min_d = max(arg_max[0] - margin[di], 0) + max_d = arg_max[-1] + margin[di] + 1 + box_start[di], box_end[di] = min_d, max_d return box_start, box_end @@ -1203,8 +1208,8 @@ def compute_divisible_spatial_size(spatial_shape: Sequence[int], k: Union[Sequen def equalize_hist( - img: np.ndarray, - mask: Optional[np.ndarray] = None, + img: NdarrayOrTensor, + mask: Optional[NdarrayOrTensor] = None, num_bins: int = 256, min: int = 0, max: int = 255, @@ -1226,8 +1231,14 @@ def equalize_hist( dtype: data type of the output, default to `float32`. """ - orig_shape = img.shape - hist_img = img[np.array(mask, dtype=bool)] if mask is not None else img + img_np: np.ndarray + img_np, *_ = convert_data_type(img, np.ndarray) # type: ignore + mask_np: Optional[np.ndarray] = None + if mask is not None: + mask_np, *_ = convert_data_type(mask, np.ndarray) # type: ignore + + orig_shape = img_np.shape + hist_img = img_np[np.array(mask_np, dtype=bool)] if mask_np is not None else img_np if has_skimage: hist, bins = exposure.histogram(hist_img.flatten(), num_bins) else: @@ -1239,9 +1250,9 @@ def equalize_hist( cum = rescale_array(arr=cum, minv=min, maxv=max) # apply linear interpolation - img = np.interp(img.flatten(), bins, cum) + img_np = np.interp(img_np.flatten(), bins, cum) - return img.reshape(orig_shape).astype(dtype) + return img_np.reshape(orig_shape).astype(dtype) class Fourier: diff --git a/monai/transforms/utils_pytorch_numpy_unification.py b/monai/transforms/utils_pytorch_numpy_unification.py index 2c370a4707..52c5248f96 100644 --- a/monai/transforms/utils_pytorch_numpy_unification.py +++ b/monai/transforms/utils_pytorch_numpy_unification.py @@ -9,7 +9,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Union +from typing import Sequence, Union import numpy as np import torch @@ -114,17 +114,23 @@ def percentile(x: NdarrayOrTensor, q) -> Union[NdarrayOrTensor, float, int]: return result -def where(condition: NdarrayOrTensor, x, y) -> NdarrayOrTensor: +def where(condition: NdarrayOrTensor, x=None, y=None) -> NdarrayOrTensor: """ Note that `torch.where` may convert y.dtype to x.dtype. """ result: NdarrayOrTensor if isinstance(condition, np.ndarray): - result = np.where(condition, x, y) + if x is not None: + result = np.where(condition, x, y) + else: + result = np.where(condition) else: - x = torch.as_tensor(x, device=condition.device) - y = torch.as_tensor(y, device=condition.device, dtype=x.dtype) - result = torch.where(condition, x, y) + if x is not None: + x = torch.as_tensor(x, device=condition.device) + y = torch.as_tensor(y, device=condition.device, dtype=x.dtype) + result = torch.where(condition, x, y) + else: + result = torch.where(condition) # type: ignore return result @@ -211,7 +217,7 @@ def ravel(x: NdarrayOrTensor): return np.ravel(x) -def any_np_pt(x: NdarrayOrTensor, axis: int): +def any_np_pt(x: NdarrayOrTensor, axis: Union[int, Sequence[int]]): """`np.any` with equivalent implementation for torch. For pytorch, convert to boolean for compatibility with older versions. @@ -223,13 +229,18 @@ def any_np_pt(x: NdarrayOrTensor, axis: int): Returns: Return a contiguous flattened array/tensor. """ - if isinstance(x, torch.Tensor): + if isinstance(x, np.ndarray): + return np.any(x, axis) + + # pytorch can't handle multiple dimensions to `any` so loop across them + axis = [axis] if not isinstance(axis, Sequence) else axis + for ax in axis: try: - return torch.any(x, axis) + x = torch.any(x, ax) except RuntimeError: # older versions of pytorch require the input to be cast to boolean - return torch.any(x.bool(), axis) - return np.any(x, axis) + x = torch.any(x.bool(), ax) + return x def maximum(a: NdarrayOrTensor, b: NdarrayOrTensor) -> NdarrayOrTensor: diff --git a/tests/test_crop_foreground.py b/tests/test_crop_foreground.py index 71e488cac8..0bae1f90f3 100644 --- a/tests/test_crop_foreground.py +++ b/tests/test_crop_foreground.py @@ -12,60 +12,79 @@ import unittest import numpy as np +import torch from parameterized import parameterized from monai.transforms import CropForeground +from tests.utils import TEST_NDARRAYS -TEST_CASE_1 = [ - {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 0}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), - np.array([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]]), -] - -TEST_CASE_2 = [ - {"select_fn": lambda x: x > 1, "channel_indices": None, "margin": 0}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 3, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0]]]), - np.array([[[3]]]), -] - -TEST_CASE_3 = [ - {"select_fn": lambda x: x > 0, "channel_indices": 0, "margin": 0}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), - np.array([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]]), -] - -TEST_CASE_4 = [ - {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 1}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0]]]), -] - -TEST_CASE_5 = [ - {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": [2, 1]}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), -] - -TEST_CASE_6 = [ - {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 0, "k_divisible": 4}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), - np.array([[[1, 2, 1, 0], [2, 3, 2, 0], [1, 2, 1, 0], [0, 0, 0, 0]]]), -] - -TEST_CASE_7 = [ - {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 0, "k_divisible": 10, "constant_values": 2}, - np.array([[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), - np.zeros((1, 0, 0)), -] +TEST_COORDS, TESTS = [], [] + +for p in TEST_NDARRAYS: + TEST_COORDS.append( + [ + {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 0}, + p([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), + p([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]]), + ] + ) + + TESTS.append( + [ + {"select_fn": lambda x: x > 1, "channel_indices": None, "margin": 0}, + p([[[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 3, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0]]]), + p([[[3]]]), + ] + ) + + TESTS.append( + [ + {"select_fn": lambda x: x > 0, "channel_indices": 0, "margin": 0}, + p([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), + p([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]]), + ] + ) + + TESTS.append( + [ + {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 1}, + p([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), + p([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0]]]), + ] + ) + + TESTS.append( + [ + {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": [2, 1]}, + p([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), + p([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), + ] + ) + + TESTS.append( + [ + {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 0, "k_divisible": 4}, + p([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), + p([[[1, 2, 1, 0], [2, 3, 2, 0], [1, 2, 1, 0], [0, 0, 0, 0]]]), + ] + ) + + TESTS.append( + [ + {"select_fn": lambda x: x > 0, "channel_indices": None, "margin": 0, "k_divisible": 10}, + p([[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), + p(np.zeros((1, 0, 0), dtype=np.int64)), + ] + ) class TestCropForeground(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5, TEST_CASE_6, TEST_CASE_7]) + @parameterized.expand(TEST_COORDS + TESTS) def test_value(self, argments, image, expected_data): result = CropForeground(**argments)(image) - np.testing.assert_allclose(result, expected_data) + torch.testing.assert_allclose(result, expected_data, rtol=1e-7, atol=0) - @parameterized.expand([TEST_CASE_1]) + @parameterized.expand(TEST_COORDS) def test_return_coords(self, argments, image, _): argments["return_coords"] = True _, start_coord, end_coord = CropForeground(**argments)(image) diff --git a/tests/test_crop_foregroundd.py b/tests/test_crop_foregroundd.py index efe6b65b4b..5fa474d6ac 100644 --- a/tests/test_crop_foregroundd.py +++ b/tests/test_crop_foregroundd.py @@ -12,85 +12,128 @@ import unittest import numpy as np +import torch from parameterized import parameterized from monai.transforms import CropForegroundd -from monai.utils import NumpyPadMode +from tests.utils import TEST_NDARRAYS, assert_allclose -TEST_CASE_1 = [ - { - "keys": ["img", "label"], - "source_key": "label", - "select_fn": lambda x: x > 0, - "channel_indices": None, - "margin": 0, - "mode": "constant", - "constant_values": 2, - }, - { - "img": np.array([[[1, 0, 2, 0, 1], [0, 1, 2, 1, 0], [2, 2, 3, 2, 2], [0, 1, 2, 1, 0], [1, 0, 2, 0, 1]]]), - "label": np.array([[[0, 0, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 0, 0, 0]]]), - }, - np.array([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]]), -] +TEST_POSITION, TESTS = [], [] +for p in TEST_NDARRAYS: -TEST_CASE_2 = [ - {"keys": ["img"], "source_key": "img", "select_fn": lambda x: x > 1, "channel_indices": None, "margin": 0}, - {"img": np.array([[[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 3, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0]]])}, - np.array([[[3]]]), -] - -TEST_CASE_3 = [ - {"keys": ["img"], "source_key": "img", "select_fn": lambda x: x > 0, "channel_indices": 0, "margin": 0}, - {"img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]])}, - np.array([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]]), -] - -TEST_CASE_4 = [ - {"keys": ["img"], "source_key": "img", "select_fn": lambda x: x > 0, "channel_indices": None, "margin": 1}, - {"img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]])}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0]]]), -] - -TEST_CASE_5 = [ - {"keys": ["img"], "source_key": "img", "select_fn": lambda x: x > 0, "channel_indices": None, "margin": [2, 1]}, - {"img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]])}, - np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), -] - -TEST_CASE_6 = [ - { - "keys": ["img", "seg"], - "source_key": "img", - "select_fn": lambda x: x > 0, - "channel_indices": 0, - "margin": 0, - "k_divisible": [4, 6], - "mode": ["edge", NumpyPadMode.CONSTANT], - }, - { - "img": np.array([[[0, 2, 1, 2, 0], [1, 1, 2, 1, 1], [2, 2, 3, 2, 2], [1, 1, 2, 1, 1], [0, 0, 0, 0, 0]]]), - "seg": np.array([[[0, 2, 1, 2, 0], [1, 1, 2, 1, 1], [2, 2, 3, 2, 2], [1, 1, 2, 1, 1], [0, 0, 0, 0, 0]]]), - }, - np.array([[[0, 2, 1, 2, 0, 0], [1, 1, 2, 1, 1, 1], [2, 2, 3, 2, 2, 2], [1, 1, 2, 1, 1, 1]]]), -] + TEST_POSITION.append( + [ + { + "keys": ["img", "label"], + "source_key": "label", + "select_fn": lambda x: x > 0, + "channel_indices": None, + "margin": 0, + }, + { + "img": p( + np.array([[[1, 0, 2, 0, 1], [0, 1, 2, 1, 0], [2, 2, 3, 2, 2], [0, 1, 2, 1, 0], [1, 0, 2, 0, 1]]]) + ), + "label": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 0, 0, 0]]]) + ), + }, + p(np.array([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]])), + ] + ) + TESTS.append( + [ + {"keys": ["img"], "source_key": "img", "select_fn": lambda x: x > 1, "channel_indices": None, "margin": 0}, + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 3, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0]]]) + ) + }, + p(np.array([[[3]]])), + ] + ) + TESTS.append( + [ + {"keys": ["img"], "source_key": "img", "select_fn": lambda x: x > 0, "channel_indices": 0, "margin": 0}, + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]) + ) + }, + p(np.array([[[1, 2, 1], [2, 3, 2], [1, 2, 1]]])), + ] + ) + TESTS.append( + [ + {"keys": ["img"], "source_key": "img", "select_fn": lambda x: x > 0, "channel_indices": None, "margin": 1}, + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]) + ) + }, + p(np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0]]])), + ] + ) + TESTS.append( + [ + { + "keys": ["img"], + "source_key": "img", + "select_fn": lambda x: x > 0, + "channel_indices": None, + "margin": [2, 1], + }, + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]) + ) + }, + p(np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]])), + ] + ) + TESTS.append( + [ + { + "keys": ["img"], + "source_key": "img", + "select_fn": lambda x: x > 0, + "channel_indices": 0, + "margin": 0, + "k_divisible": [4, 6], + "mode": "edge", + }, + { + "img": p( + np.array( + [[[0, 2, 1, 2, 0], [1, 1, 2, 1, 1], [2, 2, 3, 2, 2], [1, 1, 2, 1, 1], [0, 0, 0, 0, 0]]], + dtype=np.float32, + ) + ) + }, + p(np.array([[[0, 2, 1, 2, 0, 0], [1, 1, 2, 1, 1, 1], [2, 2, 3, 2, 2, 2], [1, 1, 2, 1, 1, 1]]])), + ] + ) class TestCropForegroundd(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5, TEST_CASE_6]) - def test_value(self, argments, image, expected_data): - result = CropForegroundd(**argments)(image) - np.testing.assert_allclose(result["img"], expected_data) + @parameterized.expand(TEST_POSITION + TESTS) + def test_value(self, argments, input_data, expected_data): + result = CropForegroundd(**argments)(input_data) + r, i = result["img"], input_data["img"] + self.assertEqual(type(r), type(i)) + if isinstance(r, torch.Tensor): + self.assertEqual(r.device, i.device) + assert_allclose(r, expected_data) - @parameterized.expand([TEST_CASE_1]) - def test_foreground_position(self, argments, image, _): - result = CropForegroundd(**argments)(image) + @parameterized.expand(TEST_POSITION) + def test_foreground_position(self, argments, input_data, _): + result = CropForegroundd(**argments)(input_data) np.testing.assert_allclose(result["foreground_start_coord"], np.array([1, 1])) np.testing.assert_allclose(result["foreground_end_coord"], np.array([4, 4])) argments["start_coord_key"] = "test_start_coord" argments["end_coord_key"] = "test_end_coord" - result = CropForegroundd(**argments)(image) + result = CropForegroundd(**argments)(input_data) np.testing.assert_allclose(result["test_start_coord"], np.array([1, 1])) np.testing.assert_allclose(result["test_end_coord"], np.array([4, 4])) diff --git a/tests/test_generate_spatial_bounding_box.py b/tests/test_generate_spatial_bounding_box.py index 32a45d8d1c..d73b9fafcc 100644 --- a/tests/test_generate_spatial_bounding_box.py +++ b/tests/test_generate_spatial_bounding_box.py @@ -15,60 +15,79 @@ from parameterized import parameterized from monai.transforms import generate_spatial_bounding_box +from tests.utils import TEST_NDARRAYS -TEST_CASE_1 = [ - { - "img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), - "select_fn": lambda x: x > 0, - "channel_indices": None, - "margin": 0, - }, - ([1, 1], [4, 4]), -] - -TEST_CASE_2 = [ - { - "img": np.array([[[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 3, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0]]]), - "select_fn": lambda x: x > 1, - "channel_indices": None, - "margin": 0, - }, - ([2, 2], [3, 3]), -] - -TEST_CASE_3 = [ - { - "img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]), - "select_fn": lambda x: x > 0, - "channel_indices": 0, - "margin": 0, - }, - ([1, 1], [4, 4]), -] - -TEST_CASE_4 = [ - { - "img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), - "select_fn": lambda x: x > 0, - "channel_indices": None, - "margin": 1, - }, - ([0, 0], [4, 5]), -] - -TEST_CASE_5 = [ - { - "img": np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]), - "select_fn": lambda x: x > 0, - "channel_indices": None, - "margin": [2, 1], - }, - ([0, 0], [5, 5]), -] +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]) + ), + "select_fn": lambda x: x > 0, + "channel_indices": None, + "margin": 0, + }, + ([1, 1], [4, 4]), + ] + ) + TESTS.append( + [ + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 3, 1, 0], [0, 1, 1, 1, 0], [0, 0, 0, 0, 0]]]) + ), + "select_fn": lambda x: x > 1, + "channel_indices": None, + "margin": 0, + }, + ([2, 2], [3, 3]), + ] + ) + TESTS.append( + [ + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 1, 2, 1, 0], [0, 0, 0, 0, 0]]]) + ), + "select_fn": lambda x: x > 0, + "channel_indices": 0, + "margin": 0, + }, + ([1, 1], [4, 4]), + ] + ) + TESTS.append( + [ + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]) + ), + "select_fn": lambda x: x > 0, + "channel_indices": None, + "margin": 1, + }, + ([0, 0], [4, 5]), + ] + ) + TESTS.append( + [ + { + "img": p( + np.array([[[0, 0, 0, 0, 0], [0, 1, 2, 1, 0], [0, 2, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]]) + ), + "select_fn": lambda x: x > 0, + "channel_indices": None, + "margin": [2, 1], + }, + ([0, 0], [5, 5]), + ] + ) class TestGenerateSpatialBoundingBox(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_4, TEST_CASE_5]) + @parameterized.expand(TESTS) def test_value(self, input_data, expected_box): result = generate_spatial_bounding_box(**input_data) self.assertTupleEqual(result, expected_box) diff --git a/tests/test_histogram_normalize.py b/tests/test_histogram_normalize.py index b69fb1d927..e0178166d9 100644 --- a/tests/test_histogram_normalize.py +++ b/tests/test_histogram_normalize.py @@ -15,28 +15,37 @@ from parameterized import parameterized from monai.transforms import HistogramNormalize - -TEST_CASE_1 = [ - {"num_bins": 4, "min": 1, "max": 5, "mask": np.array([1, 1, 1, 1, 1, 0])}, - np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]), - np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0]), -] - -TEST_CASE_2 = [ - {"num_bins": 4, "max": 4, "dtype": np.uint8}, - np.array([0.0, 1.0, 2.0, 3.0, 4.0]), - np.array([0, 0, 1, 3, 4]), -] - -TEST_CASE_3 = [ - {"num_bins": 256, "max": 255, "dtype": np.uint8}, - np.array([[[100.0, 200.0], [150.0, 250.0]]]), - np.array([[[0, 170], [70, 255]]]), -] +from tests.utils import TEST_NDARRAYS + +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + {"num_bins": 4, "min": 1, "max": 5, "mask": np.array([1, 1, 1, 1, 1, 0])}, + p(np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])), + np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0]), + ] + ) + + TESTS.append( + [ + {"num_bins": 4, "max": 4, "dtype": np.uint8}, + p(np.array([0.0, 1.0, 2.0, 3.0, 4.0])), + np.array([0, 0, 1, 3, 4]), + ] + ) + + TESTS.append( + [ + {"num_bins": 256, "max": 255, "dtype": np.uint8}, + p(np.array([[[100.0, 200.0], [150.0, 250.0]]])), + np.array([[[0, 170], [70, 255]]]), + ] + ) class TestHistogramNormalize(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): result = HistogramNormalize(**argments)(image) np.testing.assert_allclose(result, expected_data) diff --git a/tests/test_histogram_normalized.py b/tests/test_histogram_normalized.py index 68647e82fb..314c7bd75b 100644 --- a/tests/test_histogram_normalized.py +++ b/tests/test_histogram_normalized.py @@ -15,28 +15,37 @@ from parameterized import parameterized from monai.transforms import HistogramNormalized - -TEST_CASE_1 = [ - {"keys": "img", "num_bins": 4, "min": 1, "max": 5, "mask_key": "mask"}, - {"img": np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0]), "mask": np.array([1, 1, 1, 1, 1, 0])}, - np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0]), -] - -TEST_CASE_2 = [ - {"keys": "img", "num_bins": 4, "max": 4, "dtype": np.uint8}, - {"img": np.array([0.0, 1.0, 2.0, 3.0, 4.0])}, - np.array([0, 0, 1, 3, 4]), -] - -TEST_CASE_3 = [ - {"keys": "img", "num_bins": 256, "max": 255, "dtype": np.uint8}, - {"img": np.array([[[100.0, 200.0], [150.0, 250.0]]])}, - np.array([[[0, 170], [70, 255]]]), -] +from tests.utils import TEST_NDARRAYS + +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + {"keys": "img", "num_bins": 4, "min": 1, "max": 5, "mask_key": "mask"}, + {"img": p(np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])), "mask": p(np.array([1, 1, 1, 1, 1, 0]))}, + np.array([1.0, 1.5, 2.5, 4.0, 5.0, 5.0]), + ] + ) + + TESTS.append( + [ + {"keys": "img", "num_bins": 4, "max": 4, "dtype": np.uint8}, + {"img": p(np.array([0.0, 1.0, 2.0, 3.0, 4.0]))}, + np.array([0, 0, 1, 3, 4]), + ] + ) + + TESTS.append( + [ + {"keys": "img", "num_bins": 256, "max": 255, "dtype": np.uint8}, + {"img": p(np.array([[[100.0, 200.0], [150.0, 250.0]]]))}, + np.array([[[0, 170], [70, 255]]]), + ] + ) class TestHistogramNormalized(unittest.TestCase): - @parameterized.expand([TEST_CASE_1, TEST_CASE_2, TEST_CASE_3]) + @parameterized.expand(TESTS) def test_value(self, argments, image, expected_data): result = HistogramNormalized(**argments)(image)["img"] np.testing.assert_allclose(result, expected_data) diff --git a/tests/test_rand_histogram_shift.py b/tests/test_rand_histogram_shift.py index b258cc5a7e..fa51dacefa 100644 --- a/tests/test_rand_histogram_shift.py +++ b/tests/test_rand_histogram_shift.py @@ -15,28 +15,35 @@ from parameterized import parameterized from monai.transforms import RandHistogramShift - -TEST_CASES = [ - [ - {"num_control_points": 5, "prob": 0.0}, - {"img": np.arange(8).reshape((1, 2, 2, 2))}, - np.arange(8).reshape((1, 2, 2, 2)), - ], - [ - {"num_control_points": 5, "prob": 0.9}, - {"img": np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32)}, - np.array([[[[0.0, 0.57227867], [1.1391707, 1.68990281]], [[2.75833219, 4.34445884], [5.70913743, 7.0]]]]), - ], - [ - {"num_control_points": (5, 20), "prob": 0.9}, - {"img": np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32)}, - np.array([[[[0.0, 1.17472492], [2.21553091, 2.88292011]], [[3.98407301, 5.01302123], [6.09275004, 7.0]]]]), - ], -] +from tests.utils import TEST_NDARRAYS + +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + {"num_control_points": 5, "prob": 0.0}, + {"img": p(np.arange(8).reshape((1, 2, 2, 2)))}, + np.arange(8).reshape((1, 2, 2, 2)), + ] + ) + TESTS.append( + [ + {"num_control_points": 5, "prob": 0.9}, + {"img": p(np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32))}, + np.array([[[[0.0, 0.57227867], [1.1391707, 1.68990281]], [[2.75833219, 4.34445884], [5.70913743, 7.0]]]]), + ] + ) + TESTS.append( + [ + {"num_control_points": (5, 20), "prob": 0.9}, + {"img": p(np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32))}, + np.array([[[[0.0, 1.17472492], [2.21553091, 2.88292011]], [[3.98407301, 5.01302123], [6.09275004, 7.0]]]]), + ] + ) class TestRandHistogramShift(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_histogram_shift(self, input_param, input_data, expected_val): g = RandHistogramShift(**input_param) g.set_random_state(123) diff --git a/tests/test_rand_histogram_shiftd.py b/tests/test_rand_histogram_shiftd.py index 806e4f5cf2..2191e99518 100644 --- a/tests/test_rand_histogram_shiftd.py +++ b/tests/test_rand_histogram_shiftd.py @@ -14,47 +14,60 @@ import numpy as np from parameterized import parameterized -from monai.transforms import RandHistogramShiftD - -TEST_CASES = [ - [ - {"keys": ("img",), "num_control_points": 5, "prob": 0.0}, - {"img": np.arange(8).reshape((1, 2, 2, 2)), "seg": np.ones(8).reshape((1, 2, 2, 2))}, - {"img": np.arange(8).reshape((1, 2, 2, 2)), "seg": np.ones(8).reshape((1, 2, 2, 2))}, - ], - [ - {"keys": ("img",), "num_control_points": 5, "prob": 0.9}, - {"img": np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32), "seg": np.ones(8).reshape((1, 2, 2, 2))}, - { - "img": np.array( - [[[[0.0, 0.57227867], [1.1391707, 1.68990281]], [[2.75833219, 4.34445884], [5.70913743, 7.0]]]] - ), - "seg": np.ones(8).reshape((1, 2, 2, 2)), - }, - ], - [ - {"keys": ("img",), "num_control_points": (5, 20), "prob": 0.9}, - {"img": np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32), "seg": np.ones(8).reshape((1, 2, 2, 2))}, - { - "img": np.array( - [[[[0.0, 1.17472492], [2.21553091, 2.88292011]], [[3.98407301, 5.01302123], [6.09275004, 7.0]]]] - ), - "seg": np.ones(8).reshape((1, 2, 2, 2)), - }, - ], -] +from monai.transforms.intensity.dictionary import RandHistogramShiftd +from tests.utils import TEST_NDARRAYS, assert_allclose + +TESTS = [] +for p in TEST_NDARRAYS: + TESTS.append( + [ + {"keys": ("img",), "num_control_points": 5, "prob": 0.0}, + {"img": p(np.arange(8).reshape((1, 2, 2, 2))), "seg": p(np.ones(8).reshape((1, 2, 2, 2)))}, + {"img": np.arange(8).reshape((1, 2, 2, 2)), "seg": np.ones(8).reshape((1, 2, 2, 2))}, + ] + ) + TESTS.append( + [ + {"keys": ("img",), "num_control_points": 5, "prob": 0.9}, + { + "img": p(np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32)), + "seg": p(np.ones(8).reshape((1, 2, 2, 2))), + }, + { + "img": np.array( + [[[[0.0, 0.57227867], [1.1391707, 1.68990281]], [[2.75833219, 4.34445884], [5.70913743, 7.0]]]] + ), + "seg": np.ones(8).reshape((1, 2, 2, 2)), + }, + ] + ) + TESTS.append( + [ + {"keys": ("img",), "num_control_points": (5, 20), "prob": 0.9}, + { + "img": p(np.arange(8).reshape((1, 2, 2, 2)).astype(np.float32)), + "seg": p(np.ones(8).reshape((1, 2, 2, 2))), + }, + { + "img": np.array( + [[[[0.0, 1.17472492], [2.21553091, 2.88292011]], [[3.98407301, 5.01302123], [6.09275004, 7.0]]]] + ), + "seg": np.ones(8).reshape((1, 2, 2, 2)), + }, + ] + ) class TestRandHistogramShiftD(unittest.TestCase): - @parameterized.expand(TEST_CASES) + @parameterized.expand(TESTS) def test_rand_histogram_shiftd(self, input_param, input_data, expected_val): - g = RandHistogramShiftD(**input_param) + g = RandHistogramShiftd(**input_param) g.set_random_state(123) res = g(input_data) for key in res: result = res[key] expected = expected_val[key] if isinstance(expected_val, dict) else expected_val - np.testing.assert_allclose(result, expected, rtol=1e-4, atol=1e-4) + assert_allclose(result, expected, rtol=1e-4, atol=1e-4, type_test=False) if __name__ == "__main__": From ce38a93e2379b16b059a22485b39e269538bb901 Mon Sep 17 00:00:00 2001 From: Nic Ma Date: Sun, 10 Oct 2021 07:58:09 +0800 Subject: [PATCH 89/89] [DLMED] fix wrong doc-string (#3096) Signed-off-by: Nic Ma --- monai/metrics/rocauc.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/monai/metrics/rocauc.py b/monai/metrics/rocauc.py index c2679cc2ea..d331f01707 100644 --- a/monai/metrics/rocauc.py +++ b/monai/metrics/rocauc.py @@ -104,9 +104,11 @@ def compute_roc_auc( Args: y_pred: input data to compute, typical classification model output. - it must be One-Hot format and first dim is batch, example shape: [16] or [16, 2]. - y: ground truth to compute ROC AUC metric, the first dim is batch. - example shape: [16, 1] will be converted into [16, 2] (where `2` is inferred from `y_pred`). + the first dim must be batch, if multi-classes, it must be in One-Hot format. + for example: shape `[16]` or `[16, 1]` for a binary data, shape `[16, 2]` for 2 classes data. + y: ground truth to compute ROC AUC metric, the first dim must be batch. + if multi-classes, it must be in One-Hot format. + for example: shape `[16]` or `[16, 1]` for a binary data, shape `[16, 2]` for 2 classes data. average: {``"macro"``, ``"weighted"``, ``"micro"``, ``"none"``} Type of averaging performed if not binary classification. Defaults to ``"macro"``.

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

51MGRrdcoGn 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ͼ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