diff --git a/README.md b/README.md index 016e88d..0fbfb09 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ # Nondefaced-Detector + +[![PyPI version](https://badge.fury.io/py/nondefaced-detector.svg)](https://badge.fury.io/py/nondefaced-detector) +[![Downloads](https://pepy.tech/badge/nondefaced-detector)](https://pepy.tech/project/nondefaced-detector) +[![Documentation Status](https://readthedocs.org/projects/nondefaced-detector/badge/?version=latest)](https://nondefaced-detector.readthedocs.io/en/latest/?badge=latest) +[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_License,_2.0-lightgrey.svg)](https://opensource.org/licenses/Apache-2.0) + A framework to detect if a 3D MRI volume has been defaced. ## Table of contents @@ -44,7 +50,7 @@ NOTE: The CPU container will be very slow for training. We highly recommend that ### Pip ```bash -$ pip install --no-cache-dir nondefaced-detector[gpu] +$ pip install --no-cache-dir nondefaced-detector[cpu/gpu] ``` @@ -56,7 +62,7 @@ Pre-trained networks are avalaible in the *Nondefaced-detector* [models](https:/ ```bash $ docker run --rm -v $PWD:/data nondefaced-detector:latest-cpu \ predict \ - --model-path=/opt/nondefaced-detector/nondefaced_detector/models/pretrained_weights \ + --model-path=$MODEL_PATH \ /data/example1.nii.gz ``` @@ -86,8 +92,9 @@ Steps to reproduce inference results from the paper. **Step 1:** Get the preprocessed dataset. You need to have [datalad](https://handbook.datalad.org/en/latest/intro/installation.html) installed. ```bash -$ datalad clone https://gin.g-node.org/shashankbansal56/nondefaced-detector-reproducibility /data/nondefaced-detector-reproducibility -$ cd /data/nondefaced-detector-reproducibility +$ datalad clone https://gin.g-node.org/shashankbansal56/nondefaced-detector-reproducibility /opt/nondefaced-detector-reproducibility +$ cd /opt/nondefaced-detector-reproducibility +$ datalad get pretrained_weights/* $ datalad get test_ixi/tfrecords/* ``` @@ -105,12 +112,20 @@ $ conda activate tf-cpu ```bash $ git clone https://github.com/poldracklab/nondefaced-detector.git ``` -**Step 4:** Run the standalone inference script. The inference script uses the pre-trained model weights under `nondefaced_detector/models/pretrained_weights` +**Step 4:** Run the standalone inference script. ```bash $ cd nondefaced-detector $ pip install -e . $ cd nondefaced_detector -$ python inference.py < PATH_TO_TFRECORDS [/data/nondefaced-detector-reproducibility/test_ixi/tfrecords] > +$ python inference.py -h +usage: inference.py [-h] tfrecords_path model_path + +positional arguments: + tfrecords_path Path to tfrecords. + model_path Path to pretrained model weights. + +optional arguments: + -h, --help show this help message and exit ``` ## Paper @@ -148,7 +163,7 @@ Shashank Bansal - shashankbansal56@gmail.com -## Acknowledgements +## Acknowledgements ### Training Dataset The original model was trained on 980 defaced MRI scans from 36 different studies that are publicly available at [OpenNeuro.org](https://openneuro.org/) diff --git a/docker/cpu.Dockerfile b/docker/cpu.Dockerfile index 2b750d2..4080e1c 100644 --- a/docker/cpu.Dockerfile +++ b/docker/cpu.Dockerfile @@ -1,6 +1,36 @@ FROM tensorflow/tensorflow:2.4.1-jupyter -RUN apt-get install -y vim +RUN apt-get install software-properties-common -y && add-apt-repository ppa:git-core/ppa -y + +RUN apt-get update -y && apt-get upgrade -y + +RUN apt-get install -y vim wget + +ENV PATH="/root/miniconda3/bin:${PATH}" +ARG PATH="/root/miniconda3/bin:${PATH}" + +RUN wget \ + https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \ + && mkdir /root/.conda \ + && bash Miniconda3-latest-Linux-x86_64.sh -b \ + && rm -f Miniconda3-latest-Linux-x86_64.sh + +RUN conda --version + +RUN conda install -c conda-forge datalad -y + +RUN git config --global user.email "detector@nondefaced.com" +RUN git config --global user.name "nondefaced-detector" + +RUN datalad clone https://gin.g-node.org/shashankbansal56/nondefaced-detector-reproducibility /opt/nondefaced-detector-reproducibility + +RUN cd /opt/nondefaced-detector-reproducibility + +RUN datalad get pretrained_weights/* +RUN datalad get examples/* + +ENV MODEL_PATH='/opt/nondefaced-detector-reproducibility/pretrained_weights' +ARG MODEL_PATH='/opt/nondefaced-detector-reproducibility/pretrained_weights' RUN pip3 install nobrainer \ sklearn \ diff --git a/docker/gpu.Dockerfile b/docker/gpu.Dockerfile index 4f83042..a1dc526 100755 --- a/docker/gpu.Dockerfile +++ b/docker/gpu.Dockerfile @@ -1,6 +1,36 @@ FROM tensorflow/tensorflow:latest-gpu-jupyter -RUN apt-get install -y vim +RUN apt-get install software-properties-common -y && add-apt-repository ppa:git-core/ppa -y + +RUN apt-get update -y && apt-get upgrade -y + +RUN apt-get install -y vim wget + +ENV PATH="/root/miniconda3/bin:${PATH}" +ARG PATH="/root/miniconda3/bin:${PATH}" + +RUN wget \ + https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \ + && mkdir /root/.conda \ + && bash Miniconda3-latest-Linux-x86_64.sh -b \ + && rm -f Miniconda3-latest-Linux-x86_64.sh + +RUN conda --version + +RUN conda install -c conda-forge datalad -y + +RUN git config --global user.email "detector@nondefaced.com" +RUN git config --global user.name "nondefaced-detector" + +RUN datalad clone https://gin.g-node.org/shashankbansal56/nondefaced-detector-reproducibility /opt/nondefaced-detector-reproducibility + +RUN cd /opt/nondefaced-detector-reproducibility + +RUN datalad get pretrained_weights/* +RUN datalad get examples/* + +ENV MODEL_PATH='/opt/nondefaced-detector-reproducibility/pretrained_weights' +ARG MODEL_PATH='/opt/nondefaced-detector-reproducibility/pretrained_weights' RUN pip3 install --upgrade tensorflow-gpu==2.3.2 RUN pip3 install nobrainer \ diff --git a/guide/notebooks/Data_generation_and_preprocessing.ipynb b/guide/notebooks/Data_generation_and_preprocessing.ipynb deleted file mode 100755 index f9849d6..0000000 --- a/guide/notebooks/Data_generation_and_preprocessing.ipynb +++ /dev/null @@ -1,691 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Experiment Details\n", - "\n", - "TBA\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: tqdm in /home/shank/miniconda3/envs/fitlins38/lib/python3.8/site-packages (4.57.0)\n", - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "pip install tqdm" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import nobrainer" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of processors: 16\n", - "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}\n", - "[('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/example1.nii.gz', '1'), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/example2.nii.gz', '1'), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/example3.nii.gz', '1'), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/example1.nii.gz', '0'), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/example2.nii.gz', '0'), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/example3.nii.gz', '0')]\n" - ] - } - ], - "source": [ - "import multiprocessing as mp\n", - "from pathlib import Path\n", - "import tensorflow as tf\n", - "import functools\n", - "import tempfile\n", - "import sys, os\n", - "from tqdm import tqdm\n", - "\n", - "from nondefaced_detector.preprocessing.normalization import clip, normalize, standardize\n", - "from nondefaced_detector.preprocessing.conform import conform_data\n", - "from nondefaced_detector.helpers import utils\n", - "\n", - "print(\"Number of processors: \", mp.cpu_count())\n", - "print(os.sched_getaffinity(0))\n", - "\n", - "from nobrainer.io import read_csv, verify_features_labels\n", - "\n", - "\n", - "# verify_features_labels(temp)\n", - "\n", - "def preprocess(\n", - " vol_path,\n", - " conform_volume_to=(128, 128, 128),\n", - " conform_zooms=(2.0, 2.0, 2.0),\n", - " save_path=None,\n", - " with_label=False,\n", - "):\n", - " \n", - " try:\n", - " vpath = vol_path\n", - " if with_label:\n", - " if len(vol_path) != 2:\n", - " raise ValueError(\n", - " \"The vol_path must have length of 2 when with_label=True\"\n", - " )\n", - " \n", - " vpath, label = vol_path\n", - " \n", - " spath = os.path.join(os.path.dirname(vpath), 'preprocessed')\n", - " if save_path:\n", - " spath = os.path.join(save_path, 'preprocessed')\n", - " \n", - " os.makedirs(spath, exist_ok=True)\n", - "\n", - " volume, affine, _ = utils.load_vol(vpath)\n", - "\n", - " # Prepocessing\n", - " volume = clip(volume, q=90)\n", - " volume = normalize(volume)\n", - " volume = standardize(volume)\n", - " \n", - " \n", - " tmp_preprocess_vol = tempfile.NamedTemporaryFile(\n", - " suffix=\".nii.gz\",\n", - " delete=True,\n", - " dir=spath,\n", - " )\n", - " \n", - " utils.save_vol(tmp_preprocess_vol.name, volume, affine)\n", - " \n", - " \n", - " tmp_conform_vol = os.path.join(spath, os.path.basename(vpath))\n", - " \n", - " conform_data(\n", - " tmp_preprocess_vol.name,\n", - " out_file=tmp_conform_vol,\n", - " out_size=conform_volume_to,\n", - " out_zooms=conform_zooms)\n", - " \n", - " tmp_preprocess_vol.close()\n", - " \n", - " if with_label:\n", - " return (tmp_conform_vol, label)\n", - " return tmp_conform_vol\n", - " \n", - " except Exception as e:\n", - " print(e)\n", - " return\n", - " \n", - "def cleanup_files(*args):\n", - " for p in args:\n", - " if os.path.exists(p):\n", - " os.remove(p)\n", - " \n", - "def preprocess_csv(\n", - " volume_filepaths,\n", - " num_parallel_calls=None,\n", - " conform_volume_to=(128, 128, 128),\n", - " conform_zooms=(2.0, 2.0, 2.0),\n", - " save_path=None,\n", - " with_label=True,\n", - "):\n", - "\n", - " try:\n", - " map_fn = functools.partial(\n", - " preprocess,\n", - " conform_volume_to=conform_volume_to,\n", - " conform_zooms=conform_zooms,\n", - " save_path=save_path,\n", - " with_label=with_label\n", - " )\n", - " \n", - " if num_parallel_calls is None:\n", - " # Get number of eligible CPUs.\n", - " num_parallel_calls = len(os.sched_getaffinity(0))\n", - " \n", - " print(\"Preprocessing {} examples\".format(len(volume_filepaths)))\n", - " \n", - " outputs = []\n", - " \n", - " if num_parallel_calls == 1:\n", - " for vf in tqdm(volume_filepaths, total=len(volume_filepaths)):\n", - " result = map_fn(vf)\n", - " outputs.append(result) \n", - " else:\n", - " pool = mp.Pool(num_parallel_calls)\n", - " for result in tqdm(pool.imap(func=map_fn, iterable=volume_filepaths), total=len(volume_filepaths)):\n", - " outputs.append(result)\n", - " \n", - " return outputs\n", - " \n", - " except Exception as e:\n", - " print(e)\n", - " return\n", - "\n", - "# import csv\n", - "# temp = []\n", - "# with open('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/example.csv', 'r') as file:\n", - "# reader = csv.reader(file)\n", - "# for row in reader:\n", - "# temp.append(row[0])\n", - " \n", - "\n", - "temp = read_csv('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/example.csv', skip_header=False)\n", - "\n", - "# vpaths = list(zip(*temp))[0]\n", - "# print(preprocess(temp[0], with_label=True))\n", - "# outputs = preprocess_csv(temp)\n", - "# print(outputs)\n", - "print(temp)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of processors: 16\n", - "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}\n", - "Verifying 6 examples\n", - "6/6 [==============================] - 0s 7ms/step\n", - "Preprocessing 6 examples\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 6/6 [00:05<00:00, 1.04it/s]" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Verifying 6 examples\n", - "\r", - "0/6 [..............................] - ETA: 0s" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", - "6/6 [==============================] - 0s 7ms/step\n" - ] - } - ], - "source": [ - "import multiprocessing as mp\n", - "from pathlib import Path\n", - "import tensorflow as tf\n", - "import functools\n", - "import tempfile\n", - "import sys, os\n", - "from tqdm import tqdm\n", - "\n", - "from nondefaced_detector.preprocessing.normalization import clip, normalize, standardize\n", - "from nondefaced_detector.preprocessing.conform import conform_data\n", - "from nondefaced_detector.helpers import utils\n", - "from nondefaced_detector.preprocess import preprocess_parallel\n", - "\n", - "print(\"Number of processors: \", mp.cpu_count())\n", - "print(os.sched_getaffinity(0))\n", - "\n", - "from nobrainer.io import read_csv, verify_features_labels\n", - "\n", - "num_parallel_calls=-1\n", - "volume_shape=(128,128,128)\n", - "preprocess_path=None\n", - "volume_filepaths = read_csv('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/example.csv', skip_header=False)\n", - "\n", - "num_parallel_calls = None if num_parallel_calls == -1 else num_parallel_calls\n", - "if num_parallel_calls is None:\n", - " # Get number of processes allocated to the current process.\n", - " # Note the difference from `os.cpu_count()`.\n", - " num_parallel_calls = len(os.sched_getaffinity(0))\n", - "\n", - "invalid_pairs = verify_features_labels(\n", - " volume_filepaths,\n", - " check_labels_int=True,\n", - " num_parallel_calls=num_parallel_calls,\n", - " verbose=1,\n", - ")\n", - "\n", - "## UNCOMMENT the following when https://github.com/neuronets/nobrainer/pull/125\n", - "## is merged\n", - "# if not invalid_pairs:\n", - "# click.echo(click.style(\"Passed verification.\", fg=\"green\"))\n", - "# else:\n", - "# click.echo(click.style(\"Failed verification.\", fg=\"red\"))\n", - "# for pair in invalid_pairs:\n", - "# click.echo(pair[0])\n", - "# click.echo(pair[1])\n", - "# sys.exit(-1)\n", - "\n", - "ppaths = preprocess_parallel(\n", - " volume_filepaths,\n", - " conform_volume_to=volume_shape,\n", - " num_parallel_calls=num_parallel_calls,\n", - " save_path=preprocess_path,\n", - ")\n", - "\n", - "invalid_pairs = verify_features_labels(\n", - " ppaths,\n", - " volume_shape=volume_shape,\n", - " check_labels_int=True,\n", - " num_parallel_calls=num_parallel_calls,\n", - " verbose=1,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/preprocessed/tfrecords/data-train_shard-{shard:03d}.tfrec\n", - "2/2 [==============================] - 1s 32ms/step\n" - ] - } - ], - "source": [ - "import nobrainer\n", - "\n", - "\n", - "tfrecords_template = 'tfrecords/data-train_shard-{shard:03d}.tfrec'\n", - "\n", - "os.makedirs(os.path.dirname(tfrecords_template), exist_ok=True)\n", - "\n", - "print(tfrecords_path)\n", - "\n", - "nobrainer.tfrecord.write(\n", - " features_labels=ppaths,\n", - " filename_template=tfrecords_template,\n", - " examples_per_shard=3)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "data-train_shard-000.tfrec data-train_shard-001.tfrec\r\n" - ] - } - ], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os, sys\n", - "sys.path.append(\"..\")\n", - "import numpy as np\n", - "from glob import glob\n", - "import pandas as pd\n", - "import random\n", - "from random import shuffle\n", - "\n", - "# Define paths\n", - "ROOT_DIR = '/home/shank/HDDLinux/Stanford/data/mriqc-shared/conformed'\n", - "\n", - "face_path = os.path.join(ROOT_DIR, 'face/128')\n", - "defaced_path = os.path.join(ROOT_DIR, 'face_defaced/128')\n", - "refaced_path = os.path.join(ROOT_DIR, 'face_refaced/128')\n", - "\n", - "paths_d = []\n", - "paths_f = []\n", - "paths_r = []\n", - "\n", - "for path in glob(defaced_path + \"/*/*.nii*\"):\n", - " DS = path.split('/')[-2]\n", - " paths_d.append(path)\n", - " \n", - "for path in glob(refaced_path + \"/*/*.nii*\"):\n", - " DS = path.split('/')[-2]\n", - " paths_r.append(path)\n", - " \n", - "for path in glob(face_path + \"/*/*.nii*\"):\n", - " DS = path.split('/')[-2]\n", - " paths_f.append(path)\n", - " \n", - "\n", - "def generate_datasets(fpaths, dpaths, size, typ ='faced'):\n", - " \n", - " if typ not in ['faced', 'refaced']:\n", - " print(\"Incorrect value for t. Choose from [faced, refaced]\")\n", - " return\n", - " \n", - " random.shuffle(fpaths)\n", - " test_f = fpaths[:size]\n", - " main_f = fpaths[size:]\n", - "\n", - " test_d = []\n", - " for t in test_f:\n", - " if typ == 'faced':\n", - " test_d.append(t.replace('face', 'face_defaced'))\n", - " \n", - " if typ == 'refaced':\n", - " DS = t.split('/')[-2]\n", - " sub = t.split('/')[-1].replace('_defaced_refaced', '').split('.nii.gz')[0]\n", - " search_pattern = os.path.join(DS, sub)\n", - " \n", - " # match pattern from defaced dataset\n", - " for _d in dpaths:\n", - " if search_pattern in _d:\n", - " test_d.append(_d)\n", - " \n", - "\n", - " test = test_f + test_d\n", - " labels_test = [1]*len(test_f) + [0]*len(test_d)\n", - " \n", - " # remove T_A_D from defaced volume set\n", - " main_d = list(set(dpaths) - set(test_d))\n", - " \n", - " labels_main = [1]*len(main_f) + [0]*len(main_d)\n", - " main = main_f + main_d\n", - " \n", - " return main, labels_main, test, labels_test\n", - "\n", - "A_2, L_A_2, T_A, L_T_A = generate_datasets(paths_f, paths_d, 49, typ='faced')\n", - "B_2, L_B_2, T_B, L_T_B = generate_datasets(paths_r, paths_d, 49, typ='refaced')\n", - "\n", - "print(len(A_2), len(T_A))\n", - "print(len(B_2), len(T_B))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from nondefaced_detector import preprocess\n", - "vol_path = '../../examples/sample_vols/IXI002-Guys-0828-T1.nii.gz'\n", - "save_path = ''\n", - "ppath, cpath = preprocess.preprocess(vol_path, save_path=save_path)\n", - "print(ppath, cpath)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate n-fold CV Datasets" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from operator import itemgetter\n", - "from sklearn.model_selection import KFold\n", - "from sklearn.model_selection import StratifiedKFold\n", - "from sklearn.model_selection import train_test_split\n", - "import pandas as pd\n", - "import random\n", - "from random import shuffle\n", - "import os\n", - "\n", - "def generate_CSV(paths, labels, save_path, test_paths=None, test_labels=None, n=15, mode='CV'):\n", - " \n", - " os.makedirs(save_path, exist_ok=True)\n", - " \n", - " df = pd.DataFrame()\n", - " df[\"X\"] = paths\n", - " df[\"Y\"] = labels\n", - " df.to_csv(os.path.join(save_path, \"all.csv\"))\n", - " \n", - " if mode == 'CV':\n", - " SPLITS = n\n", - " skf = StratifiedKFold(n_splits=SPLITS)\n", - " fold_no = 1\n", - "\n", - " for train_index, test_index in skf.split(paths, labels):\n", - " out_path = os.path.join(save_path, \"train_test_fold_{}/csv/\".format(fold_no))\n", - "\n", - " if not os.path.exists(out_path):\n", - " os.makedirs(out_path)\n", - "\n", - " image_train, image_test = (\n", - " itemgetter(*train_index)(paths),\n", - " itemgetter(*test_index)(paths),\n", - " )\n", - "\n", - " label_train, label_test = (\n", - " itemgetter(*train_index)(labels),\n", - " itemgetter(*test_index)(labels),\n", - " )\n", - "\n", - " train_data = {\"X\": image_train , \"Y\": label_train}\n", - " df_train = pd.DataFrame(train_data)\n", - " df_train.to_csv(os.path.join(out_path, \"training.csv\"), index=False)\n", - "\n", - " validation_data = {\"X\": image_test, \"Y\": label_test}\n", - " df_validation = pd.DataFrame(validation_data)\n", - " df_validation.to_csv(os.path.join(out_path, \"validation.csv\"), index=False)\n", - "\n", - " fold_no += 1\n", - " else:\n", - " train_data = {\"X\": paths , \"Y\": labels}\n", - " df_train = pd.DataFrame(train_data)\n", - " df_train.to_csv(os.path.join(save_path, \"training.csv\"), index=False)\n", - " \n", - " test_data = {\"X\": test_paths , \"Y\": test_labels}\n", - " df_test = pd.DataFrame(test_data)\n", - " df_test.to_csv(os.path.join(save_path, \"testing.csv\"), index=False)\n", - " \n", - "ROOTDIR = '/home/shank/HDDLinux/Stanford/data/mriqc-shared/experiments'\n", - "\n", - "## CROSS VALIDATION\n", - "# generate_CSV(A_2, L_A_2, \"experiments/experiment_A/csv_F15\")\n", - "generate_CSV(B_2, L_B_2, os.path.join(ROOTDIR, \"experiment_B/128/csv_F15\"), mode='CV')\n", - "\n", - "\n", - "## DEFINE A ROOT DIR where all the data will be stored <<<<<\n", - "# ROOTDIR = '/work/06850/sbansal6/maverick2/mriqc-shared/experiments' \n", - "\n", - "## FULL DATASET\n", - "# generate_CSV(A_2,\n", - "# L_A_2,\n", - "# os.path.join(ROOTDIR, 'experiment_A/128/csv_full'),\n", - "# test_paths=T_A,\n", - "# test_labels=L_T_A,\n", - "# mode='full')\n", - "\n", - "# generate_CSV(B_2,\n", - "# L_B_2,\n", - "# os.path.join(ROOTDIR, 'experiment_B/128/csv_full'),\n", - "# test_paths=T_B,\n", - "# test_labels=L_T_B,\n", - "# mode='full')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Generate tfrecords for n-fold CV datasets" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "import nobrainer\n", - "import os, sys\n", - "sys.path.append(\"..\")\n", - "import numpy as np\n", - "import nibabel as nb\n", - "from glob import glob\n", - "from pathlib import Path\n", - "from shutil import *\n", - "import subprocess\n", - "from operator import itemgetter\n", - "import pandas as pd\n", - "\n", - "\n", - "def generate_tfrecords(csv_path, records_save_path, mode='CV'):\n", - " \n", - " os.makedirs(records_save_path, exist_ok=True)\n", - " train_csv_path = os.path.join(csv_path, \"training.csv\")\n", - " train_paths = pd.read_csv(train_csv_path)[\"X\"].values\n", - " train_labels = pd.read_csv(train_csv_path)[\"Y\"].values\n", - " train_D = list(zip(train_paths, train_labels))\n", - " \n", - " random.shuffle(train_D)\n", - " train_write_path = os.path.join(records_save_path, 'data-train_shard-{shard:03d}.tfrec')\n", - " \n", - " nobrainer.tfrecord.write(\n", - " features_labels=train_D,\n", - " filename_template=train_write_path,\n", - " examples_per_shard=3)\n", - " \n", - " if mode =='CV':\n", - " vt_csv_path = os.path.join(csv_path, \"validation.csv\")\n", - " namefill = 'valid'\n", - " else:\n", - " vt_csv_path = os.path.join(csv_path, \"testing.csv\")\n", - " namefill = 'test'\n", - " \n", - " vt_paths = pd.read_csv(vt_csv_path)[\"X\"].values\n", - " vt_labels = pd.read_csv(vt_csv_path)[\"Y\"].values\n", - " vt_D = list(zip(vt_paths, vt_labels))\n", - " random.shuffle(vt_D)\n", - " vt_write_path = os.path.join(records_save_path, 'data-{}_shard-{shard:03d}.tfrec'.format(namefill))\n", - "\n", - " nobrainer.tfrecord.write(\n", - " features_labels=vt_D,\n", - " filename_template=vt_write_path,\n", - " examples_per_shard=1)\n", - " \n", - "\n", - "ROOTDIR = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments'\n", - "\n", - "# Cross-Validation \n", - "# SPLITS = 15\n", - "# for fold in range(1, SPLITS+1):\n", - "# print(\"FOLD: \", fold)\n", - "# csv_path = os.path.join(\n", - "# ROOTDIR, \"experiment_B/128/csv_F15/train_test_fold_{}/csv/\".format(fold)\n", - "# )\n", - " \n", - "# tf_records_dir = os.path.join(\n", - "# ROOTDIR, \"experiment_B/128/tfrecords_F15/tfrecords_fold_{}/\".format(fold)\n", - "# )\n", - "# generate_tfrecords(csv_path, tf_records_dir)\n", - "\n", - "\n", - "# Test (full dataset)\n", - "# experiment_A\n", - "# csv_path = os.path.join(ROOT_DIR, \"experiment_A/128/csv_full\")\n", - "# tf_records_dir = os.path.join(ROOT_DIR, \"experiment_A/128/tfrecords_full\")\n", - "# generate_tfrecords(csv_path, tf_records_dir, mode='test')\n", - "\n", - "# experiment_B\n", - "# csv_path = os.path.join(ROOT_DIR, \"experiment_B/128/csv_full\")\n", - "# tf_records_dir = os.path.join(ROOT_DIR, \"experiment_B/128/tfrecords_full\")\n", - "# generate_tfrecords(csv_path, tf_records_dir, mode='test')\n", - "\n", - "## Main held-out Test Dataset\n", - "csv_path = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/test_ixi/csv/testing.csv'\n", - "records_save_path = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/test_ixi/tfrecords_new'\n", - "paths = pd.read_csv(csv_path)[\"X\"].values\n", - "labels = pd.read_csv(csv_path)[\"Y\"].values\n", - "\n", - "vt_D = list(zip(paths, labels))\n", - "random.shuffle(vt_D)\n", - "\n", - "write_path = os.path.join(records_save_path, 'data-test_shard-{shard:03d}.tfrec')\n", - "\n", - "nobrainer.tfrecord.write(\n", - " features_labels=vt_D,\n", - " filename_template=write_path,\n", - " examples_per_shard=1)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/guide/notebooks/metrics.ipynb b/guide/notebooks/metrics.ipynb deleted file mode 100755 index 2e81fdb..0000000 --- a/guide/notebooks/metrics.ipynb +++ /dev/null @@ -1,495 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# About\n", - "\n", - "TBA" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "from matplotlib.pyplot import figure, grid, fill_between, plot\n", - "\n", - "def plot(metric_data, n_folds=15, figsize=(10, 4), color='g', label='Make up a label', xlabel='Epoch', ylabel=''):\n", - " \n", - " fold_mean = np.mean(metric_data, axis=0)\n", - " fold_std = np.std(metric_data, axis=0)\n", - " \n", - " _, axes = plt.subplots(1, figsize=figsize)\n", - " \n", - " axes.grid()\n", - " axes.fill_between(range(1, n_folds+1), fold_mean - fold_std,\n", - " fold_mean + fold_std, alpha=0.1,\n", - " color=color)\n", - " \n", - " \n", - " axes.plot(range(1, n_folds+1), fold_mean, 'o-', color=color, label=label)\n", - "\n", - " axes.set_xlabel(xlabel)\n", - " axes.set_ylabel(ylabel)\n", - " axes.legend(loc=\"best\")\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Cross-Validation Metrics" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## From history.history objects" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Available Metrics: dict_keys(['loss', 'tp', 'fp', 'tn', 'fn', 'accuracy', 'precision', 'recall', 'auc', 'val_loss', 'val_tp', 'val_fp', 'val_tn', 'val_fn', 'val_accuracy', 'val_precision', 'val_recall', 'val_auc'])\n", - "(15, 15)\n" - ] - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlkAAAEGCAYAAABWyID4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAA1S0lEQVR4nO3de3ycZbnv/881k3NTUlpo6TllU5AiUCCLU7pcrYCWtbYgLEUQeYGnioII6GIXAWXjZnEQfx426vpVBRS77BI8ASLKKUtSQGihtNAih9KmJwr0kCZtkjld+485dCYzmZm2SSfJfN+vV1555n7uZ3LNnWTmmvu55n7M3RERERGR/hUodQAiIiIiw5GSLBEREZEBoCRLREREZAAoyRIREREZAEqyRERERAZARakD6O2ggw7yxsbGUoex3+3cuZMRI0aUOoxBTWOUn8YnP41PYRqj/DQ+hZXjGC1duvQ9dz84175Bl2Q1NjayZMmSUoex37W0tDB79uxShzGoaYzy0/jkp/EpTGOUn8ansHIcIzNb29c+nS4UERERGQBKskREREQGgJIsERERkQGgJEtERERkACjJEhERERkASrJEREREBoCSLBEREZEBoCRLREREZAAUTLLM7C4ze8fMXu5jv5nZD8zsDTNbbmbHp+272MxeT3xd3J+Bi4gUY+GKhTR+r5EP/vcHafxeIwtXLCx1SKmYAv87MChiGmxjpPEpPqZyHSN3JxqLEo6G6Yn00B3pZld4F52hTtq729myawubOzfzzs53cPcBjSWfYlZ8vwe4E/hFH/vPBKYnvk4CfgycZGajgW8CTYADS83sAXfftq9Bi5TSwhULue7x62hrb2NKwxRuPu1mLjz6wlKHNWgMpvFZuGIh8x6cx67wLgDWtq9l3oPzABST4hmS8QzGmPYlHncn5jGc+Pf0r2gsSiQWIerR1HbydsxjqeMBDEvdp5nx0GsPccczd7CpYxOTGybz76f9e0nGpmCS5e5/NbPGPF3OBn7h8Uf6rJmNMrPxwGzgUXffCmBmjwJzgV/tc9QiJbInTybJf37HcXccT7Xn2+59HJB60knfTu6/f+X93NJ6Cxs7NjLhhQnMb57POUeeU/CxmFnGE9PeMAyz3ffxm1W/4Wt/+RpdkS4gPj6ff+DzdHR38PGjPg5AwAIZ39PjSN2XE39i9cSTbCz+JJu8HfPY7vZe/SK+u//Vj1yd+l0l7Qrv4spHrqQqUJXxu4l5LON3kD7Ge9LW+356t93WelvOmC7/4+Ws2bYmYzyT4+I4hsW/p41Ret/ex6T/as3Tb2T2v6X1lj7jadvetvvxJR9Pjr/T9McHmS+cjoNDjLQ+nnZc+n2584vlv8gZz6UPXcpf1/416/H2l77+FxauWNhnPK1rW+PHJn4PvV/o09ty/V7zteW7rwVLF+SM6Ut//BIvb3654P3miq2vfu6edz/AbYtz/01f8acriEQjBANBKgOVBANBghYkYAECFiAYCFIRqKDCKqgKVlEZrKQyUBnfDlQSCARSPzt5TEWggiqryvm3n/TbVb/luieuSz0PtbW3lSwJtWKm0RJJ1kPu/v4c+x4CbnX31sTtx4H/RTzJqnH3/5NovwHocvc7ctzHPGAewLhx405YtGjR3j6eIauzs5P6+vpShzEoPbb5MX761k95p+cdxlaP5XPTPsfp405P7U8+sefkRfTpvT+xGY6F6Yn10BXtoifWQ3esm2tXXMu2cPZkbENFA1dPv3r3C5jneDJK3G9yO+uJ0OIvhsntjHZyP/G+sO0Ffr3+14Q9nGqvtEo+OuGjHNNwTCoBSf+KeYwo2e05+xXZP9l3efvyjFiSghZkfM34VL/UccSyf1aiXYauAJkJdPJ/IP3vOGNf4u88QIAdkR193u+BlQful/jT5fp/TxpVOWr3c0fGU4jn/J7eL72t9/NTxj7Pvo+eWE+fMVVYRap/79f3VNI7RFRYPAGrDFRSaZWphKwyUBnfF6ig0iqzbj+39Tm6Y91Z9zeuehyLTu7//GLOnDlL3b0p52Po95+2F9x9AbAAoKmpycvt4pIw+C6q2fudeO82IOd2rr45Z2FyvMNP7+fuxIjxh1f/wHfe+A7dkfg/zOaezXznje/QMKmBD077ID2ReBLUFe6iO9xNV6Qr9dUdjp+j744k2sNdGdtdkcTt9O20fZFYpOjxao+0881V3+yfwd9HYQ9z34b7uG/DfXt9H8kns+Q7zdR3y7xdYRUEg7vbwtuzEyyIz0odN/m4VL+M+7EKAoFA6kkyGIi/0w1aMGM7EEi09dpO3l/6dkUwHuvVf76a97rey4rn4LqD+flHf571Lrmv24ZREajYnTibpd6RJxOG1DEYgUCAAIFUe/I+zYxTfnYKGzo2ZMU0ceREnvnsM7v/b2Kx1P9T8v8i6tHU7eSsUjIhTf0fEYvPHMUS7XgqafdY4v/Tdv+ffnTRR3l759tZ8RxSfwh//OQf428IMCyQGBsCBILxxxQkMSuR+H0kHy+QGo/kdjFtZsaMH85g3Y51WfFMPmAyr17+6j7PvvaWb0YE4PD/e3if8bz25ddSt/em7qfYhKf3fR/5wyP7jGnlZSvzHpv8W0qKxqK5ZyATx0U9mvk8T/bf5gfu+QAbOzZmxTN2xFjuOeseeqI9qRnm5Om+SCxCOBYmHI1/hWIhQpEQ4ViYUDS0uy25HQ2l+vdEezKOS253RjsJx8I5EyyAd3re2e+vs/2RZG0AJqfdnpRo20B8Niu9vaUffp7spfSEJzVrEMv8Y79/5f3c/vTtbOrYxPj68Vx9ytV85PCPxO/A2P1uLbGdOn3hZMzipM/EhGNhdoZ20hXuYmd4J7vCu9gV3pW5HdrJrkj8e7J9Z2gnT7U9RSgayngc3ZFurnnsmj1+/NXBamora6mtqKW2spa6yjpqK2o5oOYADqk4JGNfcruuso7aylpqgjXUVdZx7ePXsqVrS9Z9H1x3MD8762epsXBLnN7xzHervd/1Fkpak9u92yD++/zkbz+Z87EaxoMXPJiZICUSmlxJU3pb8gWvL30l047TfFdzzifbCSMncMcZd4DFj0nN1uX6G3JSL9rJF+DkaYL028nTDemzIhmJkcW/vvDQFzJOZdRV1vHdud/lzOln5n2cA+W2M27LOOWcjOm2M25jcsPkPEfund5/g+ltjnP7Gbdz6R8vzYrn9tNv59hxx+Y97TUQbjn9lpzjc8vpt1BXWTegP3tP46mpqNnv8RSKqb5q/58Ruf2M23PGc8cZd/DBQz+YqqkKRUOpr3AsnJGspd6c9HqDtTdO/MmJOd/ITGmYsncPcB/0R5L1AHC5mS0iXvje7u6bzOzPwL+bWXJ+90PAtf3w86SXZLLUO3kKRUNEYhFC0VCqdiXX1HYgEH9X+uBrD/L1x7+eOo+9sXMj1z0RL2A+fsLx8QQotJPOcCe7QvEkqTPUyc7wzlRylPE9sR2O5Z7d6M0wRlSNoL6ynrqqOuqr6rMSrHQ3fOCGzKSpoi4rOaqtiH9VV1Sn6gty1dCkJz3pNS+JwOIv6gS44QM3cO3j16bGCKC2opbrP3A9Mw+ZmTFTl5xhiMViuxPUHElGvmQjPVntXUNlZkwYOSFnUjN+5HiOPPjI7EQtrSYmGQsk6p8iUUIWytqXKwECMmZqkl9fn/V1/u3Rf8san5tm38SEAyZkzPrkS476y6eO+RRmNmgK8WF3Tcj+iilXfU76ZNBFx15EIBAYNGO0v8dnqMUzGGPa23hSNZWJ78kZq1A0PqsV8UjG81DyuSI1ex0I5rzf+bPmc82j12Q8D9VV1nHzaTf30yMuXsGaLDP7FfEZqYOAzcQ/MVgJ4O7/YfH/4DuJF7XvAj7t7ksSx34G+Hrirm5297sLBdTU1ORLlizZqwczlPU+Xdj7ExbJQt9k0pTcDkfjCUzyBTr5Ap7+4pd8R5D+rqAn0sO6Het4a/tbrN2+ljXb1/CfK/6Tnmjf5/p7q6moYUTlCOqr6qmrrMtKkEZUjoh/VY3Y3a+qLuOYVL+qEdRW1Ga9wPb1jmTCyAn89yX/nVGImys5St5OzoKkz9akf891Wif99E96XHvz6blCp1/7autd+J6r6D1XUvPtM77Nx2Z8LOfprPSEBsic+en1PT6M2W35DKZPF6YbbKfkByONUX4an8L6c4ySr3/pny5MJmE90Z7Ua2P6G8HkDPiDrz3I7YtvZ2PHxgH/dKGZ7X1NlrtfUGC/A5f1se8u4K5igix30ViUDTs2xGedEn9Qvd91picAydM8VcG+P2XRGerkzW1vppKote1rU0nVxo6NGfUAI6tG9plgGcYfP/nHVLI0omoEdZV1VAT2bCI0NcPTK1mIeYxYLMbO0M6M/o5z1clXcf2T16dqsiCeRNzwjzcwpnZMximj9ASid8LUny48+sI9/mdNJTX9fKblshMvY1TtqEGV1OzN+IiI9BaweP1fZXxeJ4u7Z8yEpZ+SPOvwszjzsDMJWIBpB07b61OP+2pQFL6Xu55IT7wmKhYu6uOpSe7Otu5t8QQqkUitaV+Tuv3urncz+o+pHUPjqEZOnnQyjaMaaRzVyNSGqUw7cBoH1hzIST89qc9Zo2MPOTb1M5OJUSgayipczwww82ZyxiiZHKbXAvWutUkmSVefcjWHjDxkUCURg00yqdG7bBEpJ2aWqjPtS8xjJUuwQElWyS1csZD5j81nw44NTFg+gfmz5nPukeem9rs7m3duTiVOb21/KzUrtWb7Gnb0ZH7ceXz9eBpHNXLGoWcwddTUjGRqZPXIvLHMb57PNY9lnseuqajhqpOvojPUmToVmUyMKgOVGafc0guTe5+e2pc/ciURIiKyN0qZYIGSrJLqvbDlho4NXP3nq/ndqt9RGayMz061r8k4VRa0IJMPmEzjqEaOf9/xGYnU5AMmU1tZW9TPjnmMcDRMJBZJ1fd8+LAPEyPGt5/+Nht2bGDSAZP41pxv8cmjP5mROImIiEhhSrJK6LrHr8taJTccC/PEmic4fMzhNI5q5AONH4if0hs1jamjpjJx5EQqg7nPT+eSPGcdjoaJxqKpT41VBipTyxgkV9mtCFRwxUlXcMVJV/T3QxURESk7SrJKqK29LWe7YTx58ZN7fH/J2amoR3cvG0B8fagDqg+gpqImlVD19dFXERER6R9KskpocsPknInWhJETCh6bXL4hWXieXMspuUZU+nWgBnrxQBEREcmmJKuEbvjHG/jiw1/MuHxLbUUt82fNT912d8KxcOqiuMm1QCoDldRX1VNbUUtVxe5P6omIiMjgoFflEjr90NM5dNShrN6+mmgsyoSRE/jqqV/lQ//jQ3SGOlOra1cHqxlZMzJ1uq+YS5+IiIhIaSnJKpGeSA87enbQ1t7GxcdezMfqPsbhJxyedbpPs1MiIiJDk17BS6Sjp4Pl7yynO9rNqZNPJbA1wKEHHlrqsERERKSf6JxTCcQ8xvbu7Ty34TmCFuT48cfr9J+IiMgwo1f2EugKdxH1KIvXLebYQ46lrqJOSZaIiMgwo1f2Emjvaac70s1Lb7/ErCmzcFzLLIiIiAwzSrL2s0gsQmeokxfffpGoR5k1eRZmhqEkS0REZDhRkrWf7QztBIfWtlZqgjUce8ixVAWqSh2WiIiI9DMlWfvZlq4t1FTWsLhtMf8w8R8IWpC6qrpShyUiIiL9TEnWftQd6SYcDbOtaxuvbnmVWVNmEY1FqatUkiUiIjLcKMnaj3b07CAYCLJ43WKAVNF7ZaCyxJGJiIhIf1OStZ/EPEZ7dzs1FTW0trXSUN3A0WOPxsyoDCrJEhERGW6UZO0nXeEuYh4jYAFa21o5ZdIpOE5VoEprZImIiAxDenXfT7Z1baMqWMXa7WtZt2Mds6bMIhwNM6JqRKlDExERkQGgJGs/CEfD7AzvpLqimta2VoBU0XttZW2JoxMREZGBoCRrP+gMdaZOCbaua2XciHEcNvowFb2LiIgMY0qyBpi7s617G9UV1cQ8xuK2xTRPaY6v8q6idxERkWFLSdYA64n2EI6GqQhU8Op7r7KlawuzpswiEouo6F1ERGQY0yv8ANvRs4OKQAVARj2Wit5FRESGNyVZAyh9bSyIJ1nTRk1j4siJKnoXEREZ5pRkDaBd4V24O2ZGOBrm2fXPMmvKLAAVvYuIiAxzSrIG0LaubanC9mWbl7EzvDOVZKnoXUREZHhTkjVAwtEwu8K7qK6oBuKnCg3j1MmnquhdRESkDOhVfoCkr40FsLhtMUeNPYrRtaNV9C4iIlIGlGQNAHdnW9e2VMF7V7iLpZuW8o9T/hGASCyioncREZFhrqgky8zmmtnfzewNM5ufY/9UM3vczJabWYuZTUrbFzWzZYmvB/oz+MGqO9JNOBYmGAgC8NyG5whFQ6l6LEBF7yIiIsNcRaEOZhYEfgicAawHnjezB9x9ZVq3O4BfuPvPzeyDwC3ARYl9Xe4+s3/DHtzau9tTa2NBvB6rMlDJiRNPBFT0LiIiUg6Kmck6EXjD3Ve7ewhYBJzdq88M4InE9pM59peNaCxKR6gjdaoQ4tcrPGH8CdRV1qnoXUREpEyYu+fvYPYxYK67fy5x+yLgJHe/PK3PfwJ/c/fvm9m5wG+Ag9x9i5lFgGVABLjV3X+f42fMA+YBjBs37oRFixb1x2MriZjHCEfDBALxJGpHeAcff/bjXDTlIj419VPEPEbQghkzXQCdnZ3U19eXIuQhQ2OUn8YnP41PYRqj/DQ+hZXjGM2ZM2epuzfl2lfwdGGRvgbcaWaXAH8FNgDRxL6p7r7BzA4FnjCzFe7+ZvrB7r4AWADQ1NTks2fP7qew9r+29jZiHqMqWAXAw68/jOOce8q5HDXxKDp6Oph4wETqqzL/CFtaWhjKj3t/0Bjlp/HJT+NTmMYoP41PYRqjTMUkWRuAyWm3JyXaUtx9I3AugJnVA//q7tsT+zYkvq82sxbgOCAjyRouQtEQXeEuRlaPTLW1trUyonIEMw+ZCYBhKnoXEREpA8UUBj0PTDezaWZWBZwPZHxK0MwOMksVGV0L3JVoP9DMqpN9gGYgvWB+WOkMdRK0YEZba1srJ006aXehu6GidxERkTJQMMly9whwOfBnYBXwa3d/xcxuMrOzEt1mA383s9eAccDNifYjgSVm9hLxgvhbe30qcdhIro2VXOEdYFPHJt7c9mZq6QYVvYuIiJSPomqy3P1h4OFebd9I274fuD/HcU8DR+9jjENCd6Q7a5HR1nWtAKkkKxwNc0D1ASWJT0RERPYvTan0k95rYwE8tfYpRteO5siDjgS00ruIiEg5UZLVD6KxKDt6dmSsjeXuLG5bTPPk5tTpQRW9i4iIlA8lWf1gZ2gnWHwl96Q3t73J2zvfzriUjoreRUREyoeSrH6wtWsr1cHqjLbWtsx6rEgsQnWwWkXvIiIiZUKv+PsoFA3RE+3JmqFqbWtl0gGTmNowFYgXvddV1pUiRBERESkBJVn7qKOnI2t2KhqL8vS6p5k1eVbqFKKK3kVERMqLkqx94O5s796elTy9/M7LtPe0Z9RjqehdRESkvCjJ2gddkS4isUjWTFayHqt5SvPuRhW9i4iIlBUlWftge/f2nIlT67pWjhhzBGNHjAVU9C4iIlKO9Kq/lyKxCJ09nVmfKuyJ9PDchucyThWq6F1ERKT8KMnaS7tCu7LWxgJYumkp3ZHujCQr6lEVvYuIiJQZJVl7KdfaWBCvxwpYgJMnnby70VHRu4iISJlRkrUXeiI9OdfGgniSdey4YzMvBK2idxERkbKjJGsvdPR0EAwEc7Yve3tZxqlCFb2LiIiUJ73y76GYx9jevT3jYtBJz254lqhHVfQuIiIiSrL2VHekm6hHc85Mtba1UhOsoWlCU6pNRe8iIiLlSUnWHuprbSyAxW2LaZrYlDnLpaJ3ERGRsqQkaw9EYhE6ejpynip8b9d7rHpvVcapQkBF7yIiImVKSdYe2BnaiWE59y1uWwzArMkqehcRERElWXtka9dWaiqzZ7EgXo91QPUBHDPumFSbit5FRETKl5KsIvVEeghFQ1QEKnLub13XyimTTslY2kFF7yIiIuVLSVaR+lobC6CtvY229rbseiwVvYuIiJQtJVlFyLc2FsRPFQIqehcREZEUJVlF6Ap39bk2FsSTrHEjxjF99PRUm4reRUREypsygCJs69pGVbAq5z53Z/G6xTRPbsZs9ycPVfQuIiJS3pRkFRCJRdgZ3kl1RXXO/a++9yrv7Xov61Shit5FRETKm5KsAvKtjQXxTxVCjnosFb2LiIiUNSVZebg7W7q29Lk2FsTrsRpHNTLxgImZO1T0LiIiUtaUZOXRE+0hHA33uTZWJBbh2fXPZs1iqehdRERElAXksaNnR58JFsCyt5fRGerMSrJU9C4iIiJKsvoQ8xjt3e19ro0Fu9fHap7cnNGuoncREREpKskys7lm9ncze8PM5ufYP9XMHjez5WbWYmaT0vZdbGavJ74u7s/gB1JXuIuYxzKWZeitta2Vow4+itG1ozN3qOhdRESk7BVMsswsCPwQOBOYAVxgZjN6dbsD+IW7HwPcBNySOHY08E3gJOBE4JtmdmD/hT9w8q2NBfEkbOmmpdmfKgQVvYuIiEhRM1knAm+4+2p3DwGLgLN79ZkBPJHYfjJt/4eBR919q7tvAx4F5u572AMrHA3nXRsL4PmNzxOKhnLWY6noXURERIrJBCYC69Jur0+0pXsJODexfQ4w0szGFHnsoNMZ6iyYJLW2tVIRqOCkiSdltEdiEUZUjhjI8ERERGQI6Pujc3vma8CdZnYJ8FdgAxAt9mAzmwfMAxg3bhwtLS39FNbeCUVD8QVI+y7H4tFVj/K++vex5qU1Ge0xj1EZqNzjmazOzs6SP+7BTmOUn8YnP41PYRqj/DQ+hWmMMhWTZG0AJqfdnpRoS3H3jSRmssysHvhXd99uZhuA2b2Oben9A9x9AbAAoKmpyWfPnt27y37THelm7fa1jKwe2Wef7d3bef2p17n6lKs56h+OytjX2dNJ44GNeeu5cmlpaaGUj3so0Bjlp/HJT+NTmMYoP41PYRqjTMVMtzwPTDezaWZWBZwPPJDewcwOMktN3VwL3JXY/jPwITM7MFHw/qFE26BVaG0sgGfWPYPjfRe965OFIiIiZa9gkuXuEeBy4snRKuDX7v6Kmd1kZmclus0G/m5mrwHjgJsTx24FvkU8UXseuCnRNihFY9GCa2NBvB6rrrKOmYfMzGhPFr3nW/ZBREREykNRNVnu/jDwcK+2b6Rt3w/c38exd7F7ZmtQ64oUXhsL4heFPnniyVmnBCOxCA3VDQMZooiIiAwRWmcgzdaurXmXbQDY1LGJN7a+QfOU5qx9UY/mvZi0iIiIlA8lWQmhaIiucFfBgvXF6xYD5K7Hcva44F1ERESGJyVZCTtDOwlasGC/1rZWRteOZsbBvRe9R0XvIiIikqIkC3B3tnVtK3iq0N1pbWvl1MmnZq2DpaJ3ERERSacki/jaWOFYmGAg/0zW6u2r2dS5KeepQq30LiIiIumUZAHt3e0F18aC+KlCgFmTs5MsFb2LiIhIurJPsqKxKDt6dhRcGwviSdbEkRNpHNWYvVNF7yIiIpKm7JOsnaGdYBSspYrGojy97mlmTZmVu6+K3kVERCRN2SdZ23u2FzUD9cq7r7C9e3vOeiwVvYuIiEhvZZ1kFbs2Fuyux2qenL0IqYreRUREpLeyTrI6Q51ZSzH0pbWtlcPHHM64+nFZ+1T0LiIiIr2VbZKVXBurmIL3nkgPf9vwt5yfKozfmYreRUREJFPZJlldkS4isUjBtbEAXtj0At2R7pz1WO6uoncRERHJUrZJVnt3O5XB4hKj1rZWAhbg5EknZ+2LxCIqehcREZEsZZlkRWNROno6qA7mv4xOUuu6Vo4ddywNNQ1Z+1T0LiIiIrmUZZIV81hRa2NBvDh+2dvLaJ6S/alCUNG7iIiI5FaWSdaeeHb9s0RikZz1WICK3kVERCQnJVkFtLa1Uh2spml8U9Y+Fb2LiIhIX5RkFdDa1krThCZqK2uz9kViEWoqalT0LiIiIlmUZOXx3q73WPXeqj5PFUZiEeoq6vZzVCIiIjIUKMnKY/G6xQB9JllRj+ac4RIRERFRkpXH4rbFjKwayTHjjsndwSl6rS0REREpL0qy8mhta+WUyadQEajI2qeidxEREclHSVYf1rWvY2372j6vV6iidxEREclHSVYfWttagb7rsVT0LiIiIvkoyepDa1srY0eM5fAxh+fcr6J3ERERyUdJVg7uzuJ1i2me3Nz36UAVvYuIiEgeSrJy+PuWv/Purnf7PFWooncREREpRElWDsXUY6noXURERPJRkpVDa1srjQ2NTDpgUs79KnoXERGRQpRk9RKJRXh2/bM0T2nus4+K3kVERKQQJVm9vPT2S3SEOvo8VQjxmiwVvYuIiEg+RSVZZjbXzP5uZm+Y2fwc+6eY2ZNm9qKZLTezf060N5pZl5ktS3z9R38/gP7Wui5ej9U8OfdMlrtjZip6FxERkbyyrxfTi5kFgR8CZwDrgefN7AF3X5nW7Xrg1+7+YzObATwMNCb2venuM/s16gHU2tbKjINnMKZuTM79KnoXERGRYhQzk3Ui8Ia7r3b3ELAIOLtXHwcOSGw3ABv7L8T9pyvcxdKNS/OeKlTRu4iIiBSj4EwWMBFYl3Z7PXBSrz43An8xsy8DI4DT0/ZNM7MXgR3A9e7+VO8fYGbzgHkA48aNo6Wlpdj494rjhKIhApaZY76w7QV6oj1M6Z7CK8+/kvPYmMeoDFRmHbuvOjs7B/xxD3Uao/w0PvlpfArTGOWn8SlMY5SpmCSrGBcA97j7d8zsFOBeM3s/sAmY4u5bzOwE4PdmdpS770g/2N0XAAsAmpqafPbs2f0UVm7haJi3tr9FfVV9RvsDTz1ARaCC8+acx4iqETmP7ejpYNqB06gKVvVrTC0tLQz04x7qNEb5aXzy0/gUpjHKT+NTmMYoUzHTMRuAyWm3JyXa0n0W+DWAuz8D1AAHuXuPu29JtC8F3gRyXwxwEGhta+W4Q47rM8FS0buIiIgUq5gk63lguplNM7Mq4HzggV592oDTAMzsSOJJ1rtmdnCicB4zOxSYDqzur+D7U3t3O8vfWV6wHktF7yIiIlKMgqcL3T1iZpcDfwaCwF3u/oqZ3QQscfcHgK8CPzGzq4gXwV/i7m5mHwBuMrMwEAMudfetA/Zo9sEz658h5rGCSVZDdcN+jEpERESGqqJqstz9YeLLMqS3fSNteyWQtbCUu/8G+M0+xrhftLa1UltRy/Hjj++zj1Z6FxERkWJpxfeE1rZWTp50ct6Cdq30LiIiIsVSkgW83fk2r299veCldAIWUNG7iIiIFEVJFrC4bTFAwXqs6opqFb2LiIhIUZRkEb9e4YE1BzLj4Bl99onEIoyozL20g4iIiEhvZZ9kuTutba2cOvnUvKu4Rz1KTUXNfoxMREREhrKyT7Le2v4WGzs25j1VCCp6FxERkT1T9klWa1srkL8eS0XvIiIisqeUZLW1MmHkBKaNmtZnHxW9i4iIyJ4q6yQr5jGeXvc0s6bMyptAqehdRERE9lRZJ1kr313Jtu5tzJqcvx4rec1CERERkWKVdZKVrMdqnpJ1RaAsKnoXERGRPVH2Sdb00dM5pP6QPvuo6F1ERET2RtkmWaFoiGfXP1tw6QYVvYuIiMjeKNska/nm5XRFuopKslT0LiIiInuqbJOsZ9Y9Q8ACnDLplLz9VPQuIiIie6Nsk6yn1z/NMWOPoaGmoWBfFb2LiIjInirLJKsz1MnyzcuLupSOit5FRERkb5RdkrVwxUKOuPMIIrEIi15exG9X/bbPvip6FxERkb1VUeoA9qeFKxYy78F57ArvAuC9rve45tFrADj3yHOz+kdiEUbVjNqfIYqIiMgwUVYzWdc9fl0qwUrqinRxa+utOfur6F1ERET2VlklWW3tbTnbN3Zs7PMYFb2LiIjI3iirJGtKw5Sc7RNGTshqU9G7iIiI7IuySrJuPu1m6irrMtpqK2qZP2t+Vl8VvYuIiMi+KKsk68KjL2TBRxYwpWEKhjFx5ERuP+P2nEXv4VhYK72LiIjIXiurTxdCPNE6b8Z5vLX9Leqr6vvsF41FVfQuIiIie62sZrL2hJmp6F1ERET2mpKsHNwdw1T0LiIiIntNSVYOyfWxVPQuIiIie0tJVg7hWDjrU4giIiIie0JJVg4qehcREZF9pSQrBxW9i4iIyL5SktWLit5FRESkPxSVZJnZXDP7u5m9YWZZy6Ob2RQze9LMXjSz5Wb2z2n7rk0c93cz+3B/Bj8QVPQuIiIi/aFgkmVmQeCHwJnADOACM5vRq9v1wK/d/TjgfOBHiWNnJG4fBcwFfpS4v0FLRe8iIiLSH4qZyToReMPdV7t7CFgEnN2rjwMHJLYbgI2J7bOBRe7e4+5vAW8k7m/QUtG7iIiI9Adz9/wdzD4GzHX3zyVuXwSc5O6Xp/UZD/wFOBAYAZzu7kvN7E7gWXf/ZaLfz4A/ufv9vX7GPGAewLhx405YtGhRfz2+nBwnFA0RsOwcM+YxqoJVGPv3dGFnZyf19X1f5kc0RoVofPLT+BSmMcpP41NYOY7RnDlzlrp7U659/XXtwguAe9z9O2Z2CnCvmb2/2IPdfQGwAKCpqclnz57dT2HlFo6Gc1670N3ZFd7FYaMP2+81WS0tLQz04x7qNEb5aXzy0/gUpjHKT+NTmMYoUzFJ1gZgctrtSYm2dJ8lXnOFuz9jZjXAQUUeO2io6F1ERET6SzE1Wc8D081smplVES9kf6BXnzbgNAAzOxKoAd5N9DvfzKrNbBowHXiuv4Lvbyp6FxERkf5ScCbL3SNmdjnwZyAI3OXur5jZTcASd38A+CrwEzO7ingR/CUeL/Z6xcx+DawEIsBl7h4dqAezr1T0LiIiIv2lqJosd38YeLhX2zfStlcCzX0cezNw8z7EuN9opXcRERHpL1rxPUErvYuIiEh/UpKVoKJ3ERER6U9KshJU9C4iIiL9SUlWQiwWU9G7iIiI9BslWUmGit5FRESk3yjJQkXvIiIi0v+UZBGvx1LRu4iIiPQnJVnEP1mooncRERHpT0qyUNG7iIiI9D8lWaCidxEREel3ZZ9kqehdREREBkLZJ1kqehcREZGBUPZJloreRUREZCBUlDqAYoTDYdavX093d3e/3J+7E4lFCFmImMfoCfTwjr3TL/e9txoaGli1alVJYxgMampqmDRpEpWVOn0rIiJD25BIstavX8/IkSNpbGzsl9N6MY8RioYIWICYx6gKVhGw0k7qdXR0MHLkyJLGUGruzpYtW1i/fj3Tpk0rdTgiIiL7ZEicLuzu7mbMmDEDVjdlqB5rMDAzxowZ028zliIiIqU0JJIsYEASLHcnQEBF74OIfhciIjJcDJkkayA4XvLThCIiIjI8DcsMY+GKhTR+r5HA/w7Q+L1GFq5YmLujFzdzsmXLFmbOnMnMmTM55JBDmDhxYup2KBTKe+ySJUu44oorCv6M008/vWAfERERGTqGROH7nli4YiHzHpzHrvAuANa2r2Xeg/MAuPDoCzM7W3FJ1pgxY1i2bBkAN954I/X19Xzta19L7Y9EIlRU5B7KpqYmmpqaCv6Mxx57rGCfwSYajRIMBksdhoiIyKA05JKsKx+5kmVvL+tz/7Prn6Un2pPRtiu8i8/+4bP8ZOlPUm0xjwEQsAAzD5nJ9+Z+b4/iuOSSS6ipqeHFF1+kubmZ888/n6985St0d3dTW1vL3XffzRFHHEFLSwt33HEHDz30EDfeeCNtbW2sXr2atrY2rrzyytQs1/jx4+ns7KSlpYUbb7yRgw46iJdffpkTTjiBX/7yl5gZDz/8MFdffTUjRoygubmZ1atX89BDD2XEtWbNGi666CJ27twJwJ133smpp54KwG233cYvf/lLAoEAZ555JrfeeitvvPEGl156Ke+++y7BYJD77ruPdevWpWIGuPzyy2lqauKSSy6hsbGRT3ziEzz66KNcc801dHR0sGDBAkKhEIcddhj33nsvdXV1bN68mUsvvZTVq1cD8OMf/5hHHnmE0aNHc+WVVwJw3XXXMXbsWL7yla/s0diLiIgMBUMuySqkd4KVr31fP1W4fv16nn76aYLBIDt27OCpp56ioqKCxx57jK9//ev85je/yTrm1Vdf5cknn6Sjo4MjjjiCL37xi1lrQr344ou88sorTJgwgebmZhYvXkxTUxNf+MIX+Otf/8q0adO44IILcsY0duxYHn30UWpqanj99de54IILWLJkCX/605/4wx/+wN/+9jfq6urYunUrABdeeCHz58/nnHPOobu7m1gsxrp16/I+7jFjxvDCCy8A8VOpn//85wG4/vrr+dnPfsaXv/xlrrjiCv7pn/6J3/3ud0SjUTo7O5kwYQLnnnsuV155JbFYjEWLFvHcc8/t8biLiIgMBUMuySo049T4vUbWtq/Nap/aMJWWS1qA+CxWT6SHymAlFYG9H4KPf/zjqdNl7e3tXHzxxbz++uuYGeFwOOcx//Iv/0J1dTXV1dWMHTuWzZs3M2nSpIw+J554Yqpt5syZrFmzhvr6eg499NDU+lEXXHABCxYsyLr/cDjM5ZdfzrJlywgGg7z22mtA/HTkpz/9aerq4qvbjx49mo6ODjZs2MA555wDxBcCLcYnPvGJ1PbLL7/M9ddfz/bt2+ns7OTDH/4wAE888QS/+MUvAAgGgzQ0NNDQ0MCYMWN48cUX2bx5M8cddxxjxowp6meKiIgMNcOu8P3m027OukxOXWUdN592c1bffZ3JGjFiRGr7hhtuYM6cObz88ss8+OCDfa71VF1dndoOBoNEIpG96tOX7373u4wbN46XXnqJJUuWFCzMz6WiooJYLJa63fuxpD/uSy65hDvvvJMVK1bwzW9+s+AaV5/73Oe45557uPvuu/nMZz6zx7GJiIgMFcMuybrw6AtZ8JEFTG2YimFMbZjKgo8syCp6N7N+XZOpvb2diRMnAnDPPff02/0mHXHEEaxevZo1a9YA8F//9V99xjF+/HgCgQD33nsv0WgUgDPOOIO7776bXbviHwjYunUrI0eOZNKkSfz+978HoKenh127djF16lRWrlxJT08P27dv5/HHH+8zro6ODsaPH084HGbhwt2f4jzttNP48Y9/DMQL5Nvb2wE455xzeOSRR3j++edTs14iIiLD0bBLsiCeaK25cg2xb8ZYc+Wa7E8VEp/F6s+V3q+55hquvfZajjvuuD2aeSpWbW0tP/rRj5g7dy4nnHACI0eOpKGhIavfl770JX7+859z7LHH8uqrr6ZmnebOnctZZ51FU1MTM2fO5I477gDg3nvv5Qc/+AHHHHMMp556Km+//TaTJ0/mvPPO4/3vfz/nnXcexx13XJ9xfetb3+Kkk06iubmZ973vfan273//+zz55JMcffTRnHDCCaxcuRKAqqoq5syZw3nnnadPJoqIyLBm7l7qGDI0NTX5kiVLMtpWrVrFkUce2W8/w92JenSf6rH6WzHXLuzs7KS+vh5357LLLmP69OlcddVV+ynC/hGLxTj++OO57777mD59es4+ff2+W1pamD179gBHOHRpfPLT+BSmMcpP41NYOY6RmS1195xrNQ3LmaxCzGxQJVjF+slPfsLMmTM56qijaG9v5wtf+EKpQ9ojK1eu5LDDDuO0007rM8ESEREZLoZeplHGrrrqqiE3c5VuxowZqXWzREREhrshM5M12E5rysDQ71lERIaLIZFk1dTUsGXLFr0AD3PuzpYtW4per0tERGQwGxKnCydNmsT69et59913Sx3KgOnu7lZyQTyh7r04q4iIyFBUVJJlZnOB7wNB4Kfufmuv/d8F5iRu1gFj3X1UYl8UWJHY1+buZ+1pkJWVlamVzoerlpaWvEsliIiIyNBSMMkysyDwQ+AMYD3wvJk94O4rk33c/aq0/l8G0rOFLnef2W8Ri4iIiAwBxdRknQi84e6r3T0ELALOztP/AuBX/RGciIiIyFBVcDFSM/sYMNfdP5e4fRFwkrtfnqPvVOBZYJK7RxNtEWAZEAFudfff5zhuHjAPYNy4cScsWrRoHx7S0JRcaFT6pjHKT+OTn8anMI1RfhqfwspxjObMmdPnYqT9Xfh+PnB/MsFKmOruG8zsUOAJM1vh7m+mH+TuC4AFAGb27pw5c9b2c1xDwUHAe6UOYpDTGOWn8clP41OYxig/jU9h5ThGU/vaUUyStQGYnHZ7UqItl/OBy9Ib3H1D4vtqM2shXq/1Zvahqf4HFxHTsGNmS/rKhCVOY5Sfxic/jU9hGqP8ND6FaYwyFVOT9Tww3cymmVkV8UTqgd6dzOx9wIHAM2ltB5pZdWL7IKAZWNn7WBEREZHhpuBMlrtHzOxy4M/El3C4y91fMbObgCXunky4zgcWeWaR15HA/29mMeIJ3a3pn0oUERERGa6Kqsly94eBh3u1faPX7RtzHPc0cPQ+xFdOFpQ6gCFAY5Sfxic/jU9hGqP8ND6FaYzSFPx0oYiIiIjsuSFx7UIRERGRoUZJloiIiMgAUJJVYmY22cyeNLOVZvaKmX2l1DENRmYWNLMXzeyhUscyGJnZKDO738xeNbNVZnZKqWMaTMzsqsT/18tm9iszK/ursZvZXWb2jpm9nNY22sweNbPXE98PLGWMpdTH+Hw78T+23Mx+Z2ajShhiyeUao7R9XzUzT6wsULaUZJVeBPiqu88ATgYuM7MZJY5pMPoKsKrUQQxi3wcecff3AceisUoxs4nAFUCTu7+f+Kekzy9tVIPCPcDcXm3zgcfdfTrweOJ2ubqH7PF5FHi/ux8DvAZcu7+DGmTuIXuMMLPJwIeAtv0d0GCjJKvE3H2Tu7+Q2O4g/uI4sbRRDS5mNgn4F+CnpY5lMDKzBuADwM8A3D3k7ttLGtTgUwHUmlkFUAdsLHE8JefufwW29mo+G/h5YvvnwEf3Z0yDSa7xcfe/uHskcfNZ4otzl60+/oYAvgtcA5T9J+uUZA0iZtZIfEX8v5U4lMHme8T/YWMljmOwmga8C9ydOKX6UzMbUeqgBovEVSfuIP6uehPQ7u5/KW1Ug9Y4d9+U2H4bGFfKYAa5zwB/KnUQg42ZnQ1scPeXSh3LYKAka5Aws3rgN8CV7r6j1PEMFmb2P4F33H1pqWMZxCqA44Efu/txwE7K+zRPhkRd0dnEk9EJwAgz+1Rpoxr8EgtLl/1MRC5mdh3xUo+FpY5lMDGzOuDrwDcK9S0XSrIGATOrJJ5gLXT335Y6nkGmGTjLzNYAi4APmtkvSxvSoLMeWO/uyRnQ+4knXRJ3OvCWu7/r7mHgt8CpJY5psNpsZuMBEt/fKXE8g46ZXQL8T+BC10KTvf0P4m9mXko8Z08CXjCzQ0oaVQkpySoxMzPitTSr3P3/K3U8g427X+vuk9y9kXix8hPurlmINO7+NrDOzI5INJ2GrhGarg042czqEv9vp6EPBvTlAeDixPbFwB9KGMugY2ZziZcunOXuu0odz2Dj7ivcfay7Nyaes9cDxyeeo8qSkqzSawYuIj5Dsyzx9c+lDkqGnC8DC81sOTAT+PfShjN4JGb47gdeAFYQf94r+0t/mNmvgGeAI8xsvZl9FrgVOMPMXic+A3hrKWMspT7G505gJPBo4rn6P0oaZIn1MUaSRpfVERERERkAmskSERERGQBKskREREQGgJIsERERkQGgJEtERERkACjJEhERERkASrJEZEgxs2jacifLzKzfVrc3s0Yze7m/7k9EyltFqQMQEdlDXe4+s9RBiIgUopksERkWzGyNmd1uZivM7DkzOyzR3mhmT5jZcjN73MymJNrHmdnvzOylxFfyUjtBM/uJmb1iZn8xs9qSPSgRGdKUZInIUFPb63ThJ9L2tbv70cRX5v5eou3/Aj9392OIX9D3B4n2HwD/7e7HEr/W4yuJ9unAD939KGA78K8D+mhEZNjSiu8iMqSYWae71+doXwN80N1XJy66/ra7jzGz94Dx7h5OtG9y94PM7F1gkrv3pN1HI/Cou09P3P5fQKW7/5/98NBEZJjRTJaIDCfex/ae6EnbjqLaVRHZS0qyRGQ4+UTa92cS208D5ye2LwSeSmw/DnwRwMyCZtawv4IUkfKgd2giMtTUmtmytNuPuHtyGYcDzWw58dmoCxJtXwbuNrN/A94FPp1o/wqwwMw+S3zG6ovApoEOXkTKh2qyRGRYSNRkNbn7e6WORUQEdLpQREREZEBoJktERERkAGgmS0RERGQAKMkSERERGQBKskREREQGgJIsERERkQGgJEtERERkAPw/iuvDiJH3xqQAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlMAAAEGCAYAAABB6hAxAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAA9lElEQVR4nO3deXxcZd338c+VNE3SpA20paV7QUC2UrqICyKtiAJisRWBiktZrFtBkK2IL1QUKYtsgmjZb+S5I2JBvGW1UryfB5FNUVpA21KhCyVJSZo0k2SW6/njyulMkkkySWbmnDPzfb9e85qZM5M515w2M99cy+8Yay0iIiIiMjglfjdAREREJMwUpkRERESGQGFKREREZAgUpkRERESGQGFKREREZAiG+bXjsWPH2unTp/u1e9/s2rWLqqoqv5sRWDo+/dMx6puOT/90jPqm49O3Yj0+L730Ur21dq90j/kWpqZPn86LL77o1+59s2bNGubNm+d3MwJLx6d/OkZ90/Hpn45R33R8+lasx8cY85/eHtMwn4iIiMgQKEyJiIiIDIHClIiIiMgQ+DZnSkRExG/RaJTNmzfT1ta2e1tNTQ2vvfaaj60KtkI/PhUVFUyePJmysrKMf0ZhSkREitbmzZsZOXIk06dPxxgDQHNzMyNHjvS5ZcFVyMfHWktDQwObN29mn332yfjnNMwnIiJFq62tjTFjxuwOUlLcjDGMGTOmS09lJhSmRESkqClISarB/H9QmBIREREZAoUpEZFiEY9DUxPEYtDa6u6Lr+bPn88TTzzRZduNN97IN77xjV5/Zt68ebuLXp9wwgk0Njb2eM4PfvADrrvuuj73/fDDD7Nu3brd9y+//HL++Mc/DqD14lGYEhEpdPE4vPcevPkmbN/u7r/9NqxfD//5j3usrQ0SCb9bGnz33w/Tp0NJibu+//4hvdzixYupra3tsq22tpbFixdn9POPPvooe+yxx6D23T1MXXHFFXziE58Y1Gv5JR6QPwgUpkREClUsBjt2wMaNUFcHFRVQXe2CwMiR7gJQX+9C1fr1sGUL7NwJ7e1grb/tD5r774elS92xstZdL106pEB18skn84c//IGOjg4ANm3axNatWznqqKP4xje+wdy5cznkkEP4/ve/n/bnp0+fTn19PQBXXnklBxxwAB/96Ed54403dj/n9ttv5wMf+AAzZ87kc5/7HK2trTz77LM88sgjXHTRRRx++OFs2LCBJUuW8OCDDwKwevVqZs2axYwZMzjzzDNpb2/fvb8rr7yS2bNnM2PGDF5//fUebdq0aRNHHXUUs2fPZvbs2Tz77LO7H7v66quZMWMGM2fOZPny5QCsX7+eT3ziE8ycOZPZs2ezYcMG1qxZw4knnrj755YtW8Y999yzuw2XXHIJs2fP5je/+U3a9wewfft2Fi5cyMyZM5k5cybPPvssl19+OTfeeOPu173sssu46aabBvRvlo5KI4iIFJpYDBobXZAyBiorXYBKp6zMXcAFhI4OeOcdd7+kxIWv6mooL08+r1Cddx78/e9UxuNQWtrz8eeecyEzVWsrnHUW3H57+tc8/HBI+fLubvTo0RxxxBE89thjnHTSSdTW1nLKKadgjOHKK69k9OjRxONxjjnmGP7xj39w2GGHpX2dl156idraWv7+978Ti8WYPXs2c+bMAWDRokV89atfBeB73/sed955J+eccw4LFizgxBNP5OSTT+7yWm1tbSxZsoTVq1dzwAEH8OUvf5nbbruN8847D4AxY8bw8ssv8/Of/5zrrruOO+64o8vPjxs3jqeeeoqKigr+/e9/s3jxYl588UUee+wxfve73/HXv/6VESNGsGPHDgBOP/10li9fzsKFC2lrayORSPD222/3esxS2wDQ0NCQ9v2de+65HH300Tz00EPE43FaWlqYOHEiixYt4rzzziORSFBbW8vzzz/f574yoZ4pEZFCEY26XqaNG12YGjECqqp6D1LdGeNCkxegKipcWNi61Q0RbtzoXr9Y51t1D1L9bc9Q6lBf6hDfAw88wOzZs5k1axZr167tMiTX3f/+7/+ycOFCRowYwahRo1iwYMHux1599VWOOuooZsyYwf3338/atWv7bM8bb7zBPvvswwEHHADAV77yFf785z/vftx77Tlz5rBp06YePx+NRvnqV7/KjBkz+PznP7+73X/84x8544wzGDFiBOCCZHNzM1u2bGHhwoWAK5jpPd6XU089td/396c//Wn33LPS0lJqamqYPn06Y8aM4W9/+xtPPvkks2bNYsyYMf3urz/qmRIRCbuODheeGhtdIKqqctdDVVLiApXHm8De2aNARYUbKqyshOHDMw9tQdXZgxTprSjl9OluaK+7adNgzZpB7/akk07i/PPP5+WX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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "from glob import glob\n", - "import json, re\n", - "import os, sys\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "sys.path.append('..')\n", - "\n", - "# Plane Options: ['axial', 'coronal', 'sagittal', 'combined']\n", - "plane = 'combined'\n", - "\n", - "ROOTDIR = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128'\n", - "files = glob(ROOTDIR + '/model_save_dir_F15/train_test_fold*/metrics/' + plane + '*')\n", - "\n", - "# files = glob( '../metrics/CV/train_test_fold*/metrics/' + plane + '*' )\n", - "\n", - "all_metrics = {}\n", - "for file in files:\n", - " fold = file.split('/')[-3].split('fold_')[-1]\n", - " all_metrics[int(fold)] = json.load(open(file))\n", - " \n", - "train_acc_arr = []\n", - "val_acc_arr = []\n", - "train_loss_arr = []\n", - "val_loss_arr = []\n", - "\n", - "print(\"Available Metrics: \", all_metrics[1].keys())\n", - "\n", - "def get_metrics_hist(all_metrics, metric='accuracy', n_folds=15):\n", - " arr = []\n", - " for i in range(1, n_folds+1):\n", - " metrics = all_metrics[i]\n", - " temp = list(range(n_folds))\n", - " for j in range(len(temp)):\n", - " temp[j] = metrics[metric][str(j)]\n", - "\n", - " arr.append(temp) \n", - " return np.array(arr)\n", - "\n", - "train_acc_arr = get_metrics_hist(all_metrics)\n", - "print(train_acc_arr.shape)\n", - "val_acc_arr = get_metrics_hist(all_metrics, metric='val_accuracy')\n", - "train_loss_arr = get_metrics_hist(all_metrics, metric='loss')\n", - "val_loss_arr = get_metrics_hist(all_metrics, metric='val_loss')\n", - "\n", - "plot(train_acc_arr, label='Training accuracy', n_folds=15)\n", - "plot(val_acc_arr, label='Validation accuracy', color='r', n_folds=15)\n", - "plot(train_loss_arr, label='Training loss', n_folds=15)\n", - "plot(val_loss_arr, label='Validation loss', color='r', n_folds=15)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[0.50375 0.50458333 0.49791667 0.49125 0.5 0.51666667\n", - " 0.5925 0.67041667 0.79958333 0.92875 0.98708332 0.98666666\n", - " 0.99291666 0.99375 0.99208333]\n", - "[0.02150581 0.01280191 0.01640419 0.01510381 0.01547848 0.05091182\n", - " 0.14558073 0.17579383 0.18200943 0.10512393 0.01803739 0.02737345\n", - " 0.01247219 0.01094493 0.01174083]\n" - ] - } - ], - "source": [ - "print(np.mean(val_acc_arr, axis=0))\n", - "print(np.std(val_acc_arr, axis=0))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## From tensorboard logs\n", - "\n", - "Plots and logs at https://tensorboard.dev/experiment/6PdJ4SokT4mTGVvNRS64dA/" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
runtagstepvalue
0train_test_fold_1/tb_logs/axial/trainepoch_accuracy00.948815
1train_test_fold_1/tb_logs/axial/trainepoch_accuracy10.994073
2train_test_fold_1/tb_logs/axial/trainepoch_accuracy20.988147
3train_test_fold_1/tb_logs/axial/trainepoch_accuracy30.996767
4train_test_fold_1/tb_logs/axial/trainepoch_accuracy40.995690
...............
16195train_test_fold_9/tb_logs/sagittal/validationepoch_tp1070.000000
16196train_test_fold_9/tb_logs/sagittal/validationepoch_tp1171.000000
16197train_test_fold_9/tb_logs/sagittal/validationepoch_tp1271.000000
16198train_test_fold_9/tb_logs/sagittal/validationepoch_tp1375.000000
16199train_test_fold_9/tb_logs/sagittal/validationepoch_tp1470.000000
\n", - "

16200 rows × 4 columns

\n", - "
" - ], - "text/plain": [ - " run tag step \\\n", - "0 train_test_fold_1/tb_logs/axial/train epoch_accuracy 0 \n", - "1 train_test_fold_1/tb_logs/axial/train epoch_accuracy 1 \n", - "2 train_test_fold_1/tb_logs/axial/train epoch_accuracy 2 \n", - "3 train_test_fold_1/tb_logs/axial/train epoch_accuracy 3 \n", - "4 train_test_fold_1/tb_logs/axial/train epoch_accuracy 4 \n", - "... ... ... ... \n", - "16195 train_test_fold_9/tb_logs/sagittal/validation epoch_tp 10 \n", - "16196 train_test_fold_9/tb_logs/sagittal/validation epoch_tp 11 \n", - "16197 train_test_fold_9/tb_logs/sagittal/validation epoch_tp 12 \n", - "16198 train_test_fold_9/tb_logs/sagittal/validation epoch_tp 13 \n", - "16199 train_test_fold_9/tb_logs/sagittal/validation epoch_tp 14 \n", - "\n", - " value \n", - "0 0.948815 \n", - "1 0.994073 \n", - "2 0.988147 \n", - "3 0.996767 \n", - "4 0.995690 \n", - "... ... \n", - "16195 70.000000 \n", - "16196 71.000000 \n", - "16197 71.000000 \n", - "16198 75.000000 \n", - "16199 70.000000 \n", - "\n", - "[16200 rows x 4 columns]" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "from matplotlib import pyplot as plt\n", - "import seaborn as sns\n", - "from scipy import stats\n", - "import tensorboard as tb\n", - "\n", - "experiment_id = \"6PdJ4SokT4mTGVvNRS64dA\"\n", - "experiment = tb.data.experimental.ExperimentFromDev(experiment_id)\n", - "df = experiment.get_scalars()\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Available Metrics: ['epoch_accuracy' 'epoch_auc' 'epoch_fn' 'epoch_fp' 'epoch_loss'\n", - " 'epoch_precision' 'epoch_recall' 'epoch_tn' 'epoch_tp']\n" - ] - } - ], - "source": [ - "import numpy as np\n", - "print(\"Available Metrics: \", df['tag'].unique())\n", - "\n", - "def get_metrics_tb(df, metric='epoch_accuracy', n_epochs = 15, n_folds=15, plane='combined', run='train'):\n", - " \n", - " temp = df[df[\"run\"].str.contains(plane + '/' + run)]\n", - " m = temp[temp[\"tag\"].str.contains(metric)]\n", - "\n", - " arr = []\n", - " for i in range(1, n_epochs+1):\n", - " fold_i = m[m[\"run\"].str.match('train_test_fold_' + str(i) + '/')]\n", - " arr.append(fold_i['value'].tolist())\n", - " \n", - " return np.array(arr)\n", - "\n", - "train_acc_arr = get_metrics_tb(df)\n", - "val_acc_arr = get_metrics_tb(df, metric='epoch_accuracy', run='validation')\n", - "train_loss_arr = get_metrics_tb(df, metric='epoch_loss', run='train')\n", - "val_loss_arr = get_metrics_tb(df, metric='epoch_loss', run='validation')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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N9ELwLOdz7L6ntUArFy8sqT/cA5PzZgxg82bNwNw4403MmXKFD72sY/l9ieTSSKR8kPZ3NxMc3PzkPfxq1/9asg+400qlSIcDlc6DBERkXHpiEuyrvr5VWx+fvOA+/+w8w/EU/GCtt5EL+/66bv4+sNfz7UFHgAQshBLjlnCrRfeOqI4Vq1aRU1NDZs2beLss8/msssu4yMf+QixWIza2lpuv/12TjrpJFpbW/nSl77Evffey4033siOHTt4+umn2bFjB1dddVVulmvOnDn09PTQ2trKjTfeyMyZM3n88cc544wz+O53v4uZcd999/HRj36U+vp6zj77bJ5++mnuvffegrieeeYZrrjiCvbv3w/Abbfdxqtf/WoAvvCFL/Dd736XUCjERRddxC233MJTTz3F+973Pvbs2UM4HOY//uM/eO6553IxA1x55ZU0NzezatUqFi5cyKWXXsr999/PJz7xCbq7u1m7di39/f0cf/zxfOc736Guro7du3fzvve9j6effhqAr33ta/z85z9n+vTpXHXVVQBce+21zJo1i4985CMjGnsREZEjwRGXZA2lOMEarP1QzyrcuXMn//M//0M4HKarq4vf/va3RCIRfvWrX/HpT3+aH/3oRyXX+eMf/8gDDzxAd3c3J510Eu9///tL1oTatGkTW7duZe7cuZx99tn87ne/o7m5mfe+9708+OCDHHfccVx++eVlY5o1axb3338/NTU1/OlPf+Lyyy9n48aN/Nd//Rc//elPeeihh6irq+Oll14CYOXKlVxzzTVccsklxGIxgiDgueeeG/Rxz5gxg0ceeQRIH0p9z3veA8B1113HN7/5TT70oQ/x4Q9/mNe+9rX85Cc/IZVK0dPTw9y5c1mxYgVXXXUVQRCwbt062traRjzuIiIiR4JhJVlmdiHwFSAMfMPdbynafyzwbWBaps817n6fmUWBbwBLM/d1p7t//lACHmrGaeGtC3m289mS9gWNC2hd1QqkZ7HiyTjRcJRI6ODzzLe97W25w2WdnZ28/e1v509/+hNmRiKRKHudN77xjVRXV1NdXc2sWbPYvXs38+bNK+jT0tKSa1uyZAnPPPMMU6ZM4RWveEVu/ajLL7+ctWvXltx+IpHgyiuvZPPmzYTDYbZv3w6kD0e+4x3voK4uvbr99OnT6e7upr29nUsuuQRILwQ6HJdeemlu+/HHH+e6665j37599PT08IY3vAGAX//619x5550AhMNhGhsbaWxsZMaMGWzatIndu3dz+umnM2PGjGHdp4iIyJFmyMJ3MwsDXwUuAhYBl5vZoqJu1wE/dPfTgcuA/5NpfxtQ7e6LgTOA95rZwlGKvaw1560p+Zqcumgda85bU9L3UGey6uvrc9vXX3895557Lo8//jj33HPPgGs9VVdX57bD4TDJZPKg+gzkX//1X5k9ezaPPvooGzduHLIwv5xIJEIQBLnLxY8l/3GvWrWK2267jS1btnDDDTcMucbVu9/9bu644w5uv/123vnOd444NhERkSPFcM4ubAGecven3b0fWAe8uaiPA1Mz241AR157vZlFgFqgH+g65KgHsXLxSta+aS0LGhdgGAsaF7D2TWtLit7NbFTXZOrs7KSpqQmAO+64Y9RuN+ukk07i6aef5plnngHgBz/4wYBxzJkzh1AoxHe+8x1SqRQAr3/967n99tvp7U2fEPDSSy/R0NDAvHnz+M///E8A4vE4vb29LFiwgCeeeIJ4PM6+fftYv379gHF1d3czZ84cEokEd9114CzO8847j6997WtAukC+s7MTgEsuuYSf//znbNiwITfrJSIiMhEN51hZE5BfpLMTOLOoz43AL83sQ0A9kF2P4G7SCdkuoA642t1fKr4DM1sNrAaYPXs2ra2tBfsbGxvp7u4eRqhpFy+8mIvfdXFBW/71HcfdSVj5Q3qDicfjRKNREokEfX19udv94Ac/yPve9z5uuukmLrjgAtyd7u5uent7SSaTdHd3566bvU4QBPT09OQuF/cH6O/vJxaLkUwm+Zd/+RcuuOAC6uvrWbp0KYlEomRc/vEf/5ErrriCO+64g/PPP5/6+nq6u7s5++yzecMb3sDSpUupqqriggsu4IYbbuBrX/saV111Fddddx3RaJRvf/vbHHfccbzlLW9h0aJFLFiwgMWLFxOLxeju7sbd6enpyc22XXvttbS0tDBjxgyam5tzj2fNmjV8+MMf5utf/zrhcJgvf/nLnHlm+mlzzjnn0NjYmEv4isVisZLnAJA7MUDK0/gMTuMzNI3R4DQ+Q9MYFXH3QX+At5Kuw8pevgK4rajPR4F/ymz/NfAE6Vmys4G7gCgwC3gSeMVg93fGGWd4sSeeeKKk7VAEQeCJVGJUb/NQdXV1Ddmnu7vb3dPxv//97/cvf/nLYx3WqEulUn7aaaf59u3bB+wz0L/3Aw88MEZRTQwan8FpfIamMRqcxmdok3GMgI0+QE4znMOF7cD8vMvzMm353gX8MJO0/R6oAWYC/wD83N0T7v4C8Dtg6EWjxpiZHVLBe6V8/etfZ8mSJZxyyil0dnby3ve+t9IhjcgTTzzB8ccfz3nnnccJJ5xQ6XBERETG1HAyjQ3ACWZ2HOnk6jLSyVO+HcB5wB1mdjLpJGtPpv11wHfMrB44C7h1dEKffK6++mquvvrqSodx0BYtWpRbN0tERGSiG3Imy92TwJXAL4BtpM8i3GpmN5lZtvDpn4D3mNmjwPeBVZkptK8CU8xsK+lk7XZ3f+xgAk3fnEx0+ncWEZGJYljHzNz9PuC+orbP5G0/Qbr+qvh6PaSXcTgkNTU17N27lxkzZozqGYEyvrg7e/fuHfZ6XSIiIuPZEVGYNG/ePHbu3MmePXsqHcqYicViSi5IJ9TFi7OKiIgciY6IJCsajeZWOp+oWltbOf300ysdhoiIiIyS4ZxdKCIiIiIjpCRLREREZAwoyRIREREZAzbeTpk3sz3As5WOowJmAi9WOohxTmM0OI3P4DQ+Q9MYDU7jM7TJOEYL3P3ocjvGXZI1WZnZRnev+Gr445nGaHAan8FpfIamMRqcxmdoGqNCOlwoIiIiMgaUZImIiIiMASVZ48faSgdwBNAYDU7jMziNz9A0RoPT+AxNY5RHNVkiIiIiY0AzWSIiIiJjQEmWiIiIyBhQklVhZjbfzB4wsyfMbKuZfaTSMY1HZhY2s01mdm+lYxmPzGyamd1tZn80s21m9teVjmk8MbOrM6+vx83s+2Y26b+N3cy+ZWYvmNnjeW3Tzex+M/tT5vdRlYyxkgYYn/+deY09ZmY/MbNpFQyx4sqNUd6+fzIzN7OZlYhtvFCSVXlJ4J/cfRFwFvBBM1tU4ZjGo48A2yodxDj2FeDn7v5XwGlorHLMrAn4MNDs7q8CwsBllY1qXLgDuLCo7RpgvbufAKzPXJ6s7qB0fO4HXuXupwLbgU8d7qDGmTsoHSPMbD5wAbDjcAc03ijJqjB33+Xuj2S2u0n/cWyqbFTji5nNA94IfKPSsYxHZtYI/A3wTQB373f3fRUNavyJALVmFgHqgI4Kx1Nx7v4g8FJR85uBb2e2vw285XDGNJ6UGx93/6W7JzMX/wDMO+yBjSMDPIcA/hX4BDDpz6xTkjWOmNlC4HTgoQqHMt7cSvoFG1Q4jvHqOGAPcHvmkOo3zKy+0kGNF+7eDnyJ9KfqXUCnu/+yslGNW7PdfVdm+3lgdiWDGefeCfxXpYMYb8zszUC7uz9a6VjGAyVZ44SZTQF+BFzl7l2Vjme8MLO/BV5w94crHcs4FgGWAl9z99OB/UzuwzwFMnVFbyadjM4F6s3s/6lsVOOfp9f3mfQzEeWY2bWkSz3uqnQs44mZ1QGfBj5T6VjGCyVZ44CZRUknWHe5+48rHc84czZwsZk9A6wDXmdm361sSOPOTmCnu2dnQO8mnXRJ2vnAX9x9j7sngB8Dr65wTOPVbjObA5D5/UKF4xl3zGwV8LfAStdCk8VeSfrDzKOZ9+x5wCNmdkxFo6ogJVkVZmZGupZmm7t/udLxjDfu/il3n+fuC0kXK//a3TULkcfdnweeM7OTMk3nAU9UMKTxZgdwlpnVZV5v56ETAwbyM+Dtme23Az+tYCzjjpldSLp04WJ37610POONu29x91nuvjDznr0TWJp5j5qUlGRV3tnAFaRnaDZnfv5XpYOSI86HgLvM7DFgCfC5yoYzfmRm+O4GHgG2kH7fm/Rf/WFm3wd+D5xkZjvN7F3ALcDrzexPpGcAb6lkjJU0wPjcBjQA92feq/+9okFW2ABjJHn0tToiIiIiY0AzWSIiIiJjQEmWiIiIyBhQkiUiIiIyBpRkiYiIiIwBJVkiIiIiY0BJlogcUcwslbfcyWYzG7XV7c1soZk9Plq3JyKTW6TSAYiIjFCfuy+pdBAiIkPRTJaITAhm9oyZfdHMtphZm5kdn2lfaGa/NrPHzGy9mR2baZ9tZj8xs0czP9mv2gmb2dfNbKuZ/dLMaiv2oETkiKYkS0SONLVFhwsvzdvX6e6LSa/MfWum7f8Fvu3up5L+Qt9/y7T/G/Abdz+N9Hc9bs20nwB81d1PAfYBfzemj0ZEJiyt+C4iRxQz63H3KWXanwFe5+5PZ750/Xl3n2FmLwJz3D2Rad/l7jPNbA8wz93jebexELjf3U/IXP4kEHX3zx6GhyYiE4xmskRkIvEBtkcinredQrWrInKQlGSJyERyad7v32e2/we4LLO9EvhtZns98H4AMwubWePhClJEJgd9QhORI02tmW3Ou/xzd88u43CUmT1Gejbq8kzbh4DbzezjwB7gHZn2jwBrzexdpGes3g/sGuvgRWTyUE2WiEwImZqsZnd/sdKxiIiADheKiIiIjAnNZImIiIiMAc1kiYiIiIwBJVkiIiIiY0BJloiIiMgYUJIlIiIiMgaUZImIiIiMgf8f3XrQjitZ4TgAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlMAAAEGCAYAAABB6hAxAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAA/NklEQVR4nO3deZxbZdk38N+VfbZOS1u6DbVlsUhZ2loWWVtUKIu0FHxoZRWhgqgIyENxAV8URUBAlFfEhe2t9lFkqbaIWJiCikJBtkLxAdqB6Uz3bTJ7kvv948ppMpnMJJOc5Jwkv+/nk89kkszJnTPJyXXu+7qvW4wxICIiIqLceJxuABEREVEpYzBFRERElAcGU0RERER5YDBFRERElAcGU0RERER58Dn1xKNGjTKTJk1y6ukd097ejpqaGqeb4VrcP5lxHw2O+ycz7qPBcf9kVon76OWXX95qjBmd7j7HgqlJkyZh9erVTj29YxobGzFr1iynm+Fa3D+ZcR8NjvsnM+6jwXH/ZFaJ+0hEmga6j8N8RERERHlgMEVERESUBwZTRERERHlwLGeKiIioUvT29qK5uRldXV1ON8UW9fX1ePvtt51uRkGEQiE0NDTA7/dn/TcMpoiIiAqsubkZdXV1mDRpEkTE6ebkra2tDXV1dU43w3bGGGzbtg3Nzc2YPHly1n/HYT4iIqIC6+rqwsiRI8sikCpnIoKRI0cOuQeRwRQREVERMJAqDbn8nxhMEREREeUhYzAlIvuIyLMi8paIrBGRK9M8RkTkbhF5V0ReF5EZhWku2aqnB9i2DTDG6ZYQEVEBzZ49G0899VSf2+666y5cfvnlA/7NrFmz9hTXPvXUU7Fz585+j/nOd76D22+/fdDnfvzxx/HWW2/t+f2GG27AX//61yG0Pr3GxkacfvrpeW/HDtn0TEUAXGOMOQjAUQCuEJGDUh5zCoAD4pdFAH5mayvJXsYAO3YA69YBmzdrUEVERO6xZAkwaRLg8ejPJUvy2tzChQuxdOnSPrctXboUCxcuzOrvV6xYgeHDh+f03KnB1E033YRPfepTOW3LrTIGU8aYVmPMK/HrbQDeBjAh5WFzATxk1D8BDBeRcba3lvLX1QU0NWkQVVMD+HxAR4fTrSIiIsuSJcCiRXqsNkZ/LlqUV0B19tlnY/ny5eiJnzyvX78eLS0tOO6443D55Zdj5syZmDp1Km688ca0fz9p0iRs3boVAHDzzTdj+vTpOPbYY/HOO+/secwvfvELHH744TjssMNw1llnoaOjA//4xz+wbNkyXHvttZg2bRree+89XHTRRXjkkUcAACtXrsT06dNxyCGH4OKLL0Z3d/ee57vxxhsxY8YMHHLIIVi7du2gr2/79u2YN28eDj30UBx11FF4/fXXAQCrVq3CtGnTMG3aNEyfPh1tbW1obW3F8ccfj2nTpuHggw/G888/n/N+tQypNIKITAIwHcC/Uu6aAODDpN+b47e1pvz9ImjPFcaMGYPGxsahtbYMhMNh5153JAJEo4CIXgD9oK5bBwQCzrQphaP7p0RwHw2O+ycz7qPBFWL/1NfXo62tDQAQvO46eN54Y8DHel96CRIPKvbo6ID5whcQvffetH8TO+QQdP/whwNu0+/3Y8aMGXj00Udx2mmn4cEHH8S8efMQDoexePFi7LXXXohGo/jMZz6DOXPm4OCDD0Y0GkV7ezva2tpgjEE4HMZbb72F3/zmN3juuedgjMFxxx2Hgw8+GG1tbfj0pz+NBQsWANDep3vuuQeXXXYZTjnlFMyZMwfz5s0DoDW3Ojs7sWXLFlx44YVYtmwZDjjgACxatAh33nknrrjiChhjUFtbi1WrVuEXv/gFfvCDH+CnP/1pyi7pQCQSQVtbG66//nocdNBBePjhh7Fq1Sqcd955+Pvf/45bbrkFt912G4466iiEw2FEIhHcf//9mDVrFq699lpEo1F0dHTs+d9Yurq6hvQeyDqYEpFaAH8A8DVjzO6snyGJMeY+APcBwMyZM02lLZIIOLQ4ZEcHsHGjBlM1NYlAytLWBuy3n/ZSOawSF88cKu6jwXH/ZMZ9NLhC7J+33347UZcpEAC83oEfnBpIxUl3N3wD/V0ggECGuk/nn38+nnjiCSxYsACPPfYYfvWrX6Gurg5LlizBfffdh0gkgtbWVjQ1NeETn/gEvF4vampqUFdXBxFBbW0tXnnlFZx11lmoq6tDXV0d5s2bh2AwiLq6Orzyyis4//zzsXPnToTDYZx88smoq6uD3+9HVVXVntdv/d7S0oJ9990XM2ZomvUll1yCe+65B4sXL4aI4HOf+xzq6upwzDHHYMWKFf3qWlVXV8Pn86Gurg4vvvgi/vCHP6Curg6nn346Lr/8chhjcMIJJ+Bb3/oWzj33XMyfPx8jRozAsccei4svvhgejwfz5s3DtGnT+u2rUCiE6dOnD7o/k2X17SkifmggtcQY82iah2wAsE/S7w3x28hJkQiwZQuwaxdQVQWEQukfJ6LDf7W1xW0fEVEluuuuwe+fNEmH9lJ95CNAHj1mc+fOxVVXXYVXXnkFHR0d+PjHP45169bh9ttvx0svvYQRI0bgoosuyrlK+0UXXYTHH38chx12GB544IG8e/eCwSAAwOv1IhKJ5LSNxYsX47TTTsOKFStwzDHH4KmnnsLxxx+P5557DsuXL8dFF12Eq6++GhdccEFebc1mNp8A+BWAt40xdwzwsGUALojP6jsKwC5jTOsAj6VCMwbYvVuH79rbgWHDgMHK4vt8+ngiInLezTcD1dV9b6uu1tvzUFtbi9mzZ+Piiy/ek3i+e/du1NTUoL6+Hps2bcKTTz456DaOP/54PP744+js7ERbWxv++Mc/7rmvra0N48aNQ29vL5Yk5XfV1dX1G0YDgClTpmD9+vV49913AQAPP/wwTjjhhJxe23HHHbfnORsbGzFq1CgMGzYM7733Hg455BBcd911OPzww7F27Vo0NTVhzJgxuPTSS3HJJZfglVdeyek5k2XTM3UMgPMBvCEir8Zv+waAiQBgjLkXwAoApwJ4F0AHgM/n3TLKTU8PsGmTDu1VVw/elWwJBoFwGIjFdOYIERE559xz9ec3vwl88AEwcaIGUtbteVi4cCHOPPPMPTP7DjvsMEyfPh0HHngg9tlnHxxzzDGD/v2MGTNwzjnn4Oijj8bYsWNx+OGH77nvu9/9Lo488kiMHj0aRx555J4AasGCBbj00ktx991370k8B3Qo7f7778dnP/tZRCIRHH744bjssstyel3f+c53cPHFF+PQQw9FdXU1HnzwQQBa/uHZZ5+Fx+PB1KlTccopp2Dp0qW47bbb4Pf7UVtbi4ceeiin50wmxqEaQzNnzjRW/YpKUrBchVhMh/O2bNEAqqpqaH8fDgP77DP0v7MZczky4z4aHPdPZtxHgytUztTHPvYxW7fppHJdm8+S7v8lIi8bY2ame7zzGceUv64uTTDv6dHeqFx6lzweHRJ0OJgiIiIqNRzTKWXRqPZErV+vv9fW5j5MFwwyb4qIiCgH7JkqVe3t2hsViwF1df3LHQyV1wt0dmrvlktqThERlRNjDBc7LgG5pD+xZ6rURCJAayvw4Yc6Qy9d3ah8dHbaty0iIgKgydbbtm3L6YuaiscYg23btiE0UCmhAbBnqlQYo8U1N23S4GnYMPufIxDQob76evu3TURUwRoaGtDc3IwtW7Y43RRbdHV1DTngKBWhUAgNDQ1D+hsGU6Wgu1vX0htKuYNcBAI6qy8aLdxzEBFVIL/fj8mTJzvdDNs0NjYOqUJ4uWMw5WaxGLBzpyaZ+/2aG1VoxujswJqawj8XERFRGWAw5VadnZobFYnoLL1iJS36fNo7xWCKiIgoK0xAd5toVIf0mpq0zEExAylASyS0tWkPFREREWXEnik3sRLMAXvKHeTC49GArrt74IWRiYiIaA8GU27Q26u9UW1tmmDuc/jf4vHoMCODKSIioowYTDnJGC1FsGmTzp4rRLmDXASDus7fiBFOt4SIiMj1GEw5pbtbK5hbM+dyXQamEHw+7SXr7dVZhERERDQgBlNO2LpVL8Fgccod5EJEAz4GU0RERINyUXdIBeju1rXvduzQICoYdLpFA/P7ufAxERFRFtgzVSzt7UBzs14vhRpOVjX0WMxdQ5BEREQuw2/JYti5UxcmrqpyptxBLkQ0Qb672+mWEBERuRqDqUIyRpeC2bhRi286XfJgqHw+7VEjIiKiATGYKpRoFGhpAbZv1/yoUhwqCwSYN0VERJRBCX7Dl4DeXh3W6+x0rpK5HbxefS09PU63hIiIyLUYTNmtqwv44APtmaqudro1+bOqoRMREVFaDKbsFA5rIOX1arJ5OfD7tRo6ERERpcVgyi47dmjpg6oqzTUqF4GA9kxFo063hIiIyJUYTOXLGF1bb9MmnbHn9TrdIvuJ6PAlERER9cNgKh/WjL1du0p3xl42vF5dq4+IiIj6KdNv/yJInrFXW1u6M/ayEQxqMGWM0y0hIiJyHQZTuejqApqadKmVcpixl4nHw2roREREA2AwNVRtbRpI+f1AKOR0a4pHBOjocLoVRERErsNgKlvGaDXzDRu0N8rvd7pFxRUMskQCERFRGgymshGLAZs36zp7dXXlOWMvE59P88R6e51uCRERkauU2Mq7DrBm7FlLw1S6zs7K65UjIiIaBHumBtPToxXNe3p0xl6l8/tZIoGIiCgFg6mBdHZqorkx5bM0TL4CAaC9XYc9iYiICACDqfR279YeqUCgsmbsZSKiwSWroRMREe2RMZgSkV+LyGYReXOA+2eJyC4ReTV+ucH+ZhaJNWOvpaUyZ+xlw+fT3ikiIiICkF3P1AMA5mR4zPPGmGnxy035N8sBsZiur7d5c+XO2MsGq6ETERH1kTGYMsY8B2B7EdrinEhE60ft3g0MG1beS8Pky+PR8gg9PU63hIiIyBXEZNHDICKTAPzJGHNwmvtmAfgDgGYALQC+boxZM8B2FgFYBABjxoz5+NKlS3Ntt32M0eDAmKIsVBzu6kJtqedhxWI63FeA3rtwOIxazpwcFPfR4Lh/MuM+Ghz3T2aVuI9mz579sjFmZrr77AimhgGIGWPCInIqgB8bYw7ItM2ZM2ea1atXZ3zugursBJqbNTAIBovylI1r1mDW1KlFea6C6e3V3ruJE23fdGNjI2bNmmX7dssJ99HguH8y4z4aHPdPZpW4j0RkwGAq764YY8xuY0w4fn0FAL+IjMp3uwW3e7eWPggGixZIlQ2/XwPRSMTplhARETku72BKRMaKaJKRiBwR3+a2fLdbMMYAW7fqjL3aWu2Votx0dzvdAiIiIsdljCRE5LcAZgEYJSLNAG4E4AcAY8y9AM4GcLmIRAB0Alhgshk7dII1Y2/3bp2xx0Tz3FnV0GtqnG4JERGRozIGU8aYhRnu/ymAn9rWokKxZux1d3ONPTtYJRLGjGFQSkREFa0yKqB3d2tF80iEa+zZRUR7+jjUR0REFa78g6mODk00F+Eae3bzenX/EhERVbDyDqa6urRHKhTijL1CCASAnTudbgUREZGjyjuYika1ECdn7BWGz6c1p3p7nW4JERGRY8o7mKLCE9GaU0RERBWKwRTlx+/XUhNEREQVisEU5ScQ0CT0WMzplhARETmCwRTlx6ox1dXlbDuIiIgcwmCK8uf1AuGw060gIiJyBIMpyl8wqHlTLl1FiIiIqJAYTFH+PB7NmerpcbolRERERcdgiuwhwmroRERUkRhMFcujjwJHHIETTj4ZOOII/b2cBAIskUBERBWJpcGL4dFHgf/+b6CzEwIAGzbo7wAwf76TLbOP369J6JEIK84TEVFFYc9UMdxyS/8q4Z2dens5MYYlEoiIqOIwmCq03l7tiUpnwwbgL38pnwDE7wfa2pxuBRERUVExmCqkN94ATjtt4PtFgM9/Hjj0UOCKK4AVK0p7nbtgUIf6WA2diIgqCIOpQujsBL73PQ2ktm4FLrkEqKrq+5iqKuDOO4Hf/AaYNw947jng0kuBQw4BvvhF4IkngPZ2R5qfMxENpLq7nW4JERFR0TBT2G5//7sml69fD3zuc8C3vgXU1wOHHQbccgtMSwtk/Hhg8eJE8vkJJwDf/z7wz38Cy5cDTz4J/OlPQCgEzJqlQdmnPgUMG+bkK8uO16slElKDRyIiojLFYMouu3YBN98MLFkCTJoE/O53wDHHJO6fPx+YPx+r1qzBrKlT+/+9zwcce6xevvc9YPVqDayWLwf+/GctPXDccRpYnXQSMGJE0V7akASDui9GjnS6JUREREXBYMoOTz4JfPObOqT3pS8BV1+dX8+M1wsceaRevvMd4JVXEoHVypWJwOu004A5c4C99rLtpeTN6pnq6dEAkIiIqMwxZyofmzdrntMllwCjRmmw881v2jvE5fEAM2cCN94I/Otf+hxf/CKwbh1w7bXAtGnAf/0X8OCD2h43ECmfGYpEREQZMJjKhTHA0qWaz7RypeY/LV+uyeOFJKLB0ze+oblZTz2lswBbW/W2GTOAs84Cfv1rvc0prIZOREQVhMHUUDU1AQsWANdcA3zsY8DTTwNf+YrWWComEeDgg4HrrtOZgCtXAlddBezcCXz729qbNXcu8POfA83NxW1bIKBDfdFocZ+XiIjIAQymshWJAPfeC5x4IvDaa1q9/Pe/B/bbz+mWaWB14IEa4K1cCaxatWf5Gtx0k+ZenXYa8H//r84yBPasFYiGhsKsFWgMSyQQEVFFYAJ6Nt56C/j61zWIOukkLWMwbpzTrRrY/vsDV16pl3XrtBjoihU62/DmmzWA2rhRA0SgMGsF+nxawLO62p7tERERuRR7pgbT1QX88IfAKadowPGzn2k+kpsDqVSTJ2te1fLlWsfqhhs0Ud0KpCx2rxUYDGrelDH2bZOIiMiFGEwN5MUXgZNPBu6+GzjzTODZZ4EzztAhtVK1zz46E7C3N/39LS32PZfHozlTPT32bZOIiMiFGEylamvTmXFnnqk5P7/5DXDXXe6q5ZSv8eOHdnuuPB5NRCciIipjDKaS/fWvwOzZwEMPae2olSt1qZdys3hx/1pYwaDebqdAQKuhExERlTEmoAPAtm2aS/T44zor7r77tGZTubKSzG+5RYf2RDS3yq7kc4vfrz19kYgmpBMREZWhyu6ZMgZ45BHtfVq+XGfsPflkeQdSlvnzNS+suVmHNdeuBV56yf7nYTV0IiIqc5UbTDU3A+efr+UD9t0X+MtftOhlJa4nd+GFujDxHXfYv22fj9XQiYiorGUMpkTk1yKyWUTeHOB+EZG7ReRdEXldRNzdrRONanmD2bN1rbvvfhd47DHgox91umXOqa7WBZqfe87+3qlgUOtNxWL2bpeIiMglsumZegDAnEHuPwXAAfHLIgA/y79ZBfKf/+gsvW9/GzjqKKCxEbj4YsDrdbplzrvgAl2s+fbb7d2uCKuhExFRWcsYTBljngOwfZCHzAXwkFH/BDBcRJyvarlkia6dd+CBulzKpZdq9fL339faUQ89BEyY4HQr3aO6Grj8cuBvf9MeOzt5vUB7u73bJCIicgk7cqYmAPgw6ffm+G3OWbIEWLQI+PBD7RXZsEGXUznsMF237qyzSrv4ZqFceKH2Tv3oR/Zu16qGTkREVIaKOl9dRBZBhwIxZswYNDY2FuR5jrrmGoTSFIvs+uAD/HPjRl2XziHhri40rlnj2PNn0jB/Pva/7z78+7e/xa5DD7Vvw7EY0NSUMYgNh8MFe1+UC+6jwXH/ZMZ9NDjun8y4j/oSk8XaaSIyCcCfjDEHp7nv5wAajTG/jf/+DoBZxpjWwbY5c+ZMs3r16pwanZHHk35NOBGdxeegxjVrMGvqVEfbMKjOTuATnwAOOAD4/e/t2244DIwZA9TXD/qwxsZGzJo1y77nLUPcR4Pj/smM+2hw3D+ZVeI+EpGXjTEz091nxzDfMgAXxGf1HQVgV6ZAquAmTkx/u93LpZSjqipdGPkf/wBeeMG+7QYCHOojIqKylE1phN8CeAHAFBFpFpEviMhlInJZ/CErALwP4F0AvwDwpYK1Nls336wJ1cmqquxfLqVcnXcesPfe9uZOBQLa6xWN2rdNIiIiF8iYM2WMWZjhfgPgCttaZIdzz9Wf11+vw3rjx2sgZfdyKeXK6p268UbtoTr6aHu2a4xWQ6+psWd7RERELlC+FdDPPRd4+21dJuXFFxlIDdW552qOk51V0X0+zZ0iIiIqI+UbTFF+rN6pF14A/v53e7YZDOrCx1lMeiAiIioVDKZoYFbv1I9+ZE8A5PFozhSroRMRURlhMEUDC4WAL39ZK6Lb1Tvl8WgiOhERUZlgMEWD+9zngLFj7eudCgaBXbvy3w4REZFLMJiiwVm9Uy++qOv25cvn02G+3t78t0VEROQCDKYos4UL7e2dEmHeFBERlQ0GU5RZKAR85SvASy8Bzz+f//b8flZDJyKissFgirKzcCEwbpw9vVOBgNabisXsaRsREZGDGExRdoJB7Z1avRp47rn8tiWiARmH+oiIqAwwmKLsLVigS/PY0Tvl8wHt7fa0i4iIyEEMpih7Vu/Uyy8Dq1blt61AQPOmWA2diIhKHIMpGhqrd+r22/MLhLxeLY/AEglERFTiGEzR0AQCwFe/Cvz730BjY37bYjV0IiIqAwymaOjOOQeYMCH/3Cm/n9XQiYio5DGYoqFL7p169tn8ttPZqYsfExERlSgGU8UUi5VPwvV//RfQ0JB/75QI0NVlX7uIiIiKjMFUMUQiQFubBg3GAD09Trcof4EAcOWVwKuvAitX5r4dn0/3DRERUYliMFVIXV0aKEQiWj183301COnuLo/q35/9LLDPPsAdd+TeOxUM6j4qlx47IiKqOAym7GYM0NGhAUIgAEycCEyeDAwbprPXRHTR4HDY6Zbmz+/X3qnXXgP++tfctsFq6EREVOIYTNklGtUAqaMDGD5cA6iGBqCqSgOGZPX1wIgR5VEB/OyzNWDMp3dKRPcbERFRCWIwla+eHu2F6u0FxozRobxRo7RXajCjR2vPTqknX1u9U6+/Djz9dG7bCAZZIoGIiEoWg6lcGKNT+tvadOiuoUF7ourrtbJ3NjwerSQeiZR+aYCzzgI+8pHce6d8Pg1KWQ2diIhKEIOpoYhGdWguHAZqa4FJk3SIq6am/1BeNgIBDaja20s7AdvqnXrjjdx7p0RYDZ2IiEoSg6ls9PZqL1RPjw7h7befDukFg/lvu7ZWt1nqCelnnaXBZa51p/x+lkggIqKSxGBqMNZQnjG6fMrkyZo47vPZ+zwjRwLV1aXdM+PzaVX0N98E/vKXof99IMAkdCIiKkkMplLFYonSBlVVOow3aZL2IHkKtLtEtA4VUNp5Q/n0Tonovi+H+ltERFRRGExZIhEdauvs1NIG++6r+UxVVcV5fp9Pn6+zs3QDCp8P+NrXgDVrgD//Obe/L9XXTkREFYvBVHd3okr52LGaDzVqlObwFFtVVekX9DzzTB0OveOOoQdGwaAm+ZdyMj4REVWcygymkquU+/26JEpylXIn1dfrpVQLelq9U2+9NfTeKWvfl3LuGBERVZzKCqasKuXt7Ro4WVXKq6tzK21QCCLA3ntrkFeqS6zMm5d775QIsGFDeSwGTUREFaEygqnUKuX77acBS6Yq5U7xejV/qre3NAt6+nzAVVcBb78NPPnk0P5WRP++ubk0XzsREVWc8g+mIpHcq5Q7KRDQGX6lWtBz3jxN4s81d8oYoKWFCelEduvs1OMiP1tEtinvYCoU0l6ofKqUO6muTpPhSzF/yuvV3qm1a4EVK4b+91VVetDfsqU0g0kiN+rp0V7fSAT48MPSLsVC5CJZBVMiMkdE3hGRd0VkcZr7LxKRLSLyavxyif1NzYHXa0+VcieNHJkILErN3LnA/vsDd96Z21lwbS2wcyewY4ftTSOqOJGIBlI+nx4bIxGgqak0jy1ELpMxmBIRL4B7AJwC4CAAC0XkoDQP/R9jzLT45Zc2t7NyWQU9jSm9s8jk3qnly3PbRm0tsHkzl5ohykcsBrS26k/rBLOqStMJmpr0hIU9wEQ5y6Zn6ggA7xpj3jfG9ABYCmBuYZtFffh8upxNKRb0/MxngAMOyL13SkSHaFtagK4u+9tHVAm2bNHjR3V139t9Pj1h2bQJ2LiRkz6IcpRNMDUBwIdJvzfHb0t1loi8LiKPiMg+trSOEqqqdCZiqRX0tHqn3nkH+OMfc99GKKRDFKXWO0fktB079FJbm/5+j0dLxYTDmkfFsiREQyYmQ9euiJwNYI4x5pL47+cDONIY8+Wkx4wEEDbGdIvIFwGcY4w5Mc22FgFYBABjxoz5+NKlS+17JSUiHA6jdqCDWjZ6e7WHx+niokMRjeLwL34REMFL99476GzKcFcXakOh9Hda71W3lrQokrzfQ2WO+ydJLKbBUcpnbsDPmTF68ftL6xhjM76HMqvEfTR79uyXjTEz093ny+LvNwBI7mlqiN+2hzFmW9KvvwRwa7oNGWPuA3AfAMycOdPMmjUri6cvL42NjcjrdUejwAcf6PVSSq5fvBj40pcwa906TUwfQOOaNZg1derA2+no0F668eNLb3amTfJ+D5U57p+47m5g/Xod2ksJpgb9nEUi+jnbe29gxIiK/JzxPZQZ91Ff2Zx6vATgABGZLCIBAAsALEt+gIiMS/r1DABv29dE6sMq6NnTU1r5DZ/5DPDRj2ruVD7trq7W4YitW+1rG1G5sWbuBYNDr6vn82lZli1bNFexlI4zRA7JGEwZYyIAvgzgKWiQ9DtjzBoRuUlEzog/7KsiskZEXgPwVQAXFarBBD1Ajh9fWgU9PR7Nnfrf/809d8pSWwts26ZlE4ior1hMl2QCch8SF9GAqrNTZ/uV6tJWREWS1aC4MWaFMeajxpj9jDE3x2+7wRizLH79emPMVGPMYcaY2caYtYVsNEEPdCNHllZBz9NPB6ZMyb93SkQDqo0bS+v1ExWaMTozr7tbh8PzZa1b2tTE8iREg6jcDMNyUGoFPa3eqXffBZYty/z4TNuqrtahDJ41E6kdO4BduwaeuZeLYFCPMxs2cEUCogEwmCplHg8wdqwe3CIRp1uTndNOAz72sfx7pwDN7QgGE8tjEFWytjYtcFtXZ/+2vV7d7vbt/LwRpcFgqtT5/VrQs6OjNM4Yrd6p994Dnngi/+1ZOSEbNpReQVMiu3R1abJ4IdcgtfKoenp02I9FdIn2YDBVDqyCnqWS03DKKYneKTvOcKuq9AC/aVNpBJREdurt1d6iUGjoM/dyUVWlz9PUpEOKRMRgqmwMHw7U12sPldt5PMDVVwPvv29P7xSgZ+S7d+ssP6JKEY1qr6zHo73UxRII6GeutVVPYtgrTBWOwVS5ENEiex5PaSRkz5ljb+8UoEm3W7dqUEVU7ozRGa2RiPZKFZu1DM2uXboMDZd6ogrGYKqceL2aP9Xb6/5Cex4PcM01wLp1wGOP2bNNq2RCS0vpzHAkytXWrVrANnXx4mKrrdWArqmJnztyRmen4yfRDKbKTTCoM/xKoaDnnDnA1KnAXXfZ1zuVXDKBC7ZSudq1S4e03bI2WlWVDv01NWl5Brcfe6g8dHfrMPf69fq+cxCDqXI0bBiw117uL2gporlT69cDjz5q33Z9Pr1wCjeVo44OzVWqrXXXunk+n7Zp0yYdfnR77ziVrt5efZ+tX6+zSmtqnG4Rg6myNWqU9lK5vdv95JO1d+rHP7Y38AkGNSm2tZXJsVQ+enr0TLy6Wnth3cbKowqHNY+KvcNkp2hUh7fff19nr9fW2lPp3wYu/DSSLTweXb8vFnN374yI5k6tXw/84Q/2bru6Ws9aWLWZykE0qr2tVs+rm9XU6LFn/Xr395CT+8ViOrS9bp0O59XWJpY6cgkGU+WsVAp6nnQS0NAAXHstTjj5ZOCII+wb9qup0Q+fw+PpRHmJxXRihTHa61oKQiG9fPCBVk538zGI3MkY7YFav16HjoPBwhamzQODqXJXXa0lE8Jhp1sysMce02UwolGIMTqM8d//bV9AVVen2y+VoqZEqbZs0SF7lwxpZM3n02G/LVs0GGQeFWWrs1MnNLS06Puorq44RWlzxGCqEowYod2ibs2fuuWW/rkVnZ16ux1E9GympYVLYFDpsXpW3TJzb6isZWisL8dSqINHzrFm6H3wgf5eV+f+YW0wmKoMIlouQcSdCaEtLUO7PRderw45NDezuCCVjvZ2nbVUqoFUMivHZf169hJTf8kz9Lq7NYiy1l4tAQymKoVV0LO7232z28aPT3+7McA3v2nfEjF+vybmb9jA4QZyv+5uDf7dOnMvF8Ggvp4NGzgxhFS6GXpOVPTPU5l8QikrwSAwbpz7zgoXL+6fCxIKAcceCzz8MHD00cBPfmLPMGUopLMbN27kgZzcKxLRQCoYLIkhjiHxerXXYft21oKrZNYMvfffd+0MvaFgMFVprIKebkpInz8fuPVWYMIEGBHtQbvtNuB//gd45hkNpm65BTj+eOD3v8+/Z626Wl//li32tJ/ITrGY9twAJTXMMSRWHlVPD5ehqTTJM/Q2bdITXJfO0BsKBlOVaPRoPeN1UzL2/PnAiy9i1VNPAS++qL8DwP77A/ffDzzyiLb7a18DTjkFeP75/J6vtlbPjFkygdzEGP2C6e4uvZl7uaiq0p6qpiZNOG5vd18aAtmno0P/1xs2JCrmu3iG3lAwmKpEVkHPaLR0utg/8QngT38C7rkH2LkTWLAAOP98YO3a3LZnLYq8aZO7eumosu3YoUMf5ZBwnq1AQHvMYzEd9nv/fc2TdONkGcqNlf9nzdAbNqzshq8ZTFWq5IKepRJQeTzAvHnAqlXAt78NrF4NfPrTWpNq06bctldTo2dJnK5NTmtr03podXVOt8QZgYC+9lBIe43ff1+/gEth0XZKz5qht26dBsfDhpXt0DWDqUpWXa2Vx3t7tXemVA5YoRBw2WXA3/8OXHwx8LvfabL6HXcMfekKr1eHPFkygZzU1aWlQMogdyRv1knOsGH6mbR6q3bs4Ge0VKTO0LOC5DLGYKrS1dYCkycDI0dqQFVKiaB77QX8n/8DNDYCJ54I/OhHGlQtWTK03jbrTKmlhfkaVHxWwBAKFT5/5NFHgSOOsH/ZpkIJBhP1hqwv55YW9y+RValiMU3DKJMZekPBYIr0THDkSA2qQiFg9+7SOgOcNAn4+c+BJ54AJk7UYb+TTgJWrsz+gFtVpd3QmzbxIE3FE43qMLOIDr0X0qOP6mdjw4bCLNtUSF6v9lbV1Wkv3gcf6NDRrl2lk6ZQzpJn6G3erMfTCutlZTBFCYGA5lFNnKgH+XC4tHpqZs4EHn8cuO8+zYG64AJNVH/zzez+vqZGA0m7ioQSDcYYrXcWiRRn5t7NN/fvee7sBL7//cI/t51CIR0C9Pv15Oe993Q/dnbyRMgJ6WbolUuR2SEor3R6skd1tfb27NqltZg8Hr2tFIgAp52miekPPwzceScwZw5w1ll6Fj5hwuB/X1urwwl+P1BfX5w2U2Xatk3P5ocNK8z2u7uBf/1La7U9+6wGHOm0tgLTpgFTpvS/uDkZ3uvVz6sxmiu5a5d+bkeOLKsp965ljA5Ph8OJALeCMZii9DyexALJW7fqgSoUKp2ZGIEA8IUvAGefreUUfvlLLa1wySXAFVcM/MG3Sia0tuqBuVSCSCotu3fr58ruYGXDhkTw9Pzz2msQDGppkS1b9HOcqr5ecw7/8x/gt7/Vv7FMmNA3uDrwQK395qYaWCKJ9kQi2lu1aRMwfLh+zss88bngIpHEpbtbh1m7u/VizdBz0qOPalHnlhYdVbn5ZuDcc4veDAZTNDi/X5egGT5cD1BtbTocVirduPX1wDe+oUN+P/wh8NOfAr/5DXDNNfqBS5enYvXENTdrD12pBJCVKhLRHL+eHh3q6ekBPvxQg4hgUP/HXq8OQbiht6KzUw/8tbX555T09mqJkGee0YtVd62hQU8kTjwROOYYfT9bOVPJQ31VVcD3vpcokmvVelq7FnjnHQ2w1q4F/va3RN0nEf1cpAZZ++5b+LyvTKxhJiuHZ8cOfQ/stZcet9zw/3ejWCwRMPX2aqBkfZaSUz28Xr1YnymnA9XU93RTE7BokV4vckDFYIqyU1UFfOQjeka9eXPibLBUEgwbGnR9v0svBW66SRdQ/tWv9OfJJ/d/HT6fHjCam7XAqderQZbHUzqvudxYB/zeXj077uzUn9ai1SKJQoCxmH6Z7tyZ+Htj9P8YCOgXbCikj7cuxfii7enJf/HijRt1BuvKldr71Nam79UjjtD6a5/8pPYepb5PrYDplltgWlog48frupjW7YC2aeJEvZx0UuL2SESTi9euTQRY77wDPP10Yv/7/cB++wEf/WgiwJoyRbc10L5N7lVI155cJfdW9fbqPhPRk6v6ev3/V6LkXibr5KO7u++EI5HEyYdbZ+LFYlqL7Lvf7Z8H2NGhx3UGU+Ra1sGopkbzPayzvlI6MB16qK7v99e/anfwF76Q+BKaMaPvY4NB/aBaVXstHk/i7Mzv7/tlbAVc1mMYfOUm9YBvnSUDiaDI50sf0Fsz49L1khij2w2H9cTAGL2I6P/K79cgy+rRsv6vdlRrjkY1kLLeL9mKRIB//1uDp2eeAdas0dvHjQPOOEN7n449Nruq6fPnA/PnY9WaNZg1dWr2bfD5NEDbf/++t3d1aQL4O+8kLq++CixblnhMKAQccEDfAGvKFM3nSu5VsGYXWu20i/VeMEb/5zt26Ptmr73yC2rdKl0vkzU0Z/UyWe936zjmdA9Tsq4uHQXZuFEvra19f27cqPcPNuM89ZhdBAymaOh8PmDMGA2sNm3SA1QpdaGLaIL67NmaI/KjHwGf+Yx+MS1erD1wlnS5IcYkluLp6dHfY7HETCLrp/Ulbx20kntBrC/q5OAr+VIpjNGDojVM19GhX66pB32/354lVjIFWtGoJjNbgVby31k9WsGgXk8eOswUMBujXwbGZPfFtXWr5j098wzw3HPaw+b1AocfrsPWJ56ogYnTgXooBEydqpdk7e3ag5Xci/W3v+kamxaR/rPvrNmF8+bZ/zkQSeRA9vRob5jHk8itKrXh/NRepq4uvUQifY9BdvcyxXsTTxhqb6Ix+j5ODZJSr2/f3v9vq6qAsWP1BOKII/Tn2LE6wSjd4ydOzPtlDhWDKcpdKKRvWmsZDGPc2y2cjs+n6/udeSbws58B994LPPkk8PnPa/7HT36SfvgheTgpG1awFYvpwc66nm4atzF9zxiTAzAr+DJGzzKtQCP5p5tFo4nAqatLA6fkZXys1x0K5fZFmutB3mL9X9P9b61Aq6ND3+/JgbMV7FlDh6m9lSL6+ejoGDggjEaB115LJI+/+qrevvfeOgx94onAcceVzgzTmhpg+nS9JNuxQwOsd94Brr8+/d+2tupw4fjxemlo0ET4hobE7+PH59ebEgjoxSoyuW2bfmGPHFm45HqrF3Qo15NvS04A7+nR90zqCVuhe5mScpQESPQmRqPA0Uf3DYrSBUpdXf23OWqUBkbjx+vogHV97NjEZdiw9Me34cP75wFWV+uoQ5GJcagux8yZM83q1asdeW4nNTY2YtasWU43w37RqJ4hbNumB6kcP9CNQx1+sFNrK3D77cDSpf3vq6oCbr3V3uGHgSQHX8mB1xNPAHfcAdPaChk3Drj6au1RS+bzJYICj6f/T+vLPTUIS/5pR/tTE1m7uhLd8tbZshV02GGg5Opi/M+sQMu6WL1qf/yjLnHU2qpn0tdf37ct27frOpPPPKM5UNu36/6fMUODp09+EjjooIL0VDr6ObMccYR+GacaPlzzXZqb9f7m5vTFdEeP1iDLuqQGXSNGDO0Ew5qd5vOhcf16zJo5M/G/tD6DyZ/NdLdb1622Jj8WSAwpD3Y9Wep76Otf1/eQ9Tm3UyymPYrhsF7a2vpeb28HbrtNe22zEQgkepOSA6Pk28aMyb9HsIiz+UTkZWPMzLT3MZgqrrINpizd3XoW3t6uZwhD/LJ0xUF++nR9DalCIeDUU/VLOhTSn9lcT70tFBr6gTCbYCH5QG4d2FMP8Nl83pPzvQYKyjweXRPxxhv1y66hQYefTj1V3wPWc1l/4/dnHxT09OgBPPnAbl1Pd1s4DCxfnv6sN/l/Vl3d/2L9Xwa7L9desnT/r698RffLM89oHlQsprk7s2dr8HT88RoEFJgrPmdDCYB7erRnwwquNmxIXKzfU///1dX9e7SSg66xY/sfn+JfzKalJXHCMndu38+rdV1kaNcLsX+M0dfd1pYIeFKDIOt68iXdY8Ph3NppufXWvsHSUIPZfFhDm8kpGgUwWDCV1TediMwB8GMAXgC/NMbcknJ/EMBDAD4OYBuAc4wx6/NpNJWoYFAPVuGwBiRdXaW3rMCWLelv7+rSaejWTLLOztyWshBJBFXZBmRLlqSvXn3DDfqFbAU/1tTl5Evq7ck5XMn3pSbND/RTRIdDb7gh8QX24YfA176miZ9HH60H6myDodTbrETzTAIBfW/V1qYPpJL/Z52dOsyWy5puoVD2QZh1209+kv7/deutuv+mTQOuukqDqMMOq6w8OUvS7MKMs/kCgcQsw3SM0Z49K7hKDbhee61/bo3Ho1/8VnAVDmsPYW+vDmG1tOisMOs9HYv17YFM7om0ciiTH2Mlgic/Jt3fDvSYZcvSv4euukr3mRUUZbNKhderNc2sJXlqa3XIeMKE/rfX1va9nvz7ySfrfkk1YYIjtZ3cJGMwJSJeAPcA+DSAZgAvicgyY8xbSQ/7AoAdxpj9RWQBgB8COKcQDaYSIJL4gO7Yocm01syrUjB+fPrhhwkTgBde6Htb6jR9K8ga7LbBrnd26kE/3WPS2bEDuPJK+/dBLrq7gR/8YOD7PR49IFsBkHV91Kj+t6VeT3db8vDAQENGqf8z60w+ObhKvp5622D3bd3a//bkHLCBvPqqvmbaM7swbyKa7zRypM7YTaezs39vVnOzBgerV+sJQarubuDuu/ViJ2uoe7ATn+TiqckiEQ3uBgp4rOvJAVIuveHpXH99+t6yxYvz33aJy6Zn6ggA7xpj3gcAEVkKYC6A5GBqLoDvxK8/AuCnIiLGqTFEcgdrAeW6Ou3t2b1bP3hOF/bLZPHi7A8Y1sywQi+7MVCwMHaszpBKPbMd6Ix3qI9JdwYejWoPy0AefDB9YGTXAT2dbP9nVv0ha2q83SIRbcPs2ZrnkmrCBAZSTqmqSl/ewdLQkL7XUkQ/Y8lD39n0BKfr+c129icw+AnCXXcN6aXbJptaZRUqm2BqAoDkkL0ZwJEDPcYYExGRXQBGAtia/CARWQRgEQCMGTMGjY2NubW6hIXD4Yp83QASX95WLk0a4a4uNFp1dJwyZQr2/upXse/99yO4ZQu6R4/G+5//PDZPmZKo8VNke593HqbcdRe8ST0f0WAQ71x4ITannsEmn/UWyFEPPIBQmryyrr33xj/HjUvcYPXapMtBs5PL/md7X3BB+v/Xeedhs9Pvb7jkc+YyR40enf49PXo0/pnuZMmaaJHLUH8WBvzMO/0emjIFuP9+hLu6UGtNNHL6vWQFwevWOdaEjAnoInI2gDnGmEviv58P4EhjzJeTHvNm/DHN8d/fiz9ma7ptAkxAr1ix2KALKLsiMdatkpNjx48HrrtO6/GkTqFOTTZPN+3aMtAsooHus5LPn3hC80mSe4JCIV2a5PTT0xfSTM69KmBBU1e8h2Ix/X/deqv91b1t4Ip95DbpEr5DIa17dcYZzrRp2TKdYZw8m2/evETuYnIeY5HzUl31HiqRBPQNAPZJ+r0hflu6xzSLiA9APTQRnagvtyygnDrNOXX2W67bTHdAGyxgGYqTTgJOOgmr1q3DrP32030ZifQ9sKZe0t2XbrZRuku6+y1XXaU1kKwEXWtK8sKF/cs6WMODVo0p62w+uYxA6r5KDb6KVdA03UzI1Gnw2fB4tGzF3LmJ/JdSKWpbCZJ7lazlcE46SSc/3HGHnrBMmAB861u6xqFTLrhAL1abrc9MctJ78nEsm2ONNTKQ/JlODcpS76eMsgmmXgJwgIhMhgZNCwB8LuUxywBcCOAFAGcDeIb5UjSo1AWUrSrqQ5V6IElXEmCgA4KVv5C8bEhyrsNga/ENtM1i3N7SMnDeRzGde276GTxDCXis/1Xyl0TyF0Xyshipi66msnJRrKKmqaUiUp/Xemzyvk7uNbPKOaTmvGSq05Xuf9fbq0OdpZI3WC7SBU3WckTBoBaDrKpKFFm9+mrg6quxqlRHENKVQkm9Ld2JTrogLblGVrrjaCymn8lSqxxfIBmDqXgO1JcBPAUtjfBrY8waEbkJwGpjzDIAvwLwsIi8C2A7NOAiyix1AeVYLLGG1EC1kZI/2MlfdqnVwpMLVKbrsSHnDTW/a7AvA+tL0yo9kVofK12Pl90FSwfi92vicHu7njx0d5deyRA3Sxc0Abp/raAptTp9OSrEe3igenXWOpNtbbqfraryFSqrd5QxZgWAFSm33ZB0vQvAZ+1tGlUMkcQCyk1NetBL/hJMXUA4OUDil1FlySb4sno93aimBpg0KbFagNsWmXU7a6irtzcRTFtBciCQCJqsQrHZzpyjgVmfuVQej86AjES03MjOnYnAylpeqYKUaXhOJck6Y3TrFyGRHTweLY8wbJj2UrW16UQM5lQlJAdNycNzHo8GTXV1iZ4mBk3O8vkS5U8qOLBiMEVE5IRAILFagLX2XCktFG4XK8fNKjGQHDRZ9ckCgcTJVqXtn1JSwYEVgykiIqdYqwVUVyeG/oLBsv3C6SMW0zIEsZj20lVXM2gqJxUWWDGYIiJymtcLjB6tgVW5D/1ZVeK9Xl0hYdiw8k0IJ1UBgRXfwUREbhEKac0ua3arSL/CtiWru1un0lsTBGprK3OB50pXpoEVgykiIjdJnt26dat+0ThR2NYO1sLSkYiWQdlnH/3JITwCyiqwYjBFRORGPp8uZF1fr8uJhMPaS1UKvTmxmH4xRqPa/uHDWQKCBpccWEWjOhRcQoEVgykiIjerqtLaVLt26dCfz6e3uZHVuyAC7LWX5kOx2jsNlddbcoEVgykiIrdLXtPSWpamuto9ids9PRpEBQLAmDHaznJMnqfiGyywAvQ954LeWpd8EomIKKPkZWk2btQAxsllaTo7++ZDVWKdLCqegQKrcDi3tV1txGCKiKjU1NQAkyc7syyNMUBHh+ZF1dXpcB7zoajYUgOr5DUZHcBgioioFFnL0tTV6dBfoWtTWT0BIjrkOGxYac4wpPIzlMXSC4TBFBFRKQsG+y5LA9hbfqC3V4cTfT7mQxENgMEUEVGpS16WZts2Hf7Ld1mari5NLA+FNE/LydwsIpdjMEVEVC68XmDvvXUIbuNGHfqrqcl+tpMxOpQXjWoP1Lhx7i3DQOQiDKaIiMpNKAR85CNaQmHTJg2mBluWxsqHArTA5vDhzIciGgIGU0RE5Sh5WZotW7ToZ1VV3yKavb26Zl7yQstuqV1FVEL4qSEiKmc+nw7X1dfr0F93tw7ntbVp79O4cUMbCiSifhhMERFVgurqxLI0TU3AxIk6HMikcqK8MZgiIqoU1rI0fj8Ty4lsxH5dIiIiojwwmCIiIiLKA4MpIiIiojwwmCIiIiLKA4MpIiIiojwwmCIiIiLKA4MpIiIiojwwmCIiIiLKgxhjnHlikS0Amhx5cmeNArDV6Ua4GPdPZtxHg+P+yYz7aHDcP5lV4j76iDFmdLo7HAumKpWIrDbGzHS6HW7F/ZMZ99HguH8y4z4aHPdPZtxHfXGYj4iIiCgPDKaIiIiI8sBgqvjuc7oBLsf9kxn30eC4fzLjPhoc909m3EdJmDNFRERElAf2TBERERHlgcEUERERUR4YTBWBiOwjIs+KyFsiskZErnS6TW4lIl4R+beI/MnptriNiAwXkUdEZK2IvC0in3C6TW4jIlfFP2NvishvRSTkdJucJCK/FpHNIvJm0m17icjTIvK/8Z8jnGyj0wbYR7fFP2evi8hjIjLcwSY6Kt3+SbrvGhExIjLKiba5CYOp4ogAuMYYcxCAowBcISIHOdwmt7oSwNtON8Klfgzgz8aYAwEcBu6nPkRkAoCvAphpjDkYgBfAAmdb5bgHAMxJuW0xgJXGmAMArIz/XskeQP999DSAg40xhwL4D4Dri90oF3kA/fcPRGQfACcB+KDYDXIjBlNFYIxpNca8Er/eBv0SnOBsq9xHRBoAnAbgl063xW1EpB7A8QB+BQDGmB5jzE5HG+VOPgBVIuIDUA2gxeH2OMoY8xyA7Sk3zwXwYPz6gwDmFbNNbpNuHxlj/mKMicR//SeAhqI3zCUGeA8BwJ0A/hsAZ7GBwVTRicgkANMB/MvhprjRXdAPZ8zhdrjRZABbANwfHwb9pYjUON0oNzHGbABwO/RMuRXALmPMX5xtlSuNMca0xq9vBDDGycaUgIsBPOl0I9xEROYC2GCMec3ptrgFg6kiEpFaAH8A8DVjzG6n2+MmInI6gM3GmJedbotL+QDMAPAzY8x0AO3g8Ewf8dyfudDAczyAGhE5z9lWuZvR2jjsWRiAiHwTmqaxxOm2uIWIVAP4BoAbnG6LmzCYKhIR8UMDqSXGmEedbo8LHQPgDBFZD2ApgBNF5P852yRXaQbQbIyxejQfgQZXlPApAOuMMVuMMb0AHgVwtMNtcqNNIjIOAOI/NzvcHlcSkYsAnA7gXMOCjMn2g56wvBY/XjcAeEVExjraKocxmCoCERForsvbxpg7nG6PGxljrjfGNBhjJkGThp8xxrBXIc4YsxHAhyIyJX7TJwG85WCT3OgDAEeJSHX8M/dJMEk/nWUALoxfvxDAEw62xZVEZA405eAMY0yH0+1xE2PMG8aYvY0xk+LH62YAM+LHqIrFYKo4jgFwPrS35dX45VSnG0Ul5ysAlojI6wCmAfi+s81xl3iv3SMAXgHwBvT4VtFLXojIbwG8AGCKiDSLyBcA3ALg0yLyv9DevFucbKPTBthHPwVQB+Dp+PH6Xkcb6aAB9g+l4HIyRERERHlgzxQRERFRHhhMEREREeWBwRQRERFRHhhMEREREeWBwRQRERFRHhhMEZEriUg0qZTIqyJiW8V3EZkkIm/atT0iqmw+pxtARDSATmPMNKcbQUSUCXumiKikiMh6EblVRN4QkRdFZP/47ZNE5BkReV1EVorIxPjtY0TkMRF5LX6xlpjxisgvRGSNiPxFRKoce1FEVNIYTBGRW1WlDPOdk3TfLmPMIdBK1XfFb/sJgAeNMYdCF6a9O3773QBWGWMOg65nuCZ++wEA7jHGTAWwE8BZBX01RFS2WAGdiFxJRMLGmNo0t68HcKIx5v34AuIbjTEjRWQrgHHGmN747a3GmFEisgVAgzGmO2kbkwA8bYw5IP77dQD8xpjvFeGlEVGZYc8UEZUiM8D1oehOuh4Fc0iJKEcMpoioFJ2T9POF+PV/AFgQv34ugOfj11cCuBwARMQrIvXFaiQRVQaeiRGRW1WJyKtJv//ZGGOVRxghIq9De5cWxm/7CoD7ReRaAFsAfD5++5UA7ouvdh+FBlathW48EVUO5kwRUUmJ50zNNMZsdbotREQAh/mIiIiI8sKeKSIiIqI8sGeKiIiIKA8MpoiIiIjywGCKiIiIKA8MpoiIiIjywGCKiIiIKA//H2W9QIHorYJpAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plot(train_acc_arr, label='Training accuracy')\n", - "plot(val_acc_arr, label='Validation accuracy', color='r')\n", - "plot(train_loss_arr, label='Training loss')\n", - "plot(val_loss_arr, label='Validation loss', color='r')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Trained Model\n", - "\n", - "- model trained on the entire dataset\n", - "\n", - "Plots and logs at https://tensorboard.dev/experiment/HJGL6qx1RBme4fqkIlypPg/" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/guide/notebooks/playground.ipynb b/guide/notebooks/playground.ipynb deleted file mode 100755 index 17dcfbc..0000000 --- a/guide/notebooks/playground.ipynb +++ /dev/null @@ -1,502 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Convert test data to tfrecords" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "import nobrainer\n", - "import os, sys\n", - "sys.path.append(\"..\")\n", - "import numpy as np\n", - "import nibabel as nb\n", - "from glob import glob\n", - "from pathlib import Path\n", - "from shutil import *\n", - "import subprocess\n", - "from operator import itemgetter\n", - "import pandas as pd\n", - "\n", - "test_root_dir = \"/tf/shank/HDDLinux/Stanford/data/mriqc-shared/test_ixi\"\n", - "csv_path = os.path.join(test_root_dir, \"csv\")\n", - "tf_records_dir = os.path.join(test_root_dir, \"tfrecords\")\n", - "\n", - "os.makedirs(tf_records_dir, exist_ok=True)\n", - "\n", - "test_csv_path = os.path.join(csv_path, \"testing.csv\")\n", - "test_paths = pd.read_csv(test_csv_path)[\"X\"].values\n", - "test_labels = pd.read_csv(test_csv_path)[\"Y\"].values\n", - "test_D = list(zip(test_paths, test_labels))\n", - "test_write_path = os.path.join(tf_records_dir, 'data-test_shard-{shard:03d}.tfrec')\n", - "\n", - "nobrainer.tfrecord.write(\n", - " features_labels=test_D,\n", - " filename_template=test_write_path,\n", - " examples_per_shard=3)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "test_root_dir = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/test_ixi'\n", - "model_save_path = os.path.join(ROOTDIR_B, \"model_save_dir_full\")\n", - "tfrecords_path = os.path.join(test_root_dir, \"tfrecords\")\n", - "plane = \"axial\"\n", - "dataset_plane = get_dataset(\n", - " file_pattern=os.path.join(tfrecords_path, \"data-test_*\"),\n", - " n_classes=2,\n", - " batch_size=16,\n", - " volume_shape=(128, 128, 128),\n", - " plane=plane,\n", - " mode='test'\n", - " )\n", - "\n", - "print(dataset_plane)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Inference" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys, os\n", - "sys.path.append('..')\n", - "from models.modelN import CombinedClassifier\n", - "from dataloaders.dataset import get_dataset\n", - "\n", - "\n", - "# Tf packages\n", - "import tensorflow as tf\n", - "\n", - "def inference(tfrecords_path, weights_path):\n", - " \n", - " model = CombinedClassifier(\n", - " input_shape=(128, 128), dropout=0.4, wts_root=None, trainable=True)\n", - " \n", - " model.load_weights(os.path.abspath(weights_path))\n", - " model.trainable = False\n", - " \n", - " dataset_test = get_dataset(\n", - " file_pattern=os.path.join(tfrecords_path, \"data-test_*\"),\n", - " n_classes=2,\n", - " batch_size=16,\n", - " volume_shape=(128, 128, 128),\n", - " plane='combined',\n", - " mode='test'\n", - " )\n", - "\n", - " METRICS = [\n", - " metrics.BinaryAccuracy(name=\"accuracy\"),\n", - " metrics.Precision(name=\"precision\"),\n", - " metrics.Recall(name=\"recall\"),\n", - " metrics.AUC(name=\"auc\"),\n", - " ]\n", - " \n", - " model.compile(\n", - " loss=tf.keras.losses.binary_crossentropy,\n", - " optimizer=Adam(learning_rate=1e-3),\n", - " metrics=METRICS,\n", - " )\n", - " \n", - " results = model.evaluate(dataset_test, batch_size=16)\n", - " predictions = (model.predict(dataset_test) > 0.5).astype(int)\n", - " \n", - " \n", - "ROOTDIR_B = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128'\n", - "ROOTDIR_A = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_A/128'\n", - "test_root_dir = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/test_ixi'\n", - "\n", - "model_save_path = os.path.join(ROOTDIR_B, \"model_save_dir_full\")\n", - "tfrecords_path = os.path.join(test_root_dir, \"tfrecords\")\n", - "print(\"TFRECORDS: \", tfrecords_path)\n", - "weights_path = os.path.join(model_save_path, 'weights/combined/best-wts.h5')\n", - " \n", - "model = CombinedClassifier(\n", - " input_shape=(128, 128), dropout=0.4, wts_root=None, trainable=True\n", - ")\n", - "model.load_weights(os.path.abspath(weights_path))\n", - "\n", - "print(os.path.join(tfrecords_path, \"data-test_*\"))\n", - "\n", - "dataset_test = get_dataset(\n", - " file_pattern=os.path.join(tfrecords_path, \"data-test_*\"),\n", - " n_classes=2,\n", - "# n_slices = 24,\n", - " batch_size=16,\n", - " volume_shape=(128, 128, 128),\n", - " plane='combined',\n", - " mode='test'\n", - ")\n", - "\n", - "print(dataset_test)\n", - "\n", - "METRICS = [\n", - " metrics.BinaryAccuracy(name=\"accuracy\"),\n", - " metrics.Precision(name=\"precision\"),\n", - " metrics.Recall(name=\"recall\"),\n", - " metrics.AUC(name=\"auc\"),\n", - " ]\n", - "\n", - "model.compile(\n", - " loss=tf.keras.losses.binary_crossentropy,\n", - " optimizer=Adam(learning_rate=1e-3),\n", - " metrics=METRICS,\n", - ")\n", - "\n", - " \n", - "results = model.evaluate(dataset_test, batch_size=16)\n", - "predictions = (model.predict(dataset_test) > 0.5).astype(int)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "planes = ['coronal'] #, 'coronal', 'sagittal']\n", - "\n", - "for plane in planes:\n", - " \n", - " model = modelN.Submodel(\n", - " input_shape=(128, 128),\n", - " dropout=0.2,\n", - " name=plane,\n", - " include_top=True,\n", - " weights=None,\n", - " trainable=False,\n", - " )\n", - " \n", - " print(os.path.join(model_save_path, plane, 'best-wts.h5'))\n", - " \n", - " model.load_weights(os.path.join(model_save_path, 'weights', plane, 'best-wts.h5'))\n", - " \n", - " dataset_plane = get_dataset(\n", - " file_pattern=os.path.join(tfrecords_path, \"data-test_*\"),\n", - " n_classes=2,\n", - " batch_size=16,\n", - " volume_shape=(128, 128, 128),\n", - " plane=plane,\n", - " mode='test',)\n", - " \n", - " METRICS = [\n", - " metrics.BinaryAccuracy(name=\"accuracy\"),\n", - " metrics.Precision(name=\"precision\"),\n", - " metrics.Recall(name=\"recall\"),\n", - " metrics.AUC(name=\"auc\"),\n", - " ]\n", - " \n", - " model.summary()\n", - " \n", - " model.compile(\n", - " loss=tf.keras.losses.binary_crossentropy,\n", - " optimizer=Adam(learning_rate=1e-3),\n", - " metrics=METRICS,\n", - " )\n", - " \n", - "# results = model.evaluate(dataset_plane, batch_size=16)\n", - " predictions = (model.predict(dataset_plane) > 0.5).astype(int)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(len(predictions.flatten()))" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Preprocessing 6 examples\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 6/6 [00:05<00:00, 1.11it/s]" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/preprocessed/example1.nii.gz', '/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/preprocessed/example2.nii.gz', '/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/preprocessed/example3.nii.gz', '/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/preprocessed/example1.nii.gz', '/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/preprocessed/example2.nii.gz', '/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/preprocessed/example3.nii.gz']\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\n" - ] - } - ], - "source": [ - "import csv\n", - "\n", - "path = '/home/shank/Stanford/nondefaced-detector/examples/sample_vols/example.csv'\n", - "\n", - " \n", - "if path.endswith('csv'):\n", - " filepaths = []\n", - " skip_header =True\n", - " with open(path, newline=\"\") as csvfile:\n", - " reader = csv.reader(csvfile, delimiter=\",\")\n", - " if skip_header:\n", - " next(reader)\n", - " \n", - " for row in reader:\n", - " filepaths.append(row[0])\n", - "\n", - "from nondefaced_detector.preprocess import preprocess, cleanup_files\n", - "from nondefaced_detector.preprocess import preprocess_parallel\n", - "\n", - "num_parallel_calls = None\n", - "if num_parallel_calls is None:\n", - " # Get number of processes allocated to the current process.\n", - " # Note the difference from `os.cpu_count()`.\n", - " num_parallel_calls = len(os.sched_getaffinity(0))\n", - "\n", - "outputs = preprocess_parallel(\n", - " filepaths,\n", - " num_parallel_calls=num_parallel_calls,\n", - " with_label=False,\n", - ")\n", - "\n", - "print(outputs)\n", - "\n", - "# cleanup_files(outputs)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "100%|██████████| 6/6 [00:02<00:00, 2.81it/s]\n" - ] - } - ], - "source": [ - "\"\"\"Methods to predict using trained models\"\"\"\n", - "\n", - "import functools\n", - "import os\n", - "\n", - "import numpy as np\n", - "import tensorflow as tf\n", - "import multiprocessing as mp\n", - "\n", - "from pathlib import Path\n", - "from tqdm import tqdm\n", - "\n", - "from nondefaced_detector.helpers import utils\n", - "from nondefaced_detector.models.modelN import CombinedClassifier\n", - "\n", - "\n", - "def _predict(volume, model):\n", - " \"\"\"Return predictions from `inputs`.\n", - "\n", - " This is a general prediction method.\n", - "\n", - " Parameters\n", - " ---------\n", - "\n", - " Returns\n", - " ------\n", - " \"\"\"\n", - " \n", - " if not isinstance(volume, (np.ndarray)):\n", - " raise ValueError(\"volume is not a numpy ndarray\")\n", - " \n", - " ds = _structural_slice(volume, plane=\"combined\", n_slices=n_slices)\n", - " ds = tf.data.Dataset.from_tensor_slices(ds)\n", - " ds = ds.batch(batch_size=1, drop_remainder=False)\n", - "\n", - " predicted = model.predict(ds)\n", - "\n", - " return predicted\n", - "\n", - "\n", - "def predict(volumes, model_path, n_slices=32):\n", - " \n", - " if not isinstance(volumes, list):\n", - " raise ValueError('Volumes need to be a list of paths to preprocessed MRI volumes.')\n", - " \n", - " outputs = []\n", - " model = _get_model(model_path)\n", - " \n", - " for path in tqdm(volumes, total=len(volumes)):\n", - " vol,_,_ = utils.load_vol(path)\n", - " predicted = _predict(vol, model)\n", - " \n", - " outputs.append((path, predicted[0][0]))\n", - " \n", - " return outputs\n", - " \n", - " \n", - "def _structural_slice(x, plane, n_slices=16):\n", - "\n", - " \"\"\"Transpose dataset based on the plane\n", - "\n", - " Parameters\n", - " ----------\n", - " x:\n", - "\n", - " plane:\n", - "\n", - " n_slices:\n", - "\n", - " Returns\n", - " -------\n", - " \"\"\"\n", - "\n", - " options = [\"sagittal\", \"coronal\", \"axial\", \"combined\"]\n", - "\n", - " if isinstance(plane, str) and plane in options:\n", - " idxs = np.random.randint(x.shape[0], size=(n_slices, 3))\n", - " if plane == \"sagittal\":\n", - " midx = idxs[:, 0]\n", - " x = x\n", - "\n", - " if plane == \"coronal\":\n", - " midx = idxs[:, 1]\n", - " x = tf.transpose(x, perm=[1, 2, 0])\n", - "\n", - " if plane == \"axial\":\n", - " midx = idxs[:, 2]\n", - " x = tf.transpose(x, perm=[2, 0, 1])\n", - "\n", - " if plane == \"combined\":\n", - " temp = {}\n", - " for op in options[:-1]:\n", - " temp[op] = _structural_slice(x, op, n_slices)\n", - " x = temp\n", - "\n", - " if not plane == \"combined\":\n", - " x = tf.squeeze(tf.gather_nd(x, midx.reshape(n_slices, 1, 1)), axis=1)\n", - " x = tf.math.reduce_mean(x, axis=0, keepdims=True)\n", - " x = tf.expand_dims(x, axis=-1)\n", - " x = tf.convert_to_tensor(x)\n", - "\n", - " return x\n", - " else:\n", - " raise ValueError(\n", - " \"Expected plane to be one of [sagittal, coronal, axial, combined]\"\n", - " )\n", - "\n", - "\n", - "def _get_model(model_path):\n", - "\n", - " \"\"\"Return `tf.keras.Model` object from a filepath.\n", - "\n", - " Parameters\n", - " ----------\n", - " path: str, path to HDF5 or SavedModel file.\n", - "\n", - " Returns\n", - " -------\n", - " Instance of `tf.keras.Model`.\n", - "\n", - " Raises\n", - " ------\n", - " `ValueError` if cannot load model.\n", - " \"\"\"\n", - "\n", - " try:\n", - " p = Path(model_path).resolve()\n", - "\n", - " model = CombinedClassifier(input_shape=(128, 128), wts_root=p, trainable=False)\n", - "\n", - " combined_weights = list(Path(os.path.join(p, \"combined\")).glob(\"*.h5\"))[\n", - " 0\n", - " ].resolve()\n", - "\n", - " model.load_weights(combined_weights)\n", - " model.trainable = False\n", - "\n", - " return model\n", - "\n", - " except Exception as e:\n", - " print(e)\n", - " pass\n", - "\n", - " raise ValueError(\"Failed to load model.\")\n", - " \n", - "preds = predict(outputs, model_path='/home/shank/Stanford/nondefaced-detector/nondefaced_detector/models/pretrained_weights')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/preprocessed/example1.nii.gz', 0.99998486), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/preprocessed/example2.nii.gz', 0.9999981), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/faced/preprocessed/example3.nii.gz', 0.9970654), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/preprocessed/example1.nii.gz', 0.016103715), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/preprocessed/example2.nii.gz', 0.9974597), ('/home/shank/Stanford/nondefaced-detector/examples/sample_vols/defaced/preprocessed/example3.nii.gz', 0.0201056)]\n" - ] - } - ], - "source": [ - "print(preds)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/guide/notebooks/training.ipynb b/guide/notebooks/training.ipynb deleted file mode 100755 index 8acab77..0000000 --- a/guide/notebooks/training.ipynb +++ /dev/null @@ -1,1070 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "import nobrainer\n", - "import os, sys\n", - "sys.path.append('..')\n", - "import numpy as np\n", - "import nibabel as nb\n", - "from glob import glob\n", - "\n", - "\n", - "import defacing\n", - "from defacing import dataloaders, training" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import nobrainer\n", - "from nobrainer.io import _is_gzipped\n", - "from nobrainer.volume import to_blocks\n", - "import sys, os\n", - "sys.path.append('../')\n", - "from defacing.preprocessing.augmentation import VolumeAugmentations, SliceAugmentations\n", - "from defacing.helpers.utils import load_vol\n", - "import tensorflow as tf\n", - "import glob\n", - "import numpy as np\n", - "\n", - "AUTOTUNE = tf.data.experimental.AUTOTUNE\n", - "\n", - "def get_dataset(\n", - " file_pattern,\n", - " n_classes,\n", - " batch_size,\n", - " volume_shape,\n", - " plane,\n", - " n_slices = 24,\n", - " block_shape=None,\n", - " n_epochs=None,\n", - " mapping=None,\n", - " shuffle_buffer_size=None,\n", - " num_parallel_calls=AUTOTUNE,\n", - " mode='train',\n", - "):\n", - "\n", - " \"\"\" Returns tf.data.Dataset after preprocessing from\n", - " tfrecords for training and validation\n", - "\n", - " Parameters\n", - " ----------\n", - " file_pattern:\n", - "\n", - " n_classes:\n", - " \"\"\"\n", - "\n", - " files = glob.glob(file_pattern)\n", - "\n", - " if not files:\n", - " raise ValueError(\"no files found for pattern '{}'\".format(file_pattern))\n", - "\n", - " compressed = _is_gzipped(files[0])\n", - " shuffle = bool(shuffle_buffer_size)\n", - "\n", - " ds = nobrainer.dataset.tfrecord_dataset(\n", - " file_pattern=file_pattern,\n", - " volume_shape=volume_shape,\n", - " shuffle=shuffle,\n", - " scalar_label=True,\n", - " compressed=compressed,\n", - " num_parallel_calls=num_parallel_calls,\n", - " )\n", - " \n", - " \n", - " def _ss(x, y):\n", - " \n", - " x, y = structural_slice(x, y, plane, n_slices)\n", - " return (x, y)\n", - " \n", - " \n", - " ds = ds.map(_ss, num_parallel_calls)\n", - " \n", - " ds = ds.prefetch(buffer_size=batch_size)\n", - " \n", - " if batch_size is not None:\n", - " ds = ds.batch(batch_size=batch_size, drop_remainder=False)\n", - " \n", - " if mode == 'train':\n", - " if shuffle_buffer_size:\n", - " ds = ds.shuffle(buffer_size=shuffle_buffer_size)\n", - "\n", - "# Repeat the dataset n_epochs times\n", - " ds = ds.repeat(n_epochs)\n", - "\n", - " return ds\n", - "\n", - "\n", - "def structural_slice(x, y, plane, n_slices = 4):\n", - "\n", - " \"\"\" Transpose dataset based on the plane\n", - "\n", - " Parameters\n", - " ----------\n", - " x:\n", - "\n", - " y:\n", - "\n", - " plane:\n", - " \n", - " n:\n", - "\n", - " augment:\n", - " \"\"\"\n", - "\n", - " options = [\"sagittal\", \"coronal\", \"axial\", \"combined\"]\n", - " shape = np.array(x.shape)\n", - " if isinstance(plane, str) and plane in options:\n", - " idxs = np.random.randint(x.shape[0], size=(n_slices, 3))\n", - "# idxs = np.array([[64, 64, 64]])\n", - " if plane == \"sagittal\":\n", - " midx = idxs[:, 0]\n", - " x = x\n", - "\n", - " if plane == \"coronal\":\n", - " midx = idxs[:, 1]\n", - " x = tf.transpose(x, perm=[1, 2, 0])\n", - "\n", - "\n", - " if plane == \"axial\":\n", - " midx = idxs[:, 2]\n", - " x = tf.transpose(x, perm=[2, 0, 1])\n", - "\n", - "\n", - " if plane == \"combined\":\n", - " temp = {}\n", - " for op in options[:-1]:\n", - " temp[op] = structural_slice(x, y, op, n_slices)[0]\n", - " x = temp\n", - "\n", - " if not plane == \"combined\":\n", - " x = tf.squeeze(tf.gather_nd(x, midx.reshape(n_slices, 1, 1)), axis=1)\n", - " x = tf.math.reduce_mean(x, axis=0)\n", - " x = tf.expand_dims(x, axis=-1)\n", - " x = tf.convert_to_tensor(x)\n", - " return x, y\n", - " else:\n", - " raise ValueError(\"expected plane to be one of [sagittal, coronal, axial]\")\n", - "\n", - "\n", - "if __name__ == \"__main__\":\n", - " ROOTDIR = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128/tfrecords_full'\n", - " n_classes = 2\n", - " global_batch_size = 8\n", - " volume_shape = (128, 128, 128)\n", - " ds = get_dataset(\n", - " os.path.join(ROOTDIR, \"data-train_*\"),\n", - " n_classes=n_classes,\n", - " batch_size=global_batch_size,\n", - " volume_shape=volume_shape,\n", - " plane=\"sagittal\",\n", - " shuffle_buffer_size=3,\n", - " )\n", - " \n", - " import matplotlib.pyplot as plt\n", - "\n", - " # x, y = next(ds.as_numpy_operator())\n", - " # print(x.shape, y)\n", - " times = 0\n", - " for x, y in ds.as_numpy_iterator():\n", - " if times == 3:\n", - " break\n", - " print(x.shape, y)\n", - " times += 1\n", - "\n", - " fig = plt.figure(figsize=(25, 8))\n", - "\n", - " for i in range(1, 9):\n", - " fig.add_subplot(1,8, i)\n", - " plt.imshow(x[i-1, :, :])\n", - "\n", - "\n", - " print(ds)\n", - " \n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Std packages\n", - "import sys, os\n", - "import glob\n", - "import math\n", - "\n", - "sys.path.append('..')\n", - "\n", - "# Custom packages\n", - "import defacing\n", - "from defacing.models import modelN\n", - "# from defacing.dataloaders.dataset import get_dataset\n", - "\n", - "# Tf packages\n", - "import tensorflow as tf\n", - "import pandas as pd\n", - "import numpy as np\n", - "from sklearn.utils import class_weight\n", - "from tensorflow.keras import backend as K\n", - "from tensorflow.keras.optimizers import Adam\n", - "from tensorflow.keras.callbacks import (\n", - " ModelCheckpoint,\n", - " LearningRateScheduler,\n", - " TensorBoard,\n", - " EarlyStopping,\n", - ")\n", - "from tensorflow.keras import metrics\n", - "from tensorflow.keras import losses\n", - "\n", - "\n", - "def scheduler(epoch):\n", - " if epoch < 3:\n", - " return 0.001\n", - " else:\n", - " return 0.001 * tf.math.exp(0.1 * (10 - epoch))\n", - "\n", - "\n", - "def train(\n", - " csv_path,\n", - " model_save_path,\n", - " tfrecords_path,\n", - " volume_shape=(64, 64, 64),\n", - " image_size=(64, 64),\n", - " dropout=0.2,\n", - " batch_size=16,\n", - " n_slices=16,\n", - " n_classes=2,\n", - " n_epochs=15,\n", - " percent=100,\n", - " mode='CV',\n", - "):\n", - " \n", - " \n", - " train_csv_path = os.path.join(csv_path, \"training.csv\")\n", - " train_paths = pd.read_csv(train_csv_path)[\"X\"].values\n", - " train_labels = pd.read_csv(train_csv_path)[\"Y\"].values\n", - " \n", - " if mode == 'CV':\n", - " valid_csv_path = os.path.join(csv_path, \"validation.csv\")\n", - " valid_paths = pd.read_csv(valid_csv_path)[\"X\"].values\n", - " valid_labels = pd.read_csv(valid_csv_path)[\"Y\"].values\n", - " \n", - " weights = class_weight.compute_class_weight('balanced',\n", - " np.unique(train_labels),\n", - " train_labels)\n", - " weights = dict(enumerate(weights))\n", - " \n", - " print(weights)\n", - " \n", - " planes = [\"axial\", \"coronal\", \"sagittal\", \"combined\"]\n", - " \n", - "\n", - " global_batch_size = batch_size\n", - " \n", - " os.makedirs(model_save_path, exist_ok=True)\n", - " cp_save_path = os.path.join(model_save_path, \"weights\")\n", - " logdir_path = os.path.join(model_save_path, \"tb_logs\")\n", - " metrics_path = os.path.join(model_save_path, \"metrics\")\n", - " \n", - " os.makedirs(metrics_path, exist_ok=True)\n", - "# os.makedirs(logdir_path, exist_ok=True)\n", - " \n", - " for plane in planes:\n", - "\n", - " logdir = os.path.join(logdir_path, plane)\n", - " os.makedirs(logdir, exist_ok=True)\n", - "\n", - " tbCallback = TensorBoard(log_dir=logdir)\n", - "\n", - " os.makedirs(os.path.join(cp_save_path, plane), exist_ok=True)\n", - "\n", - " model_checkpoint = ModelCheckpoint(\n", - " os.path.join(cp_save_path, plane, \"best-wts.h5\"),\n", - " monitor=\"val_loss\",\n", - " save_weights_only=True,\n", - " mode=\"min\",\n", - " )\n", - "\n", - "# with strategy.scope():\n", - "\n", - " if not plane == \"combined\": \n", - " lr = 1e-3\n", - " model = modelN.Submodel(\n", - " input_shape=image_size,\n", - " dropout=dropout,\n", - " name=plane,\n", - " include_top=True,\n", - " weights=None,\n", - " )\n", - " else:\n", - " lr = 5e-4\n", - " model = modelN.CombinedClassifier(\n", - " input_shape=image_size,\n", - " dropout=dropout,\n", - " trainable=True,\n", - " wts_root=cp_save_path,\n", - " )\n", - "\n", - " print(\"Submodel: \", plane)\n", - "# print(model.summary())\n", - "\n", - " METRICS = [\n", - " metrics.TruePositives(name=\"tp\"),\n", - " metrics.FalsePositives(name=\"fp\"),\n", - " metrics.TrueNegatives(name=\"tn\"),\n", - " metrics.FalseNegatives(name=\"fn\"),\n", - " metrics.BinaryAccuracy(name=\"accuracy\"),\n", - " metrics.Precision(name=\"precision\"),\n", - " metrics.Recall(name=\"recall\"),\n", - " metrics.AUC(name=\"auc\"),\n", - " ]\n", - "\n", - " model.compile(\n", - " loss=tf.keras.losses.binary_crossentropy,\n", - " optimizer=Adam(learning_rate=lr),\n", - " metrics=METRICS,\n", - " )\n", - "\n", - " print(\"GLOBAL BATCH SIZE: \", global_batch_size)\n", - "\n", - " dataset_train = get_dataset(\n", - " file_pattern=os.path.join(tfrecords_path, 'data-train_*'),\n", - " n_classes=n_classes,\n", - " batch_size=global_batch_size,\n", - " volume_shape=volume_shape,\n", - " plane=plane,\n", - " n_slices=n_slices,\n", - " shuffle_buffer_size=global_batch_size,\n", - " )\n", - " \n", - " steps_per_epoch = math.ceil(len(train_paths)/batch_size)\n", - " print(steps_per_epoch)\n", - " \n", - " # CALLBACKS\n", - " lrcallback = tf.keras.callbacks.LearningRateScheduler(scheduler)\n", - " \n", - " if mode == 'CV':\n", - " earlystopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=3)\n", - " \n", - " dataset_valid = get_dataset(\n", - " file_pattern=os.path.join(tfrecords_path, \"data-valid_*\"),\n", - " n_classes=n_classes,\n", - " batch_size=global_batch_size,\n", - " volume_shape=volume_shape,\n", - " plane=plane,\n", - " n_slices=n_slices,\n", - " shuffle_buffer_size=global_batch_size,\n", - " )\n", - " \n", - " validation_steps = math.ceil(len(valid_paths)/batch_size)\n", - " \n", - " history = model.fit(\n", - " dataset_train,\n", - " epochs=n_epochs,\n", - " steps_per_epoch=steps_per_epoch,\n", - " validation_data=dataset_valid,\n", - " validation_steps=validation_steps,\n", - " callbacks=[tbCallback, model_checkpoint],\n", - " class_weight = weights,\n", - " )\n", - " \n", - " hist_df = pd.DataFrame(history.history)\n", - " \n", - " else:\n", - " earlystopping = tf.keras.callbacks.EarlyStopping(monitor='loss', patience=3)\n", - " print(model.summary())\n", - " print(\"Steps/Epoch: \", steps_per_epoch)\n", - " history = model.fit(\n", - " dataset_train,\n", - " epochs=n_epochs,\n", - " steps_per_epoch=steps_per_epoch,\n", - " callbacks=[tbCallback, model_checkpoint, earlystopping],\n", - " class_weight = weights,\n", - " )\n", - " \n", - " hist_df = pd.DataFrame(history.history)\n", - " jsonfile = os.path.join(metrics_path, plane + '.json')\n", - " \n", - " with open(jsonfile, mode='w') as f:\n", - " hist_df.to_json(f)\n", - " \n", - " del model\n", - " K.clear_session()\n", - " \n", - " return history\n", - "\n", - "\n", - "# if __name__ == \"__main__\":\n", - "# ROOTDIR = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128'\n", - "# csv_path = os.path.join(ROOTDIR, \"csv_full\")\n", - "# model_save_path = os.path.join(ROOTDIR, \"model_save_dir_full\")\n", - "# tfrecords_path = os.path.join(ROOTDIR, 'tfrecords_full')\n", - " \n", - "# history = train(\n", - "# csv_path,\n", - "# model_save_path,\n", - "# tfrecords_path,\n", - "# volume_shape=(128, 128, 128),\n", - "# image_size=(128, 128),\n", - "# mode='full'\n", - "# )\n", - " \n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Std packages\n", - "import sys, os\n", - "import glob\n", - "import math\n", - "import tensorflow as tf\n", - "\n", - "sys.path.append('..')\n", - "\n", - "# Custom packages\n", - "# import defacing\n", - "# from defacing.models import modelN\n", - "# from defacing.dataloaders.dataset import get_dataset\n", - "# from defacing.training.training import train\n", - "\n", - "for fold in range(8, 16):\n", - " ROOTDIR = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128'\n", - " \n", - " csv_path = os.path.join(ROOTDIR, 'csv_F15/train_test_fold_{}/csv'.format(fold))\n", - " model_save_path = os.path.join(ROOTDIR, 'model_save_dir_F15/train_test_fold_{}'.format(fold))\n", - " tfrecords_path = os.path.join(ROOTDIR, 'tfrecords_F15/tfrecords_fold_{}'.format(fold))\n", - " \n", - " history = train(\n", - " csv_path,\n", - " model_save_path,\n", - " tfrecords_path,\n", - " volume_shape = (128, 128, 128),\n", - " image_size = (128, 128),\n", - " mode = 'CV',\n", - " n_slices=24,\n", - " batch_size = 32,\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pip install -U tensorboard_plugin_profile\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import tensorflow as tf\n", - "device_name = tf.test.gpu_device_name()\n", - "if not device_name:\n", - " raise SystemError('GPU device not found')\n", - "print('Found GPU at: {}'.format(device_name))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from nondefaced_detector import preprocess\n", - "vol_path = '../../examples/sample_vols/IXI002-Guys-0828-T1.nii.gz'\n", - "save_path = ''\n", - "ppath, cpath = preprocess.preprocess(vol_path, save_path=save_path)\n", - "print(ppath, cpath)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys, os\n", - "from nondefaced_detector.models.modelN import CombinedClassifier\n", - "from nondefaced_detector.helpers import utils\n", - "\n", - "import tensorflow as tf\n", - "from tensorflow.keras import backend as K\n", - "from tensorflow.keras.optimizers import Adam\n", - "from tensorflow.keras import metrics\n", - "from tensorflow.keras import losses\n", - "\n", - "weights_path = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128/model_save_dir_full/weights/combined/best-wts.h5'\n", - "wts_root = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128/model_save_dir_full/weights'\n", - "\n", - "model = CombinedClassifier(\n", - " input_shape=(128, 128), dropout=0.4, wts_root=wts_root, trainable=False)\n", - " \n", - "model.load_weights(os.path.abspath(weights_path))\n", - "model.trainable = False\n", - "\n", - "METRICS = [\n", - " metrics.TruePositives(name=\"tp\"),\n", - " metrics.FalsePositives(name=\"fp\"),\n", - " metrics.TrueNegatives(name=\"tn\"),\n", - " metrics.FalseNegatives(name=\"fn\"),\n", - " metrics.BinaryAccuracy(name=\"accuracy\"),\n", - " metrics.Precision(name=\"precision\"),\n", - " metrics.Recall(name=\"recall\"),\n", - " metrics.AUC(name=\"auc\"),\n", - "]\n", - "\n", - "# model.compile(\n", - "# loss=tf.keras.losses.binary_crossentropy,\n", - "# optimizer=Adam(learning_rate=1e-3),\n", - "# metrics=METRICS,\n", - "# )\n", - "\n", - "volume, affine, _ = utils.load_vol(cpath)\n", - "\n", - "print(volume.shape)\n", - "\n", - "# dataset_test = get_dataset(\n", - "# file_pattern=,\n", - "# n_classes=2,\n", - "# batch_size=128,\n", - "# volume_shape=(128, 128, 128),\n", - "# plane='combined',\n", - "# mode='test'\n", - "# )\n", - "\n", - "\n", - "# print(volume.shape)\n", - "\n", - "# model.predict(volume)\n", - "\n", - " \n" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"model_146\"\n", - "__________________________________________________________________________________________________\n", - "Layer (type) Output Shape Param # Connected to \n", - "==================================================================================================\n", - "axial (InputLayer) [(None, 128, 128, 1) 0 \n", - "__________________________________________________________________________________________________\n", - "sagittal (InputLayer) [(None, 128, 128, 1) 0 \n", - "__________________________________________________________________________________________________\n", - "coronal (InputLayer) [(None, 128, 128, 1) 0 \n", - "__________________________________________________________________________________________________\n", - "conv2d_732 (Conv2D) (None, 128, 128, 8) 80 axial[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_738 (Conv2D) (None, 128, 128, 8) 80 sagittal[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_744 (Conv2D) (None, 128, 128, 8) 80 coronal[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_732 (BatchN (None, 128, 128, 8) 32 conv2d_732[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_738 (BatchN (None, 128, 128, 8) 32 conv2d_738[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_744 (BatchN (None, 128, 128, 8) 32 conv2d_744[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_732 (Activation) (None, 128, 128, 8) 0 batch_normalization_732[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_738 (Activation) (None, 128, 128, 8) 0 batch_normalization_738[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_744 (Activation) (None, 128, 128, 8) 0 batch_normalization_744[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_733 (Conv2D) (None, 128, 128, 8) 584 activation_732[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_739 (Conv2D) (None, 128, 128, 8) 584 activation_738[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_745 (Conv2D) (None, 128, 128, 8) 584 activation_744[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_733 (BatchN (None, 128, 128, 8) 32 conv2d_733[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_739 (BatchN (None, 128, 128, 8) 32 conv2d_739[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_745 (BatchN (None, 128, 128, 8) 32 conv2d_745[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_733 (Activation) (None, 128, 128, 8) 0 batch_normalization_733[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_739 (Activation) (None, 128, 128, 8) 0 batch_normalization_739[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_745 (Activation) (None, 128, 128, 8) 0 batch_normalization_745[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_366 (MaxPooling2D (None, 64, 64, 8) 0 activation_733[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_369 (MaxPooling2D (None, 64, 64, 8) 0 activation_739[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_372 (MaxPooling2D (None, 64, 64, 8) 0 activation_745[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_734 (Conv2D) (None, 64, 64, 16) 1168 max_pooling2d_366[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_740 (Conv2D) (None, 64, 64, 16) 1168 max_pooling2d_369[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_746 (Conv2D) (None, 64, 64, 16) 1168 max_pooling2d_372[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_734 (BatchN (None, 64, 64, 16) 64 conv2d_734[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_740 (BatchN (None, 64, 64, 16) 64 conv2d_740[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_746 (BatchN (None, 64, 64, 16) 64 conv2d_746[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_734 (Activation) (None, 64, 64, 16) 0 batch_normalization_734[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_740 (Activation) (None, 64, 64, 16) 0 batch_normalization_740[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_746 (Activation) (None, 64, 64, 16) 0 batch_normalization_746[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_735 (Conv2D) (None, 64, 64, 16) 2320 activation_734[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_741 (Conv2D) (None, 64, 64, 16) 2320 activation_740[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_747 (Conv2D) (None, 64, 64, 16) 2320 activation_746[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_735 (BatchN (None, 64, 64, 16) 64 conv2d_735[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_741 (BatchN (None, 64, 64, 16) 64 conv2d_741[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_747 (BatchN (None, 64, 64, 16) 64 conv2d_747[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_735 (Activation) (None, 64, 64, 16) 0 batch_normalization_735[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_741 (Activation) (None, 64, 64, 16) 0 batch_normalization_741[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_747 (Activation) (None, 64, 64, 16) 0 batch_normalization_747[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_367 (MaxPooling2D (None, 32, 32, 16) 0 activation_735[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_370 (MaxPooling2D (None, 32, 32, 16) 0 activation_741[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_373 (MaxPooling2D (None, 32, 32, 16) 0 activation_747[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_736 (Conv2D) (None, 32, 32, 32) 4640 max_pooling2d_367[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_742 (Conv2D) (None, 32, 32, 32) 4640 max_pooling2d_370[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_748 (Conv2D) (None, 32, 32, 32) 4640 max_pooling2d_373[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_736 (BatchN (None, 32, 32, 32) 128 conv2d_736[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_742 (BatchN (None, 32, 32, 32) 128 conv2d_742[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_748 (BatchN (None, 32, 32, 32) 128 conv2d_748[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_736 (Activation) (None, 32, 32, 32) 0 batch_normalization_736[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_742 (Activation) (None, 32, 32, 32) 0 batch_normalization_742[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_748 (Activation) (None, 32, 32, 32) 0 batch_normalization_748[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_737 (Conv2D) (None, 32, 32, 32) 9248 activation_736[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_743 (Conv2D) (None, 32, 32, 32) 9248 activation_742[0][0] \n", - "__________________________________________________________________________________________________\n", - "conv2d_749 (Conv2D) (None, 32, 32, 32) 9248 activation_748[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_737 (BatchN (None, 32, 32, 32) 128 conv2d_737[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_743 (BatchN (None, 32, 32, 32) 128 conv2d_743[0][0] \n", - "__________________________________________________________________________________________________\n", - "batch_normalization_749 (BatchN (None, 32, 32, 32) 128 conv2d_749[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_737 (Activation) (None, 32, 32, 32) 0 batch_normalization_737[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_743 (Activation) (None, 32, 32, 32) 0 batch_normalization_743[0][0] \n", - "__________________________________________________________________________________________________\n", - "activation_749 (Activation) (None, 32, 32, 32) 0 batch_normalization_749[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_368 (MaxPooling2D (None, 16, 16, 32) 0 activation_737[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_371 (MaxPooling2D (None, 16, 16, 32) 0 activation_743[0][0] \n", - "__________________________________________________________________________________________________\n", - "max_pooling2d_374 (MaxPooling2D (None, 16, 16, 32) 0 activation_749[0][0] \n", - "__________________________________________________________________________________________________\n", - "flatten_122 (Flatten) (None, 8192) 0 max_pooling2d_368[0][0] \n", - "__________________________________________________________________________________________________\n", - "flatten_123 (Flatten) (None, 8192) 0 max_pooling2d_371[0][0] \n", - "__________________________________________________________________________________________________\n", - "flatten_124 (Flatten) (None, 8192) 0 max_pooling2d_374[0][0] \n", - "__________________________________________________________________________________________________\n", - "add_21 (Add) (None, 8192) 0 flatten_122[0][0] \n", - " flatten_123[0][0] \n", - " flatten_124[0][0] \n", - "__________________________________________________________________________________________________\n", - "dense_80 (Dense) (None, 256) 2097408 add_21[0][0] \n", - "__________________________________________________________________________________________________\n", - "dropout_80 (Dropout) (None, 256) 0 dense_80[0][0] \n", - "__________________________________________________________________________________________________\n", - "output_node (Dense) (None, 1) 257 dropout_80[0][0] \n", - "==================================================================================================\n", - "Total params: 2,153,129\n", - "Trainable params: 2,115,929\n", - "Non-trainable params: 37,200\n", - "__________________________________________________________________________________________________\n", - "None\n" - ] - } - ], - "source": [ - "\"\"\"Methods to predict using trained models\"\"\"\n", - "\n", - "import os\n", - "import numpy as np\n", - "import tensorflow as tf\n", - "\n", - "from pathlib import Path\n", - "\n", - "from nondefaced_detector.models.modelN import CombinedClassifier\n", - "from nondefaced_detector.helpers import utils\n", - "\n", - "\n", - "def predict(\n", - " input_volume,\n", - " model_path,\n", - " batch_size=1,\n", - " n_samples=1,\n", - " n_slices=32,\n", - "):\n", - " \"\"\"Return predictions from `inputs`.\n", - "\n", - " This is a general prediction method.\n", - "\n", - " Parameters\n", - " ---------\n", - "\n", - "\n", - " Returns\n", - " ------\n", - " \"\"\"\n", - "\n", - " if n_samples < 1:\n", - " raise Exception(\"n_samples cannot be lower than 1.\")\n", - "\n", - " model = _get_model(model_path)\n", - "\n", - " ds = _structural_slice(input_volume, plane='combined', n_slices=n_slices)\n", - " ds = tf.data.Dataset.from_tensor_slices(ds)\n", - " ds = ds.batch(batch_size=batch_size, drop_remainder=False)\n", - "\n", - " predicted = model.predict(ds)\n", - "\n", - " return predicted\n", - "\n", - "\n", - "def _structural_slice(x, plane, n_slices=16):\n", - "\n", - " \"\"\"Transpose dataset based on the plane\n", - "\n", - " Parameters\n", - " ----------\n", - " x:\n", - "\n", - " plane:\n", - "\n", - " n_slices:\n", - "\n", - " Returns\n", - " -------\n", - " \"\"\"\n", - "\n", - " options = [\"sagittal\", \"coronal\", \"axial\", \"combined\"]\n", - "\n", - " if isinstance(plane, str) and plane in options:\n", - " idxs = np.random.randint(x.shape[0], size=(n_slices, 3))\n", - " if plane == \"sagittal\":\n", - " midx = idxs[:, 0]\n", - " x = x\n", - "\n", - " if plane == \"coronal\":\n", - " midx = idxs[:, 1]\n", - " x = tf.transpose(x, perm=[1, 2, 0])\n", - "\n", - " if plane == \"axial\":\n", - " midx = idxs[:, 2]\n", - " x = tf.transpose(x, perm=[2, 0, 1])\n", - "\n", - " if plane == \"combined\":\n", - " temp = {}\n", - " for op in options[:-1]:\n", - " temp[op] = _structural_slice(x, op, n_slices)\n", - " x = temp\n", - "\n", - " if not plane == \"combined\":\n", - " x = tf.squeeze(tf.gather_nd(x, midx.reshape(n_slices, 1, 1)), axis=1)\n", - " x = tf.math.reduce_mean(x, axis=0, keepdims=True)\n", - " x = tf.expand_dims(x, axis=-1)\n", - " x = tf.convert_to_tensor(x)\n", - "\n", - " return x\n", - " else:\n", - " raise ValueError(\"Expected plane to be one of [sagittal, coronal, axial, combined]\")\n", - "\n", - "\n", - "def _get_model(model_path):\n", - "\n", - " \"\"\"Return `tf.keras.Model` object from a filepath.\n", - "\n", - " Parameters\n", - " ----------\n", - " path: str, path to HDF5 or SavedModel file.\n", - "\n", - " Returns\n", - " -------\n", - " Instance of `tf.keras.Model`.\n", - "\n", - " Raises\n", - " ------\n", - " `ValueError` if cannot load model.\n", - " \"\"\"\n", - "\n", - " try:\n", - " model = CombinedClassifier(\n", - " input_shape=(128, 128), wts_root=model_path, trainable=False\n", - " )\n", - " \n", - " p = Path(model_path).resolve()\n", - " \n", - " combined_weights = list(\n", - " Path(os.path.join(p, 'combined')).glob('*.h5')\n", - " )[0].resolve()\n", - " \n", - "\n", - " model.load_weights(combined_weights)\n", - " model.trainable = False\n", - "\n", - " return model\n", - "\n", - " except Exception as e:\n", - " print(e)\n", - " pass\n", - "\n", - " raise ValueError(\"Failed to load model.\")\n", - "\n", - "\n", - "if __name__==\"__main__\":\n", - "\n", - " from nondefaced_detector import preprocess\n", - " from nondefaced_detector.helpers import utils\n", - "\n", - "# weights_path = 'models/pretrained_weights/combined/best-wts.h5'\n", - " wts_root = '../../nondefaced_detector/models/pretrained_weights'\n", - " model = _get_model(wts_root)\n", - " \n", - "# vol_path = '../examples/sample_vols/IXI002-Guys-0828-T1.nii.gz'\n", - "# ppath, cpath = preprocess.preprocess(vol_path)\n", - "\n", - "# volume, affine,_ = utils.load_vol(cpath)\n", - "\n", - "# predicted = predict(volume, wts_root, weights_path)\n", - "\n", - "# print(predicted)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[0.9999958]]\n" - ] - } - ], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "/usr/bin/python3\r\n" - ] - } - ], - "source": [ - "!which python3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "import sys, os\n", - "sys.path.append('..')\n", - "from defacing.models.modelN import CombinedClassifier\n", - "# from defacing.dataloaders.dataset import get_dataset\n", - "\n", - "\n", - "# Tf packages\n", - "import tensorflow as tf\n", - "from tensorflow.keras import backend as K\n", - "from tensorflow.keras.optimizers import Adam\n", - "from tensorflow.keras import metrics\n", - "from tensorflow.keras import losses\n", - "\n", - "def inference(tfrecords_path, weights_path, wts_root):\n", - " \n", - " model = CombinedClassifier(\n", - " input_shape=(128, 128), dropout=0.4, wts_root=wts_root, trainable=False)\n", - " \n", - " model.load_weights(os.path.abspath(weights_path))\n", - " model.trainable = False\n", - " \n", - " dataset_test = get_dataset(\n", - " file_pattern=os.path.join(tfrecords_path, \"data-test_*\"),\n", - " n_classes=2,\n", - " batch_size=128,\n", - " volume_shape=(128, 128, 128),\n", - " plane='combined',\n", - " mode='test'\n", - " )\n", - "\n", - " METRICS = [\n", - " metrics.TruePositives(name=\"tp\"),\n", - " metrics.FalsePositives(name=\"fp\"),\n", - " metrics.TrueNegatives(name=\"tn\"),\n", - " metrics.FalseNegatives(name=\"fn\"),\n", - " metrics.BinaryAccuracy(name=\"accuracy\"),\n", - " metrics.Precision(name=\"precision\"),\n", - " metrics.Recall(name=\"recall\"),\n", - " metrics.AUC(name=\"auc\"),\n", - " ]\n", - " \n", - " model.compile(\n", - " loss=tf.keras.losses.binary_crossentropy,\n", - " optimizer=Adam(learning_rate=1e-3),\n", - " metrics=METRICS,\n", - " )\n", - " eval_dict = model.evaluate(dataset_test, return_dict=True)\n", - " predictions = (model.predict(dataset_test) > 0.5).astype(int)\n", - " \n", - " \n", - " return eval_dict, predictions\n", - "\n", - "\n", - "ROOTDIR = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/test_ixi'\n", - "tfrecords_path = os.path.join(ROOTDIR, \"tfrecords_new\")\n", - "weights_path = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128/model_save_dir_full/weights/combined/best-wts.h5'\n", - "wts_root = '/tf/shank/HDDLinux/Stanford/data/mriqc-shared/experiments/experiment_B/128/model_save_dir_full/weights'\n", - "edict, preds = inference(tfrecords_path, weights_path, wts_root)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(preds)\n", - "print(edict)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "\n", - "# x, y = next(ds.as_numpy_operator())\n", - "# print(x.shape, y)\n", - "times = 0\n", - "for x, y in ds.as_numpy_iterator():\n", - " if times == 3:\n", - " break\n", - " print(x.shape, y)\n", - " times += 1\n", - " \n", - " fig = plt.figure(figsize=(25, 8))\n", - " \n", - " for i in range(1, 9):\n", - " fig.add_subplot(1,8, i)\n", - " plt.imshow(x[i-1, :, :])\n", - " \n", - "# all_imgs = []\n", - "# for i in range(len(batch_predictions)):\n", - "# if batch_predictions.flatten()[i] != y.flatten()[i].astype(int):\n", - "# incorr += 1\n", - "# print(\"Predicted: \",batch_predictions.flatten()[i], \"Actual: \", y.flatten()[i].astype(int))\n", - "# else:\n", - "# corr += 1\n", - " \n", - "# fig = plt.figure(figsize=(25, 8))\n", - "# rows, cols = 3, 16\n", - " \n", - "# for i in range(1, cols*rows + 1):\n", - "# # if i/cols == 1:\n", - "# # use = x['coronal']\n", - "# # if i/cols == 2:\n", - "# # use = x['sagittal']\n", - " \n", - "# fig.add_subplot(rows, cols, i)\n", - " \n", - "# plt.imshow(use[(i-1)%cols,:,:, 0])\n", - "\n", - "\n", - "# plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/nondefaced_detector/__init__.py b/nondefaced_detector/__init__.py index 11947b5..85eeb8c 100755 --- a/nondefaced_detector/__init__.py +++ b/nondefaced_detector/__init__.py @@ -8,12 +8,15 @@ import nondefaced_detector.prediction import nondefaced_detector.preprocess import nondefaced_detector.preprocessing +import nondefaced_detector.utils try: __version__ = get_distribution("nondefaced-detector").version except DistributionNotFound: # package is not installed - pass + raise ValueError( + "nondefaced-detector must be installed" + ) if LooseVersion(tf.__version__) < LooseVersion("2.0.0"): raise ValueError( diff --git a/nondefaced_detector/_version.py b/nondefaced_detector/_version.py deleted file mode 100755 index 4a5f82e..0000000 --- a/nondefaced_detector/_version.py +++ /dev/null @@ -1,566 +0,0 @@ -<<<<<<< HEAD -"""Version file, automatically generated by setuptools_scm.""" -__version__ = "0.1.1.dev6+gb37b863.d20210406" -======= -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.19 (https://github.com/python-versioneer/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "$Format:%d$" - git_full = "$Format:%H$" - git_date = "$Format:%ci$" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "pep440" - cfg.tag_prefix = "" - cfg.parentdir_prefix = "" - cfg.versionfile_source = "nondefaced-detector/_version.py" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Create decorator to mark a method as the handler of a VCS.""" - - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip().decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] - if verbose: - print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post0.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post0.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post0.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post0.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split("/"): - root = os.path.dirname(root) - except NameError: - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None, - } - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } ->>>>>>> b51026b... [WORKING] preprocess_parallel: preprocess volumes from a csv diff --git a/nondefaced_detector/cli/main.py b/nondefaced_detector/cli/main.py index 83f4413..f988cfa 100755 --- a/nondefaced_detector/cli/main.py +++ b/nondefaced_detector/cli/main.py @@ -28,9 +28,10 @@ from nondefaced_detector import prediction -from nondefaced_detector.helpers import utils +from nondefaced_detector.helpers import utils from nondefaced_detector.preprocess import preprocess, cleanup_files from nondefaced_detector.preprocess import preprocess_parallel +from nondefaced_detector.utils import get_datalad _option_kwds = {"show_default": True} @@ -189,8 +190,9 @@ def convert( "-m", "--model-path", type=click.Path(exists=True), - required=True, - help="Path to model weights. NOTE: A version of pretrained model weights can be found here: https://github.com/poldracklab/nondefaced-detector/tree/master/model_weights", + help="Path to model weights. \ + NOTE: A version of pretrained model weights can be found here: \ + https://gin.g-node.org/shashankbansal56/nondefaced-detector-reproducibility/pretrained_weights", **_option_kwds, ) @click.option( @@ -273,6 +275,15 @@ def predict( if not os.path.exists(infile): raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), infile) + print("model_path:", model_path) + if not model_path: + print("Model weights not found. \ + Downloading to /tmp/nondefaced-detector-reproducibility") + + cache_dir = get_datalad() + model_path = os.path.join(cache_dir, 'pretrained_weights') + + required_dirs = ["axial", "coronal", "sagittal", "combined"] for plane in required_dirs: diff --git a/nondefaced_detector/dataloaders/__init__.py b/nondefaced_detector/dataloaders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nondefaced_detector/helpers/__init__.py b/nondefaced_detector/helpers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nondefaced_detector/inference.py b/nondefaced_detector/inference.py index 47b8ff7..0619a1f 100755 --- a/nondefaced_detector/inference.py +++ b/nondefaced_detector/inference.py @@ -43,3 +43,18 @@ def inference(tfrecords_path, weights_path, wts_root): ) model.evaluate(dataset_test) + + +if __name__ == "__main__": + + parser = argparse.ArgumentParser() + + parser.add_argument("tfrecords", metavar="tfrecords_path", help="Path to tfrecords.") + parser.add_argument("model_path", metavar="model_path", help="Path to pretrained model weights.") + + args = parser.parse_args() + + tfrecords_path = args.tfrecords + model_path = args.model_path + combined_path = os.path.join(model_path, "combined/best-wts.h5") + inference(tfrecords_path, combined_path, model_path) diff --git a/nondefaced_detector/models/__init__.py b/nondefaced_detector/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nondefaced_detector/preprocessing/__init__.py b/nondefaced_detector/preprocessing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nondefaced_detector/tests/__init__.py b/nondefaced_detector/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nondefaced_detector/tests/utils_test.py b/nondefaced_detector/tests/utils_test.py new file mode 100644 index 0000000..fcbb5da --- /dev/null +++ b/nondefaced_detector/tests/utils_test.py @@ -0,0 +1,16 @@ +import os +import pytest + +import datalad.api + +from nondefaced_detector.utils import get_datalad + + +def test_utils(): + + get_datalad() + cache_dir = '/tmp/nondefaced-detector-reproducibility' + assert(os.path.exists(cache_dir)) + assert(os.path.exists(os.path.join(cache_dir, 'pretrained_weights'))) + datalad.api.ls(cache_dir, long_=True) + assert(datalad.api.remove(cache_dir)) diff --git a/nondefaced_detector/training/__init__.py b/nondefaced_detector/training/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nondefaced_detector/utils.py b/nondefaced_detector/utils.py new file mode 100644 index 0000000..18b84f6 --- /dev/null +++ b/nondefaced_detector/utils.py @@ -0,0 +1,66 @@ +"""Utilities for Nondefaced-detector.""" + + +import os +import tempfile + +import datalad.api + + +_cache_dir = os.path.join(tempfile.gettempdir(), "nondefaced-detector-reproducibility") + + +def get_datalad( + cache_dir=_cache_dir, + datalad_repo="https://gin.g-node.org/shashankbansal56/nondefaced-detector-reproducibility", + examples=False, + test_ixi=False, +): + """Download a datalad dataset/repo. + + The weights can be found at + https://gin.g-node.org/shashankbansal56/nondefaced-detector-reproducibility/ + + Parameters + ---------- + cache_dir: str, directory where to clone datalad repo. Save to a /tmp by default + + """ + + os.makedirs(cache_dir, exist_ok=True) + + try: + datalad.api.clone(path=cache_dir, source=datalad_repo) + datalad.api.get( + path=os.path.join(cache_dir, "pretrained_weights"), + dataset=cache_dir, + recursive=True, + ) + + if examples: + datalad.api.get( + path=os.path.join(cache_dir, "examples"), + dataset=cache_dir, + recursive=True, + ) + + if test_ixi: + inp = str( + input( + "The test_ixi subdirectory contains large files and will take a while to download. \ + Are you sure you want to download these? [y/n]" + ) + ) + + if "y" in inp.lower(): + datalad.api.get( + path=os.path.join(cache_dir, "test_ixi"), + dataset=cache_dir, + recursive=True, + ) + + return cache_dir + + except Exception as e: + print(e) + print("Something went wrong! Cleaning up...") diff --git a/setup.cfg b/setup.cfg index c1bbb7b..381f5f7 100755 --- a/setup.cfg +++ b/setup.cfg @@ -31,9 +31,10 @@ packages = find: python_requires = >=3.6 install_requires = click - numpy + datalad nibabel nobrainer + numpy tqdm [options.entry_points]