diff --git a/app/inference.demo.ipynb b/app/inference.demo.ipynb new file mode 100644 index 0000000..2b3eb7a --- /dev/null +++ b/app/inference.demo.ipynb @@ -0,0 +1,520 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "#### How to use this notebook?\n", + "\n", + "```\n", + "conda activate deepFCD\n", + "pip install jupyterlab\n", + "git clone https://github.com/NOEL-MNI/deepFCD\n", + "cd deepFCD/app\n", + "```\n", + "\n", + "- Using the GPU: cuda0\n", + " ```\n", + " THEANO_FLAGS=mode=FAST_RUN,device=cuda0,floatX=float32,dnn.enabled=False jupyter lab --no-browser .\n", + " ```\n", + "\n", + "- Using the GPU: cudaX [replace X with the desired GPU-ID]\n", + " ```\n", + " THEANO_FLAGS=mode=FAST_RUN,device=cudaX,floatX=float32,dnn.enabled=False jupyter lab --no-browser .\n", + " ```\n", + "\n", + "- Using the CPU [not recommended, runtimes can exceed several hours/days depending on the hardware]\n", + " ```\n", + " THEANO_FLAGS=mode=FAST_RUN,device=cpu,floatX=float32,dnn.enabled=False jupyter lab --no-browser .\n", + " ```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using Theano backend.\n", + "Can not use cuDNN on context None: Disabled by dnn.enabled flag\n", + "Mapped name None to device cuda0: NVIDIA TITAN RTX (0000:81:00.0)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Error: /tmp/qab_5801.log - No such file or directory.\n" + ] + } + ], + "source": [ + "import os\n", + "import sys\n", + "import multiprocessing\n", + "from config.experiment import options\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "import time\n", + "import numpy as np\n", + "import setproctitle as spt\n", + "from tqdm import tqdm\n", + "\n", + "os.environ[\"KERAS_BACKEND\"] = \"theano\"\n", + "\n", + "# deepFCD imports\n", + "from models.noel_models_keras import *\n", + "from keras.models import load_model\n", + "from keras import backend as K\n", + "from utils.metrics import *\n", + "from utils.base import *\n", + "\n", + "# deepMask imports\n", + "import torch\n", + "from mo_dots import Data\n", + "from deepMask.app.utils.data import *\n", + "from deepMask.app.utils.deepmask import *\n", + "from deepMask.app.utils.image_processing import noelImageProcessor\n", + "import deepMask.app.vnet as vnet" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Directory Organization\n", + "```bash\n", + "/data\n", + "└── FCD_001/ # [this patient-specific directory is contained within ${IO_DIRECTORY}]\n", + " ├── noel_deepFCD_dropoutMC # [deepFCD output images]\n", + " │ ├── FCD_001_noel_deepFCD_dropoutMC_prob_mean_0.nii.gz # [mean PROBABILITY image from CNN-1]\n", + " │ ├── FCD_001_noel_deepFCD_dropoutMC_prob_mean_1.nii.gz # [mean PROBABILITY image from CNN-2]\n", + " │ ├── FCD_001_noel_deepFCD_dropoutMC_prob_var_0.nii.gz # [mean UNCERTAINTY image from CNN-1]\n", + " │ └── FCD_001_noel_deepFCD_dropoutMC_prob_var_1.nii.gz # [mean UNCERTAINTY image from CNN-2]\n", + " ├── t1.nii.gz # [input #1: T1-weighted image]\n", + " └── t2.nii.gz # [input #2: T2-weighted FLAIR image]\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Configuration" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "experiment: noel_deepFCD_dropoutMC\n" + ] + } + ], + "source": [ + "# global configuration\n", + "args = Data()\n", + "args.dir = '/host/hamlet/local_raid/data/ravnoor/sandbox'\n", + "args.id = 'PX_012_2'\n", + "# args.dir = '/data'\n", + "# args.id = 'FCD_001'\n", + "args.brain_masking = False # set to True or any non-zero value for brain extraction or skull-removal\n", + "args.outdir = os.path.join(args.dir, args.id)\n", + "args.seed = 666\n", + "\n", + "args.t1_fname = 't1.nii.gz'\n", + "args.t2_fname = 't2.nii.gz'\n", + "args.t1 = os.path.join(args.outdir, args.t1_fname)\n", + "args.t2 = os.path.join(args.outdir, args.t2_fname)\n", + "cwd = os.getcwd()\n", + "\n", + "# deepFCD configuration\n", + "K.set_image_dim_ordering('th')\n", + "K.set_image_data_format('channels_first') # TH dimension ordering in this code\n", + "\n", + "options['parallel_gpu'] = False\n", + "modalities = ['T1', 'FLAIR']\n", + "x_names = options['x_names']\n", + "options['dropout_mc'] = True\n", + "options['batch_size'] = 350000\n", + "options['mini_batch_size'] = 2048\n", + "options['load_checkpoint_1'] = True\n", + "options['load_checkpoint_2'] = True\n", + "\n", + "# trained model weights based on 148 histologically-verified FCD subjects\n", + "options['test_folder'] = args.dir\n", + "options['weight_paths'] = os.path.join(cwd, 'weights')\n", + "options['experiment'] = 'noel_deepFCD_dropoutMC'\n", + "spt.setproctitle(options['experiment'])\n", + "print(\"experiment: {}\".format(options['experiment']))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Skipping image preprocessing and brain masking, presumably images are co-registered, bias-corrected, and skull-stripped\n" + ] + } + ], + "source": [ + "if args.brain_masking:\n", + " # trained weights based on manually corrected masks from\n", + " # 153 patients with cortical malformations\n", + " args.inference = os.path.join(cwd, 'deepMask/app/weights', 'vnet_masker_model_best.pth.tar')\n", + " # resize all input images to this resolution matching training data\n", + " args.resize = (160,160,160)\n", + " args.use_gpu = False\n", + " args.preprocess = True\n", + " args.cuda = torch.cuda.is_available() and args.use_gpu\n", + " torch.manual_seed(args.seed)\n", + " args.device_ids = list(range(torch.cuda.device_count()))\n", + " if args.cuda:\n", + " torch.cuda.manual_seed(args.seed)\n", + " print(\"build vnet, using GPU\")\n", + " else:\n", + " print(\"build vnet, using CPU\")\n", + " model = vnet.build_model(args)\n", + " template = os.path.join(cwd, 'deepMask/app/template', 'mni_icbm152_t1_tal_nlin_sym_09a.nii.gz')\n", + "\n", + " # MRI pre-processing configuration\n", + " args.output_suffix = '_brain_final.nii.gz'\n", + " \n", + " 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()\n", + "else:\n", + " args.output_suffix = '.nii.gz'\n", + " args.t1 = os.path.join(args.outdir, args.t1_fname)\n", + " args.t2 = os.path.join(args.outdir, args.t2_fname)\n", + " print(\"Skipping image preprocessing and brain masking, presumably images are co-registered, bias-corrected, and skull-stripped\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Initialize the CNN, and load the model weights from disk" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loading DNN1, model[0]: /local_raid/data/ravnoor/02_docker/deepFCD/app/weights/noel_deepFCD_dropoutMC_model_1.h5 exists\n", + "loading DNN2, model[1]: /local_raid/data/ravnoor/02_docker/deepFCD/app/weights/noel_deepFCD_dropoutMC_model_2.h5 exists\n", + "_________________________________________________________________\n", + "Layer (type) Output Shape Param # \n", + "=================================================================\n", + "input_2 (InputLayer) (None, 2, 16, 16, 16) 0 \n", + "_________________________________________________________________\n", + "conv3d_4 (Conv3D) (None, 48, 16, 16, 16) 2640 \n", + "_________________________________________________________________\n", + "batch_normalization_3 (Batch (None, 48, 16, 16, 16) 192 \n", + "_________________________________________________________________\n", + "dropout_4 (Dropout) (None, 48, 16, 16, 16) 0 \n", + "_________________________________________________________________\n", + "max_pooling3d_4 (MaxPooling3 (None, 48, 8, 8, 8) 0 \n", + "_________________________________________________________________\n", + "conv3d_5 (Conv3D) (None, 96, 8, 8, 8) 124512 \n", + "_________________________________________________________________\n", + "batch_normalization_4 (Batch (None, 96, 8, 8, 8) 384 \n", + "_________________________________________________________________\n", + "dropout_5 (Dropout) (None, 96, 8, 8, 8) 0 \n", + "_________________________________________________________________\n", + "max_pooling3d_5 (MaxPooling3 (None, 96, 4, 4, 4) 0 \n", + "_________________________________________________________________\n", + "dropout_6 (Dropout) (None, 96, 4, 4, 4) 0 \n", + "_________________________________________________________________\n", + "conv3d_6 (Conv3D) (None, 2, 4, 4, 4) 5186 \n", + "_________________________________________________________________\n", + "max_pooling3d_6 (MaxPooling3 (None, 2, 1, 1, 1) 0 \n", + "_________________________________________________________________\n", + "flatten_2 (Flatten) (None, 2) 0 \n", + "_________________________________________________________________\n", + "activation_2 (Activation) (None, 2) 0 \n", + "=================================================================\n", + "Total params: 132,914\n", + "Trainable params: 132,626\n", + "Non-trainable params: 288\n", + "_________________________________________________________________\n", + "None\n" + ] + } + ], + "source": [ + "# initialize empty model\n", + "model = None\n", + "# initialize the CNN architecture\n", + "model = off_the_shelf_model(options)\n", + "\n", + "load_weights = os.path.join(options['weight_paths'], 'noel_deepFCD_dropoutMC_model_1.h5')\n", + "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))\n", + "model[0] = load_model(load_weights)\n", + "\n", + "load_weights = os.path.join(options['weight_paths'], 'noel_deepFCD_dropoutMC_model_2.h5')\n", + "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))\n", + "model[1] = load_model(load_weights)\n", + "print(model[1].summary())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test the trained CNN model to get predictions" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "serving predictions using the trained model: 0%|\u001b[34m \u001b[0m| 0/1 [00:00