From c5f225a94e7f9ca387a7e29fd2252ff6a4d6d10f Mon Sep 17 00:00:00 2001 From: yc7620 Date: Thu, 10 Feb 2022 09:36:59 +0200 Subject: [PATCH 1/6] intensity augmentation transforms Signed-off-by: yc7620 --- monai/config/deviceconfig.py | 8 +- monai/data/dataset.py | 2 +- monai/data/dataset_summary.py | 2 +- monai/handlers/parameter_scheduler.py | 2 +- monai/losses/image_dissimilarity.py | 6 +- monai/networks/blocks/activation.py | 2 + monai/networks/blocks/selfattention.py | 2 +- monai/networks/blocks/upsample.py | 4 +- monai/networks/blocks/warp.py | 2 +- monai/networks/layers/convutils.py | 2 +- monai/networks/nets/dints.py | 10 +- monai/networks/nets/highresnet.py | 2 +- monai/networks/nets/regunet.py | 6 +- monai/networks/nets/segresnet.py | 6 +- monai/networks/utils.py | 2 +- monai/transforms/__init__.py | 2 + monai/transforms/intensity/array.py | 128 +++++++++++++++++- monai/transforms/smooth_field/array.py | 2 +- .../transforms/utils_create_transform_ims.py | 2 +- tests/test_lmdbdataset.py | 6 +- tests/test_tile_on_grid.py | 2 +- tests/test_tile_on_grid_dict.py | 2 +- 22 files changed, 164 insertions(+), 38 deletions(-) diff --git a/monai/config/deviceconfig.py b/monai/config/deviceconfig.py index fd7ca572e6..91b944bde5 100644 --- a/monai/config/deviceconfig.py +++ b/monai/config/deviceconfig.py @@ -161,9 +161,9 @@ def get_system_info() -> OrderedDict: ), ) mem = psutil.virtual_memory() - _dict_append(output, "Total physical memory (GB)", lambda: round(mem.total / 1024**3, 1)) - _dict_append(output, "Available memory (GB)", lambda: round(mem.available / 1024**3, 1)) - _dict_append(output, "Used memory (GB)", lambda: round(mem.used / 1024**3, 1)) + _dict_append(output, "Total physical memory (GB)", lambda: round(mem.total / 1024 ** 3, 1)) + _dict_append(output, "Available memory (GB)", lambda: round(mem.available / 1024 ** 3, 1)) + _dict_append(output, "Used memory (GB)", lambda: round(mem.used / 1024 ** 3, 1)) return output @@ -209,7 +209,7 @@ def get_gpu_info() -> OrderedDict: _dict_append(output, f"GPU {gpu} Is integrated", lambda: bool(gpu_info.is_integrated)) _dict_append(output, f"GPU {gpu} Is multi GPU board", lambda: bool(gpu_info.is_multi_gpu_board)) _dict_append(output, f"GPU {gpu} Multi processor count", lambda: gpu_info.multi_processor_count) - _dict_append(output, f"GPU {gpu} Total memory (GB)", lambda: round(gpu_info.total_memory / 1024**3, 1)) + _dict_append(output, f"GPU {gpu} Total memory (GB)", lambda: round(gpu_info.total_memory / 1024 ** 3, 1)) _dict_append(output, f"GPU {gpu} CUDA capability (maj.min)", lambda: f"{gpu_info.major}.{gpu_info.minor}") return output diff --git a/monai/data/dataset.py b/monai/data/dataset.py index 156708c7dd..8c50446815 100644 --- a/monai/data/dataset.py +++ b/monai/data/dataset.py @@ -513,7 +513,7 @@ def __init__( self.db_file = self.cache_dir / f"{db_name}.lmdb" self.lmdb_kwargs = lmdb_kwargs or {} if not self.lmdb_kwargs.get("map_size", 0): - self.lmdb_kwargs["map_size"] = 1024**4 # default map_size + self.lmdb_kwargs["map_size"] = 1024 ** 4 # default map_size # lmdb is single-writer multi-reader by default # the cache is created without multi-threading self._read_env = None diff --git a/monai/data/dataset_summary.py b/monai/data/dataset_summary.py index 956e038569..2b4df4ebbf 100644 --- a/monai/data/dataset_summary.py +++ b/monai/data/dataset_summary.py @@ -150,7 +150,7 @@ def calculate_statistics(self, foreground_threshold: int = 0): self.data_max, self.data_min = max(voxel_max), min(voxel_min) self.data_mean = (voxel_sum / voxel_ct).item() - self.data_std = (torch.sqrt(voxel_square_sum / voxel_ct - self.data_mean**2)).item() + self.data_std = (torch.sqrt(voxel_square_sum / voxel_ct - self.data_mean ** 2)).item() def calculate_percentiles( self, diff --git a/monai/handlers/parameter_scheduler.py b/monai/handlers/parameter_scheduler.py index 67c51fd351..c0e18edcd0 100644 --- a/monai/handlers/parameter_scheduler.py +++ b/monai/handlers/parameter_scheduler.py @@ -134,7 +134,7 @@ def _exponential(initial_value: float, gamma: float, current_step: int) -> float Returns: float: new parameter value """ - return initial_value * gamma**current_step + return initial_value * gamma ** current_step @staticmethod def _step(initial_value: float, gamma: float, step_size: int, current_step: int) -> float: diff --git a/monai/losses/image_dissimilarity.py b/monai/losses/image_dissimilarity.py index a06f6fb5cd..b527522cd7 100644 --- a/monai/losses/image_dissimilarity.py +++ b/monai/losses/image_dissimilarity.py @@ -126,7 +126,7 @@ 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})") - t2, p2, tp = target**2, pred**2, target * pred + t2, p2, tp = target ** 2, pred ** 2, target * pred kernel, kernel_vol = self.kernel.to(pred), self.kernel_vol.to(pred) # sum over kernel t_sum = separable_filtering(target, kernels=[kernel.to(pred)] * self.ndim) @@ -217,7 +217,7 @@ def __init__( self.num_bins = num_bins self.kernel_type = kernel_type if self.kernel_type == "gaussian": - self.preterm = 1 / (2 * sigma**2) + 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) @@ -280,7 +280,7 @@ def parzen_windowing_b_spline(self, img: torch.Tensor, order: int) -> Tuple[torc 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 + (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: diff --git a/monai/networks/blocks/activation.py b/monai/networks/blocks/activation.py index 1526b37056..cf27b22552 100644 --- a/monai/networks/blocks/activation.py +++ b/monai/networks/blocks/activation.py @@ -19,6 +19,7 @@ def monai_mish(x, inplace: bool = False): return torch.nn.functional.mish(x, inplace=inplace) + else: def monai_mish(x, inplace: bool = False): @@ -30,6 +31,7 @@ def monai_mish(x, inplace: bool = False): def monai_swish(x, inplace: bool = False): return torch.nn.functional.silu(x, inplace=inplace) + else: def monai_swish(x, inplace: bool = False): diff --git a/monai/networks/blocks/selfattention.py b/monai/networks/blocks/selfattention.py index cf837c5a6f..4a86cd84bc 100644 --- a/monai/networks/blocks/selfattention.py +++ b/monai/networks/blocks/selfattention.py @@ -46,7 +46,7 @@ def __init__(self, hidden_size: int, num_heads: int, dropout_rate: float = 0.0) self.drop_output = nn.Dropout(dropout_rate) self.drop_weights = nn.Dropout(dropout_rate) self.head_dim = hidden_size // num_heads - self.scale = self.head_dim**-0.5 + self.scale = self.head_dim ** -0.5 def forward(self, x): q, k, v = einops.rearrange(self.qkv(x), "b h (qkv l d) -> qkv b l h d", qkv=3, l=self.num_heads) diff --git a/monai/networks/blocks/upsample.py b/monai/networks/blocks/upsample.py index fa3929df20..c72d1bc518 100644 --- a/monai/networks/blocks/upsample.py +++ b/monai/networks/blocks/upsample.py @@ -219,7 +219,7 @@ def __init__( 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**self.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 ) @@ -247,7 +247,7 @@ def forward(self, x: torch.Tensor) -> torch.Tensor: x: Tensor in shape (batch, channel, spatial_1[, spatial_2, ...). """ x = self.conv_block(x) - if x.shape[1] % (self.scale_factor**self.dimensions) != 0: + if x.shape[1] % (self.scale_factor ** self.dimensions) != 0: raise ValueError( f"Number of channels after `conv_block` ({x.shape[1]}) must be evenly " "divisible by scale_factor ** dimensions " diff --git a/monai/networks/blocks/warp.py b/monai/networks/blocks/warp.py index 5b925258b6..9fdaab0a48 100644 --- a/monai/networks/blocks/warp.py +++ b/monai/networks/blocks/warp.py @@ -150,7 +150,7 @@ def forward(self, dvf): Returns: a dense displacement field """ - ddf: torch.Tensor = dvf / (2**self.num_steps) + ddf: torch.Tensor = dvf / (2 ** self.num_steps) for _ in range(self.num_steps): ddf = ddf + self.warp_layer(image=ddf, ddf=ddf) return ddf diff --git a/monai/networks/layers/convutils.py b/monai/networks/layers/convutils.py index 1e9ce954e8..5efb6e792f 100644 --- a/monai/networks/layers/convutils.py +++ b/monai/networks/layers/convutils.py @@ -115,7 +115,7 @@ def gaussian_1d( out = out.clamp(min=0) elif approx.lower() == "sampled": x = torch.arange(-tail, tail + 1, dtype=torch.float, device=sigma.device) - out = torch.exp(-0.5 / (sigma * sigma) * x**2) + out = torch.exp(-0.5 / (sigma * sigma) * x ** 2) if not normalize: # compute the normalizer out = out / (2.5066282 * sigma) elif approx.lower() == "scalespace": diff --git a/monai/networks/nets/dints.py b/monai/networks/nets/dints.py index a4aaf32eed..c024d6e0f1 100644 --- a/monai/networks/nets/dints.py +++ b/monai/networks/nets/dints.py @@ -124,7 +124,7 @@ def __init__(self, in_channel: int, out_channel: int, spatial_dims: int = 3): # s0 is upsampled 2x from s1, representing feature sizes at two resolutions. # in_channel * s0 (activation) + 3 * out_channel * s1 (convolution, concatenation, normalization) # s0 = s1 * 2^(spatial_dims) = output_size / out_channel * 2^(spatial_dims) - self.ram_cost = in_channel / out_channel * 2**self._spatial_dims + 3 + self.ram_cost = in_channel / out_channel * 2 ** self._spatial_dims + 3 class MixedOp(nn.Module): @@ -330,7 +330,7 @@ def __init__( # define downsample stems before DiNTS search if use_downsample: self.stem_down[str(res_idx)] = StemTS( - nn.Upsample(scale_factor=1 / (2**res_idx), mode=mode, align_corners=True), + nn.Upsample(scale_factor=1 / (2 ** res_idx), mode=mode, align_corners=True), conv_type( in_channels=in_channels, out_channels=self.filter_nums[res_idx], @@ -373,7 +373,7 @@ def __init__( else: self.stem_down[str(res_idx)] = StemTS( - nn.Upsample(scale_factor=1 / (2**res_idx), mode=mode, align_corners=True), + nn.Upsample(scale_factor=1 / (2 ** res_idx), mode=mode, align_corners=True), conv_type( in_channels=in_channels, out_channels=self.filter_nums[res_idx], @@ -789,7 +789,7 @@ def get_ram_cost_usage(self, in_size, full: bool = False): image_size = np.array(in_size[-self._spatial_dims :]) sizes = [] for res_idx in range(self.num_depths): - sizes.append(batch_size * self.filter_nums[res_idx] * (image_size // (2**res_idx)).prod()) + sizes.append(batch_size * self.filter_nums[res_idx] * (image_size // (2 ** res_idx)).prod()) sizes = torch.tensor(sizes).to(torch.float32).to(self.device) / (2 ** (int(self.use_downsample))) probs_a, arch_code_prob_a = self.get_prob_a(child=False) cell_prob = F.softmax(self.log_alpha_c, dim=-1) @@ -807,7 +807,7 @@ def get_ram_cost_usage(self, in_size, full: bool = False): * (1 + (ram_cost[blk_idx, path_idx] * cell_prob[blk_idx, path_idx]).sum()) * sizes[self.arch_code2out[path_idx]] ) - return usage * 32 / 8 / 1024**2 + return usage * 32 / 8 / 1024 ** 2 def get_topology_entropy(self, probs): """ diff --git a/monai/networks/nets/highresnet.py b/monai/networks/nets/highresnet.py index 891a65e67b..95c0c758af 100644 --- a/monai/networks/nets/highresnet.py +++ b/monai/networks/nets/highresnet.py @@ -168,7 +168,7 @@ def __init__( # residual blocks for (idx, params) in enumerate(layer_params[1:-2]): # res blocks except the 1st and last two conv layers. _in_chns, _out_chns = _out_chns, params["n_features"] - _dilation = 2**idx + _dilation = 2 ** idx for _ in range(params["repeat"]): blocks.append( HighResBlock( diff --git a/monai/networks/nets/regunet.py b/monai/networks/nets/regunet.py index 6776c7ce9e..8524563faa 100644 --- a/monai/networks/nets/regunet.py +++ b/monai/networks/nets/regunet.py @@ -92,7 +92,7 @@ def __init__( raise AssertionError self.encode_kernel_sizes: List[int] = encode_kernel_sizes - self.num_channels = [self.num_channel_initial * (2**d) for d in range(self.depth + 1)] + self.num_channels = [self.num_channel_initial * (2 ** d) for d in range(self.depth + 1)] self.min_extract_level = min(self.extract_levels) # init layers @@ -310,14 +310,14 @@ def __init__( encode_kernel_sizes: Union[int, List[int]] = 3, ): for size in image_size: - if size % (2**depth) != 0: + if size % (2 ** depth) != 0: raise ValueError( f"given depth {depth}, " f"all input spatial dimension must be divisible by {2 ** depth}, " f"got input of size {image_size}" ) self.image_size = image_size - self.decode_size = [size // (2**depth) for size in image_size] + self.decode_size = [size // (2 ** depth) for size in image_size] super().__init__( spatial_dims=spatial_dims, in_channels=in_channels, diff --git a/monai/networks/nets/segresnet.py b/monai/networks/nets/segresnet.py index 299f1ca811..d2c45dd3a3 100644 --- a/monai/networks/nets/segresnet.py +++ b/monai/networks/nets/segresnet.py @@ -102,7 +102,7 @@ def _make_down_layers(self): down_layers = nn.ModuleList() blocks_down, spatial_dims, filters, norm = (self.blocks_down, self.spatial_dims, self.init_filters, self.norm) for i in range(len(blocks_down)): - layer_in_channels = filters * 2**i + layer_in_channels = filters * 2 ** i pre_conv = ( get_conv_layer(spatial_dims, layer_in_channels // 2, layer_in_channels, stride=2) if i > 0 @@ -299,12 +299,12 @@ def _get_vae_loss(self, net_input: torch.Tensor, vae_input: torch.Tensor): if self.vae_estimate_std: z_sigma = self.vae_fc2(x_vae) z_sigma = F.softplus(z_sigma) - vae_reg_loss = 0.5 * torch.mean(z_mean**2 + z_sigma**2 - torch.log(1e-8 + z_sigma**2) - 1) + vae_reg_loss = 0.5 * torch.mean(z_mean ** 2 + z_sigma ** 2 - torch.log(1e-8 + z_sigma ** 2) - 1) x_vae = z_mean + z_sigma * z_mean_rand else: z_sigma = self.vae_default_std - vae_reg_loss = torch.mean(z_mean**2) + vae_reg_loss = torch.mean(z_mean ** 2) x_vae = z_mean + z_sigma * z_mean_rand diff --git a/monai/networks/utils.py b/monai/networks/utils.py index 47cc838fdc..a4ca0a6fd5 100644 --- a/monai/networks/utils.py +++ b/monai/networks/utils.py @@ -270,7 +270,7 @@ def pixelshuffle( dim, factor = spatial_dims, scale_factor input_size = list(x.size()) batch_size, channels = input_size[:2] - scale_divisor = factor**dim + scale_divisor = factor ** dim if channels % scale_divisor != 0: raise ValueError( diff --git a/monai/transforms/__init__.py b/monai/transforms/__init__.py index 26601de76b..b90140b455 100644 --- a/monai/transforms/__init__.py +++ b/monai/transforms/__init__.py @@ -85,6 +85,7 @@ GaussianSmooth, GibbsNoise, HistogramNormalize, + IntensityRemap, KSpaceSpikeNoise, MaskIntensity, NormalizeIntensity, @@ -98,6 +99,7 @@ RandGaussianSmooth, RandGibbsNoise, RandHistogramShift, + RandIntensityRemap, RandKSpaceSpikeNoise, RandRicianNoise, RandScaleIntensity, diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index b5cf61ce0c..7a50a528d0 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -16,7 +16,7 @@ from abc import abstractmethod from collections.abc import Iterable from functools import partial -from typing import Any, Callable, List, Optional, Sequence, Tuple, Union +from typing import Any, Callable, List, Mapping, Optional, Sequence, Tuple, Union from warnings import warn import numpy as np @@ -75,6 +75,8 @@ "RandCoarseDropout", "RandCoarseShuffle", "HistogramNormalize", + "IntensityRemap", + "RandIntensityRemap", ] @@ -182,9 +184,9 @@ def _add_noise(self, img: NdarrayOrTensor, mean: float, std: float): if isinstance(img, torch.Tensor): n1 = torch.tensor(self._noise1, device=img.device) n2 = torch.tensor(self._noise2, device=img.device) - return torch.sqrt((img + n1) ** 2 + n2**2) + return torch.sqrt((img + n1) ** 2 + n2 ** 2) - return np.sqrt((img + self._noise1) ** 2 + self._noise2**2) + return np.sqrt((img + self._noise1) ** 2 + self._noise2 ** 2) def __call__(self, img: NdarrayOrTensor, randomize: bool = True) -> NdarrayOrTensor: """ @@ -2053,3 +2055,123 @@ def __call__(self, img: NdarrayOrTensor, mask: Optional[NdarrayOrTensor] = None) out, *_ = convert_to_dst_type(src=ret, dst=img, dtype=self.dtype or img.dtype) return out + + +class IntensityRemap(RandomizableTransform): + """ + Transform for intensity remapping of images. The intensity at each + pixel is replaced by a new values coming from an intensity remappping + curve. + + The remapping curve is created by uniformly sampling values from the + possible intensities for the input image and then adding a linear + component. The curve is the rescaled to the input image intensity range. + + Intended to be used as a means to data augmentation via: + :py:class:`monai.transforms.RandIntensityRemap`. + + Implementation is described in the work: + `Intensity augmentation for domain transfer of whole breast segmentation + in MRI `_. + + Note: for large images the transform may be too slow to apply on the fly. + + Args: + kernel_size: window size for averaging operation for the remapping + curve. + slope: slope of the linear component. Easiest to leave default value + and tune the kernel_size parameter instead. + return_map: set to True for the transform to return a dictionary version + of the lookup table used in the intensity remapping. The keys + correspond to the old intensities, and the values are the new + values. + """ + + def __init__(self, kernel_size: int = 30, slope: float = 0.7, return_map: bool = False): + + super().__init__() + + self.kernel_size = kernel_size + self.slope = slope + self.return_map = return_map + + def __call__(self, img: torch.Tensor) -> Union[torch.Tensor, Tuple[torch.Tensor, Mapping]]: + """ + Args: + img: image to remap. + """ + + img = img.clone() + # sample noise + vals_to_sample = torch.unique(img).tolist() + noise = torch.from_numpy(self.R.choice(vals_to_sample, len(vals_to_sample) - 1 + self.kernel_size)) + # smooth + noise = torch.nn.AvgPool1d(self.kernel_size, stride=1)(noise.unsqueeze(0)).squeeze() + # add linear component + grid = torch.arange(len(noise)) / len(noise) + noise += self.slope * grid + # rescale + noise = (noise - noise.min()) / (noise.max() - noise.min()) * img.max() + img.min() + + # intensity remapping function + map = dict(zip(vals_to_sample, noise.tolist())) + + for key in map: + img[img == key] = map[key] + + if self.return_map: + return img, map + else: + return img + + +class RandIntensityRemap(RandomizableTransform): + """ + Transform for intensity remapping of images. The intensity at each + pixel is replaced by a new values coming from an intensity remappping + curve. + + The remapping curve is created by uniformly sampling values from the + possible intensities for the input image and then adding a linear + component. The curve is the rescaled to the input image intensity range. + + Implementation is described in the work: + `Intensity augmentation for domain transfer of whole breast segmentation + in MRI `_. + + Note: for large images the transform may be too slow to apply on the fly. + + Args: + prob: probability of applying the transform. + kernel_size: window size for averaging operation for the remapping + curve. + slope: slope of the linear component. Easiest to leave default value + and tune the kernel_size parameter instead. + channel_wise: set to True to treat each channel independently. + """ + + def __init__(self, prob: float = 0.1, kernel_size: int = 30, slope: float = 0.7, channel_wise: bool = True): + + RandomizableTransform.__init__(self, prob=prob) + self.kernel_size = kernel_size + self.slope = slope + self.channel_wise = True + + def __call__(self, img: torch.Tensor) -> torch.Tensor: + """ + Args: + img: image to remap. + """ + super().randomize(None) + if self._do_transform: + if self.channel_wise: + img = torch.stack( + [ + IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img[i]) + for i in range(len(img)) + ] + ) + else: + img = IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img) + + return img diff --git a/monai/transforms/smooth_field/array.py b/monai/transforms/smooth_field/array.py index f581687ea5..61342b8941 100644 --- a/monai/transforms/smooth_field/array.py +++ b/monai/transforms/smooth_field/array.py @@ -232,7 +232,7 @@ def __call__(self, img: NdarrayOrTensor, randomize: bool = True) -> NdarrayOrTen # everything below here is to be computed using the destination type (numpy, tensor, etc.) img = (img - img_min) / (img_rng + 1e-10) # rescale to unit values - img = img**rfield # contrast is changed by raising image data to a power, in this case the field + img = img ** rfield # contrast is changed by raising image data to a power, in this case the field out = (img * img_rng) + img_min # rescale back to the original image value range diff --git a/monai/transforms/utils_create_transform_ims.py b/monai/transforms/utils_create_transform_ims.py index b096e1b93d..9fc9206fac 100644 --- a/monai/transforms/utils_create_transform_ims.py +++ b/monai/transforms/utils_create_transform_ims.py @@ -383,7 +383,7 @@ def get_images(data, is_label=False): # 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)) + 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 diff --git a/tests/test_lmdbdataset.py b/tests/test_lmdbdataset.py index 33f27ee4bc..b624e5c4e3 100644 --- a/tests/test_lmdbdataset.py +++ b/tests/test_lmdbdataset.py @@ -57,7 +57,7 @@ SimulateDelayd(keys=["image", "label", "extra"], delay_time=[1e-7, 1e-6, 1e-5]), ], (128, 128, 128), - {"pickle_protocol": 2, "lmdb_kwargs": {"map_size": 100 * 1024**2}}, + {"pickle_protocol": 2, "lmdb_kwargs": {"map_size": 100 * 1024 ** 2}}, ] TEST_CASE_6 = [ @@ -66,7 +66,7 @@ SimulateDelayd(keys=["image", "label", "extra"], delay_time=[1e-7, 1e-6, 1e-5]), ], (128, 128, 128), - {"db_name": "testdb", "lmdb_kwargs": {"map_size": 100 * 1024**2}}, + {"db_name": "testdb", "lmdb_kwargs": {"map_size": 100 * 1024 ** 2}}, ] TEST_CASE_7 = [ @@ -75,7 +75,7 @@ SimulateDelayd(keys=["image", "label", "extra"], delay_time=[1e-7, 1e-6, 1e-5]), ], (128, 128, 128), - {"db_name": "testdb", "lmdb_kwargs": {"map_size": 2 * 1024**2}}, + {"db_name": "testdb", "lmdb_kwargs": {"map_size": 2 * 1024 ** 2}}, ] diff --git a/tests/test_tile_on_grid.py b/tests/test_tile_on_grid.py index 09434de5e0..212f461c9a 100644 --- a/tests/test_tile_on_grid.py +++ b/tests/test_tile_on_grid.py @@ -107,7 +107,7 @@ def make_image( tiles = np.stack(tiles_list, axis=0) - if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count**2: + if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count ** 2: tiles = tiles[np.argsort(tiles.sum(axis=(1, 2, 3)))] return imlarge, tiles diff --git a/tests/test_tile_on_grid_dict.py b/tests/test_tile_on_grid_dict.py index c6f35fe738..609601f222 100644 --- a/tests/test_tile_on_grid_dict.py +++ b/tests/test_tile_on_grid_dict.py @@ -116,7 +116,7 @@ def make_image( tiles = np.stack(tiles_list, axis=0) - if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count**2: + if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count ** 2: tiles = tiles[np.argsort(tiles.sum(axis=(1, 2, 3)))] return imlarge, tiles From 92043636475c5e3d14f710a32a02ced42a0a72d4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 10 Feb 2022 07:58:33 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- monai/transforms/intensity/array.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 7a50a528d0..45307ab918 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -2074,7 +2074,7 @@ class IntensityRemap(RandomizableTransform): `Intensity augmentation for domain transfer of whole breast segmentation in MRI `_. - Note: for large images the transform may be too slow to apply on the fly. + Note: for large images the transform may be too slow to apply on the fly. Args: kernel_size: window size for averaging operation for the remapping @@ -2140,7 +2140,7 @@ class RandIntensityRemap(RandomizableTransform): in MRI `_. Note: for large images the transform may be too slow to apply on the fly. - + Args: prob: probability of applying the transform. kernel_size: window size for averaging operation for the remapping From 26122560b0a67429015e7734fbfd7731dd537c43 Mon Sep 17 00:00:00 2001 From: monai-bot Date: Thu, 10 Feb 2022 08:23:06 +0000 Subject: [PATCH 3/6] [MONAI] python code formatting Signed-off-by: monai-bot --- monai/config/deviceconfig.py | 8 ++++---- monai/data/dataset.py | 2 +- monai/data/dataset_summary.py | 2 +- monai/handlers/parameter_scheduler.py | 2 +- monai/losses/image_dissimilarity.py | 6 +++--- monai/networks/blocks/activation.py | 2 -- monai/networks/blocks/selfattention.py | 2 +- monai/networks/blocks/upsample.py | 4 ++-- monai/networks/blocks/warp.py | 2 +- monai/networks/layers/convutils.py | 2 +- monai/networks/nets/dints.py | 10 +++++----- monai/networks/nets/highresnet.py | 2 +- monai/networks/nets/regunet.py | 6 +++--- monai/networks/nets/segresnet.py | 6 +++--- monai/networks/utils.py | 2 +- monai/transforms/intensity/array.py | 4 ++-- monai/transforms/smooth_field/array.py | 2 +- monai/transforms/utils_create_transform_ims.py | 2 +- tests/test_lmdbdataset.py | 6 +++--- tests/test_tile_on_grid.py | 2 +- tests/test_tile_on_grid_dict.py | 2 +- 21 files changed, 37 insertions(+), 39 deletions(-) diff --git a/monai/config/deviceconfig.py b/monai/config/deviceconfig.py index 91b944bde5..fd7ca572e6 100644 --- a/monai/config/deviceconfig.py +++ b/monai/config/deviceconfig.py @@ -161,9 +161,9 @@ def get_system_info() -> OrderedDict: ), ) mem = psutil.virtual_memory() - _dict_append(output, "Total physical memory (GB)", lambda: round(mem.total / 1024 ** 3, 1)) - _dict_append(output, "Available memory (GB)", lambda: round(mem.available / 1024 ** 3, 1)) - _dict_append(output, "Used memory (GB)", lambda: round(mem.used / 1024 ** 3, 1)) + _dict_append(output, "Total physical memory (GB)", lambda: round(mem.total / 1024**3, 1)) + _dict_append(output, "Available memory (GB)", lambda: round(mem.available / 1024**3, 1)) + _dict_append(output, "Used memory (GB)", lambda: round(mem.used / 1024**3, 1)) return output @@ -209,7 +209,7 @@ def get_gpu_info() -> OrderedDict: _dict_append(output, f"GPU {gpu} Is integrated", lambda: bool(gpu_info.is_integrated)) _dict_append(output, f"GPU {gpu} Is multi GPU board", lambda: bool(gpu_info.is_multi_gpu_board)) _dict_append(output, f"GPU {gpu} Multi processor count", lambda: gpu_info.multi_processor_count) - _dict_append(output, f"GPU {gpu} Total memory (GB)", lambda: round(gpu_info.total_memory / 1024 ** 3, 1)) + _dict_append(output, f"GPU {gpu} Total memory (GB)", lambda: round(gpu_info.total_memory / 1024**3, 1)) _dict_append(output, f"GPU {gpu} CUDA capability (maj.min)", lambda: f"{gpu_info.major}.{gpu_info.minor}") return output diff --git a/monai/data/dataset.py b/monai/data/dataset.py index 8c50446815..156708c7dd 100644 --- a/monai/data/dataset.py +++ b/monai/data/dataset.py @@ -513,7 +513,7 @@ def __init__( self.db_file = self.cache_dir / f"{db_name}.lmdb" self.lmdb_kwargs = lmdb_kwargs or {} if not self.lmdb_kwargs.get("map_size", 0): - self.lmdb_kwargs["map_size"] = 1024 ** 4 # default map_size + self.lmdb_kwargs["map_size"] = 1024**4 # default map_size # lmdb is single-writer multi-reader by default # the cache is created without multi-threading self._read_env = None diff --git a/monai/data/dataset_summary.py b/monai/data/dataset_summary.py index 2b4df4ebbf..956e038569 100644 --- a/monai/data/dataset_summary.py +++ b/monai/data/dataset_summary.py @@ -150,7 +150,7 @@ def calculate_statistics(self, foreground_threshold: int = 0): self.data_max, self.data_min = max(voxel_max), min(voxel_min) self.data_mean = (voxel_sum / voxel_ct).item() - self.data_std = (torch.sqrt(voxel_square_sum / voxel_ct - self.data_mean ** 2)).item() + self.data_std = (torch.sqrt(voxel_square_sum / voxel_ct - self.data_mean**2)).item() def calculate_percentiles( self, diff --git a/monai/handlers/parameter_scheduler.py b/monai/handlers/parameter_scheduler.py index c0e18edcd0..67c51fd351 100644 --- a/monai/handlers/parameter_scheduler.py +++ b/monai/handlers/parameter_scheduler.py @@ -134,7 +134,7 @@ def _exponential(initial_value: float, gamma: float, current_step: int) -> float Returns: float: new parameter value """ - return initial_value * gamma ** current_step + return initial_value * gamma**current_step @staticmethod def _step(initial_value: float, gamma: float, step_size: int, current_step: int) -> float: diff --git a/monai/losses/image_dissimilarity.py b/monai/losses/image_dissimilarity.py index b527522cd7..a06f6fb5cd 100644 --- a/monai/losses/image_dissimilarity.py +++ b/monai/losses/image_dissimilarity.py @@ -126,7 +126,7 @@ 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})") - t2, p2, tp = target ** 2, pred ** 2, target * pred + t2, p2, tp = target**2, pred**2, target * pred kernel, kernel_vol = self.kernel.to(pred), self.kernel_vol.to(pred) # sum over kernel t_sum = separable_filtering(target, kernels=[kernel.to(pred)] * self.ndim) @@ -217,7 +217,7 @@ def __init__( self.num_bins = num_bins self.kernel_type = kernel_type if self.kernel_type == "gaussian": - self.preterm = 1 / (2 * sigma ** 2) + 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) @@ -280,7 +280,7 @@ def parzen_windowing_b_spline(self, img: torch.Tensor, order: int) -> Tuple[torc 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 + (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: diff --git a/monai/networks/blocks/activation.py b/monai/networks/blocks/activation.py index cf27b22552..1526b37056 100644 --- a/monai/networks/blocks/activation.py +++ b/monai/networks/blocks/activation.py @@ -19,7 +19,6 @@ def monai_mish(x, inplace: bool = False): return torch.nn.functional.mish(x, inplace=inplace) - else: def monai_mish(x, inplace: bool = False): @@ -31,7 +30,6 @@ def monai_mish(x, inplace: bool = False): def monai_swish(x, inplace: bool = False): return torch.nn.functional.silu(x, inplace=inplace) - else: def monai_swish(x, inplace: bool = False): diff --git a/monai/networks/blocks/selfattention.py b/monai/networks/blocks/selfattention.py index 4a86cd84bc..cf837c5a6f 100644 --- a/monai/networks/blocks/selfattention.py +++ b/monai/networks/blocks/selfattention.py @@ -46,7 +46,7 @@ def __init__(self, hidden_size: int, num_heads: int, dropout_rate: float = 0.0) self.drop_output = nn.Dropout(dropout_rate) self.drop_weights = nn.Dropout(dropout_rate) self.head_dim = hidden_size // num_heads - self.scale = self.head_dim ** -0.5 + self.scale = self.head_dim**-0.5 def forward(self, x): q, k, v = einops.rearrange(self.qkv(x), "b h (qkv l d) -> qkv b l h d", qkv=3, l=self.num_heads) diff --git a/monai/networks/blocks/upsample.py b/monai/networks/blocks/upsample.py index c72d1bc518..fa3929df20 100644 --- a/monai/networks/blocks/upsample.py +++ b/monai/networks/blocks/upsample.py @@ -219,7 +219,7 @@ def __init__( 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 ** self.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 ) @@ -247,7 +247,7 @@ def forward(self, x: torch.Tensor) -> torch.Tensor: x: Tensor in shape (batch, channel, spatial_1[, spatial_2, ...). """ x = self.conv_block(x) - if x.shape[1] % (self.scale_factor ** self.dimensions) != 0: + if x.shape[1] % (self.scale_factor**self.dimensions) != 0: raise ValueError( f"Number of channels after `conv_block` ({x.shape[1]}) must be evenly " "divisible by scale_factor ** dimensions " diff --git a/monai/networks/blocks/warp.py b/monai/networks/blocks/warp.py index 9fdaab0a48..5b925258b6 100644 --- a/monai/networks/blocks/warp.py +++ b/monai/networks/blocks/warp.py @@ -150,7 +150,7 @@ def forward(self, dvf): Returns: a dense displacement field """ - ddf: torch.Tensor = dvf / (2 ** self.num_steps) + ddf: torch.Tensor = dvf / (2**self.num_steps) for _ in range(self.num_steps): ddf = ddf + self.warp_layer(image=ddf, ddf=ddf) return ddf diff --git a/monai/networks/layers/convutils.py b/monai/networks/layers/convutils.py index 5efb6e792f..1e9ce954e8 100644 --- a/monai/networks/layers/convutils.py +++ b/monai/networks/layers/convutils.py @@ -115,7 +115,7 @@ def gaussian_1d( out = out.clamp(min=0) elif approx.lower() == "sampled": x = torch.arange(-tail, tail + 1, dtype=torch.float, device=sigma.device) - out = torch.exp(-0.5 / (sigma * sigma) * x ** 2) + out = torch.exp(-0.5 / (sigma * sigma) * x**2) if not normalize: # compute the normalizer out = out / (2.5066282 * sigma) elif approx.lower() == "scalespace": diff --git a/monai/networks/nets/dints.py b/monai/networks/nets/dints.py index c024d6e0f1..a4aaf32eed 100644 --- a/monai/networks/nets/dints.py +++ b/monai/networks/nets/dints.py @@ -124,7 +124,7 @@ def __init__(self, in_channel: int, out_channel: int, spatial_dims: int = 3): # s0 is upsampled 2x from s1, representing feature sizes at two resolutions. # in_channel * s0 (activation) + 3 * out_channel * s1 (convolution, concatenation, normalization) # s0 = s1 * 2^(spatial_dims) = output_size / out_channel * 2^(spatial_dims) - self.ram_cost = in_channel / out_channel * 2 ** self._spatial_dims + 3 + self.ram_cost = in_channel / out_channel * 2**self._spatial_dims + 3 class MixedOp(nn.Module): @@ -330,7 +330,7 @@ def __init__( # define downsample stems before DiNTS search if use_downsample: self.stem_down[str(res_idx)] = StemTS( - nn.Upsample(scale_factor=1 / (2 ** res_idx), mode=mode, align_corners=True), + nn.Upsample(scale_factor=1 / (2**res_idx), mode=mode, align_corners=True), conv_type( in_channels=in_channels, out_channels=self.filter_nums[res_idx], @@ -373,7 +373,7 @@ def __init__( else: self.stem_down[str(res_idx)] = StemTS( - nn.Upsample(scale_factor=1 / (2 ** res_idx), mode=mode, align_corners=True), + nn.Upsample(scale_factor=1 / (2**res_idx), mode=mode, align_corners=True), conv_type( in_channels=in_channels, out_channels=self.filter_nums[res_idx], @@ -789,7 +789,7 @@ def get_ram_cost_usage(self, in_size, full: bool = False): image_size = np.array(in_size[-self._spatial_dims :]) sizes = [] for res_idx in range(self.num_depths): - sizes.append(batch_size * self.filter_nums[res_idx] * (image_size // (2 ** res_idx)).prod()) + sizes.append(batch_size * self.filter_nums[res_idx] * (image_size // (2**res_idx)).prod()) sizes = torch.tensor(sizes).to(torch.float32).to(self.device) / (2 ** (int(self.use_downsample))) probs_a, arch_code_prob_a = self.get_prob_a(child=False) cell_prob = F.softmax(self.log_alpha_c, dim=-1) @@ -807,7 +807,7 @@ def get_ram_cost_usage(self, in_size, full: bool = False): * (1 + (ram_cost[blk_idx, path_idx] * cell_prob[blk_idx, path_idx]).sum()) * sizes[self.arch_code2out[path_idx]] ) - return usage * 32 / 8 / 1024 ** 2 + return usage * 32 / 8 / 1024**2 def get_topology_entropy(self, probs): """ diff --git a/monai/networks/nets/highresnet.py b/monai/networks/nets/highresnet.py index 95c0c758af..891a65e67b 100644 --- a/monai/networks/nets/highresnet.py +++ b/monai/networks/nets/highresnet.py @@ -168,7 +168,7 @@ def __init__( # residual blocks for (idx, params) in enumerate(layer_params[1:-2]): # res blocks except the 1st and last two conv layers. _in_chns, _out_chns = _out_chns, params["n_features"] - _dilation = 2 ** idx + _dilation = 2**idx for _ in range(params["repeat"]): blocks.append( HighResBlock( diff --git a/monai/networks/nets/regunet.py b/monai/networks/nets/regunet.py index 8524563faa..6776c7ce9e 100644 --- a/monai/networks/nets/regunet.py +++ b/monai/networks/nets/regunet.py @@ -92,7 +92,7 @@ def __init__( raise AssertionError self.encode_kernel_sizes: List[int] = encode_kernel_sizes - self.num_channels = [self.num_channel_initial * (2 ** d) for d in range(self.depth + 1)] + self.num_channels = [self.num_channel_initial * (2**d) for d in range(self.depth + 1)] self.min_extract_level = min(self.extract_levels) # init layers @@ -310,14 +310,14 @@ def __init__( encode_kernel_sizes: Union[int, List[int]] = 3, ): for size in image_size: - if size % (2 ** depth) != 0: + if size % (2**depth) != 0: raise ValueError( f"given depth {depth}, " f"all input spatial dimension must be divisible by {2 ** depth}, " f"got input of size {image_size}" ) self.image_size = image_size - self.decode_size = [size // (2 ** depth) for size in image_size] + self.decode_size = [size // (2**depth) for size in image_size] super().__init__( spatial_dims=spatial_dims, in_channels=in_channels, diff --git a/monai/networks/nets/segresnet.py b/monai/networks/nets/segresnet.py index d2c45dd3a3..299f1ca811 100644 --- a/monai/networks/nets/segresnet.py +++ b/monai/networks/nets/segresnet.py @@ -102,7 +102,7 @@ def _make_down_layers(self): down_layers = nn.ModuleList() blocks_down, spatial_dims, filters, norm = (self.blocks_down, self.spatial_dims, self.init_filters, self.norm) for i in range(len(blocks_down)): - layer_in_channels = filters * 2 ** i + layer_in_channels = filters * 2**i pre_conv = ( get_conv_layer(spatial_dims, layer_in_channels // 2, layer_in_channels, stride=2) if i > 0 @@ -299,12 +299,12 @@ def _get_vae_loss(self, net_input: torch.Tensor, vae_input: torch.Tensor): if self.vae_estimate_std: z_sigma = self.vae_fc2(x_vae) z_sigma = F.softplus(z_sigma) - vae_reg_loss = 0.5 * torch.mean(z_mean ** 2 + z_sigma ** 2 - torch.log(1e-8 + z_sigma ** 2) - 1) + vae_reg_loss = 0.5 * torch.mean(z_mean**2 + z_sigma**2 - torch.log(1e-8 + z_sigma**2) - 1) x_vae = z_mean + z_sigma * z_mean_rand else: z_sigma = self.vae_default_std - vae_reg_loss = torch.mean(z_mean ** 2) + vae_reg_loss = torch.mean(z_mean**2) x_vae = z_mean + z_sigma * z_mean_rand diff --git a/monai/networks/utils.py b/monai/networks/utils.py index 90e6d2760d..a6b0699107 100644 --- a/monai/networks/utils.py +++ b/monai/networks/utils.py @@ -273,7 +273,7 @@ def pixelshuffle( dim, factor = spatial_dims, scale_factor input_size = list(x.size()) batch_size, channels = input_size[:2] - scale_divisor = factor ** dim + scale_divisor = factor**dim if channels % scale_divisor != 0: raise ValueError( diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 45307ab918..f2875ebc72 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -184,9 +184,9 @@ def _add_noise(self, img: NdarrayOrTensor, mean: float, std: float): if isinstance(img, torch.Tensor): n1 = torch.tensor(self._noise1, device=img.device) n2 = torch.tensor(self._noise2, device=img.device) - return torch.sqrt((img + n1) ** 2 + n2 ** 2) + return torch.sqrt((img + n1) ** 2 + n2**2) - return np.sqrt((img + self._noise1) ** 2 + self._noise2 ** 2) + return np.sqrt((img + self._noise1) ** 2 + self._noise2**2) def __call__(self, img: NdarrayOrTensor, randomize: bool = True) -> NdarrayOrTensor: """ diff --git a/monai/transforms/smooth_field/array.py b/monai/transforms/smooth_field/array.py index 61342b8941..f581687ea5 100644 --- a/monai/transforms/smooth_field/array.py +++ b/monai/transforms/smooth_field/array.py @@ -232,7 +232,7 @@ def __call__(self, img: NdarrayOrTensor, randomize: bool = True) -> NdarrayOrTen # everything below here is to be computed using the destination type (numpy, tensor, etc.) img = (img - img_min) / (img_rng + 1e-10) # rescale to unit values - img = img ** rfield # contrast is changed by raising image data to a power, in this case the field + img = img**rfield # contrast is changed by raising image data to a power, in this case the field out = (img * img_rng) + img_min # rescale back to the original image value range diff --git a/monai/transforms/utils_create_transform_ims.py b/monai/transforms/utils_create_transform_ims.py index 9fc9206fac..b096e1b93d 100644 --- a/monai/transforms/utils_create_transform_ims.py +++ b/monai/transforms/utils_create_transform_ims.py @@ -383,7 +383,7 @@ def get_images(data, is_label=False): # 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)) + 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 diff --git a/tests/test_lmdbdataset.py b/tests/test_lmdbdataset.py index b624e5c4e3..33f27ee4bc 100644 --- a/tests/test_lmdbdataset.py +++ b/tests/test_lmdbdataset.py @@ -57,7 +57,7 @@ SimulateDelayd(keys=["image", "label", "extra"], delay_time=[1e-7, 1e-6, 1e-5]), ], (128, 128, 128), - {"pickle_protocol": 2, "lmdb_kwargs": {"map_size": 100 * 1024 ** 2}}, + {"pickle_protocol": 2, "lmdb_kwargs": {"map_size": 100 * 1024**2}}, ] TEST_CASE_6 = [ @@ -66,7 +66,7 @@ SimulateDelayd(keys=["image", "label", "extra"], delay_time=[1e-7, 1e-6, 1e-5]), ], (128, 128, 128), - {"db_name": "testdb", "lmdb_kwargs": {"map_size": 100 * 1024 ** 2}}, + {"db_name": "testdb", "lmdb_kwargs": {"map_size": 100 * 1024**2}}, ] TEST_CASE_7 = [ @@ -75,7 +75,7 @@ SimulateDelayd(keys=["image", "label", "extra"], delay_time=[1e-7, 1e-6, 1e-5]), ], (128, 128, 128), - {"db_name": "testdb", "lmdb_kwargs": {"map_size": 2 * 1024 ** 2}}, + {"db_name": "testdb", "lmdb_kwargs": {"map_size": 2 * 1024**2}}, ] diff --git a/tests/test_tile_on_grid.py b/tests/test_tile_on_grid.py index 212f461c9a..09434de5e0 100644 --- a/tests/test_tile_on_grid.py +++ b/tests/test_tile_on_grid.py @@ -107,7 +107,7 @@ def make_image( tiles = np.stack(tiles_list, axis=0) - if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count ** 2: + if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count**2: tiles = tiles[np.argsort(tiles.sum(axis=(1, 2, 3)))] return imlarge, tiles diff --git a/tests/test_tile_on_grid_dict.py b/tests/test_tile_on_grid_dict.py index 609601f222..c6f35fe738 100644 --- a/tests/test_tile_on_grid_dict.py +++ b/tests/test_tile_on_grid_dict.py @@ -116,7 +116,7 @@ def make_image( tiles = np.stack(tiles_list, axis=0) - if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count ** 2: + if (filter_mode == "min" or filter_mode == "max") and len(tiles) > tile_count**2: tiles = tiles[np.argsort(tiles.sum(axis=(1, 2, 3)))] return imlarge, tiles From 19f0b4229a3cb237a37ff8e8de9fc6b6bae54984 Mon Sep 17 00:00:00 2001 From: yc7620 Date: Tue, 22 Feb 2022 09:47:59 +0100 Subject: [PATCH 4/6] mapping via bitbucket operation Signed-off-by: yc7620 --- monai/transforms/intensity/array.py | 69 ++++++++++++----------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index 7a50a528d0..86de06d223 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -2063,39 +2063,35 @@ class IntensityRemap(RandomizableTransform): pixel is replaced by a new values coming from an intensity remappping curve. - The remapping curve is created by uniformly sampling values from the - possible intensities for the input image and then adding a linear + The remapping curve is created by uniformly sampling values from the + possible intensities for the input image and then adding a linear component. The curve is the rescaled to the input image intensity range. Intended to be used as a means to data augmentation via: :py:class:`monai.transforms.RandIntensityRemap`. - Implementation is described in the work: - `Intensity augmentation for domain transfer of whole breast segmentation - in MRI `_. - - Note: for large images the transform may be too slow to apply on the fly. + Implementation is described in the work: + `Intensity augmentation for domain transfer of whole breast segmentation + in MRI `_. Args: - kernel_size: window size for averaging operation for the remapping + kernel_size: window size for averaging operation for the remapping curve. slope: slope of the linear component. Easiest to leave default value and tune the kernel_size parameter instead. return_map: set to True for the transform to return a dictionary version of the lookup table used in the intensity remapping. The keys - correspond to the old intensities, and the values are the new + correspond to the old intensities, and the values are the new values. """ - - def __init__(self, kernel_size: int = 30, slope: float = 0.7, return_map: bool = False): + def __init__(self, kernel_size: int = 30, slope: float = 0.7): super().__init__() self.kernel_size = kernel_size self.slope = slope - self.return_map = return_map - def __call__(self, img: torch.Tensor) -> Union[torch.Tensor, Tuple[torch.Tensor, Mapping]]: + def __call__(self, img: torch.Tensor) -> torch.Tensor: """ Args: img: image to remap. @@ -2104,25 +2100,22 @@ def __call__(self, img: torch.Tensor) -> Union[torch.Tensor, Tuple[torch.Tensor, img = img.clone() # sample noise vals_to_sample = torch.unique(img).tolist() - noise = torch.from_numpy(self.R.choice(vals_to_sample, len(vals_to_sample) - 1 + self.kernel_size)) + noise = torch.from_numpy( + self.R.choice(vals_to_sample, len(vals_to_sample) - 1 + self.kernel_size) + ) # smooth - noise = torch.nn.AvgPool1d(self.kernel_size, stride=1)(noise.unsqueeze(0)).squeeze() + noise = AvgPool1d(self.kernel_size, stride = 1)(noise.unsqueeze(0)).squeeze() # add linear component grid = torch.arange(len(noise)) / len(noise) - noise += self.slope * grid + noise += self.slope * grid # rescale noise = (noise - noise.min()) / (noise.max() - noise.min()) * img.max() + img.min() # intensity remapping function - map = dict(zip(vals_to_sample, noise.tolist())) + index_img = torch.bucketize(img, torch.tensor(vals_to_sample)) + img = noise[index_img] - for key in map: - img[img == key] = map[key] - - if self.return_map: - return img, map - else: - return img + return img class RandIntensityRemap(RandomizableTransform): @@ -2131,32 +2124,29 @@ class RandIntensityRemap(RandomizableTransform): pixel is replaced by a new values coming from an intensity remappping curve. - The remapping curve is created by uniformly sampling values from the - possible intensities for the input image and then adding a linear + The remapping curve is created by uniformly sampling values from the + possible intensities for the input image and then adding a linear component. The curve is the rescaled to the input image intensity range. - Implementation is described in the work: - `Intensity augmentation for domain transfer of whole breast segmentation - in MRI `_. + Implementation is described in the work: + `Intensity augmentation for domain transfer of whole breast segmentation + in MRI `_. - Note: for large images the transform may be too slow to apply on the fly. - Args: prob: probability of applying the transform. - kernel_size: window size for averaging operation for the remapping + kernel_size: window size for averaging operation for the remapping curve. slope: slope of the linear component. Easiest to leave default value and tune the kernel_size parameter instead. channel_wise: set to True to treat each channel independently. """ - def __init__(self, prob: float = 0.1, kernel_size: int = 30, slope: float = 0.7, channel_wise: bool = True): RandomizableTransform.__init__(self, prob=prob) self.kernel_size = kernel_size self.slope = slope self.channel_wise = True - + def __call__(self, img: torch.Tensor) -> torch.Tensor: """ Args: @@ -2166,12 +2156,9 @@ def __call__(self, img: torch.Tensor) -> torch.Tensor: if self._do_transform: if self.channel_wise: img = torch.stack( - [ - IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img[i]) - for i in range(len(img)) - ] - ) + [IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img[i]) + for i in range(len(img))]) else: img = IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img) - - return img + + return img \ No newline at end of file From b7809ae0dfc03616d071ac7a544559a1f687014c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 22 Feb 2022 08:54:44 +0000 Subject: [PATCH 5/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- monai/transforms/intensity/array.py | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index d0ab8496d7..f4c697dfa8 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -2063,25 +2063,25 @@ class IntensityRemap(RandomizableTransform): pixel is replaced by a new values coming from an intensity remappping curve. - The remapping curve is created by uniformly sampling values from the - possible intensities for the input image and then adding a linear + The remapping curve is created by uniformly sampling values from the + possible intensities for the input image and then adding a linear component. The curve is the rescaled to the input image intensity range. Intended to be used as a means to data augmentation via: :py:class:`monai.transforms.RandIntensityRemap`. - Implementation is described in the work: - `Intensity augmentation for domain transfer of whole breast segmentation - in MRI `_. + Implementation is described in the work: + `Intensity augmentation for domain transfer of whole breast segmentation + in MRI `_. Args: - kernel_size: window size for averaging operation for the remapping + kernel_size: window size for averaging operation for the remapping curve. slope: slope of the linear component. Easiest to leave default value and tune the kernel_size parameter instead. return_map: set to True for the transform to return a dictionary version of the lookup table used in the intensity remapping. The keys - correspond to the old intensities, and the values are the new + correspond to the old intensities, and the values are the new values. """ def __init__(self, kernel_size: int = 30, slope: float = 0.7): @@ -2107,7 +2107,7 @@ def __call__(self, img: torch.Tensor) -> torch.Tensor: noise = AvgPool1d(self.kernel_size, stride = 1)(noise.unsqueeze(0)).squeeze() # add linear component grid = torch.arange(len(noise)) / len(noise) - noise += self.slope * grid + noise += self.slope * grid # rescale noise = (noise - noise.min()) / (noise.max() - noise.min()) * img.max() + img.min() @@ -2124,17 +2124,17 @@ class RandIntensityRemap(RandomizableTransform): pixel is replaced by a new values coming from an intensity remappping curve. - The remapping curve is created by uniformly sampling values from the - possible intensities for the input image and then adding a linear + The remapping curve is created by uniformly sampling values from the + possible intensities for the input image and then adding a linear component. The curve is the rescaled to the input image intensity range. - Implementation is described in the work: - `Intensity augmentation for domain transfer of whole breast segmentation - in MRI `_. + Implementation is described in the work: + `Intensity augmentation for domain transfer of whole breast segmentation + in MRI `_. Args: prob: probability of applying the transform. - kernel_size: window size for averaging operation for the remapping + kernel_size: window size for averaging operation for the remapping curve. slope: slope of the linear component. Easiest to leave default value and tune the kernel_size parameter instead. @@ -2146,7 +2146,7 @@ def __init__(self, prob: float = 0.1, kernel_size: int = 30, slope: float = 0.7, self.kernel_size = kernel_size self.slope = slope self.channel_wise = True - + def __call__(self, img: torch.Tensor) -> torch.Tensor: """ Args: @@ -2156,9 +2156,9 @@ def __call__(self, img: torch.Tensor) -> torch.Tensor: if self._do_transform: if self.channel_wise: img = torch.stack( - [IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img[i]) + [IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img[i]) for i in range(len(img))]) else: img = IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img) - - return img \ No newline at end of file + + return img From 96819163dc470199a34d62d7a67b84c9a66e4c83 Mon Sep 17 00:00:00 2001 From: monai-bot Date: Tue, 22 Feb 2022 11:11:07 +0000 Subject: [PATCH 6/6] [MONAI] python code formatting Signed-off-by: monai-bot --- monai/transforms/intensity/array.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/monai/transforms/intensity/array.py b/monai/transforms/intensity/array.py index f4c697dfa8..9419873fdd 100644 --- a/monai/transforms/intensity/array.py +++ b/monai/transforms/intensity/array.py @@ -2084,6 +2084,7 @@ class IntensityRemap(RandomizableTransform): correspond to the old intensities, and the values are the new values. """ + def __init__(self, kernel_size: int = 30, slope: float = 0.7): super().__init__() @@ -2100,11 +2101,9 @@ def __call__(self, img: torch.Tensor) -> torch.Tensor: img = img.clone() # sample noise vals_to_sample = torch.unique(img).tolist() - noise = torch.from_numpy( - self.R.choice(vals_to_sample, len(vals_to_sample) - 1 + self.kernel_size) - ) + noise = torch.from_numpy(self.R.choice(vals_to_sample, len(vals_to_sample) - 1 + self.kernel_size)) # smooth - noise = AvgPool1d(self.kernel_size, stride = 1)(noise.unsqueeze(0)).squeeze() + noise = AvgPool1d(self.kernel_size, stride=1)(noise.unsqueeze(0)).squeeze() # add linear component grid = torch.arange(len(noise)) / len(noise) noise += self.slope * grid @@ -2140,6 +2139,7 @@ class RandIntensityRemap(RandomizableTransform): and tune the kernel_size parameter instead. channel_wise: set to True to treat each channel independently. """ + def __init__(self, prob: float = 0.1, kernel_size: int = 30, slope: float = 0.7, channel_wise: bool = True): RandomizableTransform.__init__(self, prob=prob) @@ -2156,8 +2156,11 @@ def __call__(self, img: torch.Tensor) -> torch.Tensor: if self._do_transform: if self.channel_wise: img = torch.stack( - [IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img[i]) - for i in range(len(img))]) + [ + IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img[i]) + for i in range(len(img)) + ] + ) else: img = IntensityRemap(self.kernel_size, self.R.choice([-self.slope, self.slope]))(img)