From 4c112f0b0502a18b79b99c267e04ba1944bb48a2 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Sat, 23 Mar 2024 17:19:58 +0300 Subject: [PATCH 01/10] Added black-comma style fix --- GANDLF/cli/deploy.py | 4 +- GANDLF/cli/generate_metrics.py | 20 ++---- GANDLF/cli/patch_extraction.py | 4 +- GANDLF/cli/preprocess_and_save.py | 4 +- GANDLF/compute/forward_pass.py | 14 +--- GANDLF/compute/generic.py | 5 +- GANDLF/compute/inference_loop.py | 34 +++------ GANDLF/compute/training_loop.py | 17 ++--- GANDLF/config_manager.py | 11 +-- GANDLF/data/augmentation/__init__.py | 5 +- GANDLF/data/augmentation/noise_enhanced.py | 4 +- GANDLF/data/augmentation/rgb_augs.py | 5 +- GANDLF/data/augmentation/wrap_torchio.py | 3 +- GANDLF/data/inference_dataloader_histopath.py | 5 +- GANDLF/data/preprocessing/__init__.py | 12 +--- .../data/preprocessing/non_zero_normalize.py | 10 +-- GANDLF/data/preprocessing/resample_minimum.py | 3 +- GANDLF/inference_manager.py | 3 +- GANDLF/metrics/classification.py | 3 +- GANDLF/metrics/regression.py | 8 +-- GANDLF/models/MSDNet.py | 6 +- GANDLF/models/deep_unet.py | 6 +- GANDLF/models/densenet.py | 18 +---- GANDLF/models/efficientnet.py | 6 +- GANDLF/models/fcn.py | 5 +- GANDLF/models/imagenet_unet.py | 10 +-- GANDLF/models/imagenet_vgg.py | 72 +++++-------------- GANDLF/models/light_unet.py | 6 +- GANDLF/models/light_unet_multilayer.py | 6 +- GANDLF/models/resnet.py | 16 +---- GANDLF/models/sdnet.py | 48 +++---------- GANDLF/models/transunet.py | 5 +- GANDLF/models/uinc.py | 5 +- GANDLF/models/unet.py | 6 +- GANDLF/models/unetr.py | 10 +-- GANDLF/models/vgg.py | 26 ++----- GANDLF/utils/imaging.py | 6 +- GANDLF/utils/modelio.py | 5 +- GANDLF/utils/tensor.py | 10 +-- .../getting_started_3d_rad_seg.py | 5 +- pyproject.toml | 20 ++++-- testing/test_full.py | 58 ++++----------- 42 files changed, 120 insertions(+), 409 deletions(-) diff --git a/GANDLF/cli/deploy.py b/GANDLF/cli/deploy.py index df0b2c6f6..fd96bd197 100644 --- a/GANDLF/cli/deploy.py +++ b/GANDLF/cli/deploy.py @@ -113,9 +113,7 @@ def deploy_docker_mlcube( os.makedirs(output_workspace_folder, exist_ok=True) if os.path.exists(mlcube_workspace_folder): shutil.copytree( - mlcube_workspace_folder, - output_workspace_folder, - dirs_exist_ok=True, + mlcube_workspace_folder, output_workspace_folder, dirs_exist_ok=True ) if config is not None: diff --git a/GANDLF/cli/generate_metrics.py b/GANDLF/cli/generate_metrics.py index 670541b55..332f85dcf 100644 --- a/GANDLF/cli/generate_metrics.py +++ b/GANDLF/cli/generate_metrics.py @@ -112,13 +112,10 @@ def generate_metrics_dict( parameters["model"]["class_list"] = [1] parameters["model"]["num_classes"] = 1 overall_stats_dict[current_subject_id][str(class_index)]["dice"] = dice( - current_prediction, - current_target, + current_prediction, current_target ).item() nsd, hd100, hd95 = _calculator_generic_all_surface_distances( - current_prediction, - current_target, - parameters, + current_prediction, current_target, parameters ) overall_stats_dict[current_subject_id][str(class_index)][ "nsd" @@ -130,13 +127,8 @@ def generate_metrics_dict( "hd95" ] = hd95.item() - ( - s, - p, - ) = _calculator_sensitivity_specificity( - current_prediction, - current_target, - parameters, + (s, p) = _calculator_sensitivity_specificity( + current_prediction, current_target, parameters ) overall_stats_dict[current_subject_id][str(class_index)][ "sensitivity" @@ -147,9 +139,7 @@ def generate_metrics_dict( overall_stats_dict[current_subject_id][ "jaccard_" + str(class_index) ] = _calculator_jaccard( - current_prediction, - current_target, - parameters, + current_prediction, current_target, parameters ).item() current_target_image = sitk.GetImageFromArray( current_target[0, 0, ...].long() diff --git a/GANDLF/cli/patch_extraction.py b/GANDLF/cli/patch_extraction.py index da0e73f53..23dd23baf 100644 --- a/GANDLF/cli/patch_extraction.py +++ b/GANDLF/cli/patch_extraction.py @@ -15,9 +15,7 @@ patch_artifact_check, # pen_marking_check, ) -from GANDLF.utils import ( - parseTrainingCSV, -) +from GANDLF.utils import parseTrainingCSV def parse_gandlf_csv(fpath): diff --git a/GANDLF/cli/preprocess_and_save.py b/GANDLF/cli/preprocess_and_save.py index c9144b88b..de192695d 100644 --- a/GANDLF/cli/preprocess_and_save.py +++ b/GANDLF/cli/preprocess_and_save.py @@ -66,9 +66,7 @@ def preprocess_and_save( ) dataloader_for_processing = DataLoader( - data_for_processing, - batch_size=1, - pin_memory=False, + data_for_processing, batch_size=1, pin_memory=False ) # initialize a new dict for the preprocessed data diff --git a/GANDLF/compute/forward_pass.py b/GANDLF/compute/forward_pass.py index b0131c3a5..9da87b8ff 100644 --- a/GANDLF/compute/forward_pass.py +++ b/GANDLF/compute/forward_pass.py @@ -345,11 +345,7 @@ def validate_network( # if jpg detected, convert to 8-bit arrays ext = get_filename_extension_sanitized(subject["1"]["path"][0]) - if ext in [ - ".jpg", - ".jpeg", - ".png", - ]: + if ext in [".jpg", ".jpeg", ".png"]: pred_mask = pred_mask.astype(np.uint8) ## special case for 2D @@ -369,8 +365,7 @@ def validate_network( # Create the subject directory if it doesn't exist in the # current_output_dir directory os.makedirs( - os.path.join(current_output_dir, "testing"), - exist_ok=True, + os.path.join(current_output_dir, "testing"), exist_ok=True ) os.makedirs( os.path.join( @@ -386,10 +381,7 @@ def validate_network( subject["subject_id"][0] + "_seg" + ext, ) - sitk.WriteImage( - result_image, - path_to_save, - ) + sitk.WriteImage(result_image, path_to_save) else: # final regression output output_prediction = output_prediction / len(patch_loader) diff --git a/GANDLF/compute/generic.py b/GANDLF/compute/generic.py index 7888a395f..8c253cc2c 100644 --- a/GANDLF/compute/generic.py +++ b/GANDLF/compute/generic.py @@ -6,10 +6,7 @@ from GANDLF.models import get_model from GANDLF.schedulers import get_scheduler from GANDLF.optimizers import get_optimizer -from GANDLF.data import ( - get_train_loader, - get_validation_loader, -) +from GANDLF.data import get_train_loader, get_validation_loader from GANDLF.utils import ( populate_header_in_parameters, parseTrainingCSV, diff --git a/GANDLF/compute/inference_loop.py b/GANDLF/compute/inference_loop.py index c7113d384..c09b44cf7 100644 --- a/GANDLF/compute/inference_loop.py +++ b/GANDLF/compute/inference_loop.py @@ -62,14 +62,7 @@ def inference_loop( or parameters["model"]["type"].lower() == "openvino" ), f"The model type is not recognized: {parameters['model']['type']}" - ( - model, - _, - _, - _, - _, - parameters, - ) = create_pytorch_objects(parameters, device=device) + (model, _, _, _, _, parameters) = create_pytorch_objects(parameters, device=device) # Loading the weights into the model main_dict = None @@ -103,12 +96,10 @@ def inference_loop( # Loading the executable OpenVINO model if os.path.isdir(modelDir): xml_to_check = os.path.join( - modelDir, - str(parameters["model"]["architecture"]) + "_best.xml", + modelDir, str(parameters["model"]["architecture"]) + "_best.xml" ) bin_to_check = os.path.join( - modelDir, - str(parameters["model"]["architecture"]) + "_best.bin", + modelDir, str(parameters["model"]["architecture"]) + "_best.bin" ) if not os.path.isfile(xml_to_check): raise ValueError( @@ -312,10 +303,7 @@ def inference_loop( ) if parameters["problem_type"] != "segmentation": - output_file = os.path.join( - subject_dest_dir, - "predictions.csv", - ) + output_file = os.path.join(subject_dest_dir, "predictions.csv") with open(output_file, "w") as f: f.write(output_to_write) @@ -323,17 +311,12 @@ def inference_loop( if probs_map is not None: try: for n in range(parameters["model"]["num_classes"]): - heatmap_gray = np.array( - probs_map[n, ...] * 255, - dtype=np.uint8, - ) + heatmap_gray = np.array(probs_map[n, ...] * 255, dtype=np.uint8) heatmaps[str(n) + "_jet"] = cv2.applyColorMap( - heatmap_gray, - cv2.COLORMAP_JET, + heatmap_gray, cv2.COLORMAP_JET ) heatmaps[str(n) + "_turbo"] = cv2.applyColorMap( - heatmap_gray, - cv2.COLORMAP_TURBO, + heatmap_gray, cv2.COLORMAP_TURBO ) heatmaps[str(n) + "_agni"] = applyCustomColorMap(heatmap_gray) @@ -367,8 +350,7 @@ def inference_loop( ) file_to_write = os.path.join( - subject_dest_dir, - "probability_map_blended_" + key + ".png", + subject_dest_dir, "probability_map_blended_" + key + ".png" ) cv2.imwrite(file_to_write, blended_image) except Exception as ex: diff --git a/GANDLF/compute/training_loop.py b/GANDLF/compute/training_loop.py index d129757e3..0a88fa647 100644 --- a/GANDLF/compute/training_loop.py +++ b/GANDLF/compute/training_loop.py @@ -100,18 +100,14 @@ def train_network( label = torch.cat([subject[key] for key in params["value_keys"]], dim=0) # min is needed because for certain cases, batch size becomes smaller than the total remaining labels label = label.reshape( - min(params["batch_size"], len(label)), - len(params["value_keys"]), + min(params["batch_size"], len(label)), len(params["value_keys"]) ) else: label = subject["label"][torchio.DATA] label = label.to(params["device"]) if params["save_training"]: - write_training_patches( - subject, - params, - ) + write_training_patches(subject, params) # ensure spacing is always present in params and is always subject-specific if "spacing" in subject: @@ -190,10 +186,7 @@ def train_network( ).tolist() else: to_print = total_epoch_train_metric[metric] / (batch_idx + 1) - print( - "Half-Epoch Average train " + metric + " : ", - to_print, - ) + print("Half-Epoch Average train " + metric + " : ", to_print) average_epoch_train_loss = total_epoch_train_loss / len(train_dataloader) print(" Epoch Final train loss : ", average_epoch_train_loss) @@ -343,9 +336,7 @@ def training_loop( # this is just used to generate the headers for the overall stats temp_tensor = torch.randint(0, params["model"]["num_classes"], (5,)) overall_metrics = overall_stats( - temp_tensor.to(dtype=torch.int32), - temp_tensor.to(dtype=torch.int32), - params, + temp_tensor.to(dtype=torch.int32), temp_tensor.to(dtype=torch.int32), params ) metrics_log = params["metrics"].copy() diff --git a/GANDLF/config_manager.py b/GANDLF/config_manager.py index 80e147064..4db8ae1c8 100644 --- a/GANDLF/config_manager.py +++ b/GANDLF/config_manager.py @@ -445,11 +445,7 @@ def _parseConfig( if len(params["data_preprocessing"]) > 0: thresholdOrClip = False # this can be extended, as required - thresholdOrClipDict = [ - "threshold", - "clip", - "clamp", - ] + thresholdOrClipDict = ["threshold", "clip", "clamp"] resize_requested = False temp_dict = deepcopy(params["data_preprocessing"]) @@ -708,10 +704,7 @@ def _parseConfig( params["optimizer"] = temp_dict # initialize defaults for inference mechanism - inference_mechanism = { - "grid_aggregator_overlap": "crop", - "patch_overlap": 0, - } + inference_mechanism = {"grid_aggregator_overlap": "crop", "patch_overlap": 0} initialize_inference_mechanism = False if not ("inference_mechanism" in params): initialize_inference_mechanism = True diff --git a/GANDLF/data/augmentation/__init__.py b/GANDLF/data/augmentation/__init__.py index 00d96451d..22b7f1949 100644 --- a/GANDLF/data/augmentation/__init__.py +++ b/GANDLF/data/augmentation/__init__.py @@ -12,10 +12,7 @@ flip, anisotropy, ) -from .rotations import ( - rotate_90, - rotate_180, -) +from .rotations import rotate_90, rotate_180 from .rgb_augs import colorjitter_transform from .hed_augs import hed_transform diff --git a/GANDLF/data/augmentation/noise_enhanced.py b/GANDLF/data/augmentation/noise_enhanced.py index 5cea5a74e..f7b8dd9bb 100644 --- a/GANDLF/data/augmentation/noise_enhanced.py +++ b/GANDLF/data/augmentation/noise_enhanced.py @@ -55,9 +55,7 @@ def apply_transform(self, subject: Subject) -> Subject: return transformed def get_params( - self, - mean_range: Tuple[float, float], - std_range: Tuple[float, float], + self, mean_range: Tuple[float, float], std_range: Tuple[float, float] ) -> Tuple[float, float]: mean = self.sample_uniform(*mean_range) std = self.sample_uniform(*std_range) diff --git a/GANDLF/data/augmentation/rgb_augs.py b/GANDLF/data/augmentation/rgb_augs.py index 3c261f188..a4610155f 100644 --- a/GANDLF/data/augmentation/rgb_augs.py +++ b/GANDLF/data/augmentation/rgb_augs.py @@ -77,10 +77,7 @@ def apply_transform(self, subject: Subject) -> Subject: else: hue = self.hue_range transform = ColorJitter( - brightness=brightness, - contrast=contrast, - saturation=saturation, - hue=hue, + brightness=brightness, contrast=contrast, saturation=saturation, hue=hue ) for _, image in self.get_images_dict(subject).items(): # proceed with processing only if the image is RGB diff --git a/GANDLF/data/augmentation/wrap_torchio.py b/GANDLF/data/augmentation/wrap_torchio.py index 68654a7d1..8d13cd0db 100644 --- a/GANDLF/data/augmentation/wrap_torchio.py +++ b/GANDLF/data/augmentation/wrap_torchio.py @@ -24,8 +24,7 @@ # define individual functions/lambdas for augmentations to handle properties def mri_artifact(parameters): return OneOf( - {RandomGhosting(): 0.5, RandomSpike(): 0.5}, - p=parameters["probability"], + {RandomGhosting(): 0.5, RandomSpike(): 0.5}, p=parameters["probability"] ) diff --git a/GANDLF/data/inference_dataloader_histopath.py b/GANDLF/data/inference_dataloader_histopath.py index 0abc2f651..f4380c412 100644 --- a/GANDLF/data/inference_dataloader_histopath.py +++ b/GANDLF/data/inference_dataloader_histopath.py @@ -62,10 +62,7 @@ def _basic_preprocessing(self): mask_xdim, mask_ydim = self._os_image.level_dimensions[self._mask_level] mask = get_tissue_mask( self._os_image.read_region( - (0, 0), - self._mask_level, - (mask_xdim, mask_ydim), - as_array=True, + (0, 0), self._mask_level, (mask_xdim, mask_ydim), as_array=True ) ) diff --git a/GANDLF/data/preprocessing/__init__.py b/GANDLF/data/preprocessing/__init__.py index 66fc1d5fe..cfb0907d1 100644 --- a/GANDLF/data/preprocessing/__init__.py +++ b/GANDLF/data/preprocessing/__init__.py @@ -2,10 +2,7 @@ from .crop_zero_planes import CropExternalZeroplanes from .non_zero_normalize import NonZeroNormalizeOnMaskedRegion -from .threshold_and_clip import ( - threshold_transform, - clip_transform, -) +from .threshold_and_clip import threshold_transform, clip_transform from .normalize_rgb import ( normalize_by_val_transform, normalize_imagenet_transform, @@ -40,12 +37,7 @@ def generic_3d_check(patch_size): """ patch_size_new = np.array(patch_size) if len(patch_size) == 2: - patch_size_new = tuple( - np.append( - np.array(patch_size), - 1, - ) - ) + patch_size_new = tuple(np.append(np.array(patch_size), 1)) return patch_size_new diff --git a/GANDLF/data/preprocessing/non_zero_normalize.py b/GANDLF/data/preprocessing/non_zero_normalize.py index 4c7a2ef3f..e5bc80e5e 100644 --- a/GANDLF/data/preprocessing/non_zero_normalize.py +++ b/GANDLF/data/preprocessing/non_zero_normalize.py @@ -23,17 +23,11 @@ def __init__(self, masking_method: TypeMaskingMethod = None, **kwargs): self.args_names = ("masking_method",) def apply_normalization( - self, - subject: Subject, - image_name: str, - mask: torch.Tensor, + self, subject: Subject, image_name: str, mask: torch.Tensor ) -> None: image = subject[image_name] mask = image.data != 0 - standardized = self.znorm( - image.data, - mask, - ) + standardized = self.znorm(image.data, mask) if standardized is None: message = ( "Standard deviation is 0 for masked values" diff --git a/GANDLF/data/preprocessing/resample_minimum.py b/GANDLF/data/preprocessing/resample_minimum.py index 7f36d1063..f4c8da517 100644 --- a/GANDLF/data/preprocessing/resample_minimum.py +++ b/GANDLF/data/preprocessing/resample_minimum.py @@ -19,8 +19,7 @@ def __init__(self, target: Optional[float] = 1, **kwargs): @staticmethod def get_reference_image( - floating_sitk: sitk.Image, - spacing: TypeTripletFloat, + floating_sitk: sitk.Image, spacing: TypeTripletFloat ) -> sitk.Image: old_spacing = np.array(floating_sitk.GetSpacing()) new_spacing = np.array(spacing) diff --git a/GANDLF/inference_manager.py b/GANDLF/inference_manager.py index 2d418340e..366791851 100644 --- a/GANDLF/inference_manager.py +++ b/GANDLF/inference_manager.py @@ -116,7 +116,6 @@ def InferenceManager( filepath_to_save = os.path.join(outputDir, "final_preds_and_avg_probs.csv") if os.path.isfile(filepath_to_save): filepath_to_save = os.path.join( - outputDir, - "final_preds_and_avg_probs" + get_unique_timestamp() + ".csv", + outputDir, "final_preds_and_avg_probs" + get_unique_timestamp() + ".csv" ) averaged_probs_df.to_csv(filepath_to_save, index=False) diff --git a/GANDLF/metrics/classification.py b/GANDLF/metrics/classification.py index f48ca37d6..2b03fb4d8 100644 --- a/GANDLF/metrics/classification.py +++ b/GANDLF/metrics/classification.py @@ -71,8 +71,7 @@ def overall_stats(prediction: torch.Tensor, target: torch.Tensor, params: dict) for metric_name, calculator in calculators.items(): if metric_name == "aucroc": one_hot_preds = one_hot( - prediction.long(), - num_classes=params["model"]["num_classes"], + prediction.long(), num_classes=params["model"]["num_classes"] ) output_metrics[metric_name] = get_output_from_calculator( one_hot_preds.float(), target, calculator diff --git a/GANDLF/metrics/regression.py b/GANDLF/metrics/regression.py index 913b37fac..55025aa7e 100644 --- a/GANDLF/metrics/regression.py +++ b/GANDLF/metrics/regression.py @@ -102,15 +102,11 @@ def overall_stats(prediction: torch.Tensor, target: torch.Tensor, params: dict) output_metrics = {} - reduction_types_keys = { - "mean": "mean", - "sum": "sum", - "none": "none", - } + reduction_types_keys = {"mean": "mean", "sum": "sum", "none": "none"} # metrics that need the "reduction" parameter for reduction_type, reduction_type_key in reduction_types_keys.items(): calculators = { - "cosinesimilarity": tm.CosineSimilarity(reduction=reduction_type_key), + "cosinesimilarity": tm.CosineSimilarity(reduction=reduction_type_key) } for metric_name, calculator in calculators.items(): output_metrics[f"{metric_name}_{reduction_type}"] = ( diff --git a/GANDLF/models/MSDNet.py b/GANDLF/models/MSDNet.py index d5e2cfbd1..d44122a94 100644 --- a/GANDLF/models/MSDNet.py +++ b/GANDLF/models/MSDNet.py @@ -35,11 +35,7 @@ def weight_init(layer): if isinstance(layer, nn.Linear): nn.init.kaiming_normal_(layer, layer.weight.data) - def __init__( - self, - parameters: dict, - num_layers=4, - ): + def __init__(self, parameters: dict, num_layers=4): """ A multi-scale dense neural network architecture that consists of multiple convolutional layers with different dilation rates. diff --git a/GANDLF/models/deep_unet.py b/GANDLF/models/deep_unet.py index 6a336eb31..c724ca54f 100644 --- a/GANDLF/models/deep_unet.py +++ b/GANDLF/models/deep_unet.py @@ -21,11 +21,7 @@ class deep_unet(ModelBase): smaller modules please have a look at the seg_modules file. """ - def __init__( - self, - parameters: dict, - residualConnections=False, - ): + def __init__(self, parameters: dict, residualConnections=False): self.network_kwargs = {"res": residualConnections} super(deep_unet, self).__init__(parameters) diff --git a/GANDLF/models/densenet.py b/GANDLF/models/densenet.py index 7abb3f7d5..b293f8830 100644 --- a/GANDLF/models/densenet.py +++ b/GANDLF/models/densenet.py @@ -113,12 +113,7 @@ def __init__( # Create an instance of _DenseLayer with the calculated number of input features and other parameters layer = _DenseLayer( - num_input_features_i, - growth_rate, - bn_size, - drop_rate, - norm, - conv, + num_input_features_i, growth_rate, bn_size, drop_rate, norm, conv ) # Add the _DenseLayer object to the block @@ -144,11 +139,7 @@ def __init__(self, num_input_features, num_output_features, Norm, Conv, AvgPool) class DenseNet(ModelBase): - def __init__( - self, - parameters: dict, - block_config=(6, 12, 24, 16), - ): + def __init__(self, parameters: dict, block_config=(6, 12, 24, 16)): """ Densenet-BC model class @@ -305,10 +296,7 @@ def forward(self, x): def densenet121(parameters): - return DenseNet( - parameters, - block_config=(6, 12, 24, 16), - ) + return DenseNet(parameters, block_config=(6, 12, 24, 16)) def densenet169(parameters): diff --git a/GANDLF/models/efficientnet.py b/GANDLF/models/efficientnet.py index 0789ba51a..57bba9dcb 100644 --- a/GANDLF/models/efficientnet.py +++ b/GANDLF/models/efficientnet.py @@ -385,11 +385,7 @@ class EfficientNet(ModelBase): scale_params (dict) - A dictionary defining scaling of depth and width for the model. """ - def __init__( - self, - parameters: dict, - scale_params, # how to scale depth and width - ): + def __init__(self, parameters: dict, scale_params): # how to scale depth and width super(EfficientNet, self).__init__(parameters) # check/define defaults diff --git a/GANDLF/models/fcn.py b/GANDLF/models/fcn.py index 36f356be8..7be792374 100644 --- a/GANDLF/models/fcn.py +++ b/GANDLF/models/fcn.py @@ -23,10 +23,7 @@ class fcn(ModelBase): DOI: 10.1109/TPAMI.2016.2572683 """ - def __init__( - self, - parameters: dict, - ): + def __init__(self, parameters: dict): super(fcn, self).__init__(parameters) self.ins = InitialConv( input_channels=self.n_channels, diff --git a/GANDLF/models/imagenet_unet.py b/GANDLF/models/imagenet_unet.py index 52749d35d..940987e1f 100644 --- a/GANDLF/models/imagenet_unet.py +++ b/GANDLF/models/imagenet_unet.py @@ -4,10 +4,7 @@ import torch import torch.nn as nn -from segmentation_models_pytorch.base import ( - SegmentationHead, - ClassificationHead, -) +from segmentation_models_pytorch.base import SegmentationHead, ClassificationHead from segmentation_models_pytorch.encoders import get_encoder from segmentation_models_pytorch.decoders.unet.decoder import UnetDecoder from segmentation_models_pytorch.base import initialization as init @@ -188,10 +185,7 @@ class ImageNet_UNet(ModelBase): ModelBase (nn.Module): The base model class. """ - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: super(ImageNet_UNet, self).__init__(parameters) # https://github.com/qubvel/segmentation_models.pytorch/issues/745 diff --git a/GANDLF/models/imagenet_vgg.py b/GANDLF/models/imagenet_vgg.py index 5a8b1059e..f12f60147 100644 --- a/GANDLF/models/imagenet_vgg.py +++ b/GANDLF/models/imagenet_vgg.py @@ -27,37 +27,21 @@ def create_torchvision_model(modelname, pretrained=True, num_classes=2, dimensio assert dimensions == 2, "ImageNet_VGG only supports 2D images" if modelname == "vgg11": - model = torchvision.models.vgg11( - pretrained=pretrained, - ) + model = torchvision.models.vgg11(pretrained=pretrained) if modelname == "vgg11_bn": - model = torchvision.models.vgg11_bn( - pretrained=pretrained, - ) + model = torchvision.models.vgg11_bn(pretrained=pretrained) if modelname == "vgg13": - model = torchvision.models.vgg13( - pretrained=pretrained, - ) + model = torchvision.models.vgg13(pretrained=pretrained) if modelname == "vgg13_bn": - model = torchvision.models.vgg13_bn( - pretrained=pretrained, - ) + model = torchvision.models.vgg13_bn(pretrained=pretrained) if modelname == "vgg16": - model = torchvision.models.vgg16( - pretrained=pretrained, - ) + model = torchvision.models.vgg16(pretrained=pretrained) if modelname == "vgg16_bn": - model = torchvision.models.vgg16_bn( - pretrained=pretrained, - ) + model = torchvision.models.vgg16_bn(pretrained=pretrained) if modelname == "vgg19": - model = torchvision.models.vgg19( - pretrained=pretrained, - ) + model = torchvision.models.vgg19(pretrained=pretrained) if modelname == "vgg19_bn": - model = torchvision.models.vgg19_bn( - pretrained=pretrained, - ) + model = torchvision.models.vgg19_bn(pretrained=pretrained) model.classifier[6] = nn.Linear( in_features=model.classifier[3].out_features, out_features=num_classes ) @@ -85,10 +69,7 @@ def apply_activation_function(activation_function, input_tensor): class imagenet_vgg11(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ Implements the VGG-11 model for ImageNet classification. @@ -122,10 +103,7 @@ def forward(self, x): class imagenet_vgg11_bn(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ VGG11 with batch normalization architecture for image classification on ImageNet dataset. @@ -159,10 +137,7 @@ def forward(self, x): class imagenet_vgg13(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ Implements the VGG-13 model for ImageNet classification. @@ -196,10 +171,7 @@ def forward(self, x): class imagenet_vgg13_bn(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ VGG13 with batch normalization architecture for image classification on ImageNet dataset. @@ -233,10 +205,7 @@ def forward(self, x): class imagenet_vgg16(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ Implements the VGG-16 model for ImageNet classification. @@ -270,10 +239,7 @@ def forward(self, x): class imagenet_vgg16_bn(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ VGG16 with batch normalization architecture for image classification on ImageNet dataset. @@ -307,10 +273,7 @@ def forward(self, x): class imagenet_vgg19(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ Implements the VGG-19 model for ImageNet classification. @@ -344,10 +307,7 @@ def forward(self, x): class imagenet_vgg19_bn(ModelBase): - def __init__( - self, - parameters, - ) -> None: + def __init__(self, parameters) -> None: """ VGG19 with batch normalization architecture for image classification on ImageNet dataset. diff --git a/GANDLF/models/light_unet.py b/GANDLF/models/light_unet.py index 460e830c3..649c08e22 100644 --- a/GANDLF/models/light_unet.py +++ b/GANDLF/models/light_unet.py @@ -18,11 +18,7 @@ class light_unet(ModelBase): This is the LIGHT U-Net architecture. """ - def __init__( - self, - parameters: dict, - residualConnections=False, - ): + def __init__(self, parameters: dict, residualConnections=False): self.network_kwargs = {"res": residualConnections} super(light_unet, self).__init__(parameters) diff --git a/GANDLF/models/light_unet_multilayer.py b/GANDLF/models/light_unet_multilayer.py index 44030a737..a4db7a70c 100644 --- a/GANDLF/models/light_unet_multilayer.py +++ b/GANDLF/models/light_unet_multilayer.py @@ -19,11 +19,7 @@ class light_unet_multilayer(ModelBase): This is the LIGHT U-Net architecture. """ - def __init__( - self, - parameters: dict, - residualConnections=False, - ): + def __init__(self, parameters: dict, residualConnections=False): self.network_kwargs = {"res": residualConnections} super(light_unet_multilayer, self).__init__(parameters) diff --git a/GANDLF/models/resnet.py b/GANDLF/models/resnet.py index e8dde75b8..e24dca221 100644 --- a/GANDLF/models/resnet.py +++ b/GANDLF/models/resnet.py @@ -19,12 +19,7 @@ class ResNet(ModelBase): in each block of the model. """ - def __init__( - self, - parameters: dict, - blockType, - block_config, - ): + def __init__(self, parameters: dict, blockType, block_config): super(ResNet, self).__init__(parameters) # Check the patch size and get the number of allowed layers @@ -195,14 +190,7 @@ class _BasicLayer(nn.Sequential): downsample (bool): whether to downsample input """ - def __init__( - self, - num_in_feats, - num_out_feats, - Norm, - Conv, - downsample, - ): + def __init__(self, num_in_feats, num_out_feats, Norm, Conv, downsample): super().__init__() # check if size needs to be changed diff --git a/GANDLF/models/sdnet.py b/GANDLF/models/sdnet.py index 4e0ac0da5..76968e344 100644 --- a/GANDLF/models/sdnet.py +++ b/GANDLF/models/sdnet.py @@ -13,12 +13,7 @@ class Decoder(ModelBase): - def __init__( - self, - parameters, - anatomy_factors, - num_layers=5, - ): + def __init__(self, parameters, anatomy_factors, num_layers=5): """ Decoder module for SDNet. @@ -155,11 +150,7 @@ def forward(self, c: torch.Tensor, s: torch.Tensor) -> torch.Tensor: class Segmentor(ModelBase): - def __init__( - self, - parameters, - anatomy_factors, - ): + def __init__(self, parameters, anatomy_factors): """ Segmentor module for SDNet. @@ -228,13 +219,7 @@ def forward(self, x: torch.Tensor) -> torch.Tensor: class ModalityEncoder(ModelBase): - def __init__( - self, - parameters, - anatomy_factors, - modality_factors, - num_layers=4, - ): + def __init__(self, parameters, anatomy_factors, modality_factors, num_layers=4): """ Modality Encoder module for SDNet. @@ -311,10 +296,7 @@ def forward(self, x: torch.Tensor, c: torch.Tensor) -> torch.Tensor: class SDNet(ModelBase): - def __init__( - self, - parameters: dict, - ): + def __init__(self, parameters: dict): """ SDNet (Structure-Disentangled Network) module. @@ -354,18 +336,10 @@ def __init__( self.cencoder = unet(parameters_unet) self.mencoder = ModalityEncoder( - parameters, - self.anatomy_factors, - self.modality_factors, - ) - self.decoder = Decoder( - parameters, - self.anatomy_factors, - ) - self.segmentor = Segmentor( - parameters, - self.anatomy_factors, + parameters, self.anatomy_factors, self.modality_factors ) + self.decoder = Decoder(parameters, self.anatomy_factors) + self.segmentor = Segmentor(parameters, self.anatomy_factors) @staticmethod def reparameterize(mu: torch.Tensor, logvar: torch.Tensor) -> torch.Tensor: @@ -404,10 +378,4 @@ def forward(self, x: torch.Tensor) -> typing.List[torch.Tensor]: reco = self.decoder(anatomy_factors, modality_factors) modality_factors_reencoded, _ = self.mencoder(reco, anatomy_factors) # sm, anatomy_factors, mu, logvar, modality_factors_reencoded - return ( - sm, - reco, - mu, - logvar, - modality_factors_reencoded, - ) + return (sm, reco, mu, logvar, modality_factors_reencoded) diff --git a/GANDLF/models/transunet.py b/GANDLF/models/transunet.py index 420aa263c..243362c03 100644 --- a/GANDLF/models/transunet.py +++ b/GANDLF/models/transunet.py @@ -95,10 +95,7 @@ class transunet(ModelBase): out (out_conv): Final output convolutional layer. """ - def __init__( - self, - parameters: dict, - ): + def __init__(self, parameters: dict): super(transunet, self).__init__(parameters) # Initialize default parameters if not found diff --git a/GANDLF/models/uinc.py b/GANDLF/models/uinc.py index 3f41fa6cc..28ce0ad03 100644 --- a/GANDLF/models/uinc.py +++ b/GANDLF/models/uinc.py @@ -25,10 +25,7 @@ class uinc(ModelBase): since the initial input and the final one do not have the same dimensions. """ - def __init__( - self, - parameters: dict, - ): + def __init__(self, parameters: dict): super(uinc, self).__init__(parameters) assert checkPatchDivisibility(parameters["patch_size"]) == True, ( diff --git a/GANDLF/models/unet.py b/GANDLF/models/unet.py index c250cd673..95120422a 100644 --- a/GANDLF/models/unet.py +++ b/GANDLF/models/unet.py @@ -20,11 +20,7 @@ class unet(ModelBase): smaller modules please have a look at the seg_modules file. """ - def __init__( - self, - parameters: dict, - residualConnections=False, - ): + def __init__(self, parameters: dict, residualConnections=False): self.network_kwargs = {"res": residualConnections} super(unet, self).__init__(parameters) diff --git a/GANDLF/models/unetr.py b/GANDLF/models/unetr.py index 58a85232e..9244b3ff1 100644 --- a/GANDLF/models/unetr.py +++ b/GANDLF/models/unetr.py @@ -505,10 +505,7 @@ def __init__( self.layers = ModuleList([]) for _ in range(0, num_layers): - layer = _TransformerLayer( - embed_size, - num_heads, - ) + layer = _TransformerLayer(embed_size, num_heads) self.layers.append(layer) def forward(self, x): @@ -560,10 +557,7 @@ class unetr(ModelBase): and some other hyperparameters, which remain constant all the modules. For more details on the smaller modules please have a look at the seg_modules file. """ - def __init__( - self, - parameters: dict, - ): + def __init__(self, parameters: dict): """ Initializes an instance of the `unetr` class. diff --git a/GANDLF/models/vgg.py b/GANDLF/models/vgg.py index 242306454..67b4f0180 100644 --- a/GANDLF/models/vgg.py +++ b/GANDLF/models/vgg.py @@ -15,11 +15,7 @@ class VGG(ModelBase): VGG model """ - def __init__( - self, - parameters: dict, - configuration, - ): + def __init__(self, parameters: dict, configuration): """ Initializer function for the VGG model @@ -165,10 +161,7 @@ class vgg11(VGG): Inherits from the VGG class and specifies the configuration for the VGG11 architecture. """ - def __init__( - self, - parameters, - ): + def __init__(self, parameters): """ Initializes the VGG11 model with the given parameters. @@ -185,10 +178,7 @@ class vgg13(VGG): Inherits from the VGG class and specifies the configuration for the VGG13 architecture. """ - def __init__( - self, - parameters, - ): + def __init__(self, parameters): """ Initializes the VGG13 model with the given parameters. @@ -205,10 +195,7 @@ class vgg16(VGG): Inherits from the VGG class and specifies the configuration for the VGG16 architecture. """ - def __init__( - self, - parameters, - ): + def __init__(self, parameters): """ Initializes the VGG16 model with the given parameters. @@ -225,10 +212,7 @@ class vgg19(VGG): Inherits from the VGG class and specifies the configuration for the VGG19 architecture. """ - def __init__( - self, - parameters, - ): + def __init__(self, parameters): """ Initializes the VGG19 model with the given parameters. diff --git a/GANDLF/utils/imaging.py b/GANDLF/utils/imaging.py index 05c2cf4ce..eb50b15ba 100644 --- a/GANDLF/utils/imaging.py +++ b/GANDLF/utils/imaging.py @@ -92,11 +92,7 @@ def resize_image( for i, n in enumerate(output_size_parsed): outputSpacing[i] = outputSpacing[i] * (inputSize[i] / n) - return resample_image( - input_image, - outputSpacing, - interpolator=interpolator, - ) + return resample_image(input_image, outputSpacing, interpolator=interpolator) def softer_sanity_check( diff --git a/GANDLF/utils/modelio.py b/GANDLF/utils/modelio.py index a7faed6ca..a83a6d952 100644 --- a/GANDLF/utils/modelio.py +++ b/GANDLF/utils/modelio.py @@ -18,10 +18,7 @@ "version": None, } -model_dict_required = { - "model_state_dict": None, - "optimizer_state_dict": None, -} +model_dict_required = {"model_state_dict": None, "optimizer_state_dict": None} best_model_path_end = "_best.pth.tar" latest_model_path_end = "_latest.pth.tar" diff --git a/GANDLF/utils/tensor.py b/GANDLF/utils/tensor.py index bc4d6417c..a357f77fd 100644 --- a/GANDLF/utils/tensor.py +++ b/GANDLF/utils/tensor.py @@ -413,17 +413,11 @@ def get_class_imbalance_weights( from GANDLF.data.ImagesFromDataFrame import ImagesFromDataFrame penalty_data = ImagesFromDataFrame( - training_df, - parameters=params, - train=False, - loader_type="penalty", + training_df, parameters=params, train=False, loader_type="penalty" ) penalty_loader = DataLoader( - penalty_data, - batch_size=1, - shuffle=True, - pin_memory=False, + penalty_data, batch_size=1, shuffle=True, pin_memory=False ) ( diff --git a/mlcube/model_mlcube/example_custom_entrypoint/getting_started_3d_rad_seg.py b/mlcube/model_mlcube/example_custom_entrypoint/getting_started_3d_rad_seg.py index 9488c9ce9..2c56b5c56 100644 --- a/mlcube/model_mlcube/example_custom_entrypoint/getting_started_3d_rad_seg.py +++ b/mlcube/model_mlcube/example_custom_entrypoint/getting_started_3d_rad_seg.py @@ -15,10 +15,7 @@ def create_csv(data_path): continue image_path = os.path.join(folder_path, "image.nii.gz") image_path = os.path.abspath(image_path) - record = { - "SubjectID": subjectID, - "Channel_0": image_path, - } + record = {"SubjectID": subjectID, "Channel_0": image_path} input_data.append(record) input_data_df = pd.DataFrame(input_data) diff --git a/pyproject.toml b/pyproject.toml index 0453d5747..c0c1505e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,25 @@ [tool.black] line-length = 88 -include = 'gandlf_*' extend-exclude = ''' -/( +( testing/data | .*.md -)/ -skip_magic_trailing_comma = true` + | /GANDLF/cli/generate_metrics.py + | /GANDLF/data/post_process/tensor.py + | /GANDLF/data/preprocessing/threshold_and_clip.py + | /GANDLF/metrics/regression.py + | /GANDLF/models/unet_multilayer.py + | /GANDLF/optimizers/__init__.py + | /GANDLF/optimizers/wrap_monai.py + | /GANDLF/schedulers/wrap_monai.py + | /GANDLF/schedulers/wrap_torch.py + | /GANDLF/utils/handle_collisions.py + | /GANDLF/utils/tensor.py + | /setup.py + | /testing/conftest.py +) ''' +skip_magic_trailing_comma = true [tool.coverage.run] source = ["./GANDLF"] diff --git a/testing/test_full.py b/testing/test_full.py index 9fc04a8cb..2c8725c91 100644 --- a/testing/test_full.py +++ b/testing/test_full.py @@ -183,9 +183,7 @@ def prerequisites_constructTrainingCSV(): with open( inputDir + "/train_" + application_data + ".csv", "r" ) as read_f, open( - inputDir + "/train_" + application_data_regression + ".csv", - "w", - newline="", + inputDir + "/train_" + application_data_regression + ".csv", "w", newline="" ) as write_reg, open( inputDir + "/train_" + application_data_classification + ".csv", "w", @@ -950,8 +948,7 @@ def test_train_scheduler_classification_rad_2d(device): # loop through selected models and train for single epoch for scheduler in global_schedulers_dict: parameters = ConfigManager( - testingDir + "/config_classification.yaml", - version_check_flag=False, + testingDir + "/config_classification.yaml", version_check_flag=False ) parameters["modality"] = "rad" parameters["patch_size"] = patch_size["2D"] @@ -1273,8 +1270,7 @@ def get_parameters_after_alteration(loss_type: str) -> dict: def test_generic_config_read(): print("24: Starting testing reading configuration") parameters = ConfigManager( - os.path.join(baseConfigDir, "config_all_options.yaml"), - version_check_flag=False, + os.path.join(baseConfigDir, "config_all_options.yaml"), version_check_flag=False ) parameters["data_preprocessing"]["resize_image"] = [128, 128] @@ -1466,9 +1462,7 @@ def test_generic_cli_function_mainrun(device): parameters["model"]["amp"] = True parameters["model"]["print_summary"] = False parameters["model"]["num_channels"] = 3 - parameters["metrics"] = [ - "dice", - ] + parameters["metrics"] = ["dice"] parameters["model"]["architecture"] = "unet" file_config_temp = write_temp_config_path(parameters) @@ -1476,13 +1470,7 @@ def test_generic_cli_function_mainrun(device): file_data = os.path.join(inputDir, "train_2d_rad_segmentation.csv") main_run( - file_data, - file_config_temp, - outputDir, - True, - device, - resume=False, - reset=True, + file_data, file_config_temp, outputDir, True, device, resume=False, reset=True ) sanitize_outputDir() @@ -1697,21 +1685,11 @@ def test_generic_preprocess_functions(): cropper = global_preprocessing_dict["crop"]([64, 64, 64]) input_transformed = cropper(input_tensor) - assert input_transformed.shape == ( - 1, - 128, - 128, - 128, - ), "Cropping should work" + assert input_transformed.shape == (1, 128, 128, 128), "Cropping should work" cropper = global_preprocessing_dict["centercrop"]([128, 128, 128]) input_transformed = cropper(input_tensor) - assert input_transformed.shape == ( - 1, - 128, - 128, - 128, - ), "Center-crop should work" + assert input_transformed.shape == (1, 128, 128, 128), "Center-crop should work" # test pure morphological operations input_tensor_3d = torch.rand(1, 1, 256, 256, 256) @@ -1900,11 +1878,7 @@ def test_generic_augmentation_functions(): # additional test for elastic params_elastic = params_all_preprocessing_and_augs["data_augmentation"]["elastic"] - for key_to_pop in [ - "num_control_points", - "max_displacement", - "locked_borders", - ]: + for key_to_pop in ["num_control_points", "max_displacement", "locked_borders"]: params_elastic.pop(key_to_pop, None) output_tensor = global_augs_dict["elastic"](params_elastic)(input_tensor) assert output_tensor != None, "Augmentation for base elastic transform should work" @@ -2050,8 +2024,7 @@ def test_generic_one_hot_logic(): # check combined foreground combined_array = np.logical_or( - np.logical_or((random_array == 1), (random_array == 2)), - (random_array == 3), + np.logical_or((random_array == 1), (random_array == 2)), (random_array == 3) ) comparison = combined_array == (img_tensor_oh_rev_array == 1) assert comparison.all(), "Arrays at the combined foreground are not equal" @@ -2097,8 +2070,7 @@ def test_generic_one_hot_logic(): # check combined foreground combined_array = np.logical_or( - np.logical_or((random_array == 1), (random_array == 2)), - (random_array == 3), + np.logical_or((random_array == 1), (random_array == 2)), (random_array == 3) ) comparison = combined_array == (img_tensor_oh_rev_array == 1) assert comparison.all(), "Arrays at the combined foreground are not equal" @@ -2994,9 +2966,7 @@ def test_collision_subjectid_test_segmentation_rad_2d(device): parameters["model"]["amp"] = True parameters["model"]["print_summary"] = False parameters["model"]["num_channels"] = 3 - parameters["metrics"] = [ - "dice", - ] + parameters["metrics"] = ["dice"] parameters["model"]["architecture"] = "unet" outputDir = os.path.join(testingDir, "data_output") @@ -3058,11 +3028,7 @@ def test_generic_random_numbers_are_deterministic_on_cpu(): def test_generic_cli_function_metrics_cli_rad_nd(): print("49: Starting metric calculation tests") for dim in ["2d", "3d"]: - for problem_type in [ - "segmentation", - "classification", - "synthesis", - ]: + for problem_type in ["segmentation", "classification", "synthesis"]: synthesis_detected = problem_type == "synthesis" problem_type_wrap = problem_type if synthesis_detected: From fccdb9a747e8cf26ccb5318fb826415f024f5fe6 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Sat, 23 Mar 2024 17:28:18 +0300 Subject: [PATCH 02/10] Resolving black version conflict --- .github/workflows/black.yml | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 80c8729f9..bd8e7b192 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -11,17 +11,5 @@ jobs: steps: - uses: actions/checkout@v2 - uses: psf/black@stable - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python-version }} - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - python -m pip install black==23.11.0 - - - name: Run tests - run: | - python -m black --check . + version: "23.11.0" From 0d6ab7f382cf901bde28d36fa0321ec567e5b91f Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Sat, 23 Mar 2024 17:31:14 +0300 Subject: [PATCH 03/10] Revert "Resolving black version conflict" This reverts commit fccdb9a747e8cf26ccb5318fb826415f024f5fe6 + fixes black version for first step --- .github/workflows/black.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index bd8e7b192..d9a0cf2cb 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -13,3 +13,17 @@ jobs: - uses: psf/black@stable with: version: "23.11.0" + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install black==23.11.0 + + - name: Run tests + run: | + python -m black --check . From 11d6fffe61ebc10fe7b54afb7b4c50c52ea19331 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Mon, 25 Mar 2024 12:32:42 +0300 Subject: [PATCH 04/10] Unified black version location --- .github/workflows/black.yml | 8 ++++++-- setup.py | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index d9a0cf2cb..a90a172a0 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -9,10 +9,14 @@ jobs: matrix: python-version: [3.9] steps: + - name: Extract black version from setup.py + run: | + echo "BLACK_VERSION=$(python -c 'import black_version from setup; print(black_version)')" >> $GITHUB_ENV + - uses: actions/checkout@v2 - uses: psf/black@stable with: - version: "23.11.0" + version: ${{ env.BLACK_VERSION }} - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 @@ -22,7 +26,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install black==23.11.0 + python -m pip install black==${{ env.BLACK_VERSION }} - name: Run tests run: | diff --git a/setup.py b/setup.py index 93222d5f4..6cc3661a9 100644 --- a/setup.py +++ b/setup.py @@ -79,10 +79,10 @@ def run(self): "utils", ] - +black_version = "23.11.0" requirements = [ "torch==2.1.2", - "black==23.11.0", + f"black=={black_version}", "numpy==1.25.0", "scipy", "SimpleITK!=2.0.*", From 700407f0a880b74cbaae6256aefd550d5d12d02e Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Mon, 25 Mar 2024 12:39:16 +0300 Subject: [PATCH 05/10] fix --- .github/workflows/black.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index a90a172a0..fc2b74e58 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Extract black version from setup.py run: | - echo "BLACK_VERSION=$(python -c 'import black_version from setup; print(black_version)')" >> $GITHUB_ENV + echo "BLACK_VERSION=$(python -c 'from setup import black_version; print(black_version)')" >> $GITHUB_ENV - uses: actions/checkout@v2 - uses: psf/black@stable From b33a94fd7c6b4047b127e9b847b6d43c6c328582 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Mon, 25 Mar 2024 12:43:31 +0300 Subject: [PATCH 06/10] debug black ci --- .github/workflows/black.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index fc2b74e58..c551ef5c2 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -9,6 +9,9 @@ jobs: matrix: python-version: [3.9] steps: + - name: Debug + run: | + python -c "import os; print(os.getcwd()); import sys; print(sys.path)" - name: Extract black version from setup.py run: | echo "BLACK_VERSION=$(python -c 'from setup import black_version; print(black_version)')" >> $GITHUB_ENV From 76c02da0aa10f980c08d691a36deab377336f566 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Mon, 25 Mar 2024 13:24:19 +0300 Subject: [PATCH 07/10] debug --- .github/workflows/black.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index c551ef5c2..e47389a1d 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -11,7 +11,7 @@ jobs: steps: - name: Debug run: | - python -c "import os; print(os.getcwd()); import sys; print(sys.path)" + python -c "import os; print(os.getcwd()); print(os.listdir(os.getcwd())); import sys; print(sys.path)" - name: Extract black version from setup.py run: | echo "BLACK_VERSION=$(python -c 'from setup import black_version; print(black_version)')" >> $GITHUB_ENV From b9683335cab6fc35f695502ce355b7989146346c Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Mon, 25 Mar 2024 13:39:10 +0300 Subject: [PATCH 08/10] black CI fix --- .github/workflows/black.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index e47389a1d..32ad1309a 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -9,14 +9,12 @@ jobs: matrix: python-version: [3.9] steps: - - name: Debug - run: | - python -c "import os; print(os.getcwd()); print(os.listdir(os.getcwd())); import sys; print(sys.path)" + - uses: actions/checkout@v2 + - name: Extract black version from setup.py run: | echo "BLACK_VERSION=$(python -c 'from setup import black_version; print(black_version)')" >> $GITHUB_ENV - - uses: actions/checkout@v2 - uses: psf/black@stable with: version: ${{ env.BLACK_VERSION }} From 518a1d43bf92e5b8e58293958050ab763be5bd49 Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Mon, 25 Mar 2024 17:45:22 +0300 Subject: [PATCH 09/10] blacked all the code base --- .github/workflows/black.yml | 2 +- GANDLF/cli/generate_metrics.py | 42 +++++------ GANDLF/data/post_process/tensor.py | 2 +- .../data/preprocessing/threshold_and_clip.py | 8 +- GANDLF/metrics/regression.py | 6 +- GANDLF/models/unet_multilayer.py | 6 +- GANDLF/optimizers/__init__.py | 2 +- GANDLF/optimizers/wrap_monai.py | 5 +- GANDLF/schedulers/wrap_monai.py | 9 ++- GANDLF/schedulers/wrap_torch.py | 74 ++++++++++++------- GANDLF/utils/handle_collisions.py | 4 +- GANDLF/utils/tensor.py | 4 +- pyproject.toml | 13 ---- setup.py | 12 +-- testing/conftest.py | 5 +- 15 files changed, 101 insertions(+), 93 deletions(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 32ad1309a..6d765961a 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -10,7 +10,7 @@ jobs: python-version: [3.9] steps: - uses: actions/checkout@v2 - + - name: Extract black version from setup.py run: | echo "BLACK_VERSION=$(python -c 'from setup import black_version; print(black_version)')" >> $GITHUB_ENV diff --git a/GANDLF/cli/generate_metrics.py b/GANDLF/cli/generate_metrics.py index 332f85dcf..f685bf1fc 100644 --- a/GANDLF/cli/generate_metrics.py +++ b/GANDLF/cli/generate_metrics.py @@ -269,9 +269,9 @@ def __percentile_clip( strictlyPositive=True, ) - overall_stats_dict[current_subject_id]["ssim"] = ( - structural_similarity_index(output_infill, gt_image_infill, mask).item() - ) + overall_stats_dict[current_subject_id][ + "ssim" + ] = structural_similarity_index(output_infill, gt_image_infill, mask).item() # ncc metrics compute_ncc = parameters.get("compute_ncc", True) @@ -312,30 +312,30 @@ def __percentile_clip( ).item() # same as above but with epsilon for robustness - overall_stats_dict[current_subject_id]["psnr_eps"] = ( - peak_signal_noise_ratio( - output_infill, gt_image_infill, epsilon=sys.float_info.epsilon - ).item() - ) + overall_stats_dict[current_subject_id][ + "psnr_eps" + ] = peak_signal_noise_ratio( + output_infill, gt_image_infill, epsilon=sys.float_info.epsilon + ).item() # only use fix data range to [0;1] if the data was normalized before if normalize: # torchmetrics PSNR but with fixed data range of 0 to 1 - overall_stats_dict[current_subject_id]["psnr_01"] = ( - peak_signal_noise_ratio( - output_infill, gt_image_infill, data_range=(0, 1) - ).item() - ) + overall_stats_dict[current_subject_id][ + "psnr_01" + ] = peak_signal_noise_ratio( + output_infill, gt_image_infill, data_range=(0, 1) + ).item() # same as above but with epsilon for robustness - overall_stats_dict[current_subject_id]["psnr_01_eps"] = ( - peak_signal_noise_ratio( - output_infill, - gt_image_infill, - data_range=(0, 1), - epsilon=sys.float_info.epsilon, - ).item() - ) + overall_stats_dict[current_subject_id][ + "psnr_01_eps" + ] = peak_signal_noise_ratio( + output_infill, + gt_image_infill, + data_range=(0, 1), + epsilon=sys.float_info.epsilon, + ).item() pprint(overall_stats_dict) if outputfile is not None: diff --git a/GANDLF/data/post_process/tensor.py b/GANDLF/data/post_process/tensor.py index 937d9e9f6..0e8c8eb44 100644 --- a/GANDLF/data/post_process/tensor.py +++ b/GANDLF/data/post_process/tensor.py @@ -3,7 +3,7 @@ from GANDLF.utils.generic import get_array_from_image_or_tensor -def get_mapped_label(input_tensor: torch.Tensor, params:dict) -> np.ndarray: +def get_mapped_label(input_tensor: torch.Tensor, params: dict) -> np.ndarray: """ This function maps the input tensor to the output tensor based on the mapping provided in the params. diff --git a/GANDLF/data/preprocessing/threshold_and_clip.py b/GANDLF/data/preprocessing/threshold_and_clip.py index 848a93008..dd440a86a 100644 --- a/GANDLF/data/preprocessing/threshold_and_clip.py +++ b/GANDLF/data/preprocessing/threshold_and_clip.py @@ -36,7 +36,9 @@ class Threshold(IntensityTransform): """ - def __init__(self, out_min: Optional[float] = None, out_max: Optional[float] = None, **kwargs): + def __init__( + self, out_min: Optional[float] = None, out_max: Optional[float] = None, **kwargs + ): super().__init__(**kwargs) self.out_min, self.out_max = out_min, out_max self.args_names = "out_min", "out_max" @@ -57,7 +59,7 @@ def threshold(self, tensor: torch.Tensor) -> torch.Tensor: # the "_transform" functions return lambdas that can be used to wrap into a Compose class -def threshold_transform(parameters:dict) -> Threshold: +def threshold_transform(parameters: dict) -> Threshold: """ This function returns a lambda function that can be used to wrap into a Compose class. @@ -70,7 +72,7 @@ def threshold_transform(parameters:dict) -> Threshold: return Threshold(out_min=parameters["min"], out_max=parameters["max"]) -def clip_transform(parameters:dict) -> Clamp: +def clip_transform(parameters: dict) -> Clamp: """ This function returns a lambda function that can be used to wrap into a Compose class. diff --git a/GANDLF/metrics/regression.py b/GANDLF/metrics/regression.py index 55025aa7e..eedbde027 100644 --- a/GANDLF/metrics/regression.py +++ b/GANDLF/metrics/regression.py @@ -109,9 +109,9 @@ def overall_stats(prediction: torch.Tensor, target: torch.Tensor, params: dict) "cosinesimilarity": tm.CosineSimilarity(reduction=reduction_type_key) } for metric_name, calculator in calculators.items(): - output_metrics[f"{metric_name}_{reduction_type}"] = ( - get_output_from_calculator(prediction, target, calculator) - ) + output_metrics[ + f"{metric_name}_{reduction_type}" + ] = get_output_from_calculator(prediction, target, calculator) # metrics that do not have any "reduction" parameter calculators = { "mse": tm.MeanSquaredError(), diff --git a/GANDLF/models/unet_multilayer.py b/GANDLF/models/unet_multilayer.py index 0cae21946..9d60d51dc 100644 --- a/GANDLF/models/unet_multilayer.py +++ b/GANDLF/models/unet_multilayer.py @@ -22,11 +22,7 @@ class unet_multilayer(ModelBase): smaller modules please have a look at the seg_modules file. """ - def __init__( - self, - parameters: dict, - residualConnections:bool=False, - ): + def __init__(self, parameters: dict, residualConnections: bool = False): """ The constructor for the unet_multilayer class. diff --git a/GANDLF/optimizers/__init__.py b/GANDLF/optimizers/__init__.py index 09323c313..e952c4226 100644 --- a/GANDLF/optimizers/__init__.py +++ b/GANDLF/optimizers/__init__.py @@ -26,7 +26,7 @@ "adagrad": adagrad, "rmsprop": rmsprop, "radam": radam, - "novograd": novograd_wrapper + "novograd": novograd_wrapper, } diff --git a/GANDLF/optimizers/wrap_monai.py b/GANDLF/optimizers/wrap_monai.py index 93e429dc1..23745e4a5 100644 --- a/GANDLF/optimizers/wrap_monai.py +++ b/GANDLF/optimizers/wrap_monai.py @@ -1,6 +1,5 @@ -from monai.optimizers import ( - Novograd -) +from monai.optimizers import Novograd + def novograd_wrapper(parameters): return Novograd( diff --git a/GANDLF/schedulers/wrap_monai.py b/GANDLF/schedulers/wrap_monai.py index 914788ab1..c73e78472 100644 --- a/GANDLF/schedulers/wrap_monai.py +++ b/GANDLF/schedulers/wrap_monai.py @@ -1,10 +1,13 @@ from monai.optimizers import WarmupCosineSchedule as WCS + def warmupcosineschedule(parameters): - parameters["scheduler"]["warmup_steps"] = parameters["scheduler"].get("warmup_steps",0.1*parameters["num_epochs"]) + parameters["scheduler"]["warmup_steps"] = parameters["scheduler"].get( + "warmup_steps", 0.1 * parameters["num_epochs"] + ) return WCS( parameters["optimizer_object"], - t_total = parameters["num_epochs"], - warmup_steps = parameters["scheduler"]["warmup_steps"] + t_total=parameters["num_epochs"], + warmup_steps=parameters["scheduler"]["warmup_steps"], ) diff --git a/GANDLF/schedulers/wrap_torch.py b/GANDLF/schedulers/wrap_torch.py index 248b15e2d..4a776ccec 100644 --- a/GANDLF/schedulers/wrap_torch.py +++ b/GANDLF/schedulers/wrap_torch.py @@ -50,8 +50,8 @@ def base_triangle(parameters): """ # pick defaults - parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr",10**-3) - parameters["scheduler"]["max_lr"] = parameters["scheduler"].get("max_lr",1) + parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr", 10**-3) + parameters["scheduler"]["max_lr"] = parameters["scheduler"].get("max_lr", 1) clr = cyclical_lr( parameters["scheduler"]["step_size"], @@ -63,9 +63,11 @@ def base_triangle(parameters): def triangle_modified(parameters): # pick defaults - parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr",0.000001) - parameters["scheduler"]["max_lr"] = parameters["scheduler"].get("max_lr",0.001) - parameters["scheduler"]["max_lr_multiplier"] = parameters["scheduler"].get("max_lr_multiplier",1.0) + parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr", 0.000001) + parameters["scheduler"]["max_lr"] = parameters["scheduler"].get("max_lr", 0.001) + parameters["scheduler"]["max_lr_multiplier"] = parameters["scheduler"].get( + "max_lr_multiplier", 1.0 + ) clr = cyclical_lr_modified( parameters["scheduler"]["step_size"], @@ -78,18 +80,30 @@ def triangle_modified(parameters): def cyclic_lr_base(parameters, mode="triangular"): # pick defaults for "min_lr", "max_lr", "max_lr_multiplier" if not present in parameters - parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr",parameters["learning_rate"] * 0.001) - parameters["scheduler"]["max_lr"] = parameters["scheduler"].get("max_lr",parameters["learning_rate"]) - parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma",0.1) - parameters["scheduler"]["scale_mode"] = parameters["scheduler"].get("scale_mode","cycle") - parameters["scheduler"]["cycle_momentum"] = parameters["scheduler"].get("cycle_momentum",False) - parameters["scheduler"]["base_momentum"] = parameters["scheduler"].get("base_momentum",0.8) - parameters["scheduler"]["max_momentum"] = parameters["scheduler"].get("max_momentum",0.9) + parameters["scheduler"]["min_lr"] = parameters["scheduler"].get( + "min_lr", parameters["learning_rate"] * 0.001 + ) + parameters["scheduler"]["max_lr"] = parameters["scheduler"].get( + "max_lr", parameters["learning_rate"] + ) + parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma", 0.1) + parameters["scheduler"]["scale_mode"] = parameters["scheduler"].get( + "scale_mode", "cycle" + ) + parameters["scheduler"]["cycle_momentum"] = parameters["scheduler"].get( + "cycle_momentum", False + ) + parameters["scheduler"]["base_momentum"] = parameters["scheduler"].get( + "base_momentum", 0.8 + ) + parameters["scheduler"]["max_momentum"] = parameters["scheduler"].get( + "max_momentum", 0.9 + ) return CyclicLR( parameters["optimizer_object"], - parameters["learning_rate"] * 0.001, #min lr - parameters["learning_rate"], #mar_lr + parameters["learning_rate"] * 0.001, # min lr + parameters["learning_rate"], # mar_lr step_size_up=parameters["scheduler"]["step_size"], step_size_down=None, mode=mode, @@ -112,14 +126,14 @@ def cyclic_lr_exp_range(parameters): def exp(parameters): - parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma",0.1) + parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma", 0.1) return ExponentialLR( parameters["optimizer_object"], parameters["scheduler"]["gamma"] ) def step(parameters): - parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma",0.1) + parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma", 0.1) return StepLR( parameters["optimizer_object"], parameters["scheduler"]["step_size"], @@ -128,14 +142,20 @@ def step(parameters): def reduce_on_plateau(parameters): - parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr",parameters["learning_rate"] * 0.001) - parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma",0.1) - parameters["scheduler"]["mode"] = parameters["scheduler"].get("mde","min") - parameters["scheduler"]["threshold_mode"] = parameters["scheduler"].get("threshold_mode","rel") - parameters["scheduler"]["factor"] = parameters["scheduler"].get("factor",0.1) - parameters["scheduler"]["patience"] = parameters["scheduler"].get("patience",10) - parameters["scheduler"]["threshold"] = parameters["scheduler"].get("threshold",0.0001) - parameters["scheduler"]["cooldown"] = parameters["scheduler"].get("cooldown",0) + parameters["scheduler"]["min_lr"] = parameters["scheduler"].get( + "min_lr", parameters["learning_rate"] * 0.001 + ) + parameters["scheduler"]["gamma"] = parameters["scheduler"].get("gamma", 0.1) + parameters["scheduler"]["mode"] = parameters["scheduler"].get("mde", "min") + parameters["scheduler"]["threshold_mode"] = parameters["scheduler"].get( + "threshold_mode", "rel" + ) + parameters["scheduler"]["factor"] = parameters["scheduler"].get("factor", 0.1) + parameters["scheduler"]["patience"] = parameters["scheduler"].get("patience", 10) + parameters["scheduler"]["threshold"] = parameters["scheduler"].get( + "threshold", 0.0001 + ) + parameters["scheduler"]["cooldown"] = parameters["scheduler"].get("cooldown", 0) return ReduceLROnPlateau( parameters["optimizer_object"], @@ -150,9 +170,9 @@ def reduce_on_plateau(parameters): def cosineannealing(parameters): - parameters["scheduler"]["T_0"] = parameters["scheduler"].get("T_0",5) - parameters["scheduler"]["T_mult"] = parameters["scheduler"].get("T_mult",1) - parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr",0.001) + parameters["scheduler"]["T_0"] = parameters["scheduler"].get("T_0", 5) + parameters["scheduler"]["T_mult"] = parameters["scheduler"].get("T_mult", 1) + parameters["scheduler"]["min_lr"] = parameters["scheduler"].get("min_lr", 0.001) return CosineAnnealingWarmRestarts( parameters["optimizer_object"], diff --git a/GANDLF/utils/handle_collisions.py b/GANDLF/utils/handle_collisions.py index 77a253d97..2596bc9fc 100644 --- a/GANDLF/utils/handle_collisions.py +++ b/GANDLF/utils/handle_collisions.py @@ -4,7 +4,9 @@ import pandas as pd -def handle_collisions(df: pd.DataFrame, headers: dict, output_path: str) -> Tuple[bool, pd.DataFrame]: +def handle_collisions( + df: pd.DataFrame, headers: dict, output_path: str +) -> Tuple[bool, pd.DataFrame]: """ This function checks for collisions in the subject IDs and updates the subject IDs in the dataframe to avoid collisions. diff --git a/GANDLF/utils/tensor.py b/GANDLF/utils/tensor.py index a357f77fd..9dfd3cb9c 100644 --- a/GANDLF/utils/tensor.py +++ b/GANDLF/utils/tensor.py @@ -84,7 +84,9 @@ def one_hot( return batch_stack -def reverse_one_hot(predmask_tensor: torch.Tensor, class_list: Union[List[int], List[str]]) -> np.array: +def reverse_one_hot( + predmask_tensor: torch.Tensor, class_list: Union[List[int], List[str]] +) -> np.array: """ This function creates a full segmentation mask Tensor from a one-hot-encoded mask and specified class list diff --git a/pyproject.toml b/pyproject.toml index c0c1505e0..c8caf08a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,19 +4,6 @@ extend-exclude = ''' ( testing/data | .*.md - | /GANDLF/cli/generate_metrics.py - | /GANDLF/data/post_process/tensor.py - | /GANDLF/data/preprocessing/threshold_and_clip.py - | /GANDLF/metrics/regression.py - | /GANDLF/models/unet_multilayer.py - | /GANDLF/optimizers/__init__.py - | /GANDLF/optimizers/wrap_monai.py - | /GANDLF/schedulers/wrap_monai.py - | /GANDLF/schedulers/wrap_torch.py - | /GANDLF/utils/handle_collisions.py - | /GANDLF/utils/tensor.py - | /setup.py - | /testing/conftest.py ) ''' skip_magic_trailing_comma = true diff --git a/setup.py b/setup.py index 6cc3661a9..176968cc4 100644 --- a/setup.py +++ b/setup.py @@ -14,9 +14,7 @@ readme = readme_file.read() except Exception as error: readme = "No README information found." - sys.stderr.write( - "Warning: Could not open '%s' due %s\n" % ("README.md", error) - ) + sys.stderr.write("Warning: Could not open '%s' due %s\n" % ("README.md", error)) class CustomInstallCommand(install): @@ -41,9 +39,7 @@ def run(self): except Exception as error: __version__ = "0.0.1" - sys.stderr.write( - "Warning: Could not open '%s' due %s\n" % (filepath, error) - ) + sys.stderr.write("Warning: Could not open '%s' due %s\n" % (filepath, error)) # Handle cases where specific files need to be bundled into the final package as installed via PyPI dockerfiles = [ @@ -58,9 +54,7 @@ def run(self): ] setup_files = ["setup.py", ".dockerignore", "pyproject.toml", "MANIFEST.in"] all_extra_files = dockerfiles + entrypoint_files + setup_files -all_extra_files_pathcorrected = [ - os.path.join("../", item) for item in all_extra_files -] +all_extra_files_pathcorrected = [os.path.join("../", item) for item in all_extra_files] # find_packages should only ever find these as subpackages of gandlf, not as top-level packages # generate this dynamically? # GANDLF.GANDLF is needed to prevent recursion madness in deployments diff --git a/testing/conftest.py b/testing/conftest.py index 6437979c2..31d8ceab0 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,7 +1,10 @@ import os, pathlib, pytest from pytest import fixture -from .test_full import prerequisites_hook_download_data, prerequisites_constructTrainingCSV +from .test_full import ( + prerequisites_hook_download_data, + prerequisites_constructTrainingCSV, +) def pytest_addoption(parser): From 03b7ce9f93f53b57d84de751fa9b2fbf552aa09b Mon Sep 17 00:00:00 2001 From: Viacheslav Kukushkin Date: Mon, 25 Mar 2024 17:58:12 +0300 Subject: [PATCH 10/10] Update setup.py Co-authored-by: Sarthak Pati --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 176968cc4..b582515c1 100644 --- a/setup.py +++ b/setup.py @@ -73,6 +73,7 @@ def run(self): "utils", ] +# specifying version for `black` separately because it is also used to [check for lint](https://github.com/mlcommons/GaNDLF/blob/master/.github/workflows/black.yml) black_version = "23.11.0" requirements = [ "torch==2.1.2",