File size: 7,017 Bytes
d014c5a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | """
Use this to run the nnU-Net inference. You can run multiple instances of this code in parallel!
Just change the `part_id` and `gpu` arguments to split the task into multiple parts.
Example of splitting it in 4 parts:
python PredictSubOrgansnUnet.py --num_parts 4 --part_id 0 --gpu 0
python PredictSubOrgansnUnet.py --num_parts 4 --part_id 1 --gpu 1
python PredictSubOrgansnUnet.py --num_parts 4 --part_id 2 --gpu 2
python PredictSubOrgansnUnet.py --num_parts 4 --part_id 3 --gpu 3
"""
import argparse
from nnunetv2.paths import nnUNet_results, nnUNet_raw
import torch
from batchgenerators.utilities.file_and_folder_operations import join
from nnunetv2.inference.predict_from_raw_data import nnUNetPredictor
import os
import pandas as pd
def split_files(files_input, files_output, num_parts, part_id):
"""
Splits the files_input and files_output into num_parts and selects the partition for the given part_id.
Args:
files_input (list): List of input files.
files_output (list): List of output files.
num_parts (int): Number of partitions.
part_id (int): Partition ID to select (starting from 0).
Returns:
tuple: (files_input_partition, files_output_partition) for the given part_id.
"""
assert len(files_input) == len(files_output), "files_input and files_output must have the same length"
assert 0 <= part_id < num_parts, "Invalid part_id. It must be in the range [0, num_parts-1]"
# Split the files based on num_parts
total_files = len(files_input)
files_per_part = (total_files + num_parts - 1) // num_parts # Ensure rounding up
start_idx = part_id * files_per_part
end_idx = min(start_idx + files_per_part, total_files)
# Return the partition
return files_input[start_idx:end_idx], files_output[start_idx:end_idx]
def parse_args():
parser = argparse.ArgumentParser(description="Run nnUNet prediction with custom arguments.")
parser.add_argument('--pth', type=str, default='/projects/bodymaps/Data/image_only/AbdomenAtlasPro/AbdomenAtlasPro/',
help="Path to input images folder")
parser.add_argument('--outdir', type=str, default='/projects/bodymaps/Pedro/data/JHH_liver_segments/',
help="Path to output folder for predictions")
parser.add_argument('--checkpoint', type=str,
default='./nnUNetOrgansAndSubSegments/',
help="Path to model checkpoint folder")
parser.add_argument('--num_parts', type=int, default=1,
help="Number of parts to split the task into")
parser.add_argument('--part_id', type=int, default=0,
help="ID of the current part (0-indexed)")
parser.add_argument('--gpu', type=int, default=0,
help="ID of the gpu to be used")
parser.add_argument('--workers', type=int, default=2,
help="Number of worker processes for preprocessing and segmentation export")
parser.add_argument('--BDMAP_format', action='store_true',
help="Enable BDMAP format")
parser.add_argument('--ids', default=None, help='Path to csv with a BDMAP ID column and the cases you want to inference')
parser.add_argument('--reset', action='store_true',
help="Overwrites old cases")
return parser.parse_args()
def filter_existing_outputs(files_input, files_output):
"""
Filter out cases where the output file already exists.
Parameters:
files_input (list): A list of input file paths (or lists of file paths).
files_output (list): A list of output file paths.
Returns:
tuple: Two lists, (filtered_files_input, filtered_files_output), where
each pair corresponds to an output that does not already exist.
"""
filtered_input = []
filtered_output = []
for inp, out in zip(files_input, files_output):
if not os.path.exists(out+'.nii.gz'):
filtered_input.append(inp)
filtered_output.append(out)
else:
print(f"Skipping already saved output: {out}")
return filtered_input, filtered_output
def main():
args = parse_args()
# Instantiate the nnUNetPredictor
predictor = nnUNetPredictor(
tile_step_size=0.5,
use_gaussian=True,
use_mirroring=True,
perform_everything_on_device=True,
device=torch.device('cuda', args.gpu),
verbose=False,
verbose_preprocessing=False,
allow_tqdm=True
)
if args.ids is not None:
ids = pd.read_csv(args.ids)
ids = sorted(ids['BDMAP ID'].to_list())
else:
ids = sorted(os.listdir(args.pth))
print(f'Number of loaded ids: {len(ids)}')
# Collect input and output files
if args.BDMAP_format:
print('Path:',args.pth)
print('Files in path:',len(ids))
files_input = [[os.path.join(args.pth, folder, 'ct.nii.gz')]
for folder in ids
if ('BDMAP' in folder)]
print('Input files before split:',len(files_input))
files_output = [os.path.join(args.outdir, folder)
for folder in ids
if ('BDMAP' in folder)]
files_input, files_output = filter_existing_outputs(files_input, files_output)
files_input, files_output = split_files(files_input, files_output, args.num_parts, args.part_id)
else:
if args.ids is None:
files_input = [[os.path.join(args.pth, file)] for file in ids if (file.endswith('.nii.gz') and file[0]!='.')]
files_output = [os.path.join(args.outdir, file.replace('.nii.gz','')) for file in ids if (file.endswith('.nii.gz') and file[0]!='.')]
else:
files_input = [[os.path.join(args.pth, file+'.nii.gz')] for file in ids]
files_output = [os.path.join(args.outdir, file) for file in ids]
files_input, files_output = filter_existing_outputs(files_input, files_output)
files_input, files_output = split_files(files_input, files_output, args.num_parts, args.part_id)
print('Input:', files_input[:10])
print('Output:', files_output[:10])
print(f'Cases to predict in part {args.part_id}: {len(files_input)}')
# Initialize the network architecture and load the checkpoint
predictor.initialize_from_trained_model_folder(
join(args.checkpoint),
use_folds=('all',),
checkpoint_name='checkpoint_final.pth',
)
# Run the prediction
predictor.predict_from_files(
files_input, files_output,
save_probabilities=False,
overwrite=args.reset,
num_processes_preprocessing=args.workers,
num_processes_segmentation_export=args.workers,
folder_with_segs_from_prev_stage=None,
num_parts=1,
part_id=0
)
if __name__ == '__main__':
main() |