internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: mlcommons/GaNDLF

Issue:
Bug during saving probabilities
**Describe the bug**
Small bug is occurring during saving probabilities in classification tasks. This is due to file existence check. It should check if the file exists instead of checking if the directory exists.



Discussion:

Resolving patch:
diff --git a/GANDLF/inference_manager.py b/GANDLF/inference_manager.py
--- a/GANDLF/inference_manager.py
+++ b/GANDLF/inference_manager.py
@@ -43,7 +43,7 @@ def InferenceManager(dataframe, outputDir, parameters, device):
         )
 
         logits_dir = os.path.join(fold_dir, "logits.csv")
-        is_logits_dir_exist = os.path.isdir(logits_dir)
+        is_logits_dir_exist = os.path.isfile(logits_dir)
 
         if is_classification and is_logits_dir_exist:
             fold_logits = np.genfromtxt(logits_dir, delimiter=",")


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Enhance affine augmentation
**Is your feature request related to a problem? Please describe.**
Currently, `RandomAffine` works in default mode, which is fine but doesn't allow for fine-tuned augmentations.

**Describe the solution you'd like**
Extend `RandomAffine` to pick up the following options from config:

- Scale 
- Degrees 
- Translation

**Describe alternatives you've considered**
N.A.

**Additional context**
N.A.



Discussion:

Resolving patch:
diff --git a/GANDLF/data/augmentation/wrap_torchio.py b/GANDLF/data/augmentation/wrap_torchio.py
--- a/GANDLF/data/augmentation/wrap_torchio.py
+++ b/GANDLF/data/augmentation/wrap_torchio.py
@@ -28,7 +28,12 @@ def mri_artifact(parameters):
 
 
 def affine(parameters):
-    return RandomAffine(p=parameters["probability"])
+    return RandomAffine(
+        scales=parameters["scales"],
+        degrees=parameters["degrees"],
+        translation=parameters["translation"],
+        p=parameters["probability"],
+    )
 
 
 def elastic(parameters):
diff --git a/GANDLF/parseConfig.py b/GANDLF/parseConfig.py
--- a/GANDLF/parseConfig.py
+++ b/GANDLF/parseConfig.py
@@ -325,11 +325,24 @@ def parseConfig(config_file_path, version_check=True):
                         .tolist(),
                     )
 
+            # special case for swap default initialization
             if "swap" in params["data_augmentation"]:
                 params["data_augmentation"]["swap"] = initialize_key(
                     params["data_augmentation"]["swap"], "num_iterations", 100
                 )
 
+            # special case for affine default initialization
+            if "affine" in params["data_augmentation"]:
+                params["data_augmentation"]["affine"] = initialize_key(
+                    params["data_augmentation"]["affine"], "scales", 0.1
+                )
+                params["data_augmentation"]["affine"] = initialize_key(
+                    params["data_augmentation"]["affine"], "degrees", 15
+                )
+                params["data_augmentation"]["affine"] = initialize_key(
+                    params["data_augmentation"]["affine"], "translation", 2
+                )
+
             # special case for random blur/noise - which takes a std-dev range
             for std_aug in ["blur", "noise"]:
                 if std_aug in params["data_augmentation"]:


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Add center cropping
**Is your feature request related to a problem? Please describe.**
We do not have any mechanism to perform cropping, which is important for certain DL training problems.

**Describe the solution you'd like**
Expose the [cropping functionality in TorchIO](https://torchio.readthedocs.io/transforms/preprocessing.html?highlight=crop#torchio.transforms.Crop) as a preprocessing mechanism.

**Describe alternatives you've considered**
N.A.

**Additional context**
Requested by @Geeks-Sid for SBU-TIL.



Discussion:

Resolving patch:
diff --git a/GANDLF/data/preprocessing/__init__.py b/GANDLF/data/preprocessing/__init__.py
--- a/GANDLF/data/preprocessing/__init__.py
+++ b/GANDLF/data/preprocessing/__init__.py
@@ -14,6 +14,8 @@
 from torchio.transforms import (
     ZNormalization,
     ToCanonical,
+    Crop,
+    CropOrPad,
 )
 
 
@@ -29,6 +31,14 @@ def to_canonical_transform(parameters):
     return ToCanonical()
 
 
+def crop_transform(patch_size):
+    return Crop(patch_size)
+
+
+def centercrop_transform(patch_size):
+    return CropOrPad(target_shape=patch_size)
+
+
 # defining dict for pre-processing - key is the string and the value is the transform object
 global_preprocessing_dict = {
     "to_canonical": to_canonical_transform,
@@ -36,6 +46,8 @@ def to_canonical_transform(parameters):
     "clip": clip_transform,
     "clamp": clip_transform,
     "crop_external_zero_planes": CropExternalZeroplanes,
+    "crop": crop_transform,
+    "centercrop": centercrop_transform,
     "normalize_by_val": normalize_by_val_transform,
     "normalize_imagenet": normalize_imagenet_transform,
     "normalize_standardize": normalize_standardize_transform,


Test patch:
diff --git a/testing/test_full.py b/testing/test_full.py
--- a/testing/test_full.py
+++ b/testing/test_full.py
@@ -943,6 +943,15 @@ def test_preprocess_functions():
         patch_size=[128, 128, 128]
     )
     input_transformed = cropper(input_tensor)
+
+    cropper = global_preprocessing_dict["crop"]([64, 64, 64])
+    input_transformed = cropper(input_tensor)
+    assert input_transformed.shape == (1, 128, 128, 128), "Resampling should work"
+
+    cropper = global_preprocessing_dict["centercrop"]([128, 128, 128])
+    input_transformed = cropper(input_tensor)
+    assert input_transformed.shape == (1, 128, 128, 128), "Resampling should work"
+
     print("passed")
 
 
@@ -1065,7 +1074,7 @@ def test_model_patch_divisibility():
 
 def test_one_hot_logic():
 
-    random_array = np.random.random_integers(0, 5, size=(20, 20, 20))
+    random_array = np.random.randint(5, size=(20, 20, 20))
     class_list = [*range(0, np.max(random_array) + 1)]
     img = sitk.GetImageFromArray(random_array)
     img_array = sitk.GetArrayFromImage(img)
Repository: mlcommons/GaNDLF

Issue:
Default mapping to GPU device during inference
**Describe the bug**
When running on CPU, this issue occurs: RuntimeError: Attempting to deserialize object on a CUDA device but torch.cuda.is_available() is False. If you are running on a CPU-only machine, please use torch.load with map_location=torch.device('cpu') to map your storages to the CPU. Hence adding `map_location` to torch.load (Ref: https://pytorch.org/docs/stable/generated/torch.load.html).
Please review.

**To Reproduce**
Steps to reproduce the behavior:
After data preprocess, run:
python gandlf_run -c <config> -i <val_dataset> -m <model_dir> -t False -d cpu

**Expected behavior**
Model should be mapped to the CPU device. Although there is a `send_model_to_device` method implemented, this error occurs before that, during `torch.load`

**Screenshots**
If applicable, add screenshots to help explain your problem.

**GaNDLF Version**
Version: 0.0.13

**Desktop (please complete the following information):**
 - OS: Linux CentOS 7.6

**Additional context**
Can provided if needed



Discussion:

Resolving patch:
diff --git a/GANDLF/compute/inference_loop.py b/GANDLF/compute/inference_loop.py
--- a/GANDLF/compute/inference_loop.py
+++ b/GANDLF/compute/inference_loop.py
@@ -51,7 +51,8 @@ def inference_loop(inferenceDataFromPickle, device, parameters, outputDir):
         )
         if not os.path.isfile(file_to_check):
             raise ValueError("The model specified model was not found:", file_to_check)
-    main_dict = torch.load(file_to_check)
+
+    main_dict = torch.load(file_to_check, map_location=torch.device(device))
     model.load_state_dict(main_dict["model_state_dict"])
 
     if not (os.environ.get("HOSTNAME") is None):


Test patch:
Repository: mlcommons/GaNDLF

Issue:
The forward pass breaks if `"data_preprocessing"` is absent in config
**Describe the bug**
See title.

**To Reproduce**
Steps to reproduce the behavior:
1. Have a config without `"data_preprocessing"` present
2. See error:
```python-traceback
Traceback (most recent call last):
  File "/path/to/GaNDLF/gandlf_run", line 87, in <module>
    args.inputdata, args.config, args.modeldir, args.train, args.device, args.resetprev
  File "/gpfs/fs001/path/to/GaNDLF/GANDLF/cli/main_run.py", line 88, in main_run
    reset_prev=reset_prev,
  File "/gpfs/fs001/path/to/GaNDLF/GANDLF/training_manager.py", line 230, in TrainingManager
    testing_data=testingData,
  File "/gpfs/fs001/path/to/GaNDLF/GANDLF/compute/training_loop.py", line 429, in training_loop
    model, val_dataloader, scheduler, params, epoch, mode="validation"
  File "/gpfs/fs001/path/to/GaNDLF/GANDLF/compute/forward_pass.py", line 287, in validate_network
    if "resample" in params["data_preprocessing"]:
TypeError: argument of type 'NoneType' is not iterable
```

**Expected behavior**
This error should not be triggered.

**Screenshots**
N.A.

**GaNDLF Version**
<!-- Put the output of the following command:
python -c 'import GANDLF as g;print(g.__version__)'
-->
0.0.14-dev

**Desktop (please complete the following information):**
 - OS: N.A.
 - Version: N.A.

**Additional context**
Reported by Ahmed.



Discussion:
I am unable to replicate this error on my machine. It should be managed by this line:
https://github.com/CBICA/GaNDLF/blob/63f3d8e9716f2fcea088b231b9c5cbf42306cff2/GANDLF/parseConfig.py#L404

Reaching out to original reporter to see if there is something missing.

Resolving patch:
diff --git a/GANDLF/parseConfig.py b/GANDLF/parseConfig.py
--- a/GANDLF/parseConfig.py
+++ b/GANDLF/parseConfig.py
@@ -292,7 +292,7 @@ def parseConfig(config_file_path, version_check_flag=True):
         sys.exit("The key 'metrics' needs to be defined")
 
     # this is NOT a required parameter - a user should be able to train with NO augmentations
-    params = initialize_key(params, "data_augmentation")
+    params = initialize_key(params, "data_augmentation", {})
     if not (params["data_augmentation"] == None):
         if len(params["data_augmentation"]) > 0:  # only when augmentations are defined
 
@@ -401,7 +401,7 @@ def parseConfig(config_file_path, version_check_flag=True):
                     )
 
     # this is NOT a required parameter - a user should be able to train with NO built-in pre-processing
-    params = initialize_key(params, "data_preprocessing")
+    params = initialize_key(params, "data_preprocessing", {})
     if not (params["data_preprocessing"] == None):
         # perform this only when pre-processing is defined
         if len(params["data_preprocessing"]) > 0:


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Add random motion as a separate data augmentation method
**Is your feature request related to a problem? Please describe.**
Currently, random motion is part of `mri_artifact`, which renders it unusable for non-MR applications.

**Describe the solution you'd like**
Add a separate motion artifact.

**Describe alternatives you've considered**
N.A.

**Additional context**
N.A.



Discussion:

Resolving patch:
diff --git a/GANDLF/data/augmentation/__init__.py b/GANDLF/data/augmentation/__init__.py
--- a/GANDLF/data/augmentation/__init__.py
+++ b/GANDLF/data/augmentation/__init__.py
@@ -1,5 +1,6 @@
 from .wrap_torchio import (
     mri_artifact,
+    motion,
     affine,
     elastic,
     swap,
@@ -21,6 +22,7 @@
     "affine": affine,
     "elastic": elastic,
     "kspace": mri_artifact,
+    "motion": motion,
     "bias": bias,
     "blur": blur,
     "noise": noise,
diff --git a/GANDLF/data/augmentation/wrap_torchio.py b/GANDLF/data/augmentation/wrap_torchio.py
--- a/GANDLF/data/augmentation/wrap_torchio.py
+++ b/GANDLF/data/augmentation/wrap_torchio.py
@@ -22,7 +22,17 @@
 # define individual functions/lambdas for augmentations to handle properties
 def mri_artifact(parameters):
     return OneOf(
-        {RandomMotion(): 0.34, RandomGhosting(): 0.33, RandomSpike(): 0.33},
+        {RandomGhosting(): 0.5, RandomSpike(): 0.5},
+        p=parameters["probability"],
+    )
+
+
+def motion(parameters):
+    return RandomMotion(
+        degrees=parameters["degrees"],
+        translation=parameters["translation"],
+        num_transforms=parameters["num_transforms"],
+        image_interpolation=parameters["interpolation"],
         p=parameters["probability"],
     )
 
diff --git a/GANDLF/parseConfig.py b/GANDLF/parseConfig.py
--- a/GANDLF/parseConfig.py
+++ b/GANDLF/parseConfig.py
@@ -325,6 +325,20 @@ def parseConfig(config_file_path, version_check_flag=True):
                     params["data_augmentation"]["affine"], "translation", 2
                 )
 
+            if "motion" in params["data_augmentation"]:
+                params["data_augmentation"]["motion"] = initialize_key(
+                    params["data_augmentation"]["motion"], "num_transforms", 2
+                )
+                params["data_augmentation"]["motion"] = initialize_key(
+                    params["data_augmentation"]["motion"], "degrees", 15
+                )
+                params["data_augmentation"]["motion"] = initialize_key(
+                    params["data_augmentation"]["motion"], "translation", 2
+                )
+                params["data_augmentation"]["motion"] = initialize_key(
+                    params["data_augmentation"]["motion"], "interpolation", "linear"
+                )
+
             # special case for random blur/noise - which takes a std-dev range
             for std_aug in ["blur", "noise"]:
                 if std_aug in params["data_augmentation"]:


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Include a git submodule update when doing pip install
**Is your feature request related to a problem? Please describe.**
Currently, the installation step requires a user to run `git submodule update --init --recursive` before doing `pip install`, which can lead to broken installation if the user forgets the step.

**Describe the solution you'd like**
Ensure the [git submodule line is working correctly in the setup.py file](https://github.com/CBICA/GaNDLF/blob/f4d0f02848c894d43259c2bb0b70612db612eb53/setup.py#L95).

**Describe alternatives you've considered**
N.A.

**Additional context**
N.A.


Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -2,11 +2,40 @@
 
 """The setup script."""
 
+
+import os
 from setuptools import setup, find_packages
+from setuptools.command.install import install
+from setuptools.command.develop import develop
+from setuptools.command.egg_info import egg_info
 
 with open("README.md") as readme_file:
     readme = readme_file.read()
 
+
+def git_submodule_update():
+    ## submodule update
+    os.system("git submodule update --init --recursive")
+
+
+class CustomInstallCommand(install):
+    def run(self):
+        install.run(self)
+        git_submodule_update()
+
+
+class CustomDevelopCommand(develop):
+    def run(self):
+        develop.run(self)
+        git_submodule_update()
+
+
+class CustomEggInfoCommand(egg_info):
+    def run(self):
+        egg_info.run(self)
+        git_submodule_update()
+
+
 # read version.py
 import sys, re
 
@@ -42,6 +71,7 @@
     "pyvips",
     "pytest",
     "coverage",
+    "pytest-cov",
     "psutil",
     "medcam",
     "opencv-python",
@@ -53,10 +83,15 @@
 setup(
     name="GANDLF",
     version=__version__,
-    author="Jose Agraz, Vinayak Ahluwalia, Bhakti Baheti, Spyridon Bakas, Ujjwal Baid, Megh Bhalerao, Brandon Edwards, Karol Gotkowski, Caleb Grenko, Orhun Güley, Sarthak Pati, Micah Sheller, Juliia Skobleva, Siddhesh Thakur, Spiros Thermos",  # alphabetical order
+    author="Jose Agraz, Vinayak Ahluwalia, Bhakti Baheti, Spyridon Bakas, Ujjwal Baid, Megh Bhalerao, Brandon Edwards, Karol Gotkowski, Caleb Grenko, Orhun Güley, Ibrahim Ethem Hamamci, Sarthak Pati, Micah Sheller, Juliia Skobleva, Siddhesh Thakur, Spiros Thermos",  # alphabetical order
     author_email="software@cbica.upenn.edu",
     python_requires=">=3.6",
     packages=find_packages(),
+    cmdclass={  # this ensures git_submodule_update is called during install
+        "install": CustomInstallCommand,
+        "develop": CustomDevelopCommand,
+        "egg_info": CustomEggInfoCommand,
+    },
     scripts=[
         "gandlf_run",
         "gandlf_constructCSV",
@@ -89,11 +124,6 @@
     zip_safe=False,
 )
 
-import os
-
-## submodule update
-os.system("git submodule update --init --recursive")
-
 ## windows vips installation
 if os.name == "nt":  # proceed for windows
     from pathlib import Path


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Add an easy way to verify installation
**Is your feature request related to a problem? Please describe.**
Currently, we are asking users to run specific commands to verify installation, which can be cumbursome.

**Describe the solution you'd like**
It would be great if this could put in a script (and extended/updated as needed).

**Describe alternatives you've considered**
N.A.

**Additional context**
N.A.



Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -99,6 +99,7 @@ def run(self):
         "gandlf_patchMiner",
         "gandlf_preprocess",
         "gandlf_anonymizer",
+        "gandlf_verifyInstall",
     ],
     classifiers=[
         "Development Status :: 3 - Alpha",


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Add the option to apply augmentation while running `gandlf_preprocess`
**Is your feature request related to a problem? Please describe.**
`gandlf_preprocess` is currently applying all options in `data_preprocessing` key, but anything related to augmentations are not getting picked.

**Describe the solution you'd like**
Provide this as an option in CLI, so that users might save on this compute during training.

**Describe alternatives you've considered**
N.A.

**Additional context**
Useful for image-to-image generative tasks.



Discussion:

Resolving patch:
diff --git a/GANDLF/cli/preprocess_and_save.py b/GANDLF/cli/preprocess_and_save.py
--- a/GANDLF/cli/preprocess_and_save.py
+++ b/GANDLF/cli/preprocess_and_save.py
@@ -17,7 +17,9 @@
 import torchio
 
 
-def preprocess_and_save(data_csv, config_file, output_dir, label_pad_mode="constant"):
+def preprocess_and_save(
+    data_csv, config_file, output_dir, label_pad_mode="constant", applyaugs=False
+):
     """
     This function performs preprocessing based on parameters provided and saves the output.
 
@@ -26,6 +28,7 @@ def preprocess_and_save(data_csv, config_file, output_dir, label_pad_mode="const
         config_file (str): The YAML file of the training configuration.
         output_dir (str): The output directory.
         label_pad_mode (str): The padding strategy for the label. Defaults to "constant".
+        applyaugs (bool): If data augmentation is to be applied before saving the image. Defaults to False.
 
     Raises:
         ValueError: Parameter check from previous
@@ -52,7 +55,7 @@ def preprocess_and_save(data_csv, config_file, output_dir, label_pad_mode="const
     parameters = populate_header_in_parameters(parameters, headers)
 
     data_for_processing = ImagesFromDataFrame(
-        dataframe, parameters, train=False, loader_type="full"
+        dataframe, parameters, train=applyaugs, loader_type="full"
     )
 
     dataloader_for_processing = DataLoader(


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Link original arch papers in the README of `GANDLF.models`
**Is your feature request related to a problem? Please describe.**
Currently, we don't have a centralized location for the main links to the arch papers.

**Describe the solution you'd like**
Put it in https://github.com/CBICA/GaNDLF/blob/master/GANDLF/models/Readme.md

**Describe alternatives you've considered**
N.A.

**Additional context**
N.A.



Discussion:

Resolving patch:
diff --git a/GANDLF/compute/training_loop.py b/GANDLF/compute/training_loop.py
--- a/GANDLF/compute/training_loop.py
+++ b/GANDLF/compute/training_loop.py
@@ -470,7 +470,8 @@ def training_loop(
                 best_model_path,
             )
             first_model_saved = True
-            print("Best epoch: ", best_train_idx)
+
+        print("Current Best epoch: ", best_train_idx)
 
         if patience > params["patience"]:
             print(


Test patch:
Repository: mlcommons/GaNDLF

Issue:
Training classification accuracy >1
**Describe the bug**
Hi, I am training a classification model on MRI brain scans using vgg16 in gandlf. We expect to have accuracy in the range of 0-1. But Training classification accuracy is displayed >1. Validation accuracy seems correct. Attaching the screenshot below. Can you please have a look?

**Screenshots**
![Screenshot from 2022-03-17 14-13-02](https://user-images.githubusercontent.com/6376680/158874773-97c9a7cd-49a1-45fa-85c9-86b93533911b.png)

**GaNDLF Version**
0.0.14




Discussion:

Resolving patch:
diff --git a/GANDLF/metrics/regression.py b/GANDLF/metrics/regression.py
--- a/GANDLF/metrics/regression.py
+++ b/GANDLF/metrics/regression.py
@@ -11,7 +11,8 @@ def classification_accuracy(output, label, params):
         predicted_classes = torch.argmax(output, 1)
     else:
         predicted_classes = output
-    acc = torch.sum(predicted_classes == label) / len(label)
+
+    acc = torch.sum(predicted_classes == label.squeeze()) / len(label)
     return acc
 
 


Test patch:
Repository: mlcommons/GaNDLF

Issue:
GaNDLF is not running on macOS
**Describe the bug**
Currently, we are requiring `torch==1.8.2`:
https://github.com/CBICA/GaNDLF/blob/e8f922266ec7af1c3fac36439290d22a5e63866d/setup.py#L56
Which is not supported by PyTorch on macOS[[ref](https://pytorch.org/get-started/locally/)].

**To Reproduce**
Steps to reproduce the behavior: https://cbica.github.io/GaNDLF/setup

**Expected behavior**
The only reason for us to drop support of an OS should be if something major is breaking.

**Screenshots**
N.A.

**GaNDLF Version**
<!-- Put the output of the following command:
python -c 'import GANDLF as g;print(g.__version__)'
-->
0.0.14-dev

**Desktop (please complete the following information):**
 - OS: macOS
 - Version: N.A.

**Additional context**
Reported by @Sofia-Mouchtaris 



Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -53,7 +53,6 @@ def run(self):
     "numpy==1.21.0",
     "scipy",
     "SimpleITK!=2.0.*",
-    "torch==1.8.2",
     "torchvision",
     "tqdm",
     "torchio==0.18.57",
@@ -82,6 +81,12 @@ def run(self):
     "onnx",
 ]
 
+# pytorch doesn't have LTS support on OSX - https://github.com/CBICA/GaNDLF/issues/389
+if sys.platform == "darwin":
+    requirements.append("torch==1.9.0")
+else:
+    requirements.append("torch==1.8.2")
+
 setup(
     name="GANDLF",
     version=__version__,


Test patch: