Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,25 @@ dependencies = [
"flake8-unused-arguments>=0.0.13",
"fvcore>=0.1.5",
"lightning>=2.2.1",
"matplotlib>=3.8.3",
"monai>=1.3.0",
"nibabel>=5.2.1",
"numpy>=1.26.4",
"pandas>=2.2.1",
"python-dotenv==1.0.0",
"scikit_image>=0.22.0",
"scikit_learn>=1.4.1.post1",
"seaborn>=0.13.2",
"SimpleITK>=2.3.1",
"tqdm>=4.66.2",
"timm>=0.9.8",
"torchmetrics>=1.4.0.post0",
"wandb>=0.16.3",
"weave>=0.39.0",
]


[project.optional-dependencies]
extras = [
"matplotlib>=3.8.3",
"monai>=1.3.0",
"SimpleITK>=2.3.1",
"pandas>=2.2.1",
]
test = [
'pytest>=7.3',
'flake8>=6.1.0',
Expand Down
3 changes: 1 addition & 2 deletions yucca/documentation/templates/functional_inference.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import lightning as L
import os
import torch
from batchgenerators.utilities.file_and_folder_operations import maybe_mkdir_p as ensure_dir_exists
from yucca.paths import (
get_models_path,
get_results_path,
Expand Down Expand Up @@ -41,7 +40,7 @@
"version_0",
"best",
)
ensure_dir_exists(save_path)
os.makedirs(save_path, exist_ok=True)

ckpt = torch.load(ckpt_path, map_location="cpu")
pred_writer = WritePredictionFromLogits(output_dir=save_path, save_softmax=False, write_interval="batch")
Expand Down
28 changes: 12 additions & 16 deletions yucca/documentation/templates/functional_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,22 @@
import os
import numpy as np
import torch
from batchgenerators.utilities.file_and_folder_operations import (
subfiles,
join,
save_pickle,
maybe_mkdir_p as ensure_dir_exists,
)
from yucca.functional.utils.files_and_folders import subfiles
from yucca.functional.utils.saving import save_pickle
from yucca.paths import get_raw_data_path, get_preprocessed_data_path
from yucca.documentation.templates.template_config import config
from yucca.functional.preprocessing import preprocess_case_for_training_with_label, preprocess_case_for_inference
from yucca.functional.utils.loading import read_file_to_nifti_or_np

raw_images_dir = join(get_raw_data_path(), config["task"], "imagesTr")
raw_labels_dir = join(get_raw_data_path(), config["task"], "labelsTr")
test_raw_images_dir = join(get_raw_data_path(), config["task"], "imagesTs")
raw_images_dir = os.path.join(get_raw_data_path(), config["task"], "imagesTr")
raw_labels_dir = os.path.join(get_raw_data_path(), config["task"], "labelsTr")
test_raw_images_dir = os.path.join(get_raw_data_path(), config["task"], "imagesTs")

target_dir = join(get_preprocessed_data_path(), config["task"], config["config_name"])
test_target_dir = join(get_preprocessed_data_path(), config["task"] + "_test", config["config_name"])
target_dir = os.path.join(get_preprocessed_data_path(), config["task"], config["config_name"])
test_target_dir = os.path.join(get_preprocessed_data_path(), config["task"] + "_test", config["config_name"])

ensure_dir_exists(target_dir)
ensure_dir_exists(test_target_dir)
os.makedirs(target_dir, exist_ok=True)
os.makedirs(test_target_dir, exist_ok=True)

# Preprocess the training data
subjects = [file[: -len(config["extension"])] for file in subfiles(raw_labels_dir, join=False) if not file.startswith(".")]
Expand All @@ -34,7 +30,7 @@
if re.search(re.escape(sub) + "_" + r"\d{3}" + ".", os.path.split(image_path)[-1])
]
images = [read_file_to_nifti_or_np(image) for image in images]
label = read_file_to_nifti_or_np(join(raw_labels_dir, sub + config["extension"]))
label = read_file_to_nifti_or_np(os.path.join(raw_labels_dir, sub + config["extension"]))
images, label, image_props = preprocess_case_for_training_with_label(
images=images,
label=label,
Expand All @@ -45,7 +41,7 @@
)
images = np.vstack((np.array(images), np.array(label)[np.newaxis]), dtype=np.float32)

save_path = join(target_dir, sub)
save_path = os.path.join(target_dir, sub)
np.save(save_path + ".npy", images)
save_pickle(image_props, save_path + ".pkl")

Expand Down Expand Up @@ -73,6 +69,6 @@
target_spacing=config["target_spacing"],
target_orientation=config["target_coordinate_system"],
)
save_path = join(test_target_dir, sub)
save_path = os.path.join(test_target_dir, sub)
torch.save(images, save_path + ".pt")
save_pickle(image_props, save_path + ".pkl")
11 changes: 6 additions & 5 deletions yucca/documentation/tests/transforms/dataloader.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from yucca.modules.data.datasets.YuccaDataset import YuccaTrainDataset\n",
"from yucca.paths import yucca_preprocessed_data\n",
"from batchgenerators.utilities.file_and_folder_operations import join, subfiles\n",
"from yucca.functional.utils.files_and_folders import subfiles\n",
"import os\n",
"from torch.utils.data import DataLoader"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [
{
Expand All @@ -28,7 +29,7 @@
"source": [
"from matplotlib import pyplot as plt\n",
"\n",
"samples = subfiles(join(yucca_preprocessed_data(), \"Task299_Combine\", \"UnsupervisedPlanner\"), suffix=\".npy\")\n",
"samples = subfiles(os.path.join(yucca_preprocessed_data(), \"Task299_Combine\", \"UnsupervisedPlanner\"), suffix=\".npy\")\n",
"\n",
"\n",
"dataset = YuccaTrainDataset(samples=samples, patch_size=(96,) * 3, composed_transforms=None, task_type=\"contrastive\")\n",
Expand Down Expand Up @@ -93,7 +94,7 @@
"metadata": {},
"outputs": [],
"source": [
"samples = subfiles(join(yucca_preprocessed_data(), \"Task001_OASIS\", \"YuccaPlanner\"), suffix=\".npy\")\n",
"samples = subfiles(os.path.join(yucca_preprocessed_data(), \"Task001_OASIS\", \"YuccaPlanner\"), suffix=\".npy\")\n",
"\n",
"print(samples)\n",
"\n",
Expand Down
2 changes: 0 additions & 2 deletions yucca/functional/evaluation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .confusion_matrix import torch_confusion_matrix_from_logits, torch_get_tp_fp_tn_fn
from .metrics import (
dice,
dice_per_label,
Expand All @@ -17,5 +16,4 @@
total_pos_gt,
total_pos_pred,
)
from .obj_metrics import get_obj_stats_for_label, obj_get_tp_fp_fn_gtvols_predvols
from .surface_metrics import get_surface_metrics_for_label
14 changes: 7 additions & 7 deletions yucca/functional/evaluation/evaluate_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import numpy as np
import nibabel as nib
import logging
import os
from typing import Optional
from yucca.functional.transforms.label_transforms import convert_labels_to_regions, translate_region_labels
from yucca.functional.utils.nib_utils import get_nib_spacing
from yucca.functional.utils.loading import read_file_to_nifti_or_np
from yucca.functional.evaluation.obj_metrics import get_obj_stats_for_label
from yucca.functional.evaluation.surface_metrics import get_surface_metrics_for_label
from tqdm import tqdm
from batchgenerators.utilities.file_and_folder_operations import join
from sklearn.metrics import confusion_matrix
from yucca.functional.evaluation.metrics import auroc

Expand Down Expand Up @@ -97,8 +97,8 @@ def evaluate_multilabel_case_segm(
assert regions is not None

case_dict = {}
predpath = join(folder_with_predictions, case)
gtpath = join(folder_with_ground_truth, case)
predpath = os.path.join(folder_with_predictions, case)
gtpath = os.path.join(folder_with_ground_truth, case)
case_dict["prediction_path"] = predpath
case_dict["ground_truth_path"] = gtpath

Expand Down Expand Up @@ -184,8 +184,8 @@ def evaluate_case_segm(
surface_tol: int = 1,
):
case_dict = {}
predpath = join(folder_with_predictions, case)
gtpath = join(folder_with_ground_truth, case)
predpath = os.path.join(folder_with_predictions, case)
gtpath = os.path.join(folder_with_ground_truth, case)

case_dict["prediction_path"] = predpath
case_dict["ground_truth_path"] = gtpath
Expand Down Expand Up @@ -269,8 +269,8 @@ def evaluate_folder_cls(

# load predictions and ground truths
for case in tqdm(subjects, desc="Evaluating"):
predpath = join(folder_with_predictions, case)
gtpath = join(folder_with_ground_truth, case)
predpath = os.path.join(folder_with_predictions, case)
gtpath = os.path.join(folder_with_ground_truth, case)

pred: int = np.loadtxt(predpath)
gt: int = np.loadtxt(gtpath)
Expand Down
3 changes: 2 additions & 1 deletion yucca/functional/planning.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import numpy as np
from typing import Optional, List, Union
from batchgenerators.utilities.file_and_folder_operations import subfiles, load_pickle
from yucca.functional.utils.files_and_folders import subfiles
from yucca.functional.utils.loading import load_pickle


def make_plans_file(
Expand Down
30 changes: 24 additions & 6 deletions yucca/functional/utils/files_and_folders.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,29 @@
import re
import shutil
import os
from batchgenerators.utilities.file_and_folder_operations import (
join,
subdirs,
)
from typing import Union, List
from typing import Union, List, Optional


def subdirs(
folder: str, join: bool = True, prefix: Optional[str] = None, suffix: Optional[str] = None, sort: bool = True
) -> List[str]:
"""
implementation by: https://github.com/MIC-DKFZ/batchgenerators
"""
subdirectories = []
with os.scandir(folder) as entries:
for entry in entries:
if (
entry.is_dir()
and (prefix is None or entry.name.startswith(prefix))
and (suffix is None or entry.name.endswith(suffix))
):
dir_path = entry.path if join else entry.name
subdirectories.append(dir_path)

if sort:
subdirectories.sort()
return subdirectories


def replace_in_file(file_path, pattern_replacement):
Expand Down Expand Up @@ -139,7 +157,7 @@ def _recursive_find_python_class(folder: list, class_name: str, current_module:
if ispkg:
next_current_module = current_module + "." + modname
tr = _recursive_find_python_class(
[join(folder[0], modname)],
[os.path.join(folder[0], modname)],
class_name,
current_module=next_current_module,
)
Expand Down
12 changes: 12 additions & 0 deletions yucca/functional/utils/loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import nibabel as nib
import numpy as np
import pickle
from PIL import Image


Expand All @@ -21,3 +22,14 @@ def read_file_to_nifti_or_np(imagepath, dtype=np.float32):
return np.atleast_1d(np.genfromtxt(imagepath, delimiter=",", dtype=dtype))
else:
raise TypeError(f"File type invalid. Found extension: {ext} and expected one in [nii, nii.gz, png, csv, txt]")


def load_pickle(file: str, mode: str = "rb"):
with open(file, mode) as f:
a = pickle.load(f)
return a


def load_json(p):
with open(p, "r") as f:
return json.load(f)
19 changes: 11 additions & 8 deletions yucca/functional/utils/saving.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import nibabel as nib
import numpy as np
import os
import pickle
from yucca.functional.utils.softmax import softmax
from yucca.functional.utils.nib_utils import reorient_nib_image
from yucca.functional.utils.file_and_folders import subfiles
from PIL import Image
from batchgenerators.utilities.file_and_folder_operations import (
join,
subfiles,
maybe_mkdir_p as ensure_dir_exists,
)


def save_pickle(obj, file: str, mode: str = "wb") -> None:
with open(file, mode) as f:
pickle.dump(obj, f)


def save_nifti_from_numpy(pred, outpath, properties, compression=9):
Expand Down Expand Up @@ -87,7 +90,7 @@ def save_multilabel_prediction_from_logits(logits, outpath, properties, compress


def merge_softmax_from_folders(folders: list, outpath, method="sum"):
ensure_dir_exists(outpath)
os.makedirs(outpath, exists_ok=True)
cases = subfiles(folders[0], suffix=".npz", join=False)
for folder in folders:
assert cases == subfiles(folder, suffix=".npz", join=False), (
Expand All @@ -98,7 +101,7 @@ def merge_softmax_from_folders(folders: list, outpath, method="sum"):
)

for case in cases:
files_for_case = [np.load(join(folder, case), allow_pickle=True) for folder in folders]
files_for_case = [np.load(os.path.join(folder, case), allow_pickle=True) for folder in folders]
properties_for_case = files_for_case[0]["properties"]
files_for_case = [file["data"].astype(np.float32) for file in files_for_case]

Expand All @@ -108,7 +111,7 @@ def merge_softmax_from_folders(folders: list, outpath, method="sum"):
files_for_case = np.argmax(files_for_case, 0)
save_nifti_from_numpy(
files_for_case,
join(outpath, case[:-4]),
os.path.join(outpath, case[:-4]),
properties=properties_for_case.item(),
)

Expand Down
23 changes: 9 additions & 14 deletions yucca/modules/callbacks/loggers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@
import logging
from argparse import Namespace
from lightning.pytorch.loggers.logger import Logger
from pytorch_lightning.utilities.rank_zero import rank_zero_only
from pytorch_lightning.core.saving import save_hparams_to_yaml
from lightning_fabric.utilities.logger import _convert_params
from lightning.pytorch.utilities.rank_zero import rank_zero_only
from lightning.pytorch.core.saving import save_hparams_to_yaml
from lightning.fabric.utilities.logger import _convert_params
from time import localtime, strftime, time
from batchgenerators.utilities.file_and_folder_operations import (
join,
maybe_mkdir_p as ensure_dir_exists,
isdir,
)
from typing import Any, Dict, Optional, Union


Expand Down Expand Up @@ -60,18 +55,18 @@ def root_dir(self):
def log_dir(self):
log_dir = self.root_dir
if self.name is not None:
log_dir = join(log_dir, self.name)
log_dir = os.path.join(log_dir, self.name)
if self.version is not None:
version = self.version if isinstance(self.version, str) else f"version_{self.version}"
log_dir = join(log_dir, version)
if not isdir(log_dir):
ensure_dir_exists(log_dir)
log_dir = os.path.join(log_dir, version)
if not os.path.isdir(log_dir):
os.makedirs(log_dir, exist_ok=True)
return log_dir

@rank_zero_only
def create_logfile(self):
ensure_dir_exists(self.log_dir)
self.log_file = join(
os.makedirs(self.log_dir, exist_ok=True)
self.log_file = os.path.join(
self.log_dir,
"training_log.txt",
)
Expand Down
Loading
Loading