-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'MIC-DKFZ:master' into seq-inf
- Loading branch information
Showing
14 changed files
with
319 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from batchgenerators.utilities.file_and_folder_operations import * | ||
import shutil | ||
from nnunetv2.dataset_conversion.generate_dataset_json import generate_dataset_json | ||
|
||
|
||
if __name__ == '__main__': | ||
""" | ||
How to train our submission to the JHU benchmark | ||
1. Execute this script here to convert the dataset into nnU-Net format. Adapt the paths to your system! | ||
2. Run planning and preprocessing: `nnUNetv2_plan_and_preprocess -d 224 -npfp 64 -np 64 -c 3d_fullres -pl | ||
nnUNetPlannerResEncL_torchres`. Adapt the number of processes to your System (-np; -npfp)! Note that each process | ||
will again spawn 4 threads for resampling. This custom planner replaces the nnU-Net default resampling scheme with | ||
a torch-based implementation which is faster but less accurate. This is needed to satisfy the inference speed | ||
constraints. | ||
3. Run training with `nnUNetv2_train 224 3d_fullres all -p nnUNetResEncUNetLPlans_torchres`. 24GB VRAM required, | ||
training will take ~28-30h. | ||
""" | ||
|
||
|
||
base = '/home/isensee/Downloads/AbdomenAtlas1.0Mini' | ||
cases = subdirs(base, join=False, prefix='BDMAP') | ||
|
||
target_dataset_id = 224 | ||
target_dataset_name = f'Dataset{target_dataset_id:3.0f}_AbdomenAtlas1.0' | ||
|
||
raw_dir = '/home/isensee/drives/E132-Projekte/Projects/Helmholtz_Imaging_ACVL/2024_JHU_benchmark' | ||
maybe_mkdir_p(join(raw_dir, target_dataset_name)) | ||
imagesTr = join(raw_dir, target_dataset_name, 'imagesTr') | ||
labelsTr = join(raw_dir, target_dataset_name, 'labelsTr') | ||
maybe_mkdir_p(imagesTr) | ||
maybe_mkdir_p(labelsTr) | ||
|
||
for case in cases: | ||
shutil.copy(join(base, case, 'ct.nii.gz'), join(imagesTr, case + '_0000.nii.gz')) | ||
shutil.copy(join(base, case, 'combined_labels.nii.gz'), join(labelsTr, case + '.nii.gz')) | ||
|
||
labels = { | ||
"background": 0, | ||
"aorta": 1, | ||
"gall_bladder": 2, | ||
"kidney_left": 3, | ||
"kidney_right": 4, | ||
"liver": 5, | ||
"pancreas": 6, | ||
"postcava": 7, | ||
"spleen": 8, | ||
"stomach": 9 | ||
} | ||
|
||
generate_dataset_json( | ||
join(raw_dir, target_dataset_name), | ||
{0: 'nonCT'}, # this was a mistake we did at the beginning and we keep it like that here for consistency | ||
labels, | ||
len(cases), | ||
'.nii.gz', | ||
None, | ||
target_dataset_name, | ||
overwrite_image_reader_writer='NibabelIOWithReorient' | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
181 changes: 181 additions & 0 deletions
181
nnunetv2/experiment_planning/experiment_planners/resampling/resample_with_torch.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
from typing import Union, List, Tuple | ||
|
||
from nnunetv2.configuration import ANISO_THRESHOLD | ||
from nnunetv2.experiment_planning.experiment_planners.default_experiment_planner import ExperimentPlanner | ||
from nnunetv2.experiment_planning.experiment_planners.residual_unets.residual_encoder_unet_planners import \ | ||
nnUNetPlannerResEncL | ||
from nnunetv2.preprocessing.resampling.resample_torch import resample_torch_fornnunet | ||
|
||
|
||
class nnUNetPlannerResEncL_torchres(nnUNetPlannerResEncL): | ||
def __init__(self, dataset_name_or_id: Union[str, int], | ||
gpu_memory_target_in_gb: float = 24, | ||
preprocessor_name: str = 'DefaultPreprocessor', plans_name: str = 'nnUNetResEncUNetLPlans_torchres', | ||
overwrite_target_spacing: Union[List[float], Tuple[float, ...]] = None, | ||
suppress_transpose: bool = False): | ||
super().__init__(dataset_name_or_id, gpu_memory_target_in_gb, preprocessor_name, plans_name, | ||
overwrite_target_spacing, suppress_transpose) | ||
|
||
def generate_data_identifier(self, configuration_name: str) -> str: | ||
""" | ||
configurations are unique within each plans file but different plans file can have configurations with the | ||
same name. In order to distinguish the associated data we need a data identifier that reflects not just the | ||
config but also the plans it originates from | ||
""" | ||
return self.plans_identifier + '_' + configuration_name | ||
|
||
def determine_resampling(self, *args, **kwargs): | ||
""" | ||
returns what functions to use for resampling data and seg, respectively. Also returns kwargs | ||
resampling function must be callable(data, current_spacing, new_spacing, **kwargs) | ||
determine_resampling is called within get_plans_for_configuration to allow for different functions for each | ||
configuration | ||
""" | ||
resampling_data = resample_torch_fornnunet | ||
resampling_data_kwargs = { | ||
"is_seg": False, | ||
'force_separate_z': False, | ||
'memefficient_seg_resampling': False | ||
} | ||
resampling_seg = resample_torch_fornnunet | ||
resampling_seg_kwargs = { | ||
"is_seg": True, | ||
'force_separate_z': False, | ||
'memefficient_seg_resampling': False | ||
} | ||
return resampling_data, resampling_data_kwargs, resampling_seg, resampling_seg_kwargs | ||
|
||
def determine_segmentation_softmax_export_fn(self, *args, **kwargs): | ||
""" | ||
function must be callable(data, new_shape, current_spacing, new_spacing, **kwargs). The new_shape should be | ||
used as target. current_spacing and new_spacing are merely there in case we want to use it somehow | ||
determine_segmentation_softmax_export_fn is called within get_plans_for_configuration to allow for different | ||
functions for each configuration | ||
""" | ||
resampling_fn = resample_torch_fornnunet | ||
resampling_fn_kwargs = { | ||
"is_seg": False, | ||
'force_separate_z': False, | ||
'memefficient_seg_resampling': False | ||
} | ||
return resampling_fn, resampling_fn_kwargs | ||
|
||
|
||
class nnUNetPlannerResEncL_torchres_sepz(nnUNetPlannerResEncL): | ||
def __init__(self, dataset_name_or_id: Union[str, int], | ||
gpu_memory_target_in_gb: float = 24, | ||
preprocessor_name: str = 'DefaultPreprocessor', plans_name: str = 'nnUNetResEncUNetLPlans_torchres_sepz', | ||
overwrite_target_spacing: Union[List[float], Tuple[float, ...]] = None, | ||
suppress_transpose: bool = False): | ||
super().__init__(dataset_name_or_id, gpu_memory_target_in_gb, preprocessor_name, plans_name, | ||
overwrite_target_spacing, suppress_transpose) | ||
|
||
def generate_data_identifier(self, configuration_name: str) -> str: | ||
""" | ||
configurations are unique within each plans file but different plans file can have configurations with the | ||
same name. In order to distinguish the associated data we need a data identifier that reflects not just the | ||
config but also the plans it originates from | ||
""" | ||
return self.plans_identifier + '_' + configuration_name | ||
|
||
def determine_resampling(self, *args, **kwargs): | ||
""" | ||
returns what functions to use for resampling data and seg, respectively. Also returns kwargs | ||
resampling function must be callable(data, current_spacing, new_spacing, **kwargs) | ||
determine_resampling is called within get_plans_for_configuration to allow for different functions for each | ||
configuration | ||
""" | ||
resampling_data = resample_torch_fornnunet | ||
resampling_data_kwargs = { | ||
"is_seg": False, | ||
'force_separate_z': None, | ||
'memefficient_seg_resampling': False, | ||
'separate_z_anisotropy_threshold': ANISO_THRESHOLD | ||
} | ||
resampling_seg = resample_torch_fornnunet | ||
resampling_seg_kwargs = { | ||
"is_seg": True, | ||
'force_separate_z': None, | ||
'memefficient_seg_resampling': False, | ||
'separate_z_anisotropy_threshold': ANISO_THRESHOLD | ||
} | ||
return resampling_data, resampling_data_kwargs, resampling_seg, resampling_seg_kwargs | ||
|
||
def determine_segmentation_softmax_export_fn(self, *args, **kwargs): | ||
""" | ||
function must be callable(data, new_shape, current_spacing, new_spacing, **kwargs). The new_shape should be | ||
used as target. current_spacing and new_spacing are merely there in case we want to use it somehow | ||
determine_segmentation_softmax_export_fn is called within get_plans_for_configuration to allow for different | ||
functions for each configuration | ||
""" | ||
resampling_fn = resample_torch_fornnunet | ||
resampling_fn_kwargs = { | ||
"is_seg": False, | ||
'force_separate_z': None, | ||
'memefficient_seg_resampling': False, | ||
'separate_z_anisotropy_threshold': ANISO_THRESHOLD | ||
} | ||
return resampling_fn, resampling_fn_kwargs | ||
|
||
|
||
class nnUNetPlanner_torchres(ExperimentPlanner): | ||
def __init__(self, dataset_name_or_id: Union[str, int], | ||
gpu_memory_target_in_gb: float = 8, | ||
preprocessor_name: str = 'DefaultPreprocessor', plans_name: str = 'nnUNetPlans_torchres', | ||
overwrite_target_spacing: Union[List[float], Tuple[float, ...]] = None, | ||
suppress_transpose: bool = False): | ||
super().__init__(dataset_name_or_id, gpu_memory_target_in_gb, preprocessor_name, plans_name, | ||
overwrite_target_spacing, suppress_transpose) | ||
|
||
def generate_data_identifier(self, configuration_name: str) -> str: | ||
""" | ||
configurations are unique within each plans file but different plans file can have configurations with the | ||
same name. In order to distinguish the associated data we need a data identifier that reflects not just the | ||
config but also the plans it originates from | ||
""" | ||
return self.plans_identifier + '_' + configuration_name | ||
|
||
def determine_resampling(self, *args, **kwargs): | ||
""" | ||
returns what functions to use for resampling data and seg, respectively. Also returns kwargs | ||
resampling function must be callable(data, current_spacing, new_spacing, **kwargs) | ||
determine_resampling is called within get_plans_for_configuration to allow for different functions for each | ||
configuration | ||
""" | ||
resampling_data = resample_torch_fornnunet | ||
resampling_data_kwargs = { | ||
"is_seg": False, | ||
'force_separate_z': False, | ||
'memefficient_seg_resampling': False | ||
} | ||
resampling_seg = resample_torch_fornnunet | ||
resampling_seg_kwargs = { | ||
"is_seg": True, | ||
'force_separate_z': False, | ||
'memefficient_seg_resampling': False | ||
} | ||
return resampling_data, resampling_data_kwargs, resampling_seg, resampling_seg_kwargs | ||
|
||
def determine_segmentation_softmax_export_fn(self, *args, **kwargs): | ||
""" | ||
function must be callable(data, new_shape, current_spacing, new_spacing, **kwargs). The new_shape should be | ||
used as target. current_spacing and new_spacing are merely there in case we want to use it somehow | ||
determine_segmentation_softmax_export_fn is called within get_plans_for_configuration to allow for different | ||
functions for each configuration | ||
""" | ||
resampling_fn = resample_torch_fornnunet | ||
resampling_fn_kwargs = { | ||
"is_seg": False, | ||
'force_separate_z': False, | ||
'memefficient_seg_resampling': False | ||
} | ||
return resampling_fn, resampling_fn_kwargs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.