From 8cfb8601aa5098e71602047d4d8dfa72652a6250 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 6 May 2022 14:42:14 -0400 Subject: [PATCH 01/23] separate preprocessing routine (NOEL-MNI/deepMask@2b4063f) - refactor to a bash script that calls `preprocess.py` - resolve `tensorflow` version issues b/w `deepFCD` and `ANTsPyNet` --- app/inference.py | 41 ++++++++--------------------- app/preprocess.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ app/preprocess.sh | 42 ++++++++++++++++++++++++++++++ app/requirements.txt | 4 +-- app/utils/helpers.py | 3 +++ 5 files changed, 118 insertions(+), 33 deletions(-) create mode 100755 app/preprocess.py create mode 100755 app/preprocess.sh create mode 100644 app/utils/helpers.py diff --git a/app/inference.py b/app/inference.py index 2fc8aa9..0575643 100755 --- a/app/inference.py +++ b/app/inference.py @@ -3,6 +3,8 @@ import os import sys import multiprocessing +from mo_dots import Data +import subprocess from config.experiment import options import warnings warnings.filterwarnings('ignore') @@ -10,6 +12,7 @@ import numpy as np import setproctitle as spt from tqdm import tqdm +from utils.helpers import * os.environ["KERAS_BACKEND"] = "theano" @@ -37,50 +40,28 @@ from utils.metrics import * from utils.base import * -# deepMask imports -import torch -from mo_dots import Data -from deepMask.app.utils.data import * -from deepMask.app.utils.deepmask import * -from deepMask.app.utils.image_processing import noelImageProcessor -import deepMask.app.vnet as vnet # configuration args = Data() -args.dir = sys.argv[4] args.id = sys.argv[1] -args.brain_masking = True # set to True or any non-zero value for brain extraction or skull-removal, False otherwise -args.preprocess = True # co-register T1 and T2 contrasts before brain extraction -args.outdir = os.path.join(args.dir, args.id) -args.seed = 666 args.t1_fname = sys.argv[2] args.t2_fname = sys.argv[3] +args.dir = sys.argv[4] +args.brain_masking = True # set to True or any non-zero value for brain extraction or skull-removal, False otherwise +args.preprocess = False # co-register T1 and T2 contrasts before brain extraction +args.outdir = os.path.join(args.dir, args.id) + args.t1 = os.path.join(args.outdir, args.t1_fname) args.t2 = os.path.join(args.outdir, args.t2_fname) cwd = os.path.dirname(__file__) if args.brain_masking: - # trained weights based on manually corrected masks from - # 153 patients with cortical malformations - args.inference = os.path.join(cwd, 'deepMask/app/weights', 'vnet_masker_model_best.pth.tar') - # resize all input images to this resolution matching training data - args.resize = (160,160,160) args.use_gpu = False - args.cuda = torch.cuda.is_available() and args.use_gpu - torch.manual_seed(args.seed) - args.device_ids = list(range(torch.cuda.device_count())) - if args.cuda: - torch.cuda.manual_seed(args.seed) - print("build vnet, using GPU") - else: - print("build vnet, using CPU") - model = vnet.build_model(args) - template = os.path.join(cwd, 'deepMask/app/template', 'mni_icbm152_t1_tal_nlin_sym_09a.nii.gz') - # MRI pre-processing configuration args.output_suffix = '_brain_final.nii.gz' - - noelImageProcessor(id=args.id, t1=args.t1, t2=args.t2, output_suffix=args.output_suffix, output_dir=args.outdir, template=template, usen3=True, args=args, model=model, preprocess=args.preprocess).pipeline() + + preprocess_sh = os.path.join(cwd, 'preprocess.sh') + subprocess.check_call([preprocess_sh, args.id, args.t1_fname, args.t2_fname, args.dir, bool2str(args.preprocess), bool2str(args.use_gpu)]) args.t1 = os.path.join(args.outdir, args.id + '_t1' + args.output_suffix) args.t2 = os.path.join(args.outdir, args.id + '_t2' + args.output_suffix) diff --git a/app/preprocess.py b/app/preprocess.py new file mode 100755 index 0000000..63936af --- /dev/null +++ b/app/preprocess.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +import os +from mo_dots import to_data +import psutil +import torch +from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter +from deepMask.app.utils.data import * +from deepMask.app.utils.deepmask import * +from deepMask.app.utils.image_processing import noelImageProcessor +import deepMask.app.vnet as vnet + +# configuration +# parse command line arguments +parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) +parser.add_argument("-i", "--id", dest='id', default="FCD_123", help="Alphanumeric patient code") +parser.add_argument("-t1", "--t1_fname", dest='t1_fname', default="t1.nii.gz", help="T1-weighted image") +parser.add_argument("-t2", "--t2_fname", dest='t2_fname', default="t2.nii.gz", help="T2-weighted image") +parser.add_argument("-d", "--dir", dest='dir', default="data/", help="Directory containing the input images") + +parser.add_argument("-p", "--preprocess", dest='preprocess', action='store_true', help="Co-register and perform non-uniformity correction of input images") +parser.add_argument("-g", "--use_gpu", dest='use_gpu', action='store_true', help="Compute using GPU, defaults to using CPU") +args = to_data(vars(parser.parse_args())) + +# set up parameters +args.outdir = os.path.join(args.dir, args.id) +args.t1 = os.path.join(args.outdir, args.t1_fname) +args.t2 = os.path.join(args.outdir, args.t2_fname) +args.seed = 666 + +cwd = os.path.dirname(__file__) + +# trained weights based on manually corrected masks from +# 153 patients with cortical malformations +args.inference = os.path.join(cwd, 'deepMask/app/weights', 'vnet_masker_model_best.pth.tar') +# resize all input images to this resolution matching training data +args.resize = (160,160,160) +args.cuda = torch.cuda.is_available() and args.use_gpu +torch.manual_seed(args.seed) +args.device_ids = list(range(torch.cuda.device_count())) + +mem_size = psutil.virtual_memory().available // (1024*1024*1024) # available RAM in GB +mem_size = 32 +if mem_size < 64 and not args.use_gpu: + os.environ["BRAIN_MASKING"] = "cpu" + os.environ["CUDA_VISIBLE_DEVICES"] = "-1" + model = None +else: + if args.cuda: + torch.cuda.manual_seed(args.seed) + print("build vnet, using GPU") + else: + print("build vnet, using CPU") + model = vnet.build_model(args) + +template = os.path.join(cwd, 'deepMask/app/template', 'mni_icbm152_t1_tal_nlin_sym_09a.nii.gz') + +# MRI pre-processing configuration +args.output_suffix = '_brain_final.nii.gz' + +noelImageProcessor(id=args.id, t1=args.t1, t2=args.t2, output_suffix=args.output_suffix, output_dir=args.outdir, template=template, usen3=True, args=args, model=model, preprocess=args.preprocess).pipeline() \ No newline at end of file diff --git a/app/preprocess.sh b/app/preprocess.sh new file mode 100755 index 0000000..50427a3 --- /dev/null +++ b/app/preprocess.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# preprocess.sh ${ID} ${T1_FNAME} ${T2_FNAME} ${BASEDIR} ${PREPROCESSING} ${USE_GPU} + + +echo "*************************************************************************" +echo "run stage:$0 $*" +echo "on: `hostname`" +echo "at: `date`" +echo "*************************************************************************" +echo "" +echo "" + + +ID=$1 # args.id = sys.argv[1] +T1_FNAME=$2 # args.t1_fname = sys.argv[2] +T2_FNAME=$3 # args.t2_fname = sys.argv[3] +BASEDIR=$4 # args.dir = sys.argv[4] +PREPROCESSING=$5 # args.preprocess = True # co-register T1 and T2 contrasts before brain extraction +USE_GPU=$6 # args.use_gpu = sys.argv[6] + +BRAIN_MASKING=cpu + +OUTDIR=${BASEDIR}/${ID}/ # args.outdir = os.path.join(args.dir, args.id) +T1=${OUTDIR}/${T1_FNAME} # args.t1 = os.path.join(args.outdir, args.t1_fname) +T2=${OUTDIR}/${T2_FNAME} # args.t2 = os.path.join(args.outdir, args.t2_fname) + +eval "$(conda shell.bash hook)" +conda activate preprocess +# echo $CONDA_PREFIX + +if [ ${PREPROCESSING} -eq 1 ] && [ ${USE_GPU} -eq 0 ]; then + ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --preprocess +elif [ ${PREPROCESSING} -eq 0 ] && [ ${USE_GPU} -eq 1 ]; then + ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --use_gpu +elif [ ${PREPROCESSING} -eq 1 ] && [ ${USE_GPU} -eq 1 ]; then + ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --preprocess --use_gpu +else + ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} +fi + +conda deactivate \ No newline at end of file diff --git a/app/requirements.txt b/app/requirements.txt index d0607f3..e71b798 100644 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -1,8 +1,5 @@ Theano==1.0.4 keras==2.2.4 -torch==1.4.0+cpu -torchvision==0.5.0+cpu -antspyx==0.3.2 h5py==2.10.0 matplotlib==3.5.1 mo-dots==9.147.22086 @@ -10,6 +7,7 @@ nibabel==3.2.2 nilearn==0.9.1 numpy==1.21.6 pandas==1.3.5 +psutil==5.9.0 scikit-image==0.19.2 scikit-learn==1.0.2 scipy==1.7.3 diff --git a/app/utils/helpers.py b/app/utils/helpers.py new file mode 100644 index 0000000..4ab3868 --- /dev/null +++ b/app/utils/helpers.py @@ -0,0 +1,3 @@ +def bool2str(v): + bn = 1 if str(v).lower() in ["yes", "true", "t", "1"] else 0 + return str(bn) \ No newline at end of file From fd70e5a0c401ab948c67b992b93ba0268790a893 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 6 May 2022 14:56:29 -0400 Subject: [PATCH 02/23] expose additional arguments to customize analysis --- app/inference.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/inference.py b/app/inference.py index 0575643..c49e962 100755 --- a/app/inference.py +++ b/app/inference.py @@ -47,8 +47,8 @@ args.t1_fname = sys.argv[2] args.t2_fname = sys.argv[3] args.dir = sys.argv[4] -args.brain_masking = True # set to True or any non-zero value for brain extraction or skull-removal, False otherwise -args.preprocess = False # co-register T1 and T2 contrasts before brain extraction +args.brain_masking = sys.argv[6] # set to True or any non-zero value for brain extraction or skull-removal, False otherwise +args.preprocess = sys.argv[7] # co-register T1 and T2 images to MNI152 space and N3 correction before brain extraction (True/False) args.outdir = os.path.join(args.dir, args.id) args.t1 = os.path.join(args.outdir, args.t1_fname) From d9f31ceddf8d2130ba08a178f0224f5c399c4214 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 6 May 2022 15:18:25 -0400 Subject: [PATCH 03/23] fix mismatched origin in output images - rely on the header alone to preserve `qform`/`sform` codes --- app/utils/base.py | 22 +++++++++++----------- app/utils/bayes_uncertainty_utils.py | 8 ++++---- app/utils/post_processor.py | 6 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/utils/base.py b/app/utils/base.py index fe84ed8..d398aa6 100644 --- a/app/utils/base.py +++ b/app/utils/base.py @@ -236,18 +236,18 @@ def test_model(model, test_x_data, options, performance=False, uncertainty=True) options['test_mean_name'] = scan + options['experiment'] + '_prob_mean_0.nii.gz' options['test_var_name'] = scan + options['experiment'] + '_prob_var_0.nii.gz' - t1, _, _ = test_scan(model[0], test_x_data, options, save_nifti=True, uncertainty=uncertainty, T=20) + t1, header = test_scan(model[0], test_x_data, options, save_nifti=True, uncertainty=uncertainty, T=20) # second network options['test_name'] = scan + options['experiment'] + '_prob_1.nii.gz' options['test_mean_name'] = scan + options['experiment'] + '_prob_mean_1.nii.gz' options['test_var_name'] = scan + options['experiment'] + '_prob_var_1.nii.gz' - t2, _, _ = test_scan(model[1], test_x_data, options, save_nifti=True, uncertainty=uncertainty, T=50, candidate_mask=t1>threshold) + t2, header = test_scan(model[1], test_x_data, options, save_nifti=True, uncertainty=uncertainty, T=50, candidate_mask=t1>threshold) if performance: # postprocess the output segmentation options['test_name'] = options['experiment'] + '_out_CNN.nii.gz' - out_segmentation, lpred, count = post_processing(t2, options, affine, header, save_nifti=True) + out_segmentation, lpred, count = post_processing(t2, options, header, save_nifti=True) outputs = [t1, t2, out_segmentation, lpred, count] else: outputs = [t1, t2] @@ -267,13 +267,13 @@ def test_scan(model, test_x_data, options, transit=None, save_nifti=False, uncer - test_scan = Output image containing the probability output segmentation - If save_nifti --> Saves a nii file at specified location options['test_folder']/['test_scan'] """ - batch_size = options['mini_batch_size'] + batch_size = options['mini_batch_size'] # get_scan name and create an empty nii image to store segmentation scans = test_x_data.keys() flair_scans = [test_x_data[s]['FLAIR'] for s in scans] flair_image = load_nii(flair_scans[0]).get_data() header = load_nii(flair_scans[0]).header - affine = header.get_qform() + # affine = header.get_qform() seg_image = np.zeros_like(flair_image) var_image = np.zeros_like(flair_image) @@ -297,33 +297,33 @@ def test_scan(model, test_x_data, options, transit=None, save_nifti=False, uncer if save_nifti: # out_scan = nib.Nifti1Image(seg_image, np.eye(4)) - out_scan = nib.Nifti1Image(seg_image, affine, header) + out_scan = nib.Nifti1Image(seg_image, header=header) out_scan.to_filename(os.path.join(options['pred_folder'], options['test_mean_name'])) if uncertainty: - out_scan = nib.Nifti1Image(var_image, affine, header) + out_scan = nib.Nifti1Image(var_image, header=header) out_scan.to_filename(os.path.join(options['pred_folder'], options['test_var_name'])) if transit is not None: if not os.path.exists(test_folder): os.mkdir(test_folder) - out_scan = nib.Nifti1Image(seg_image, affine, header) + out_scan = nib.Nifti1Image(seg_image, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_mean_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) if uncertainty: - out_scan = nib.Nifti1Image(var_image, affine, header) + out_scan = nib.Nifti1Image(var_image, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_var_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) if not os.path.exists(os.path.join(test_folder, options['experiment'])): os.mkdir(os.path.join(test_folder, options['experiment'])) - out_scan = nib.Nifti1Image(seg_image, affine, header) + out_scan = nib.Nifti1Image(seg_image, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) - return seg_image, affine, header + return seg_image, header def copy_most_recent_model(path, net_model): diff --git a/app/utils/bayes_uncertainty_utils.py b/app/utils/bayes_uncertainty_utils.py index 37e8981..8c67678 100644 --- a/app/utils/bayes_uncertainty_utils.py +++ b/app/utils/bayes_uncertainty_utils.py @@ -46,7 +46,7 @@ def test_scan_uncertainty(model, test_x_data, scan, options, intermediate=None, flair_scans = [test_x_data[s]['FLAIR'] for s in scans] flair_image = load_nii(flair_scans[0]).get_data() header = load_nii(flair_scans[0]).header - affine = header.get_qform() + # affine = header.get_qform() seg_image = np.zeros_like(flair_image) var_image = np.zeros_like(flair_image) thresh_image = np.zeros_like(flair_image) @@ -75,11 +75,11 @@ def test_scan_uncertainty(model, test_x_data, scan, options, intermediate=None, if not os.path.exists(test_folder): os.mkdir(test_folder) # out_scan = nib.Nifti1Image(seg_image, np.eye(4)) - out_scan = nib.Nifti1Image(seg_image, affine, header) + out_scan = nib.Nifti1Image(seg_image, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_mean_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) - out_scan = nib.Nifti1Image(var_image, affine, header) + out_scan = nib.Nifti1Image(var_image, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_var_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) @@ -87,7 +87,7 @@ def test_scan_uncertainty(model, test_x_data, scan, options, intermediate=None, if not os.path.exists(os.path.join(test_folder, options['experiment'])): os.mkdir(os.path.join(test_folder, options['experiment'])) - out_scan = nib.Nifti1Image(seg_image, affine, header) + out_scan = nib.Nifti1Image(seg_image, header=header) #out_scan.to_filename(os.path.join(options['test_folder'], options['test_scan'], options['experiment'], options['test_name'])) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) diff --git a/app/utils/post_processor.py b/app/utils/post_processor.py index 0df5f39..59cef67 100644 --- a/app/utils/post_processor.py +++ b/app/utils/post_processor.py @@ -7,7 +7,7 @@ import nibabel as nib -def post_processing(input_scan, options, affine, header, save_nifti=True): +def post_processing(input_scan, options, header, save_nifti=True): """ post-process the probabilistic segmentation using parameters t_bin and l_min t_bin: threshold to binarize the output segmentations @@ -57,9 +57,9 @@ def post_processing(input_scan, options, affine, header, save_nifti=True): #save the output segmentation as nifti if save_nifti: - nii_out = nib.Nifti1Image(output_scan, affine, header) + nii_out = nib.Nifti1Image(output_scan, header=header) nii_out.to_filename(os.path.join(options['pred_folder'], options['test_name'])) - labels_out = nib.Nifti1Image(labels_scan, affine, header) + labels_out = nib.Nifti1Image(labels_scan, header=header) labels_out.to_filename(os.path.join(options['pred_folder'], options['test_morph_name'])) return output_scan, pred_labels, count From ea39fb5bf274837b440be5a19867bdaaaa55c9f9 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 6 May 2022 15:34:33 -0400 Subject: [PATCH 04/23] bump `deepMask` to latest commit/version --- app/deepMask | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/deepMask b/app/deepMask index f4843ef..2b4063f 160000 --- a/app/deepMask +++ b/app/deepMask @@ -1 +1 @@ -Subproject commit f4843efda0c8bd9690a377b7b48530d604edcc5b +Subproject commit 2b4063fe9f549759a0f3591ebb7ea6af1d385d4d From 519a69f69c5e1d27ad8907dbce6d0ddcc1fa906d Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 10:31:53 -0400 Subject: [PATCH 05/23] add `nvidia-container-toolkit` dependency for gpu --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f8f292..326e034 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ chmod +x ./app/inference.py # make the script executable -ensure you have the re ${IO_DIRECTORY} \ # input/output directory cuda0 # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) ``` -### 3.2 Inference using Docker (GPU) +### 3.2 Inference using Docker (GPU), requires [nvidia-container-toolkit](https://github.com/NVIDIA/nvidia-container-toolkit) ```bash docker run --rm -it --init \ --gpus=all \ # expose the host GPUs to the guest docker container From 4c57f81c85dc2e4d639483de119c353fb2040dfb Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 10:38:37 -0400 Subject: [PATCH 06/23] comment out debug variable --- app/preprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/preprocess.py b/app/preprocess.py index 63936af..a9c859f 100755 --- a/app/preprocess.py +++ b/app/preprocess.py @@ -40,7 +40,7 @@ args.device_ids = list(range(torch.cuda.device_count())) mem_size = psutil.virtual_memory().available // (1024*1024*1024) # available RAM in GB -mem_size = 32 +# mem_size = 32 if mem_size < 64 and not args.use_gpu: os.environ["BRAIN_MASKING"] = "cpu" os.environ["CUDA_VISIBLE_DEVICES"] = "-1" From 8a0aaddf9cc971e203cb516d59f24278bad5dc84 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 10:40:31 -0400 Subject: [PATCH 07/23] add separate preprocessing environment --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 326e034..8d1a62d 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,20 @@ cd deepFCD wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh bash ~/miniconda.sh -b -p $HOME/miniconda -# create and activate a Conda environment +# create and activate a Conda environment for preprocessing +conda create -n preprocess python=3.7 +conda activate preprocess +# install dependencies using pip +python -m pip install -r app/deepMask/app/requirements.txt +conda deactivate + +# create and activate a Conda environment for deepFCD conda create -n deepFCD python=3.7 conda activate deepFCD - # install dependencies using pip -python -m pip install -r app/requirements.txt --find-links https://download.pytorch.org/whl/torch_stable.html +python -m pip install -r app/requirements.txt conda install -c conda-forge pygpu=0.7.6 + ``` From 0cc62cbdf2fcfa690ffe8712be17ca6a4c2afa9b Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 10:42:22 -0400 Subject: [PATCH 08/23] remove `--depth 1` - possible conflict with submodules --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d1a62d..3e0dbf4 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ ```bash # clone the repo with the deepMask submodule -git clone --depth 1 --recurse-submodules -j2 https://github.com/NOEL-MNI/deepFCD.git +git clone --recurse-submodules -j2 https://github.com/NOEL-MNI/deepFCD.git cd deepFCD # install Miniconda3 From 52e37b9f4995af98512d6574aa6216caa931fc39 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 10:44:20 -0400 Subject: [PATCH 09/23] update prerequisites --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e0dbf4..97ebd84 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,11 @@ 2. Keras == 2.2.4 3. Theano == 1.0.4 4. ANTsPy == 0.3.2 (for MRI preprocessing) -5. PyTorch == 1.4.0 (for deepMask) +4. ANTsPyNet == 0.1.8 (for MRI preprocessing) +5. PyTorch == 1.11.0 (for deepMask) 6. h5py == 2.10.0 + app/requirements.txt ++ app/deepMask/app/requirements.txt ``` ## Installation From be1774b91ba1dca303ce940f2bdde223c62bf006 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 10:59:44 -0400 Subject: [PATCH 10/23] replace github page with install guide url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97ebd84..a204417 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ chmod +x ./app/inference.py # make the script executable -ensure you have the re ${IO_DIRECTORY} \ # input/output directory cuda0 # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) ``` -### 3.2 Inference using Docker (GPU), requires [nvidia-container-toolkit](https://github.com/NVIDIA/nvidia-container-toolkit) +### 3.2 Inference using Docker (GPU), requires [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) ```bash docker run --rm -it --init \ --gpus=all \ # expose the host GPUs to the guest docker container From 5a291f86d0577a2ae0519f247dfe741c89e7505f Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 11:51:06 -0400 Subject: [PATCH 11/23] add missing arguments --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a204417..de90d06 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,10 @@ chmod +x ./app/inference.py # make the script executable -ensure you have the re ${T1_IMAGE} \ # T1-weighted image; for example: FCD_001_t1.nii.gz or t1.nii.gz [T1 is specified before FLAIR - order is important] ${FLAIR_IMAGE} \ # T2-weighted FLAIR image; for example: FCD_001_t2.nii.gz or flair.nii.gz [T1 is specified before FLAIR - order is important] ${IO_DIRECTORY} \ # input/output directory - cuda0 # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) + cuda0 \ # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) + 1 \ # perform (`1`) or not perform (`0`) brain extraction + 1 \ # perform (`1`) or not perform (`0`) image pre-processing + ``` ### 3.2 Inference using Docker (GPU), requires [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) ```bash @@ -116,7 +119,9 @@ docker run --rm -it --init \ ${T1_IMAGE} \ # T1-weighted image; for example: FCD_001_t1.nii.gz or t1.nii.gz [T1 is specified before FLAIR - order is important] ${FLAIR_IMAGE} \ # T2-weighted FLAIR image; for example: FCD_001_t2.nii.gz or flair.nii.gz [T1 is specified before FLAIR - order is important] /io \ # input/output directory within the container mapped to ${IO_DIRECTORY} or ${PWD} [ DO NOT MODIFY] - cuda0 # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) + cuda0 \ # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) + 1 \ # perform (`1`) or not perform (`0`) brain extraction + 1 \ # perform (`1`) or not perform (`0`) image pre-processing ``` ### 3.3 Inference using Docker (CPU) @@ -130,7 +135,9 @@ docker run --rm -it --init \ ${T1_IMAGE} \ # T1-weighted image; for example: FCD_001_t1.nii.gz or t1.nii.gz [T1 is specified before FLAIR - order is important] ${FLAIR_IMAGE} \ # T2-weighted FLAIR image; for example: FCD_001_t2.nii.gz or flair.nii.gz [T1 is specified before FLAIR - order is important] /io \ # input/output directory within the container mapped to ${IO_DIRECTORY} or ${PWD} [ DO NOT MODIFY] - cpu # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) + cpu \ # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) + 1 \ # perform (`1`) or not perform (`0`) brain extraction + 1 \ # perform (`1`) or not perform (`0`) image pre-processing ``` ## License From 1000661efa09c3bddfc35399fabf3a7fb689b0f3 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 12:33:17 -0400 Subject: [PATCH 12/23] update dependencies --- app/deepMask | 2 +- app/requirements.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/deepMask b/app/deepMask index 2b4063f..bdb0283 160000 --- a/app/deepMask +++ b/app/deepMask @@ -1 +1 @@ -Subproject commit 2b4063fe9f549759a0f3591ebb7ea6af1d385d4d +Subproject commit bdb0283e0361d17998c56d5984c1bfaacccc0da2 diff --git a/app/requirements.txt b/app/requirements.txt index e71b798..a1f5b2f 100644 --- a/app/requirements.txt +++ b/app/requirements.txt @@ -7,7 +7,6 @@ nibabel==3.2.2 nilearn==0.9.1 numpy==1.21.6 pandas==1.3.5 -psutil==5.9.0 scikit-image==0.19.2 scikit-learn==1.0.2 scipy==1.7.3 From 06f155fab6a98fdf1e2b3cd5bbdd2b4d548cc8c0 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 12:56:35 -0400 Subject: [PATCH 13/23] update `deepMask` --- app/deepMask | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/deepMask b/app/deepMask index bdb0283..ff8dae7 160000 --- a/app/deepMask +++ b/app/deepMask @@ -1 +1 @@ -Subproject commit bdb0283e0361d17998c56d5984c1bfaacccc0da2 +Subproject commit ff8dae7d64620380dde3c7cf448e6c6cd3be3def From d13c9030ff9525ddeb85d1e66a15d528273c7e38 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Fri, 13 May 2022 13:10:28 -0400 Subject: [PATCH 14/23] use absolute paths --- app/preprocess.py | 2 -- app/preprocess.sh | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/preprocess.py b/app/preprocess.py index a9c859f..b6e588d 100755 --- a/app/preprocess.py +++ b/app/preprocess.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 - import os from mo_dots import to_data import psutil diff --git a/app/preprocess.sh b/app/preprocess.sh index 50427a3..9bb689c 100755 --- a/app/preprocess.sh +++ b/app/preprocess.sh @@ -30,13 +30,13 @@ conda activate preprocess # echo $CONDA_PREFIX if [ ${PREPROCESSING} -eq 1 ] && [ ${USE_GPU} -eq 0 ]; then - ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --preprocess + python3 $PWD/preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --preprocess elif [ ${PREPROCESSING} -eq 0 ] && [ ${USE_GPU} -eq 1 ]; then - ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --use_gpu + python3 $PWD/preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --use_gpu elif [ ${PREPROCESSING} -eq 1 ] && [ ${USE_GPU} -eq 1 ]; then - ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --preprocess --use_gpu + python3 $PWD/preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} --preprocess --use_gpu else - ./preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} + python3 $PWD/preprocess.py -i ${ID} -t1 ${T1_FNAME} -t2 ${T2_FNAME} -d ${BASEDIR} fi conda deactivate \ No newline at end of file From 54ee9275681d09a1bebd052b21eeb883638a8aff Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sat, 14 May 2022 17:55:13 -0400 Subject: [PATCH 15/23] fix absolute paths for `preprocess.py` --- app/preprocess.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/preprocess.sh b/app/preprocess.sh index 9bb689c..1a9ba5c 100755 --- a/app/preprocess.sh +++ b/app/preprocess.sh @@ -25,6 +25,8 @@ OUTDIR=${BASEDIR}/${ID}/ # args.outdir = os.path.join(args.dir, args.id) T1=${OUTDIR}/${T1_FNAME} # args.t1 = os.path.join(args.outdir, args.t1_fname) T2=${OUTDIR}/${T2_FNAME} # args.t2 = os.path.join(args.outdir, args.t2_fname) +PWD=$(dirname "$0") + eval "$(conda shell.bash hook)" conda activate preprocess # echo $CONDA_PREFIX From 21c59aaa9618d9e0605a3ada2eb3d7149da37234 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sat, 14 May 2022 17:58:25 -0400 Subject: [PATCH 16/23] use relative paths (fixes gh-7) - instead of absolute paths --- app/inference.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/inference.py b/app/inference.py index c49e962..5affc0d 100755 --- a/app/inference.py +++ b/app/inference.py @@ -47,13 +47,16 @@ args.t1_fname = sys.argv[2] args.t2_fname = sys.argv[3] args.dir = sys.argv[4] +if not os.path.isabs(args.dir): + args.dir = os.path.abspath(args.dir) args.brain_masking = sys.argv[6] # set to True or any non-zero value for brain extraction or skull-removal, False otherwise args.preprocess = sys.argv[7] # co-register T1 and T2 images to MNI152 space and N3 correction before brain extraction (True/False) args.outdir = os.path.join(args.dir, args.id) args.t1 = os.path.join(args.outdir, args.t1_fname) args.t2 = os.path.join(args.outdir, args.t2_fname) -cwd = os.path.dirname(__file__) +cwd = os.path.realpath(os.path.dirname(__file__)) +print(cwd) if args.brain_masking: args.use_gpu = False From db6f06ad0317dc1eded7774067bc36633e82a722 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sat, 14 May 2022 18:13:46 -0400 Subject: [PATCH 17/23] remove unused variables --- app/preprocess.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/preprocess.sh b/app/preprocess.sh index 1a9ba5c..f722e34 100755 --- a/app/preprocess.sh +++ b/app/preprocess.sh @@ -22,8 +22,6 @@ USE_GPU=$6 # args.use_gpu = sys.argv[6] BRAIN_MASKING=cpu OUTDIR=${BASEDIR}/${ID}/ # args.outdir = os.path.join(args.dir, args.id) -T1=${OUTDIR}/${T1_FNAME} # args.t1 = os.path.join(args.outdir, args.t1_fname) -T2=${OUTDIR}/${T2_FNAME} # args.t2 = os.path.join(args.outdir, args.t2_fname) PWD=$(dirname "$0") From e2fb1cbe53a0bef3cc70068c181a5ca88957daf4 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sun, 15 May 2022 10:26:51 -0400 Subject: [PATCH 18/23] use either cpu or gpu for preprocessing & `deepFCD` --- app/inference.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/inference.py b/app/inference.py index 5affc0d..486417b 100755 --- a/app/inference.py +++ b/app/inference.py @@ -59,7 +59,10 @@ print(cwd) if args.brain_masking: - args.use_gpu = False + if options['cuda'].startswith('cuda'): + args.use_gpu = True + else: + args.use_gpu = False # MRI pre-processing configuration args.output_suffix = '_brain_final.nii.gz' From 9333cca2c696a2cb1cd27513eb8ed5a95bf341cc Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sun, 15 May 2022 10:47:32 -0400 Subject: [PATCH 19/23] fix variable data types --- app/inference.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/inference.py b/app/inference.py index 486417b..c03b287 100755 --- a/app/inference.py +++ b/app/inference.py @@ -49,16 +49,16 @@ args.dir = sys.argv[4] if not os.path.isabs(args.dir): args.dir = os.path.abspath(args.dir) -args.brain_masking = sys.argv[6] # set to True or any non-zero value for brain extraction or skull-removal, False otherwise -args.preprocess = sys.argv[7] # co-register T1 and T2 images to MNI152 space and N3 correction before brain extraction (True/False) + +args.brain_masking = int(sys.argv[6]) # set to True or any non-zero value for brain extraction or skull-removal, False otherwise +args.preprocess = int(sys.argv[7]) # co-register T1 and T2 images to MNI152 space and N3 correction before brain extraction (True/False) args.outdir = os.path.join(args.dir, args.id) args.t1 = os.path.join(args.outdir, args.t1_fname) args.t2 = os.path.join(args.outdir, args.t2_fname) cwd = os.path.realpath(os.path.dirname(__file__)) -print(cwd) -if args.brain_masking: +if bool(args.brain_masking): if options['cuda'].startswith('cuda'): args.use_gpu = True else: From 50ddc421cdbf1bf728fd5de2ce9ec8fdded81611 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sun, 15 May 2022 13:12:22 -0400 Subject: [PATCH 20/23] manually specify `OMP_NUM_THREADS` - applicable for cpu only - via an env variable --- README.md | 25 +++++++++++++++++++++---- app/inference.py | 4 ++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index de90d06..77ccec0 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,24 @@ ${IO_DIRECTORY} ### 2. Training routine [TODO] -### 3.1 Inference +### 3.1 Inference (CPU) ```bash -chmod +x ./app/inference.py # make the script executable -ensure you have the requisite permissions +chmod +x ./app/inference.py # make the script executable -ensure you have the requisite permissions +export OMP_NUM_THREADS=6 \ # specify number of threads to initialize when using the CPU - by default this variable is set to half the number of available logical cores +./app/inference.py \ # the script to perform inference on the multimodal MRI images + ${PATIENT_ID} \ # prefix for the filenames; for example: FCD_001 (needed for outputs only) + ${T1_IMAGE} \ # T1-weighted image; for example: FCD_001_t1.nii.gz or t1.nii.gz [T1 is specified before FLAIR - order is important] + ${FLAIR_IMAGE} \ # T2-weighted FLAIR image; for example: FCD_001_t2.nii.gz or flair.nii.gz [T1 is specified before FLAIR - order is important] + ${IO_DIRECTORY} \ # input/output directory + cpu \ # toggle b/w CPU/GPU - string specifies CPU ('cpu') or GPU ID ('cudaX', where N is in the range (0,N), where N is the total number of installed GPUs) + 1 \ # perform (`1`) or not perform (`0`) brain extraction + 1 \ # perform (`1`) or not perform (`0`) image pre-processing + +``` + +### 3.2 Inference (GPU) +```bash +chmod +x ./app/inference.py # make the script executable -ensure you have the requisite permissions ./app/inference.py \ # the script to perform inference on the multimodal MRI images ${PATIENT_ID} \ # prefix for the filenames; for example: FCD_001 (needed for outputs only) ${T1_IMAGE} \ # T1-weighted image; for example: FCD_001_t1.nii.gz or t1.nii.gz [T1 is specified before FLAIR - order is important] @@ -107,7 +122,8 @@ chmod +x ./app/inference.py # make the script executable -ensure you have the re 1 \ # perform (`1`) or not perform (`0`) image pre-processing ``` -### 3.2 Inference using Docker (GPU), requires [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) + +### 3.3 Inference using Docker (GPU), requires [nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) ```bash docker run --rm -it --init \ --gpus=all \ # expose the host GPUs to the guest docker container @@ -124,11 +140,12 @@ docker run --rm -it --init \ 1 \ # perform (`1`) or not perform (`0`) image pre-processing ``` -### 3.3 Inference using Docker (CPU) +### 3.4 Inference using Docker (CPU) ```bash docker run --rm -it --init \ --user="$(id -u):$(id -g)" \ # map user permissions appropriately --volume="$PWD:/io" \ # $PWD refers to the present working directory containing the input images, can be modified to a local host directory + --env OMP_NUM_THREADS=6 \ # specify number of threads to initialize - by default this variable is set to half the number of available logical cores noelmni/deep-fcd:latest \ # docker image containing all the necessary software dependencies /app/inference.py \ # the script to perform inference on the multimodal MRI images ${PATIENT_ID} \ # prefix for the filenames; for example: FCD_001 (needed for outputs only) diff --git a/app/inference.py b/app/inference.py index c03b287..269bc62 100755 --- a/app/inference.py +++ b/app/inference.py @@ -21,8 +21,8 @@ if options['cuda'].startswith('cuda1'): os.environ["THEANO_FLAGS"] = "mode=FAST_RUN,device=cuda1,floatX=float32,dnn.enabled=False" elif options['cuda'].startswith('cpu'): - os.environ['OMP_NUM_THREADS'] = str(multiprocessing.cpu_count() // 2) - var = os.getenv('OMP_NUM_THREADS', None) + cores = str(multiprocessing.cpu_count() // 2) + var = os.getenv('OMP_NUM_THREADS', cores) try: print("# of threads initialized: {}".format(int(var))) except ValueError: From b5b5bfdcd6cb0383d8e709f507844a5c2f16a1a4 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sun, 15 May 2022 13:13:24 -0400 Subject: [PATCH 21/23] update `Dockerfile` --- Dockerfile | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8114154..9b74237 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,20 +39,21 @@ RUN wget --quiet https://repo.anaconda.com/miniconda/Miniconda3-py37_4.11.0-Linu && /bin/bash Miniconda3-py37_4.11.0-Linux-x86_64.sh -b -p /home/user/conda \ && rm -f Miniconda3-py37_4.11.0-Linux-x86_64.sh -RUN python -m pip install --upgrade --force --ignore-installed pip +RUN git clone --depth 1 https://github.com/NOEL-MNI/deepMask.git \ + && rm -rf deepMask/.git -COPY app/requirements.txt /app/requirements.txt - -RUN python -m pip install -r /app/requirements.txt --find-links https://download.pytorch.org/whl/torch_stable.html - -RUN conda install -c conda-forge pygpu==0.7.6 - -RUN pip cache purge +RUN eval "$(conda shell.bash hook)" \ + && conda create -n preprocess python=3.7 \ + && conda activate preprocess \ + && python -m pip install -r deepMask/app/requirements.txt \ + && conda deactivate COPY app/ /app/ -RUN sudo chmod -R 777 /app && sudo chmod +x /app/inference.py +RUN python -m pip install -r /app/requirements.txt \ + && conda install -c conda-forge pygpu==0.7.6 \ + && pip cache purge -RUN git clone --depth 1 https://github.com/NOEL-MNI/deepMask.git && rm -rf deepMask/.git +RUN sudo chmod -R 777 /app && sudo chmod +x /app/inference.py CMD ["python3"] \ No newline at end of file From 57c08932960eb122ebf7a8a3a149ce8e69e71ba1 Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Sun, 15 May 2022 13:14:45 -0400 Subject: [PATCH 22/23] add back the required `affine` argument --- app/utils/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/utils/base.py b/app/utils/base.py index d398aa6..f5ebdc8 100644 --- a/app/utils/base.py +++ b/app/utils/base.py @@ -297,29 +297,29 @@ def test_scan(model, test_x_data, options, transit=None, save_nifti=False, uncer if save_nifti: # out_scan = nib.Nifti1Image(seg_image, np.eye(4)) - out_scan = nib.Nifti1Image(seg_image, header=header) + out_scan = nib.Nifti1Image(seg_image, affine=None, header=header) out_scan.to_filename(os.path.join(options['pred_folder'], options['test_mean_name'])) if uncertainty: - out_scan = nib.Nifti1Image(var_image, header=header) + out_scan = nib.Nifti1Image(var_image, affine=None, header=header) out_scan.to_filename(os.path.join(options['pred_folder'], options['test_var_name'])) if transit is not None: if not os.path.exists(test_folder): os.mkdir(test_folder) - out_scan = nib.Nifti1Image(seg_image, header=header) + out_scan = nib.Nifti1Image(seg_image, affine=None, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_mean_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) if uncertainty: - out_scan = nib.Nifti1Image(var_image, header=header) + out_scan = nib.Nifti1Image(var_image, affine=None, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_var_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) if not os.path.exists(os.path.join(test_folder, options['experiment'])): os.mkdir(os.path.join(test_folder, options['experiment'])) - out_scan = nib.Nifti1Image(seg_image, header=header) + out_scan = nib.Nifti1Image(seg_image, affine=None, header=header) test_name = str.replace(scan, '_flair.nii.gz', '') + '_out_pred_0.nii.gz' out_scan.to_filename(os.path.join(test_folder, test_name)) From 2739bb6b42b0f1a3eb327bedb94c1cad0b1d8a1b Mon Sep 17 00:00:00 2001 From: Ravnoor Gill Date: Mon, 16 May 2022 19:37:41 -0400 Subject: [PATCH 23/23] replace `print()` with `logging.info` - add timestamps to `stdout` --- app/inference.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/app/inference.py b/app/inference.py index 269bc62..47f4ae6 100755 --- a/app/inference.py +++ b/app/inference.py @@ -2,6 +2,7 @@ import os import sys +import logging import multiprocessing from mo_dots import Data import subprocess @@ -14,6 +15,11 @@ from tqdm import tqdm from utils.helpers import * +logging.basicConfig(level=logging.DEBUG, + style='{', + datefmt='%Y-%m-%d %H:%M:%S', + format='{asctime} {levelname} {filename}:{lineno}: {message}') + os.environ["KERAS_BACKEND"] = "theano" # GPU/CPU options @@ -24,7 +30,7 @@ cores = str(multiprocessing.cpu_count() // 2) var = os.getenv('OMP_NUM_THREADS', cores) try: - print("# of threads initialized: {}".format(int(var))) + logging.info("# of threads initialized: {}".format(int(var))) except ValueError: raise TypeError("The environment variable OMP_NUM_THREADS" " should be a number, got '%s'." % var) @@ -32,7 +38,7 @@ os.environ["THEANO_FLAGS"] = "mode=FAST_RUN,device=cpu,openmp=True,floatX=float32" else: os.environ["THEANO_FLAGS"] = "mode=FAST_RUN,device=cuda0,floatX=float32,dnn.enabled=False" -print(os.environ["THEANO_FLAGS"]) +logging.info(os.environ["THEANO_FLAGS"]) from models.noel_models_keras import * from keras.models import load_model @@ -72,7 +78,7 @@ args.t1 = os.path.join(args.outdir, args.id + '_t1' + args.output_suffix) args.t2 = os.path.join(args.outdir, args.id + '_t2' + args.output_suffix) else: - print("Skipping image preprocessing and brain masking, presumably images are co-registered, bias-corrected, and skull-stripped") + logging.info('Skipping image preprocessing and brain masking, presumably images are co-registered, bias-corrected, and skull-stripped') # deepFCD configuration K.set_image_dim_ordering('th') @@ -93,7 +99,7 @@ options['test_folder'] = args.dir options['weight_paths'] = os.path.join(cwd, 'weights') options['experiment'] = 'noel_deepFCD_dropoutMC' -print("experiment: {}".format(options['experiment'])) +logging.info("experiment: {}".format(options['experiment'])) spt.setproctitle(options['experiment']) # -------------------------------------------------- @@ -105,13 +111,13 @@ model = off_the_shelf_model(options) load_weights = os.path.join(options['weight_paths'], 'noel_deepFCD_dropoutMC_model_1.h5') -print("loading DNN1, model[0]: {} exists".format(load_weights)) if os.path.isfile(load_weights) else sys.exit("model[0]: {} doesn't exist".format(load_weights)) +logging.info("loading DNN1, model[0]: {} exists".format(load_weights)) if os.path.isfile(load_weights) else sys.exit("model[0]: {} doesn't exist".format(load_weights)) model[0] = load_model(load_weights) load_weights = os.path.join(options['weight_paths'], 'noel_deepFCD_dropoutMC_model_2.h5') -print("loading DNN2, model[1]: {} exists".format(load_weights)) if os.path.isfile(load_weights) else sys.exit("model[1]: {} doesn't exist".format(load_weights)) +logging.info("loading DNN2, model[1]: {} exists".format(load_weights)) if os.path.isfile(load_weights) else sys.exit("model[1]: {} doesn't exist".format(load_weights)) model[1] = load_model(load_weights) -print(model[1].summary()) +logging.info(model[1].summary()) # -------------------------------------------------- # test the cascaded model @@ -134,16 +140,16 @@ pred_var_fname = os.path.join(options['pred_folder'], scan + '_prob_var_1.nii.gz') if np.logical_and(os.path.isfile(pred_mean_fname), os.path.isfile(pred_var_fname)): - print("prediction for {} already exists".format(scan)) + logging.info("prediction for {} already exists".format(scan)) continue options['test_scan'] = scan start = time.time() - print('\n') - print('-'*70) - print("testing the model for scan: {}".format(scan)) - print('-'*70) + logging.info('\n') + logging.info('-'*70) + logging.info("testing the model for scan: {}".format(scan)) + logging.info('-'*70) # test0: prediction/stage1 # test1: pred/stage2 @@ -153,6 +159,6 @@ end = time.time() diff = (end - start) // 60 - print("-"*70) - print("time elapsed: ~ {} minutes".format(diff)) - print("-"*70) \ No newline at end of file + logging.info("-"*70) + logging.info("time elapsed: ~ {} minutes".format(diff)) + logging.info("-"*70) \ No newline at end of file