diff --git a/competition/.DS_Store b/competition/.DS_Store deleted file mode 100644 index 58f8cc6..0000000 Binary files a/competition/.DS_Store and /dev/null differ diff --git a/datasets/.DS_Store b/datasets/.DS_Store deleted file mode 100644 index f2c7759..0000000 Binary files a/datasets/.DS_Store and /dev/null differ diff --git a/figures/.DS_Store b/figures/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/figures/.DS_Store and /dev/null differ diff --git a/figures/superbar/.DS_Store b/figures/superbar/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/figures/superbar/.DS_Store and /dev/null differ diff --git a/keras/downstream_tasks/BraTS/DataSet.py b/keras/downstream_tasks/BraTS/DataSet.py new file mode 100755 index 0000000..dcf72c1 --- /dev/null +++ b/keras/downstream_tasks/BraTS/DataSet.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python +""" +File: DataSet +Date: 5/1/18 +Author: Jon Deaton (jdeaton@stanford.edu) + +This file provides loading of the BraTS datasets +for ease of use in TensorFlow models. +""" + +import os + +import pandas as pd +import numpy as np +import nibabel as nib + +from tqdm import tqdm +from BraTS.Patient import * +from BraTS.structure import * +from BraTS.modalities import * +from BraTS.load_utils import * + +survival_df_cache = {} # Prevents loading CSVs more than once + + +class DataSubSet: + + def __init__(self, directory_map, survival_csv, data_set_type=None): + self.directory_map = directory_map + self._patient_ids = sorted(list(directory_map.keys())) + self._survival_csv = survival_csv + self._num_patients = len(self._patient_ids) + self.type = data_set_type + + # Data caches + self._mris = None + self._segs = None + self._patients = {} + self._survival_df_cached = None + self._patients_fully_loaded = False + self._id_indexer = {patient_id: i for i, patient_id in enumerate(self._patient_ids)} + + def subset(self, patient_ids): + """ + Split this data subset into a small subset by patient ID + + :param n: The number of elements in the smaller training set + :return: A new data subset with only the specified number of items + """ + dir_map = {id: self.directory_map[id] for id in patient_ids} + return DataSubSet(dir_map, self._survival_csv) + + @property + def ids(self): + """ + List of all patient IDs in this dataset + + Will copy the ids... so modify them all you want + :return: Copy of the patient IDs + """ + return list(self._patient_ids) + + @property + def mris(self): + if self._mris is not None: + return self._mris + self._load_images() + return self._mris + + @property + def segs(self): + if self._segs is None: + self._load_images() + return self._segs + + def _load_images(self): + mris_shape = (self._num_patients,) + mri_shape + segs_shape = (self._num_patients,) + image_shape + + self._mris = np.empty(shape=mris_shape) + self._segs = np.empty(shape=segs_shape) + + if self._patients_fully_loaded: + # All the patients were already loaded + for i, patient in enumerate(tqdm(self._patients.values())): + self._mris[i] = patient.mri_data + self._segs[i] = patient.seg + else: + # Load it from scratch + for i, patient_id in enumerate(self._patient_ids): + patient_dir = self.directory_map[patient_id] + load_patient_data_inplace(patient_dir, self._mris, self._segs, i) + + @property + def patients(self): + """ + Loads ALL of the patients from disk into patient objects + + :return: A dictionary containing ALL patients + """ + for patient_id in self.ids: + yield self.patient(patient_id) + self._patients_fully_loaded = True + + def patient(self, patient_id): + """ + Loads only a single patient from disk + + :param patient_id: The patient ID + :return: A Patient object loaded from disk + """ + if patient_id not in self._patient_ids: + raise ValueError("Patient id \"%s\" not present." % patient_id) + + # Return cached value if present + if patient_id in self._patients: + return self._patients[patient_id] + + # Load patient data into memory + patient = Patient(patient_id) + patient_dir = self.directory_map[patient_id] + + df = self._survival_df + if patient_id in df.id.values: + patient.age = float(df.loc[df.id == patient_id].age) + patient.survival = int(df.loc[df.id == patient_id].survival) + + if self._mris is not None and self._segs is not None: + # Load from _mris and _segs if possible + index = self._id_indexer[patient_id] + patient.mri = self._mris[index] + patient.seg = self._segs[index] + else: + # Load the mri and segmentation data from disk + patient.mri, patient.seg = load_patient_data(patient_dir) + + self._patients[patient_id] = patient # cache the value for later + return patient + + def drop_cache(self): + self._patients.clear() + self._mris = None + self._segs = None + + + @property + def _survival_df(self): + if self._survival_csv in survival_df_cache: + return survival_df_cache[self._survival_csv] + df = load_survival(self._survival_csv) + survival_df_cache[self._survival_csv] = df + return df + + +class DataSet(object): + + def __init__(self, data_set_dir=None, brats_root=None, year=None): + + if data_set_dir is not None: + # The data-set directory was specified explicitly + assert isinstance(data_set_dir, str) + self._data_set_dir = data_set_dir + + elif brats_root is not None and isinstance(year, int): + # Find the directory by specifying the year + assert isinstance(brats_root, str) + year_dir = find_file_containing(brats_root, str(year % 100)) + self._data_set_dir = os.path.join(brats_root, year_dir) + self._brats_root = brats_root + self._year = year + + else: + # BraTS data-set location was not improperly specified + raise Exception("Specify BraTS location with \"data_set_dir\" or with \"brats_root\" and \"year\"") + + self._validation = None + self._train = None + self._hgg = None + self._lgg = None + + self._dir_map_cache = None + + self._val_dir = None + self._train_dir_cached = None + self._hgg_dir = os.path.join(self._train_dir, "HGG") + self._lgg_dir = os.path.join(self._train_dir, "LGG") + + self._train_survival_csv_cached = None + self._validation_survival_csv_cached = None + + self._train_ids = None + self._hgg_ids_cached = None + self._lgg_ids_cached = None + + self._train_dir_map_cache = None + self._validation_dir_map_cache = None + self._hgg_dir_map_cache = None + self._lgg_dir_map_cache = None + + def set(self, data_set_type): + """ + Get a data subset by type + + :param data_set_type: The DataSubsetType to get + :return: The data sub-set of interest + """ + assert isinstance(data_set_type, DataSubsetType) + if data_set_type == DataSubsetType.train: + return self.train + if data_set_type == DataSubsetType.hgg: + return self.hgg + if data_set_type == DataSubsetType.lgg: + return self.lgg + if data_set_type == DataSubsetType.validation: + return self.validation + + @property + def train(self): + """ + Training data + + Loads the training data from disk, utilizing caching + :return: A tf.data.Dataset object containing the training data + """ + if self._train is None: + try: + self._train = DataSubSet(self._train_dir_map, + self._train_survival_csv, + data_set_type=DataSubsetType.train) + except FileNotFoundError: + return None + return self._train + + @property + def validation(self): + """ + Validation data + + :return: Validation data + """ + if self._validation is None: + try: + self._validation = DataSubSet(self._validation_dir_map, + self._validation_survival_csv, + data_set_type=DataSubsetType.validation) + except FileNotFoundError: + return None + return self._validation + + @property + def hgg(self): + if self._hgg is None: + try: + self._hgg = DataSubSet(self._hgg_dir_map, + self._train_survival_csv, + data_set_type=DataSubsetType.hgg) + except FileNotFoundError: + return None + return self._hgg + + @property + def lgg(self): + if self._lgg is None: + try: + self._lgg = DataSubSet(self._lgg_dir_map, + self._train_survival_csv, + data_set_type=DataSubsetType.lgg) + except FileNotFoundError: + return None + return self._lgg + + def drop_cache(self): + """ + Drops the cached values in the object + :return: None + """ + self._validation = None + self._train = None + self._hgg = None + self._lgg = None + + self._dir_map_cache = None + self._val_dir = None + self._train_dir_cached = None + self._train_survival_csv_cached = None + self._validation_survival_csv_cached = None + + self._train_ids = None + self._hgg_ids_cached = None + self._lgg_ids_cached = None + + self._train_dir_map_cache = None + self._validation_dir_map_cache = None + self._hgg_dir_map_cache = None + self._lgg_dir_map_cache = None + + @property + def _train_survival_csv(self): + if self._train_survival_csv_cached is None: + self._train_survival_csv_cached = find_file_containing(self._train_dir, "survival") + if self._train_survival_csv_cached is None: + raise FileNotFoundError("Could not find survival CSV in %s" % self._train_dir) + return self._train_survival_csv_cached + + @property + def _validation_survival_csv(self): + if self._validation_survival_csv_cached is None: + self._validation_survival_csv_cached = find_file_containing(self._validation_dir, "survival") + if self._validation_survival_csv_cached is None: + raise FileNotFoundError("Could not find survival CSV in %s" % self._validation_dir) + return self._validation_survival_csv_cached + + @property + def _train_dir(self): + if self._train_dir_cached is not None: + return self._train_dir_cached + self._train_dir_cached = find_file_containing(self._data_set_dir, "training") + if self._train_dir_cached is None: + raise FileNotFoundError("Could not find training directory in %s" % self._data_set_dir) + return self._train_dir_cached + + @property + def _validation_dir(self): + if self._val_dir is not None: + return self._val_dir + self._val_dir = find_file_containing(self._data_set_dir, "validation") + if self._val_dir is None: + raise FileNotFoundError("Could not find validation directory in %s" % self._data_set_dir) + return self._val_dir + + @property + def _train_dir_map(self): + if self._train_dir_map_cache is None: + self._train_dir_map_cache = dict(self._hgg_dir_map) + self._train_dir_map_cache.update(self._lgg_dir_map) + return self._train_dir_map_cache + + @property + def _validation_dir_map(self): + if self._validation_dir_map_cache is None: + self._validation_dir_map_cache = self._directory_map(self._validation_dir) + return self._validation_dir_map_cache + + @property + def _hgg_dir_map(self): + if self._hgg_dir_map_cache is None: + self._hgg_dir_map_cache = self._directory_map(self._hgg_dir) + return self._hgg_dir_map_cache + + @property + def _lgg_dir_map(self): + if self._lgg_dir_map_cache is None: + self._lgg_dir_map_cache = self._directory_map(self._lgg_dir) + return self._lgg_dir_map_cache + + @property + def _hgg_ids(self): + if self._hgg_ids_cached is None: + self._hgg_ids_cached = os.listdir(self._hgg_dir) + return self._hgg_ids_cached + + @property + def _lgg_ids(self): + if self._lgg_ids_cached is None: + self._lgg_ids_cached = os.listdir(self._lgg_dir) + return self._lgg_ids_cached + + @classmethod + def _directory_map(cls, dir): + return {file: os.path.join(dir, file) + for file in os.listdir(dir) + if os.path.isdir(os.path.join(dir, file))} diff --git a/keras/downstream_tasks/BraTS/DataSet.pyc b/keras/downstream_tasks/BraTS/DataSet.pyc new file mode 100755 index 0000000..cb9d78c Binary files /dev/null and b/keras/downstream_tasks/BraTS/DataSet.pyc differ diff --git a/keras/downstream_tasks/BraTS/Patient.py b/keras/downstream_tasks/BraTS/Patient.py new file mode 100755 index 0000000..88afaab --- /dev/null +++ b/keras/downstream_tasks/BraTS/Patient.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +""" +File: Patient +Date: 5/1/18 +Author: Jon Deaton (jdeaton@stanford.edu) +""" + + +import numpy as np +import nibabel as nib + +from BraTS.modalities import * +from BraTS.load_utils import * + + +def load_patient_data(patient_data_dir): + """ + Load a single patient's image data + + :param patient_data_dir: Directory containing image data + :return: Tuple containing a tf.Tensor containing MRI data + """ + mri_data = np.empty(shape=mri_shape) + seg_data = None + for img_file in listdir(patient_data_dir): + img = nib.load(img_file).get_data() + img_type = get_modality(img_file) + + if img_type == Modality.seg: + seg_data = img + else: + channel_index = modality_indices[img_type] + mri_data[channel_index] = img + return mri_data, seg_data # Load segmentation data + + +def load_patient_data_inplace(patient_data_dir, mri_array, seg_array, index): + """ + Loads patient data into an existing mri array + + :param patient_data_dir: Directory containing patient images + :param mri_array: Array to load the patient MRI into + :param seg_array: Array to load the patient segmentation into + :param index: Index of mri_array and seg_array to load into + :return: None + """ + for img_file in listdir(patient_data_dir): + img = nib.load(img_file).get_data() + img_type = get_modality(img_file) + if img_type == Modality.seg: + seg_array[index] = img + continue + else: + channel_index = modality_indices[img_type] + mri_array[index, channel_index] = img + + +class Patient: + def __init__(self, id, age=None, survival=None, mri=None, seg=None): + self.id = id + self.age = age + self.survival = survival + self.mri = mri + self.seg = seg + + @property + def flair(self): + if not isinstance(self.mri, np.ndarray): + raise Exception("patient %s MRI is not a numpy array." % self.id) + return self.mri[0] + + @property + def t1(self): + if not isinstance(self.mri, np.ndarray): + raise Exception("patient %s MRI is not a numpy array." % self.id) + return self.mri[1] + + @property + def t1ce(self): + if not isinstance(self.mri, np.ndarray): + raise Exception("patient %s MRI is not a numpy array." % self.id) + return self.mri[2] + + @property + def t2(self): + if not isinstance(self.mri, np.ndarray): + raise Exception("patient %s MRI is not a numpy array." % self.id) + return self.mri[3] diff --git a/keras/downstream_tasks/BraTS/Patient.pyc b/keras/downstream_tasks/BraTS/Patient.pyc new file mode 100755 index 0000000..cbb0dd1 Binary files /dev/null and b/keras/downstream_tasks/BraTS/Patient.pyc differ diff --git a/keras/downstream_tasks/BraTS/__init__.py b/keras/downstream_tasks/BraTS/__init__.py new file mode 100755 index 0000000..18605d4 --- /dev/null +++ b/keras/downstream_tasks/BraTS/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +""" +File: __init__.py +Date: 5/1/18 +Author: Jon Deaton (jdeaton@stanford.edu) + +Brain Tumor Segmentation 2018 Data Set +""" + +import warnings +warnings.simplefilter(action='ignore', category=FutureWarning) + +from BraTS.DataSet import * + diff --git a/keras/downstream_tasks/BraTS/__init__.pyc b/keras/downstream_tasks/BraTS/__init__.pyc new file mode 100755 index 0000000..440c753 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__init__.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/DataSet.cpython-36.pyc b/keras/downstream_tasks/BraTS/__pycache__/DataSet.cpython-36.pyc new file mode 100644 index 0000000..ab15cc8 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/DataSet.cpython-36.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/DataSet.cpython-37.pyc b/keras/downstream_tasks/BraTS/__pycache__/DataSet.cpython-37.pyc new file mode 100755 index 0000000..b0fb3eb Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/DataSet.cpython-37.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/Patient.cpython-36.pyc b/keras/downstream_tasks/BraTS/__pycache__/Patient.cpython-36.pyc new file mode 100644 index 0000000..c01c91b Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/Patient.cpython-36.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/Patient.cpython-37.pyc b/keras/downstream_tasks/BraTS/__pycache__/Patient.cpython-37.pyc new file mode 100755 index 0000000..60c99e9 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/Patient.cpython-37.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/__init__.cpython-36.pyc b/keras/downstream_tasks/BraTS/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..db93739 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/__init__.cpython-36.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/__init__.cpython-37.pyc b/keras/downstream_tasks/BraTS/__pycache__/__init__.cpython-37.pyc new file mode 100755 index 0000000..163bff5 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/__init__.cpython-37.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/load_utils.cpython-36.pyc b/keras/downstream_tasks/BraTS/__pycache__/load_utils.cpython-36.pyc new file mode 100644 index 0000000..73ec922 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/load_utils.cpython-36.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/load_utils.cpython-37.pyc b/keras/downstream_tasks/BraTS/__pycache__/load_utils.cpython-37.pyc new file mode 100755 index 0000000..c0f3687 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/load_utils.cpython-37.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/modalities.cpython-36.pyc b/keras/downstream_tasks/BraTS/__pycache__/modalities.cpython-36.pyc new file mode 100644 index 0000000..87fea62 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/modalities.cpython-36.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/modalities.cpython-37.pyc b/keras/downstream_tasks/BraTS/__pycache__/modalities.cpython-37.pyc new file mode 100755 index 0000000..6bdb314 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/modalities.cpython-37.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/structure.cpython-36.pyc b/keras/downstream_tasks/BraTS/__pycache__/structure.cpython-36.pyc new file mode 100644 index 0000000..b8ebdd0 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/structure.cpython-36.pyc differ diff --git a/keras/downstream_tasks/BraTS/__pycache__/structure.cpython-37.pyc b/keras/downstream_tasks/BraTS/__pycache__/structure.cpython-37.pyc new file mode 100755 index 0000000..5a97969 Binary files /dev/null and b/keras/downstream_tasks/BraTS/__pycache__/structure.cpython-37.pyc differ diff --git a/keras/downstream_tasks/BraTS/load_utils.py b/keras/downstream_tasks/BraTS/load_utils.py new file mode 100755 index 0000000..bbc155f --- /dev/null +++ b/keras/downstream_tasks/BraTS/load_utils.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +""" +File: utils +Date: 5/1/18 +Author: Jon Deaton (jdeaton@stanford.edu) +""" + +import os +import pandas as pd + +def load_survival(survival_csv): + """ + Loads a survival CSV file + :param survival_csv: The path to the CSV file to load + :return: Pandas DataFrame with the survival information + """ + try: + survival = pd.read_csv(survival_csv) + except: + raise Exception("Error reading survival CSV file: %s" % survival_csv) + return rename_columns(survival) + + +def rename_columns(df): + """ + Rename the columns of a survival data CSV so that they are consistent + across different data-sets + :param df: The raw Pandas DataFrame read from the survival CSV file + :return: The same DataFrame but with the columns modified + """ + if df.shape[1] == 3: + df.columns = ['id', 'age', 'survival'] + elif df.shape[1] == 4: + df.columns = ['id', 'age', 'survival', 'resection'] + else: + raise Exception("Unknown columns in survival: %s" % df.columns) + return df + + +def find_file_containing(directory, keyword, case_sensitive=False): + """ + Finds a file in a directory containing a keyword in it's name + + :param directory: The directory to search in + :param keyword: The keyword to search in the name for + :param case_sensitive: Search with case sensitivity + :return: The joined path to the file containing the keyword in + it's name, if found, else None. + """ + assert isinstance(directory, str) + assert isinstance(keyword, str) + + if not os.path.isdir(directory): + raise FileNotFoundError(directory) + + # Iterate through files + for file in os.listdir(directory): + if keyword in (file if case_sensitive else file.lower()): + return os.path.join(directory, file) + return None + + +def find_file_named(root, name): + """ + Find a file named something + + :param root: Root directory to search recursively through + :param name: The name of the file to search for + :return: Full path to the (first!) file with the specified name found, + or None if no file was found of that name. + """ + assert isinstance(root, str) + assert isinstance(name, str) + + # Search the directory recursively + for path, dirs, files in os.walk(root): + for file in files: + if file == name: + return os.path.join(path, file) + return None + + +def listdir(directory): + """ + Gets the full paths to the contents of a directory + + :param directory: A path to some directory + :return: An iterator yielding full paths to all files in the specified directory + """ + assert isinstance(directory, str) + m = map(lambda d: os.path.join(directory, d), os.listdir(directory)) + contents = [f for f in m if not f.startswith('.')] + return contents diff --git a/keras/downstream_tasks/BraTS/load_utils.pyc b/keras/downstream_tasks/BraTS/load_utils.pyc new file mode 100755 index 0000000..c86f754 Binary files /dev/null and b/keras/downstream_tasks/BraTS/load_utils.pyc differ diff --git a/keras/downstream_tasks/BraTS/modalities.py b/keras/downstream_tasks/BraTS/modalities.py new file mode 100755 index 0000000..57b1ace --- /dev/null +++ b/keras/downstream_tasks/BraTS/modalities.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +""" +File: modalities +Date: 5/4/18 +Author: Jon Deaton (jdeaton@stanford.edu) + +Generic information about the different image types +available in the BraTS data sets. +""" + +from BraTS.load_utils import * + +from enum import Enum + +# Each of the "images" is a 3D volume of this shape +image_shape = (240, 240, 155) + +# Here, "MRI" refers to all four modalities taken during the scan +mri_shape = (4,) + image_shape + +# The segmentation map is just an image but with pixels indicating which +seg_shape = image_shape + + +class Modality(Enum): + """ + Enumeration representing the different types of modalities/images available + in the BraTS data set (T1, T2, T1CE, Flair, and Segmentation). + Segmentation isn't technically an image but it's convenient + to have it as a member of this enum because its stored in the data set + as another file just as though it were an image. + """ + t1 = 1 + t2 = 2 + t1ce = 3 + flair = 4 + seg = 5 + + +# Iterable, ordered collection of image types +modalities = [Modality.t1, Modality.t2, Modality.t1ce, + Modality.flair, Modality.seg] + +# Map from image type to name +modality_names = {Modality.t1: "t1", + Modality.t2: "t2", + Modality.t1ce: "t1ce", + Modality.flair: "flair", + Modality.seg: "seg"} + +""" +The MRI is a 4D Numpy array. The first dimension +indices through each of the four image types. This map +codifies which index in that first dimension is dedicated +to which image type (for consistency) +""" +modality_indices = {Modality.t1: 0, + Modality.t2: 1, + Modality.t1ce: 2, + Modality.flair: 3} + + +def get_modality(image_file): + """ + Determines the image type of a file from it's name + + :param image_file: File name or file path + :return: The type of image if it could be determined, None otherwise + """ + for img_type, name in modality_names.items(): + if "%s." % name in os.path.basename(image_file): + return img_type + return None + + +def get_modality_map(patient_dir): + """ + Creates a map for finding a given type of image within + a patien's directory of images + + :param patient_dir: Directory of patient images + :return: Dictionary mapping image type to file path for the image + of that type + """ + files = listdir(patient_dir) + d = {} + for file in files: + d[get_modality(file)] = file + return d + +def get_modality_file(patient_dir, modality): + return get_modality_map(patient_dir)[modality] diff --git a/keras/downstream_tasks/BraTS/modalities.pyc b/keras/downstream_tasks/BraTS/modalities.pyc new file mode 100755 index 0000000..c9e442a Binary files /dev/null and b/keras/downstream_tasks/BraTS/modalities.pyc differ diff --git a/keras/downstream_tasks/BraTS/structure.py b/keras/downstream_tasks/BraTS/structure.py new file mode 100755 index 0000000..bca7b8e --- /dev/null +++ b/keras/downstream_tasks/BraTS/structure.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +""" +File: structure +Date: 5/8/18 +Author: Jon Deaton (jdeaton@stanford.edu) +""" + +import os +from enum import Enum + +from BraTS.load_utils import find_file_containing + + +class DataSubsetType(Enum): + hgg = 0 + lgg = 1 + train = 2 + validation = 3 + + +def get_brats_subset_directory(brats_dataset_dir, data_set_type): + if data_set_type == DataSubsetType.train: + # Training data + try: + found_train = find_file_containing(brats_dataset_dir, "train", case_sensitive=False) + except FileNotFoundError: + found_train = None + if found_train is not None: + return found_train + return os.path.join(brats_dataset_dir, "training") + + if data_set_type == DataSubsetType.hgg: + train_dir = get_brats_subset_directory(brats_dataset_dir, DataSubsetType.train) + return os.path.join(train_dir, "HGG") + + if data_set_type == DataSubsetType.lgg: + train_dir = get_brats_subset_directory(brats_dataset_dir, DataSubsetType.train) + return os.path.join(train_dir, "LGG") + + if data_set_type == DataSubsetType.validation: + # Validation + try: + found_validation = find_file_containing(brats_dataset_dir, "validation", case_sensitive=False) + except FileNotFoundError: + found_validation = None + + if found_validation is not None: + return found_validation + return os.path.join(brats_dataset_dir, "validation") + diff --git a/keras/downstream_tasks/BraTS/structure.pyc b/keras/downstream_tasks/BraTS/structure.pyc new file mode 100755 index 0000000..7caec16 Binary files /dev/null and b/keras/downstream_tasks/BraTS/structure.pyc differ diff --git a/keras/downstream_tasks/BraTS/test.py b/keras/downstream_tasks/BraTS/test.py new file mode 100755 index 0000000..3e5551f --- /dev/null +++ b/keras/downstream_tasks/BraTS/test.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +""" +File: test +Date: 5/3/18 +Author: Jon Deaton (jdeaton@stanford.edu) + +This file tests the functionality of the BraTS dataset loader +""" + +import BraTS +import unittest +import numpy as np + +# If, for some reason, you wanted to test this on your machine you would +# need to set up the BraTS data-sets in some directory and set that path here +brats_root = "/Users/jonpdeaton/Datasets/BraTS" + +class BraTSTest(unittest.TestCase): + + def test_patient(self): + brats = BraTS.DataSet(brats_root=brats_root, year=2017) + patient = brats.train.patient("Brats17_TCIA_167_1") + + self.assertIsInstance(patient.id, str) + self.assertIsInstance(patient.age, float) + self.assertIsInstance(patient.survival, int) + self.assertIsInstance(patient.mri, np.ndarray) + self.assertIsInstance(patient.seg, np.ndarray) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/keras/downstream_tasks/BraTS/test_load.py b/keras/downstream_tasks/BraTS/test_load.py new file mode 100755 index 0000000..4500d30 --- /dev/null +++ b/keras/downstream_tasks/BraTS/test_load.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +""" +File: test_load +Date: 5/4/18 +Author: Jon Deaton (jdeaton@stanford.edu) +""" + +import io +import BraTS +import timeit +import cProfile, pstats + +BraTS.set_root("/Users/jonpdeaton/Datasets/BraTS") +brats = BraTS.DataSet(year=2017) + + +def load(): + subset = brats.train.subset(brats.train.ids[:10]) + x = subset.mris + + +def load_n(n=10): + for i in range(n): + p = brats.train.patient(brats.train.ids[i]) + + +s = timeit.timeit(load) +print("Time: %s sec" % s) + + + diff --git a/keras/downstream_tasks/config.py b/keras/downstream_tasks/config.py new file mode 100755 index 0000000..0d5b518 --- /dev/null +++ b/keras/downstream_tasks/config.py @@ -0,0 +1,375 @@ +import os +import shutil +import csv +import keras +import random + +class bms_config: + arch = 'Vnet' + + # data + data = '/mnt/dataset/shared/zongwei/BraTS' + csv = "data/bms" + deltr = 30 + step_pixel_size = 30 + input_rows = 64 + input_cols = 64 + input_deps = 32 + crop_rows = 100 + crop_cols = 100 + crop_deps = 50 + + # model + lr = 1e-3 + optimizer = keras.optimizers.Adam(lr=lr) + patience = 30 + verbose = 1 + batch_size = 12 + use_multiprocessing = True + workers = 4 + max_queue_size = workers * 1 + nb_epoch = 10000 + + def __init__(self, args): + self.exp_name = self.arch + '-' + args.suffix + if args.data is not None: + self.data = args.data + + if args.suffix == 'random': + self.weights = None + elif args.suffix == 'genesis': + self.weights = 'pretrained_weights/Genesis_Chest_CT.h5' + elif args.suffix == 'genesis-autoencoder': + self.weights = 'pretrained_weights/Genesis_Chest_CT-autoencoder.h5' + elif args.suffix == 'genesis-nonlinear': + self.weights = 'pretrained_weights/Genesis_Chest_CT-nonlinear.h5' + elif args.suffix == 'genesis-localshuffling': + self.weights = 'pretrained_weights/Genesis_Chest_CT-localshuffling.h5' + elif args.suffix == 'genesis-outpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-outpainting.h5' + elif args.suffix == 'genesis-inpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-inpainting.h5' + elif args.suffix == 'denoisy': + self.weights = 'pretrained_weights/denoisy.h5' + elif args.suffix == 'patchshuffling': + self.weights = 'pretrained_weights/patchshuffling.h5' + elif args.suffix == 'hg': + self.weights = 'pretrained_weights/hg.h5' + else: + raise + + train_ids = self._load_csv(os.path.join(self.csv, "fold_1.csv")) + self._load_csv(os.path.join(self.csv, "fold_2.csv")) + random.Random(4).shuffle(train_ids) + self.validation_ids = train_ids[:len(train_ids) // 8] + self.train_ids = train_ids[len(train_ids) // 8:] + self.test_ids = self._load_csv(os.path.join(self.csv, "fold_3.csv")) + self.num_train = len(self.train_ids) + self.num_validation = len(self.validation_ids) + self.num_test = len(self.test_ids) + + # logs + self.model_path = os.path.join("models/bms", "run_"+str(args.run)) + if not os.path.exists(self.model_path): + os.makedirs(self.model_path) + self.logs_path = os.path.join(self.model_path, "logs") + if not os.path.exists(self.logs_path): + os.makedirs(self.logs_path) + + def _load_csv(self, foldfile=None): + assert foldfile is not None + patient_ids = [] + with open(foldfile, 'r') as f: + reader = csv.reader(f, lineterminator='\n') + patient_ids.extend(reader) + for i, item in enumerate(patient_ids): + patient_ids[i] = item[0] + return patient_ids + + def display(self): + """Display Configuration values.""" + print("\nConfigurations:") + for a in dir(self): + if not a.startswith("__") and not callable(getattr(self, a)) and not '_ids' in a: + print("{:30} {}".format(a, getattr(self, a))) + print("\n") + +class ecc_config: + arch = 'Vnet' + + # data + data = '/mnt/dfs/zongwei/Academic/MICCAI2020/Genesis_PE/dataset/augdata/VOIR' + csv = "data/ecc" + clip_min = -1000 + clip_max = 1000 + input_rows = 64 + input_cols = 64 + input_deps = 64 + + # model + lr = 1e-3 + optimizer = keras.optimizers.Adam(lr=lr) + patience = 38 + verbose = 1 + batch_size = 24 + use_multiprocessing = False + workers = 1 + max_queue_size = workers * 1 + nb_epoch = 10000 + num_classes = 1 + verbose = 1 + + def __init__(self, args=None): + self.exp_name = self.arch + '-' + args.suffix + '-cv-' + str(args.cv) + if args.data is not None: + self.data = args.data + + if args.suffix == 'random': + self.weights = None + elif args.suffix == 'genesis': + self.weights = 'pretrained_weights/Genesis_Chest_CT.h5' + elif args.suffix == 'genesis-autoencoder': + self.weights = 'pretrained_weights/Genesis_Chest_CT-autoencoder.h5' + elif args.suffix == 'genesis-nonlinear': + self.weights = 'pretrained_weights/Genesis_Chest_CT-nonlinear.h5' + elif args.suffix == 'genesis-localshuffling': + self.weights = 'pretrained_weights/Genesis_Chest_CT-localshuffling.h5' + elif args.suffix == 'genesis-outpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-outpainting.h5' + elif args.suffix == 'genesis-inpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-inpainting.h5' + elif args.suffix == 'denoisy': + self.weights = 'pretrained_weights/denoisy.h5' + elif args.suffix == 'patchshuffling': + self.weights = 'pretrained_weights/patchshuffling.h5' + elif args.suffix == 'hg': + self.weights = 'pretrained_weights/hg.h5' + else: + raise + + # logs + assert args.subsetting is not None + self.model_path = os.path.join("models/ecc", "run_"+str(args.run), args.subsetting) + if not os.path.exists(self.model_path): + os.makedirs(self.model_path) + self.logs_path = os.path.join(self.model_path, "logs") + if not os.path.exists(self.logs_path): + os.makedirs(self.logs_path) + self.patch_csv_path = 'Patch-20mm-cv-'+str(args.cv)+'-features_output_2_iter-100000.csv' + self.candidate_csv_path = 'Candidate-20mm-cv-'+str(args.cv)+'-features_output_2_iter-100000.csv' + self.csv_froc = 'features_output_2_iter-100000.csv' + + def display(self): + print("Configurations") + for a in dir(self): + if not a.startswith("__") and not callable(getattr(self,a)): + print("{:30} {}".format(a,getattr(self,a))) + #print("\n") + +class ncc_config: + arch = 'Vnet' + + # data + data = '/mnt/dataset/shared/zongwei/LUNA16/LUNA16_FPR_32x32x32' + train_fold=[0,1,2,3,4] + valid_fold=[5,6] + test_fold=[7,8,9] + hu_min = -1000 + hu_max = 1000 + input_rows = 64 + input_cols = 64 + input_deps = 32 + + # model + lr = 1e-3 + optimizer = keras.optimizers.Adam(lr=lr) + patience = 10 + verbose = 1 + batch_size = 24 + use_multiprocessing = False + workers = 1 + max_queue_size = workers * 1 + nb_epoch = 10000 + num_classes = 1 + verbose = 1 + + def __init__(self, args=None): + self.exp_name = self.arch + '-' + args.suffix + if args.data is not None: + self.data = args.data + + if args.suffix == 'random': + self.weights = None + elif args.suffix == 'genesis': + self.weights = 'pretrained_weights/Genesis_Chest_CT.h5' + elif args.suffix == 'genesis-autoencoder': + self.weights = 'pretrained_weights/Genesis_Chest_CT-autoencoder.h5' + elif args.suffix == 'genesis-nonlinear': + self.weights = 'pretrained_weights/Genesis_Chest_CT-nonlinear.h5' + elif args.suffix == 'genesis-localshuffling': + self.weights = 'pretrained_weights/Genesis_Chest_CT-localshuffling.h5' + elif args.suffix == 'genesis-outpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-outpainting.h5' + elif args.suffix == 'genesis-inpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-inpainting.h5' + elif args.suffix == 'denoisy': + self.weights = 'pretrained_weights/denoisy.h5' + elif args.suffix == 'patchshuffling': + self.weights = 'pretrained_weights/patchshuffling.h5' + elif args.suffix == 'hg': + self.weights = 'pretrained_weights/hg.h5' + else: + raise + + # logs + self.model_path = os.path.join("models/ncc", "run_"+str(args.run)) + if not os.path.exists(self.model_path): + os.makedirs(self.model_path) + self.logs_path = os.path.join(self.model_path, "logs") + if not os.path.exists(self.logs_path): + os.makedirs(self.logs_path) + + def display(self): + print("Configurations") + for a in dir(self): + if not a.startswith("__") and not callable(getattr(self,a)): + print("{:30} {}".format(a,getattr(self,a))) + #print("\n") + +class ncs_config: + arch = 'Vnet' + + # data + data = '/mnt/dataset/shared/zongwei/LIDC' + input_rows = 64 + input_cols = 64 + input_deps = 32 + + # model + lr = 1e-3 + optimizer = keras.optimizers.Adam(lr=lr) + patience = 50 + verbose = 1 + batch_size = 16 + use_multiprocessing = False + workers = 1 + max_queue_size = workers * 1 + nb_epoch = 10000 + + def __init__(self, args): + self.exp_name = self.arch + '-' + args.suffix + if args.data is not None: + self.data = args.data + + if args.suffix == 'random': + self.weights = None + elif args.suffix == 'genesis': + self.weights = 'pretrained_weights/Genesis_Chest_CT.h5' + elif args.suffix == 'genesis-autoencoder': + self.weights = 'pretrained_weights/Genesis_Chest_CT-autoencoder.h5' + elif args.suffix == 'genesis-nonlinear': + self.weights = 'pretrained_weights/Genesis_Chest_CT-nonlinear.h5' + elif args.suffix == 'genesis-localshuffling': + self.weights = 'pretrained_weights/Genesis_Chest_CT-localshuffling.h5' + elif args.suffix == 'genesis-outpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-outpainting.h5' + elif args.suffix == 'genesis-inpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-inpainting.h5' + elif args.suffix == 'denoisy': + self.weights = 'pretrained_weights/denoisy.h5' + elif args.suffix == 'patchshuffling': + self.weights = 'pretrained_weights/patchshuffling.h5' + elif args.suffix == 'hg': + self.weights = 'pretrained_weights/hg.h5' + else: + raise + + # logs + self.model_path = os.path.join("models/ncs", "run_"+str(args.run)) + if not os.path.exists(self.model_path): + os.makedirs(self.model_path) + self.logs_path = os.path.join(self.model_path, "logs") + if not os.path.exists(self.logs_path): + os.makedirs(self.logs_path) + + def display(self): + """Display Configuration values.""" + print("\nConfigurations:") + for a in dir(self): + if not a.startswith("__") and not callable(getattr(self, a)): + print("{:30} {}".format(a, getattr(self, a))) + print("\n") + + +class lcs_config: + arch = 'Vnet' + + # data + data = '/mnt/dfs/zongwei/Academic/MICCAI2019/Data/LiTS/3D_LiTS_NPY_256x256xZ' + nii = '/mnt/dataset/shared/zongwei/LiTS/Tr' + obj = 'liver' + train_idx = [n for n in range(0, 100)] + valid_idx = [n for n in range(100, 115)] + test_idx = [n for n in range(115, 130)] + num_train = len(train_idx) + num_valid = len(valid_idx) + num_test = len(test_idx) + hu_max = 1000 + hu_min = -1000 + input_rows = 64 + input_cols = 64 + input_deps = 32 + + # model + lr = 1e-3 + optimizer = keras.optimizers.Adam(lr=lr) + patience = 20 + verbose = 1 + batch_size = 16 + use_multiprocessing = False + workers = 1 + max_queue_size = workers * 1 + nb_epoch = 10000 + + def __init__(self, args): + self.exp_name = self.arch + '-' + args.suffix + if args.data is not None: + self.data = args.data + + if args.suffix == 'random': + self.weights = None + elif args.suffix == 'genesis': + self.weights = 'pretrained_weights/Genesis_Chest_CT.h5' + elif args.suffix == 'genesis-autoencoder': + self.weights = 'pretrained_weights/Genesis_Chest_CT-autoencoder.h5' + elif args.suffix == 'genesis-nonlinear': + self.weights = 'pretrained_weights/Genesis_Chest_CT-nonlinear.h5' + elif args.suffix == 'genesis-localshuffling': + self.weights = 'pretrained_weights/Genesis_Chest_CT-localshuffling.h5' + elif args.suffix == 'genesis-outpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-outpainting.h5' + elif args.suffix == 'genesis-inpainting': + self.weights = 'pretrained_weights/Genesis_Chest_CT-inpainting.h5' + elif args.suffix == 'denoisy': + self.weights = 'pretrained_weights/denoisy.h5' + elif args.suffix == 'patchshuffling': + self.weights = 'pretrained_weights/patchshuffling.h5' + elif args.suffix == 'hg': + self.weights = 'pretrained_weights/hg.h5' + else: + raise + + # logs + self.model_path = os.path.join("models/lcs", "run_"+str(args.run)) + if not os.path.exists(self.model_path): + os.makedirs(self.model_path) + self.logs_path = os.path.join(self.model_path, "logs") + if not os.path.exists(self.logs_path): + os.makedirs(self.logs_path) + + def display(self): + """Display Configuration values.""" + print("\nConfigurations:") + for a in dir(self): + if not a.startswith("__") and not callable(getattr(self, a)) and not '_idx' in a: + print("{:30} {}".format(a, getattr(self, a))) + print("\n") diff --git a/keras/downstream_tasks/data/bms/fold_1.csv b/keras/downstream_tasks/data/bms/fold_1.csv new file mode 100755 index 0000000..a001c92 --- /dev/null +++ b/keras/downstream_tasks/data/bms/fold_1.csv @@ -0,0 +1,95 @@ +Brats18_TCIA10_330_1 +Brats18_TCIA04_437_1 +Brats18_2013_3_1 +Brats18_TCIA08_469_1 +Brats18_TCIA09_620_1 +Brats18_TCIA08_242_1 +Brats18_TCIA10_103_1 +Brats18_TCIA01_221_1 +Brats18_TCIA04_149_1 +Brats18_CBICA_ANZ_1 +Brats18_2013_18_1 +Brats18_TCIA02_314_1 +Brats18_CBICA_ATD_1 +Brats18_TCIA02_274_1 +Brats18_CBICA_AQR_1 +Brats18_CBICA_ASU_1 +Brats18_TCIA06_372_1 +Brats18_TCIA13_623_1 +Brats18_TCIA02_331_1 +Brats18_CBICA_ABE_1 +Brats18_TCIA03_199_1 +Brats18_CBICA_ASO_1 +Brats18_TCIA08_436_1 +Brats18_TCIA10_625_1 +Brats18_TCIA10_241_1 +Brats18_CBICA_ASH_1 +Brats18_TCIA12_466_1 +Brats18_TCIA01_201_1 +Brats18_CBICA_ATB_1 +Brats18_TCIA01_425_1 +Brats18_CBICA_AYA_1 +Brats18_TCIA02_608_1 +Brats18_2013_16_1 +Brats18_2013_24_1 +Brats18_TCIA04_479_1 +Brats18_TCIA13_633_1 +Brats18_TCIA01_235_1 +Brats18_2013_0_1 +Brats18_TCIA10_640_1 +Brats18_TCIA04_328_1 +Brats18_TCIA02_473_1 +Brats18_TCIA09_254_1 +Brats18_CBICA_ABM_1 +Brats18_CBICA_ATV_1 +Brats18_CBICA_AQA_1 +Brats18_TCIA10_449_1 +Brats18_TCIA01_231_1 +Brats18_2013_12_1 +Brats18_CBICA_AXN_1 +Brats18_TCIA10_130_1 +Brats18_TCIA10_261_1 +Brats18_2013_17_1 +Brats18_TCIA08_205_1 +Brats18_TCIA10_490_1 +Brats18_TCIA02_198_1 +Brats18_2013_20_1 +Brats18_CBICA_ALX_1 +Brats18_CBICA_AQV_1 +Brats18_TCIA06_184_1 +Brats18_CBICA_AXJ_1 +Brats18_CBICA_AVJ_1 +Brats18_TCIA10_276_1 +Brats18_TCIA01_448_1 +Brats18_TCIA03_498_1 +Brats18_TCIA10_310_1 +Brats18_TCIA02_283_1 +Brats18_TCIA02_151_1 +Brats18_TCIA12_298_1 +Brats18_CBICA_BFP_1 +Brats18_TCIA03_138_1 +Brats18_TCIA10_420_1 +Brats18_TCIA10_410_1 +Brats18_TCIA02_471_1 +Brats18_CBICA_ATX_1 +Brats18_CBICA_APY_1 +Brats18_TCIA02_168_1 +Brats18_TCIA13_653_1 +Brats18_CBICA_AWH_1 +Brats18_2013_14_1 +Brats18_TCIA05_478_1 +Brats18_CBICA_AXL_1 +Brats18_TCIA09_462_1 +Brats18_CBICA_ARW_1 +Brats18_TCIA03_257_1 +Brats18_TCIA02_605_1 +Brats18_TCIA01_186_1 +Brats18_2013_26_1 +Brats18_CBICA_AAP_1 +Brats18_CBICA_AXO_1 +Brats18_TCIA10_639_1 +Brats18_2013_6_1 +Brats18_TCIA08_218_1 +Brats18_CBICA_AXM_1 +Brats18_CBICA_AVG_1 +Brats18_CBICA_AAL_1 diff --git a/keras/downstream_tasks/data/bms/fold_2.csv b/keras/downstream_tasks/data/bms/fold_2.csv new file mode 100755 index 0000000..18066eb --- /dev/null +++ b/keras/downstream_tasks/data/bms/fold_2.csv @@ -0,0 +1,95 @@ +Brats18_CBICA_AVV_1 +Brats18_TCIA01_147_1 +Brats18_TCIA01_460_1 +Brats18_TCIA10_387_1 +Brats18_2013_7_1 +Brats18_TCIA12_249_1 +Brats18_TCIA09_493_1 +Brats18_TCIA01_190_1 +Brats18_TCIA10_644_1 +Brats18_TCIA12_480_1 +Brats18_2013_8_1 +Brats18_TCIA10_351_1 +Brats18_TCIA01_203_1 +Brats18_TCIA10_299_1 +Brats18_CBICA_APZ_1 +Brats18_TCIA13_618_1 +Brats18_TCIA02_300_1 +Brats18_CBICA_AQN_1 +Brats18_TCIA03_419_1 +Brats18_TCIA08_105_1 +Brats18_TCIA13_650_1 +Brats18_TCIA10_413_1 +Brats18_TCIA13_645_1 +Brats18_CBICA_AQU_1 +Brats18_CBICA_AXW_1 +Brats18_TCIA01_390_1 +Brats18_TCIA02_394_1 +Brats18_TCIA09_141_1 +Brats18_TCIA03_133_1 +Brats18_TCIA10_637_1 +Brats18_CBICA_AQO_1 +Brats18_CBICA_AQY_1 +Brats18_TCIA02_491_1 +Brats18_CBICA_ABO_1 +Brats18_TCIA04_111_1 +Brats18_2013_22_1 +Brats18_TCIA08_319_1 +Brats18_TCIA03_375_1 +Brats18_2013_9_1 +Brats18_TCIA08_113_1 +Brats18_TCIA10_202_1 +Brats18_CBICA_AOZ_1 +Brats18_TCIA05_277_1 +Brats18_2013_4_1 +Brats18_TCIA09_312_1 +Brats18_CBICA_AUQ_1 +Brats18_TCIA02_171_1 +Brats18_CBICA_AME_1 +Brats18_CBICA_BHK_1 +Brats18_TCIA08_234_1 +Brats18_CBICA_AUR_1 +Brats18_2013_11_1 +Brats18_TCIA10_152_1 +Brats18_TCIA03_121_1 +Brats18_CBICA_ALN_1 +Brats18_CBICA_AWG_1 +Brats18_CBICA_AQQ_1 +Brats18_TCIA13_630_1 +Brats18_TCIA06_247_1 +Brats18_TCIA13_615_1 +Brats18_TCIA09_451_1 +Brats18_CBICA_ASE_1 +Brats18_2013_27_1 +Brats18_TCIA10_628_1 +Brats18_TCIA06_165_1 +Brats18_CBICA_ABY_1 +Brats18_TCIA02_377_1 +Brats18_TCIA02_455_1 +Brats18_TCIA12_470_1 +Brats18_2013_13_1 +Brats18_CBICA_ASW_1 +Brats18_TCIA09_255_1 +Brats18_2013_29_1 +Brats18_TCIA04_361_1 +Brats18_TCIA13_624_1 +Brats18_2013_15_1 +Brats18_CBICA_BHM_1 +Brats18_TCIA10_175_1 +Brats18_TCIA10_393_1 +Brats18_TCIA10_629_1 +Brats18_CBICA_AAG_1 +Brats18_CBICA_AQJ_1 +Brats18_TCIA02_321_1 +Brats18_TCIA02_222_1 +Brats18_TCIA10_307_1 +Brats18_CBICA_AQD_1 +Brats18_TCIA03_338_1 +Brats18_2013_23_1 +Brats18_2013_5_1 +Brats18_TCIA04_192_1 +Brats18_TCIA06_211_1 +Brats18_TCIA02_135_1 +Brats18_TCIA05_444_1 +Brats18_CBICA_ASV_1 +Brats18_TCIA02_226_1 diff --git a/keras/downstream_tasks/data/bms/fold_3.csv b/keras/downstream_tasks/data/bms/fold_3.csv new file mode 100755 index 0000000..04babdb --- /dev/null +++ b/keras/downstream_tasks/data/bms/fold_3.csv @@ -0,0 +1,95 @@ +Brats18_CBICA_AZD_1 +Brats18_CBICA_AUN_1 +Brats18_CBICA_ANP_1 +Brats18_CBICA_AQZ_1 +Brats18_CBICA_AZH_1 +Brats18_TCIA02_370_1 +Brats18_TCIA02_374_1 +Brats18_CBICA_AOO_1 +Brats18_TCIA09_428_1 +Brats18_2013_25_1 +Brats18_CBICA_AOH_1 +Brats18_TCIA10_442_1 +Brats18_CBICA_ABN_1 +Brats18_CBICA_ATF_1 +Brats18_TCIA03_265_1 +Brats18_TCIA13_654_1 +Brats18_TCIA02_430_1 +Brats18_TCIA01_429_1 +Brats18_TCIA01_401_1 +Brats18_TCIA10_346_1 +Brats18_TCIA02_368_1 +Brats18_TCIA01_131_1 +Brats18_TCIA08_278_1 +Brats18_2013_28_1 +Brats18_2013_1_1 +Brats18_TCIA06_409_1 +Brats18_TCIA08_162_1 +Brats18_CBICA_AQT_1 +Brats18_CBICA_ASK_1 +Brats18_CBICA_AQG_1 +Brats18_CBICA_ALU_1 +Brats18_CBICA_BHB_1 +Brats18_CBICA_AYW_1 +Brats18_CBICA_ARZ_1 +Brats18_TCIA02_290_1 +Brats18_CBICA_AYI_1 +Brats18_CBICA_AXQ_1 +Brats18_CBICA_AOD_1 +Brats18_TCIA01_378_1 +Brats18_TCIA05_396_1 +Brats18_TCIA08_406_1 +Brats18_TCIA13_634_1 +Brats18_TCIA09_402_1 +Brats18_TCIA03_296_1 +Brats18_TCIA02_179_1 +Brats18_CBICA_ASA_1 +Brats18_TCIA10_109_1 +Brats18_2013_10_1 +Brats18_CBICA_ASG_1 +Brats18_TCIA08_280_1 +Brats18_TCIA02_117_1 +Brats18_TCIA13_642_1 +Brats18_TCIA09_177_1 +Brats18_TCIA08_167_1 +Brats18_TCIA10_266_1 +Brats18_TCIA10_282_1 +Brats18_2013_2_1 +Brats18_CBICA_ARF_1 +Brats18_TCIA01_180_1 +Brats18_TCIA10_408_1 +Brats18_CBICA_ANG_1 +Brats18_CBICA_AQP_1 +Brats18_TCIA01_335_1 +Brats18_TCIA10_632_1 +Brats18_TCIA02_606_1 +Brats18_TCIA02_607_1 +Brats18_CBICA_AMH_1 +Brats18_TCIA04_343_1 +Brats18_TCIA13_621_1 +Brats18_TCIA02_322_1 +Brats18_CBICA_ASY_1 +Brats18_CBICA_AWI_1 +Brats18_TCIA01_499_1 +Brats18_TCIA01_411_1 +Brats18_2013_21_1 +Brats18_CBICA_AYU_1 +Brats18_TCIA01_412_1 +Brats18_CBICA_APR_1 +Brats18_CBICA_ATP_1 +Brats18_TCIA02_118_1 +Brats18_TCIA03_474_1 +Brats18_TCIA12_101_1 +Brats18_CBICA_BFB_1 +Brats18_CBICA_AAB_1 +Brats18_TCIA02_208_1 +Brats18_TCIA06_603_1 +Brats18_2013_19_1 +Brats18_CBICA_ABB_1 +Brats18_CBICA_ANI_1 +Brats18_CBICA_ASN_1 +Brats18_TCIA10_325_1 +Brats18_TCIA06_332_1 +Brats18_CBICA_AOP_1 +Brats18_TCIA02_309_1 +Brats18_TCIA01_150_1 diff --git a/keras/downstream_tasks/data/ecc/test_cv-1.csv b/keras/downstream_tasks/data/ecc/test_cv-1.csv new file mode 100755 index 0000000..347af46 --- /dev/null +++ b/keras/downstream_tasks/data/ecc/test_cv-1.csv @@ -0,0 +1,40 @@ +FileName +Patient03284 +Patient03266 +Patient03234 +Patient03280 +Patient03286 +Patient03262 +Patient03237 +Patient03243 +Patient03275 +Patient03268 +Patient03232 +Patient03240 +Patient03228 +Patient03229 +Patient03283 +Patient03222 +Patient03271 +Patient03256 +Patient03246 +Patient03239 +Patient03251 +Patient03276 +Patient03281 +Patient03263 +Patient03250 +Patient03257 +Patient03242 +Patient03267 +Patient03258 +Patient03272 +Patient03282 +Patient03291 +Patient03244 +Patient03231 +Patient03287 +Patient03249 +Patient03253 +Patient03278 +Patient03254 diff --git a/keras/downstream_tasks/data/ecc/test_cv-2.csv b/keras/downstream_tasks/data/ecc/test_cv-2.csv new file mode 100755 index 0000000..497dd97 --- /dev/null +++ b/keras/downstream_tasks/data/ecc/test_cv-2.csv @@ -0,0 +1,40 @@ +FileName +Patient21229 +Patient21108 +Patient03209 +Patient03210 +Patient21115 +Patient21107 +Patient03130 +Patient03204 +Patient03213 +Patient03129 +Patient03206 +Patient03218 +Patient21113 +Patient21228 +Patient21106 +Patient21112 +Patient21227 +Patient21101 +Patient03122 +Patient03201 +Patient03220 +Patient03221 +Patient21100 +Patient03216 +Patient03124 +Patient03215 +Patient21118 +Patient21110 +Patient21104 +Patient03125 +Patient21117 +Patient03212 +Patient03219 +Patient21109 +Patient21102 +Patient21119 +Patient03208 +Patient21116 +Patient21103 diff --git a/keras/downstream_tasks/data/ecc/test_cv-3.csv b/keras/downstream_tasks/data/ecc/test_cv-3.csv new file mode 100755 index 0000000..46b8084 --- /dev/null +++ b/keras/downstream_tasks/data/ecc/test_cv-3.csv @@ -0,0 +1,40 @@ +FileName +Patient21222 +Patient03118 +Patient21215 +Patient28005 +Patient21214 +Patient03000 +Patient03001 +Patient28010 +Patient03102 +Patient03103 +Patient21225 +Patient03120 +Patient03002 +Patient03108 +Patient03116 +Patient03003 +Patient28008 +Patient28002 +Patient03109 +Patient21220 +Patient21206 +Patient21216 +Patient21205 +Patient21217 +Patient03104 +Patient03005 +Patient03119 +Patient03110 +Patient28004 +Patient03106 +Patient21221 +Patient21213 +Patient28007 +Patient03114 +Patient21201 +Patient28006 +Patient21224 +Patient21208 +Patient21200 diff --git a/keras/downstream_tasks/data/ecc/train_cv-1.csv b/keras/downstream_tasks/data/ecc/train_cv-1.csv new file mode 100755 index 0000000..e7ce590 --- /dev/null +++ b/keras/downstream_tasks/data/ecc/train_cv-1.csv @@ -0,0 +1,75 @@ +FileName +Patient21108 +Patient03219 +Patient03201 +Patient21103 +Patient03125 +Patient21104 +Patient28002 +Patient03114 +Patient03102 +Patient03116 +Patient28010 +Patient21113 +Patient21205 +Patient03000 +Patient03129 +Patient21206 +Patient21227 +Patient21214 +Patient21220 +Patient03216 +Patient21201 +Patient28005 +Patient03204 +Patient03209 +Patient21119 +Patient03003 +Patient03118 +Patient03210 +Patient21224 +Patient21217 +Patient21112 +Patient21102 +Patient21215 +Patient03124 +Patient21221 +Patient21225 +Patient28006 +Patient21200 +Patient21117 +Patient28008 +Patient03215 +Patient21118 +Patient03208 +Patient03001 +Patient03110 +Patient28007 +Patient03212 +Patient03005 +Patient03130 +Patient03122 +Patient21110 +Patient21229 +Patient03119 +Patient21116 +Patient03104 +Patient21208 +Patient21222 +Patient03120 +Patient03213 +Patient21106 +Patient03108 +Patient03220 +Patient03109 +Patient21107 +Patient21228 +Patient21101 +Patient21100 +Patient03218 +Patient03103 +Patient21115 +Patient03002 +Patient28004 +Patient21213 +Patient03206 diff --git a/keras/downstream_tasks/data/ecc/train_cv-2.csv b/keras/downstream_tasks/data/ecc/train_cv-2.csv new file mode 100755 index 0000000..2cd1915 --- /dev/null +++ b/keras/downstream_tasks/data/ecc/train_cv-2.csv @@ -0,0 +1,75 @@ +FileName +Patient21215 +Patient21201 +Patient03103 +Patient03114 +Patient21224 +Patient03119 +Patient28005 +Patient21208 +Patient03256 +Patient21220 +Patient21217 +Patient03234 +Patient03278 +Patient03262 +Patient21200 +Patient28007 +Patient03108 +Patient28004 +Patient03104 +Patient28010 +Patient03001 +Patient21225 +Patient03232 +Patient03268 +Patient03110 +Patient03116 +Patient03257 +Patient03280 +Patient28008 +Patient03222 +Patient03251 +Patient03239 +Patient03254 +Patient21213 +Patient03267 +Patient21222 +Patient03250 +Patient03120 +Patient03237 +Patient03242 +Patient03240 +Patient03282 +Patient03263 +Patient03102 +Patient03253 +Patient03246 +Patient03231 +Patient03229 +Patient03258 +Patient03249 +Patient21221 +Patient28006 +Patient21216 +Patient03109 +Patient03005 +Patient21214 +Patient03002 +Patient03287 +Patient03281 +Patient03106 +Patient03243 +Patient21206 +Patient03118 +Patient03003 +Patient03271 +Patient03228 +Patient28002 +Patient03284 +Patient03276 +Patient03286 +Patient21205 +Patient03275 +Patient03000 +Patient03291 diff --git a/keras/downstream_tasks/data/ecc/train_cv-3.csv b/keras/downstream_tasks/data/ecc/train_cv-3.csv new file mode 100755 index 0000000..7ec23df --- /dev/null +++ b/keras/downstream_tasks/data/ecc/train_cv-3.csv @@ -0,0 +1,75 @@ +FileName +Patient03276 +Patient03251 +Patient03215 +Patient21118 +Patient03282 +Patient03232 +Patient03287 +Patient03284 +Patient21104 +Patient03209 +Patient21108 +Patient03281 +Patient21229 +Patient03278 +Patient03256 +Patient03208 +Patient03263 +Patient21116 +Patient21103 +Patient21100 +Patient03130 +Patient03129 +Patient03262 +Patient03212 +Patient03272 +Patient03254 +Patient03221 +Patient21102 +Patient21227 +Patient03228 +Patient03218 +Patient03268 +Patient21119 +Patient21107 +Patient03210 +Patient03206 +Patient03250 +Patient03216 +Patient21101 +Patient03244 +Patient03220 +Patient03125 +Patient03229 +Patient03124 +Patient03257 +Patient03283 +Patient21112 +Patient03271 +Patient03219 +Patient21113 +Patient03275 +Patient03204 +Patient03231 +Patient03201 +Patient21117 +Patient03213 +Patient21115 +Patient21110 +Patient03258 +Patient03239 +Patient03242 +Patient21106 +Patient03280 +Patient03249 +Patient03237 +Patient03240 +Patient03266 +Patient03222 +Patient03267 +Patient03291 +Patient03234 +Patient21109 +Patient03243 +Patient03246 diff --git a/keras/downstream_tasks/data/ecc/val_cv-1.csv b/keras/downstream_tasks/data/ecc/val_cv-1.csv new file mode 100755 index 0000000..ae2133b --- /dev/null +++ b/keras/downstream_tasks/data/ecc/val_cv-1.csv @@ -0,0 +1,5 @@ +FileName +Patient21216 +Patient03106 +Patient21109 +Patient03221 diff --git a/keras/downstream_tasks/data/ecc/val_cv-2.csv b/keras/downstream_tasks/data/ecc/val_cv-2.csv new file mode 100755 index 0000000..b820563 --- /dev/null +++ b/keras/downstream_tasks/data/ecc/val_cv-2.csv @@ -0,0 +1,5 @@ +FileName +Patient03283 +Patient03266 +Patient03272 +Patient03244 diff --git a/keras/downstream_tasks/data/ecc/val_cv-3.csv b/keras/downstream_tasks/data/ecc/val_cv-3.csv new file mode 100755 index 0000000..bfd59a4 --- /dev/null +++ b/keras/downstream_tasks/data/ecc/val_cv-3.csv @@ -0,0 +1,5 @@ +FileName +Patient03286 +Patient03253 +Patient21228 +Patient03122 diff --git a/keras/downstream_tasks/lung nodule segmentation.ipynb b/keras/downstream_tasks/lung nodule segmentation.ipynb new file mode 100644 index 0000000..d025690 --- /dev/null +++ b/keras/downstream_tasks/lung nodule segmentation.ipynb @@ -0,0 +1,489 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "keras = 2.2.4\n", + "tensorflow-gpu = 1.13.1\n", + "\n", + "Configurations:\n", + "arch Vnet\n", + "batch_size 16\n", + "data /mnt/dataset/shared/zongwei/LIDC\n", + "exp_name Vnet-genesis\n", + "input_cols 64\n", + "input_deps 32\n", + "input_rows 64\n", + "logs_path models/ncs/run_1/logs\n", + "lr 0.001\n", + "max_queue_size 1\n", + "model_path models/ncs/run_1\n", + "nb_epoch 10000\n", + "optimizer adam\n", + "patience 50\n", + "verbose 1\n", + "weights pretrained_weights/Genesis_Chest_CT.h5\n", + "workers 1\n", + "\n", + "\n" + ] + } + ], + "source": [ + "#!/usr/bin/env python\n", + "# coding: utf-8\n", + "from __future__ import print_function\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "import os\n", + "os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # or any {'0', '1', '2'}\n", + "import keras\n", + "print(\"keras = {}\".format(keras.__version__))\n", + "import tensorflow as tf\n", + "print(\"tensorflow-gpu = {}\".format(tf.__version__))\n", + "try:\n", + " tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)\n", + "except:\n", + " pass\n", + "import random\n", + "import shutil\n", + "import argparse\n", + "import sklearn\n", + "from pathlib import Path\n", + "from utils import *\n", + "from unet3d import *\n", + "from config import *\n", + "\n", + "class set_args():\n", + " gpu = 0\n", + " data = None\n", + " apps = 'ncs'\n", + " run = 1\n", + " cv = None\n", + " subsetting = None\n", + " suffix = 'genesis'\n", + " task = 'segmentation'\n", + " \n", + "args = set_args()\n", + "\n", + "if args.gpu is not None:\n", + " os.environ[\"CUDA_VISIBLE_DEVICES\"] = str(args.gpu)\n", + " \n", + "from ncs_data import *\n", + "conf = ncs_config(args)\n", + "\n", + "conf.display()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Train" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "x_train: (4082, 1, 64, 64, 32) | 0.0 ~ 1.0\n", + "y_train: (4082, 1, 64, 64, 32) | 0 ~ 1\n", + "x_valid: (3126, 1, 64, 64, 32) | 0.0 ~ 1.0\n", + "y_valid: (3126, 1, 64, 64, 32) | 0 ~ 1\n", + "[INFO] Load pre-trained weights from pretrained_weights/Genesis_Chest_CT.h5\n", + "Train on 4082 samples, validate on 3126 samples\n", + "Epoch 1/10000\n", + "\n", + "> Batch size = 14\n", + "Train on 4082 samples, validate on 3126 samples\n", + "Epoch 1/10000\n", + "1036/4082 [======>.......................] - ETA: 7:37 - loss: 0.4391 - mean_iou: 0.6119 - dice_coef: 0.5609\n", + "> Batch size = 12\n", + "Train on 4082 samples, validate on 3126 samples\n", + "Epoch 1/10000\n", + "4082/4082 [==============================] - 709s 174ms/step - loss: 0.2932 - mean_iou: 0.7156 - dice_coef: 0.7068 - val_loss: 0.3287 - val_mean_iou: 0.7407 - val_dice_coef: 0.6713\n", + "\n", + "Epoch 00001: val_loss improved from inf to 0.32870, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 2/10000\n", + "4082/4082 [==============================] - 699s 171ms/step - loss: 0.2394 - mean_iou: 0.7524 - dice_coef: 0.7606 - val_loss: 0.3988 - val_mean_iou: 0.7547 - val_dice_coef: 0.6012\n", + "\n", + "Epoch 00002: val_loss did not improve from 0.32870\n", + "Epoch 3/10000\n", + "4082/4082 [==============================] - 700s 171ms/step - loss: 0.1950 - mean_iou: 0.7582 - dice_coef: 0.8050 - val_loss: 0.3279 - val_mean_iou: 0.7705 - val_dice_coef: 0.6721\n", + "\n", + "Epoch 00003: val_loss improved from 0.32870 to 0.32789, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 4/10000\n", + "3756/4082 [==========================>...] - ETA: 44s - loss: 0.1836 - mean_iou: 0.7800 - dice_coef: 0.8164\n", + "> Batch size = 10\n", + "Train on 4082 samples, validate on 3126 samples\n", + "Epoch 1/10000\n", + "4082/4082 [==============================] - 708s 173ms/step - loss: 0.1886 - mean_iou: 0.7914 - dice_coef: 0.8114 - val_loss: 0.2994 - val_mean_iou: 0.7959 - val_dice_coef: 0.7006\n", + "\n", + "Epoch 00001: val_loss improved from 0.32789 to 0.29936, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 2/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.1628 - mean_iou: 0.8009 - dice_coef: 0.8372 - val_loss: 0.2804 - val_mean_iou: 0.8049 - val_dice_coef: 0.7196\n", + "\n", + "Epoch 00002: val_loss improved from 0.29936 to 0.28040, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 3/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.1491 - mean_iou: 0.8091 - dice_coef: 0.8509 - val_loss: 0.2657 - val_mean_iou: 0.8126 - val_dice_coef: 0.7343\n", + "\n", + "Epoch 00003: val_loss improved from 0.28040 to 0.26571, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 4/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.1382 - mean_iou: 0.8161 - dice_coef: 0.8618 - val_loss: 0.2471 - val_mean_iou: 0.8187 - val_dice_coef: 0.7529\n", + "\n", + "Epoch 00004: val_loss improved from 0.26571 to 0.24712, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 5/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.1279 - mean_iou: 0.8214 - dice_coef: 0.8721 - val_loss: 0.2390 - val_mean_iou: 0.8239 - val_dice_coef: 0.7610\n", + "\n", + "Epoch 00005: val_loss improved from 0.24712 to 0.23904, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 6/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.1185 - mean_iou: 0.8267 - dice_coef: 0.8815 - val_loss: 0.2461 - val_mean_iou: 0.8287 - val_dice_coef: 0.7539\n", + "\n", + "Epoch 00006: val_loss did not improve from 0.23904\n", + "Epoch 7/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.1167 - mean_iou: 0.8308 - dice_coef: 0.8833 - val_loss: 0.2459 - val_mean_iou: 0.8322 - val_dice_coef: 0.7541\n", + "\n", + "Epoch 00007: val_loss did not improve from 0.23904\n", + "Epoch 8/10000\n", + "4082/4082 [==============================] - 703s 172ms/step - loss: 0.1251 - mean_iou: 0.8337 - dice_coef: 0.8749 - val_loss: 0.2395 - val_mean_iou: 0.8349 - val_dice_coef: 0.7605\n", + "\n", + "Epoch 00008: val_loss did not improve from 0.23904\n", + "Epoch 9/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.1071 - mean_iou: 0.8366 - dice_coef: 0.8929 - val_loss: 0.2241 - val_mean_iou: 0.8380 - val_dice_coef: 0.7759\n", + "\n", + "Epoch 00009: val_loss improved from 0.23904 to 0.22408, saving model to models/ncs/run_1/Vnet-genesis.h5\n", + "Epoch 10/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.1058 - mean_iou: 0.8395 - dice_coef: 0.8942 - val_loss: 0.2433 - val_mean_iou: 0.8406 - val_dice_coef: 0.7567\n", + "\n", + "Epoch 00010: val_loss did not improve from 0.22408\n", + "Epoch 11/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0951 - mean_iou: 0.8420 - dice_coef: 0.9049 - val_loss: 0.2280 - val_mean_iou: 0.8432 - val_dice_coef: 0.7720\n", + "\n", + "Epoch 00011: val_loss did not improve from 0.22408\n", + "Epoch 12/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.1027 - mean_iou: 0.8444 - dice_coef: 0.8973 - val_loss: 0.2540 - val_mean_iou: 0.8452 - val_dice_coef: 0.7460\n", + "\n", + "Epoch 00012: val_loss did not improve from 0.22408\n", + "Epoch 13/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0900 - mean_iou: 0.8463 - dice_coef: 0.9100 - val_loss: 0.2332 - val_mean_iou: 0.8473 - val_dice_coef: 0.7668\n", + "\n", + "Epoch 00013: val_loss did not improve from 0.22408\n", + "Epoch 14/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0853 - mean_iou: 0.8484 - dice_coef: 0.9147 - val_loss: 0.2253 - val_mean_iou: 0.8493 - val_dice_coef: 0.7747\n", + "\n", + "Epoch 00014: val_loss did not improve from 0.22408\n", + "Epoch 15/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0814 - mean_iou: 0.8504 - dice_coef: 0.9186 - val_loss: 0.2390 - val_mean_iou: 0.8512 - val_dice_coef: 0.7610\n", + "\n", + "Epoch 00015: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00015: ReduceLROnPlateau reducing learning rate to 0.0005000000237487257.\n", + "Epoch 16/10000\n", + "4082/4082 [==============================] - 705s 173ms/step - loss: 0.0713 - mean_iou: 0.8523 - dice_coef: 0.9287 - val_loss: 0.2344 - val_mean_iou: 0.8531 - val_dice_coef: 0.7656\n", + "\n", + "Epoch 00016: val_loss did not improve from 0.22408\n", + "Epoch 17/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0672 - mean_iou: 0.8541 - dice_coef: 0.9328 - val_loss: 0.2396 - val_mean_iou: 0.8550 - val_dice_coef: 0.7604\n", + "\n", + "Epoch 00017: val_loss did not improve from 0.22408\n", + "Epoch 18/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0652 - mean_iou: 0.8559 - dice_coef: 0.9348 - val_loss: 0.2411 - val_mean_iou: 0.8567 - val_dice_coef: 0.7589\n", + "\n", + "Epoch 00018: val_loss did not improve from 0.22408\n", + "Epoch 19/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0640 - mean_iou: 0.8575 - dice_coef: 0.9360 - val_loss: 0.2457 - val_mean_iou: 0.8582 - val_dice_coef: 0.7543\n", + "\n", + "Epoch 00019: val_loss did not improve from 0.22408\n", + "Epoch 20/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0617 - mean_iou: 0.8590 - dice_coef: 0.9383 - val_loss: 0.2381 - val_mean_iou: 0.8597 - val_dice_coef: 0.7619\n", + "\n", + "Epoch 00020: val_loss did not improve from 0.22408\n", + "Epoch 21/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0619 - mean_iou: 0.8604 - dice_coef: 0.9381 - val_loss: 0.2309 - val_mean_iou: 0.8610 - val_dice_coef: 0.7691\n", + "\n", + "Epoch 00021: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00021: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628.\n", + "Epoch 22/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0547 - mean_iou: 0.8617 - dice_coef: 0.9453 - val_loss: 0.2348 - val_mean_iou: 0.8624 - val_dice_coef: 0.7652\n", + "\n", + "Epoch 00022: val_loss did not improve from 0.22408\n", + "Epoch 23/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0526 - mean_iou: 0.8631 - dice_coef: 0.9474 - val_loss: 0.2351 - val_mean_iou: 0.8637 - val_dice_coef: 0.7649\n", + "\n", + "Epoch 00023: val_loss did not improve from 0.22408\n", + "Epoch 24/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0516 - mean_iou: 0.8644 - dice_coef: 0.9484 - val_loss: 0.2368 - val_mean_iou: 0.8649 - val_dice_coef: 0.7632\n", + "\n", + "Epoch 00024: val_loss did not improve from 0.22408\n", + "Epoch 25/10000\n", + "4082/4082 [==============================] - 705s 173ms/step - loss: 0.0510 - mean_iou: 0.8655 - dice_coef: 0.9490 - val_loss: 0.2353 - val_mean_iou: 0.8661 - val_dice_coef: 0.7647\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Epoch 00025: val_loss did not improve from 0.22408\n", + "Epoch 26/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0485 - mean_iou: 0.8667 - dice_coef: 0.9515 - val_loss: 0.2327 - val_mean_iou: 0.8672 - val_dice_coef: 0.7673\n", + "\n", + "Epoch 00026: val_loss did not improve from 0.22408\n", + "Epoch 27/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0475 - mean_iou: 0.8678 - dice_coef: 0.9525 - val_loss: 0.2368 - val_mean_iou: 0.8682 - val_dice_coef: 0.7632\n", + "\n", + "Epoch 00027: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00027: ReduceLROnPlateau reducing learning rate to 0.0001250000059371814.\n", + "Epoch 28/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0447 - mean_iou: 0.8688 - dice_coef: 0.9553 - val_loss: 0.2344 - val_mean_iou: 0.8693 - val_dice_coef: 0.7656\n", + "\n", + "Epoch 00028: val_loss did not improve from 0.22408\n", + "Epoch 29/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0437 - mean_iou: 0.8698 - dice_coef: 0.9563 - val_loss: 0.2325 - val_mean_iou: 0.8703 - val_dice_coef: 0.7675\n", + "\n", + "Epoch 00029: val_loss did not improve from 0.22408\n", + "Epoch 30/10000\n", + "4082/4082 [==============================] - 705s 173ms/step - loss: 0.0430 - mean_iou: 0.8708 - dice_coef: 0.9570 - val_loss: 0.2345 - val_mean_iou: 0.8712 - val_dice_coef: 0.7655\n", + "\n", + "Epoch 00030: val_loss did not improve from 0.22408\n", + "Epoch 31/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0422 - mean_iou: 0.8717 - dice_coef: 0.9578 - val_loss: 0.2383 - val_mean_iou: 0.8721 - val_dice_coef: 0.7617\n", + "\n", + "Epoch 00031: val_loss did not improve from 0.22408\n", + "Epoch 32/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0421 - mean_iou: 0.8725 - dice_coef: 0.9579 - val_loss: 0.2336 - val_mean_iou: 0.8729 - val_dice_coef: 0.7664\n", + "\n", + "Epoch 00032: val_loss did not improve from 0.22408\n", + "Epoch 33/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0415 - mean_iou: 0.8733 - dice_coef: 0.9585 - val_loss: 0.2378 - val_mean_iou: 0.8737 - val_dice_coef: 0.7622\n", + "\n", + "Epoch 00033: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00033: ReduceLROnPlateau reducing learning rate to 6.25000029685907e-05.\n", + "Epoch 34/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0402 - mean_iou: 0.8741 - dice_coef: 0.9598 - val_loss: 0.2364 - val_mean_iou: 0.8744 - val_dice_coef: 0.7636\n", + "\n", + "Epoch 00034: val_loss did not improve from 0.22408\n", + "Epoch 35/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0396 - mean_iou: 0.8749 - dice_coef: 0.9604 - val_loss: 0.2363 - val_mean_iou: 0.8752 - val_dice_coef: 0.7637\n", + "\n", + "Epoch 00035: val_loss did not improve from 0.22408\n", + "Epoch 36/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0395 - mean_iou: 0.8756 - dice_coef: 0.9605 - val_loss: 0.2357 - val_mean_iou: 0.8759 - val_dice_coef: 0.7643\n", + "\n", + "Epoch 00036: val_loss did not improve from 0.22408\n", + "Epoch 37/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0391 - mean_iou: 0.8763 - dice_coef: 0.9609 - val_loss: 0.2379 - val_mean_iou: 0.8766 - val_dice_coef: 0.7621\n", + "\n", + "Epoch 00037: val_loss did not improve from 0.22408\n", + "Epoch 38/10000\n", + "4082/4082 [==============================] - 705s 173ms/step - loss: 0.0391 - mean_iou: 0.8769 - dice_coef: 0.9609 - val_loss: 0.2384 - val_mean_iou: 0.8772 - val_dice_coef: 0.7616\n", + "\n", + "Epoch 00038: val_loss did not improve from 0.22408\n", + "Epoch 39/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0382 - mean_iou: 0.8775 - dice_coef: 0.9618 - val_loss: 0.2392 - val_mean_iou: 0.8778 - val_dice_coef: 0.7608\n", + "\n", + "Epoch 00039: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00039: ReduceLROnPlateau reducing learning rate to 3.125000148429535e-05.\n", + "Epoch 40/10000\n", + "4082/4082 [==============================] - 705s 173ms/step - loss: 0.0379 - mean_iou: 0.8781 - dice_coef: 0.9621 - val_loss: 0.2373 - val_mean_iou: 0.8784 - val_dice_coef: 0.7627\n", + "\n", + "Epoch 00040: val_loss did not improve from 0.22408\n", + "Epoch 41/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0373 - mean_iou: 0.8787 - dice_coef: 0.9627 - val_loss: 0.2385 - val_mean_iou: 0.8790 - val_dice_coef: 0.7615\n", + "\n", + "Epoch 00041: val_loss did not improve from 0.22408\n", + "Epoch 42/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0372 - mean_iou: 0.8793 - dice_coef: 0.9628 - val_loss: 0.2375 - val_mean_iou: 0.8795 - val_dice_coef: 0.7625\n", + "\n", + "Epoch 00042: val_loss did not improve from 0.22408\n", + "Epoch 43/10000\n", + "4082/4082 [==============================] - 705s 173ms/step - loss: 0.0371 - mean_iou: 0.8798 - dice_coef: 0.9629 - val_loss: 0.2390 - val_mean_iou: 0.8800 - val_dice_coef: 0.7610\n", + "\n", + "Epoch 00043: val_loss did not improve from 0.22408\n", + "Epoch 44/10000\n", + "4082/4082 [==============================] - 703s 172ms/step - loss: 0.0371 - mean_iou: 0.8803 - dice_coef: 0.9629 - val_loss: 0.2383 - val_mean_iou: 0.8806 - val_dice_coef: 0.7617\n", + "\n", + "Epoch 00044: val_loss did not improve from 0.22408\n", + "Epoch 45/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0368 - mean_iou: 0.8808 - dice_coef: 0.9632 - val_loss: 0.2388 - val_mean_iou: 0.8810 - val_dice_coef: 0.7612\n", + "\n", + "Epoch 00045: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00045: ReduceLROnPlateau reducing learning rate to 1.5625000742147677e-05.\n", + "Epoch 46/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0365 - mean_iou: 0.8813 - dice_coef: 0.9635 - val_loss: 0.2383 - val_mean_iou: 0.8815 - val_dice_coef: 0.7617\n", + "\n", + "Epoch 00046: val_loss did not improve from 0.22408\n", + "Epoch 47/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0367 - mean_iou: 0.8818 - dice_coef: 0.9633 - val_loss: 0.2396 - val_mean_iou: 0.8820 - val_dice_coef: 0.7604\n", + "\n", + "Epoch 00047: val_loss did not improve from 0.22408\n", + "Epoch 48/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0361 - mean_iou: 0.8822 - dice_coef: 0.9639 - val_loss: 0.2396 - val_mean_iou: 0.8824 - val_dice_coef: 0.7604\n", + "\n", + "Epoch 00048: val_loss did not improve from 0.22408\n", + "Epoch 49/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0367 - mean_iou: 0.8826 - dice_coef: 0.9633 - val_loss: 0.2387 - val_mean_iou: 0.8828 - val_dice_coef: 0.7613\n", + "\n", + "Epoch 00049: val_loss did not improve from 0.22408\n", + "Epoch 50/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0364 - mean_iou: 0.8830 - dice_coef: 0.9636 - val_loss: 0.2390 - val_mean_iou: 0.8832 - val_dice_coef: 0.7610\n", + "\n", + "Epoch 00050: val_loss did not improve from 0.22408\n", + "Epoch 51/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0364 - mean_iou: 0.8834 - dice_coef: 0.9636 - val_loss: 0.2395 - val_mean_iou: 0.8836 - val_dice_coef: 0.7605\n", + "\n", + "Epoch 00051: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00051: ReduceLROnPlateau reducing learning rate to 7.812500371073838e-06.\n", + "Epoch 52/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0359 - mean_iou: 0.8838 - dice_coef: 0.9641 - val_loss: 0.2394 - val_mean_iou: 0.8840 - val_dice_coef: 0.7606\n", + "\n", + "Epoch 00052: val_loss did not improve from 0.22408\n", + "Epoch 53/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0358 - mean_iou: 0.8842 - dice_coef: 0.9642 - val_loss: 0.2390 - val_mean_iou: 0.8843 - val_dice_coef: 0.7610\n", + "\n", + "Epoch 00053: val_loss did not improve from 0.22408\n", + "Epoch 54/10000\n", + "4082/4082 [==============================] - 705s 173ms/step - loss: 0.0354 - mean_iou: 0.8845 - dice_coef: 0.9646 - val_loss: 0.2390 - val_mean_iou: 0.8847 - val_dice_coef: 0.7610\n", + "\n", + "Epoch 00054: val_loss did not improve from 0.22408\n", + "Epoch 55/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0363 - mean_iou: 0.8849 - dice_coef: 0.9637 - val_loss: 0.2393 - val_mean_iou: 0.8850 - val_dice_coef: 0.7607\n", + "\n", + "Epoch 00055: val_loss did not improve from 0.22408\n", + "Epoch 56/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0360 - mean_iou: 0.8852 - dice_coef: 0.9640 - val_loss: 0.2397 - val_mean_iou: 0.8853 - val_dice_coef: 0.7603\n", + "\n", + "Epoch 00056: val_loss did not improve from 0.22408\n", + "Epoch 57/10000\n", + "4082/4082 [==============================] - 703s 172ms/step - loss: 0.0357 - mean_iou: 0.8855 - dice_coef: 0.9643 - val_loss: 0.2395 - val_mean_iou: 0.8857 - val_dice_coef: 0.7605\n", + "\n", + "Epoch 00057: val_loss did not improve from 0.22408\n", + "\n", + "Epoch 00057: ReduceLROnPlateau reducing learning rate to 3.906250185536919e-06.\n", + "Epoch 58/10000\n", + "4082/4082 [==============================] - 704s 172ms/step - loss: 0.0360 - mean_iou: 0.8858 - dice_coef: 0.9640 - val_loss: 0.2393 - val_mean_iou: 0.8860 - val_dice_coef: 0.7607\n", + "\n", + "Epoch 00058: val_loss did not improve from 0.22408\n", + "Epoch 59/10000\n", + "4082/4082 [==============================] - 704s 173ms/step - loss: 0.0353 - mean_iou: 0.8861 - dice_coef: 0.9647 - val_loss: 0.2392 - val_mean_iou: 0.8863 - val_dice_coef: 0.7608\n", + "\n", + "Epoch 00059: val_loss did not improve from 0.22408\n", + "Epoch 00059: early stopping\n" + ] + } + ], + "source": [ + "x_train, y_train = load_image(conf, 'train')\n", + "print('x_train: {} | {} ~ {}'.format(x_train.shape, np.min(x_train), np.max(x_train)))\n", + "print('y_train: {} | {} ~ {}'.format(y_train.shape, np.min(y_train), np.max(y_train)))\n", + "\n", + "x_valid, y_valid = load_image(conf, 'valid')\n", + "print('x_valid: {} | {} ~ {}'.format(x_valid.shape, np.min(x_valid), np.max(x_valid)))\n", + "print('y_valid: {} | {} ~ {}'.format(y_valid.shape, np.min(y_valid), np.max(y_valid)))\n", + "\n", + "model = unet_model_3d((1,conf.input_rows,conf.input_cols,conf.input_deps), batch_normalization=True)\n", + "if conf.weights is not None:\n", + " print(\"[INFO] Load pre-trained weights from {}\".format(conf.weights))\n", + " model.load_weights(conf.weights)\n", + "model, callbacks = model_setup(model, conf, task=args.task)\n", + "\n", + "while conf.batch_size > 1:\n", + " # To find a largest batch size that can be fit into GPU\n", + " try:\n", + " model.fit(x_train, y_train,\n", + " validation_data=(x_valid, y_valid),\n", + " batch_size=conf.batch_size,\n", + " epochs=conf.nb_epoch, \n", + " verbose=conf.verbose, \n", + " shuffle=True,\n", + " callbacks=callbacks)\n", + " break\n", + " except tf.errors.ResourceExhaustedError as e:\n", + " conf.batch_size = int(conf.batch_size - 2)\n", + " print(\"\\n> Batch size = {}\".format(conf.batch_size))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[INFO] Load trained model from models/ncs/run_1/Vnet-genesis.h5\n", + "x_test: (852, 1, 64, 64, 32) | 0.0 ~ 1.0\n", + "y_test: (852, 1, 64, 64, 32) | 0 ~ 1\n", + "852/852 [==============================] - 36s 42ms/step\n", + "852/852 [==============================] - 40s 47ms/step\n", + "[INFO] Vnet-genesis\n", + "x: (852, 1, 64, 64, 32) | 0.0 ~ 1.0\n", + "y: (852, 1, 64, 64, 32) | 0.0 ~ 1.0\n", + "p: (852, 1, 64, 64, 32) | 0.0 ~ 1.0\n", + "[INFO] Dice = 74.39%\n", + "[INFO] IoU = 59.22%\n", + "[EVAL] Dice = 75.38%\n", + "[EVAL] IoU = 77.14%\n" + ] + } + ], + "source": [ + "model = unet_model_3d((1,conf.input_rows,conf.input_cols,conf.input_deps), batch_normalization=True)\n", + "print(\"[INFO] Load trained model from {}\".format( os.path.join(conf.model_path, conf.exp_name+\".h5\") ))\n", + "model.load_weights( os.path.join(conf.model_path, conf.exp_name+\".h5\") )\n", + "\n", + "x_test, y_test = load_image(conf, 'test')\n", + "print('x_test: {} | {} ~ {}'.format(x_test.shape, np.min(x_test), np.max(x_test)))\n", + "print('y_test: {} | {} ~ {}'.format(y_test.shape, np.min(y_test), np.max(y_test)))\n", + "\n", + "_ = segmentation_model_evaluation(model=model, config=conf, x=x_test, y=y_test, note=conf.exp_name)" + ] + } + ], + "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.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/keras/downstream_tasks/ncs_data.py b/keras/downstream_tasks/ncs_data.py new file mode 100755 index 0000000..352dc4a --- /dev/null +++ b/keras/downstream_tasks/ncs_data.py @@ -0,0 +1,32 @@ +import os +import random +import copy +import keras +import shutil +import numpy as np +from tqdm import tqdm +from glob import glob +from skimage.transform import resize + +def load_image(config, status=None): + + x = np.squeeze(np.load(os.path.join(config.data, 'x_'+status+'_64x64x32.npy'))) + y = np.squeeze(np.load(os.path.join(config.data, 'm_'+status+'_64x64x32.npy'))) + x = np.expand_dims(x, axis=1) + y = np.expand_dims(y, axis=1) + + return x, y + +if __name__ == "__main__": + from config import * + + class set_args(): + apps = 'ncs' + task = 'segmentation' + suffix = 'random' + args = set_args() + + conf = ncs_config(args) + x_valid, y_valid = load_image(conf, 'valid') + print(x_valid.shape, np.min(x_valid), np.max(x_valid)) + print(y_valid.shape, np.min(y_valid), np.max(y_valid)) \ No newline at end of file diff --git a/keras/downstream_tasks/unet3d.py b/keras/downstream_tasks/unet3d.py new file mode 100755 index 0000000..f9076a9 --- /dev/null +++ b/keras/downstream_tasks/unet3d.py @@ -0,0 +1,123 @@ +import numpy as np +from keras import backend as K +from keras.engine import Input, Model +from keras.layers import Conv3D, MaxPooling3D, UpSampling3D, Activation, BatchNormalization, PReLU, Deconvolution3D +from keras.optimizers import Adam +K.set_image_data_format("channels_first") + +try: + from keras.engine import merge +except ImportError: + from keras.layers.merge import concatenate + + +def unet_model_3d(input_shape, pool_size=(2, 2, 2), n_labels=1, deconvolution=False, + depth=4, n_base_filters=32, batch_normalization=False, activation_name="sigmoid"): + """ + Builds the 3D UNet Keras model.f + :param metrics: List metrics to be calculated during model training (default is dice coefficient). + :param include_label_wise_dice_coefficients: If True and n_labels is greater than 1, model will report the dice + coefficient for each label as metric. + :param n_base_filters: The number of filters that the first layer in the convolution network will have. Following + layers will contain a multiple of this number. Lowering this number will likely reduce the amount of memory required + to train the model. + :param depth: indicates the depth of the U-shape for the model. The greater the depth, the more max pooling + layers will be added to the model. Lowering the depth may reduce the amount of memory required for training. + :param input_shape: Shape of the input data (n_chanels, x_size, y_size, z_size). The x, y, and z sizes must be + divisible by the pool size to the power of the depth of the UNet, that is pool_size^depth. + :param pool_size: Pool size for the max pooling operations. + :param n_labels: Number of binary labels that the model is learning. + :param initial_learning_rate: Initial learning rate for the model. This will be decayed during training. + :param deconvolution: If set to True, will use transpose convolution(deconvolution) instead of up-sampling. This + increases the amount memory required during training. + :return: Untrained 3D UNet Model + """ + inputs = Input(input_shape) + current_layer = inputs + levels = list() + num_layer = 0 + + # add levels with max pooling + for layer_depth in range(depth): + layer1 = create_convolution_block(input_layer=current_layer, n_filters=n_base_filters*(2**layer_depth), + batch_normalization=batch_normalization, layer_depth=num_layer) + num_layer += 1 + layer2 = create_convolution_block(input_layer=layer1, n_filters=n_base_filters*(2**layer_depth)*2, + batch_normalization=batch_normalization, layer_depth=num_layer) + num_layer += 1 + if layer_depth < depth - 1: + current_layer = MaxPooling3D(pool_size=pool_size)(layer2) + levels.append([layer1, layer2, current_layer]) + else: + current_layer = layer2 + levels.append([layer1, layer2]) + + # add levels with up-convolution or up-sampling + for layer_depth in range(depth-2, -1, -1): + up_convolution = get_up_convolution(pool_size=pool_size, deconvolution=deconvolution, + n_filters=current_layer._keras_shape[1])(current_layer) + concat = concatenate([up_convolution, levels[layer_depth][1]], axis=1) + current_layer = create_convolution_block(n_filters=levels[layer_depth][1]._keras_shape[1], layer_depth=num_layer, + input_layer=concat, batch_normalization=batch_normalization) + num_layer += 1 + current_layer = create_convolution_block(n_filters=levels[layer_depth][1]._keras_shape[1], layer_depth=num_layer, + input_layer=current_layer, + batch_normalization=batch_normalization) + num_layer += 1 + + final_convolution = Conv3D(n_labels, (1, 1, 1))(current_layer) + act = Activation(activation_name)(final_convolution) + model = Model(inputs=inputs, outputs=act) + + return model + +def create_convolution_block(input_layer, n_filters, batch_normalization=False, kernel=(3, 3, 3), activation=None, + padding='same', strides=(1, 1, 1), instance_normalization=False, layer_depth=None): + """ + + :param strides: + :param input_layer: + :param n_filters: + :param batch_normalization: + :param kernel: + :param activation: Keras activation layer to use. (default is 'relu') + :param padding: + :return: + """ + layer = Conv3D(n_filters, kernel, padding=padding, strides=strides, name="depth_"+str(layer_depth)+"_conv")(input_layer) + if batch_normalization: + layer = BatchNormalization(axis=1, name="depth_"+str(layer_depth)+"_bn")(layer) + elif instance_normalization: + try: + from keras_contrib.layers.normalization.instancenormalization import InstanceNormalization + except ImportError: + raise ImportError("Install keras_contrib in order to use instance normalization." + "\nTry: pip install git+https://www.github.com/farizrahman4u/keras-contrib.git") + layer = InstanceNormalization(axis=1, name="depth_"+str(layer_depth)+"_in")(layer) + if activation is None: + return Activation('relu', name="depth_"+str(layer_depth)+"_relu")(layer) + else: + return activation()(layer) + + +def compute_level_output_shape(n_filters, depth, pool_size, image_shape): + """ + Each level has a particular output shape based on the number of filters used in that level and the depth or number + of max pooling operations that have been done on the data at that point. + :param image_shape: shape of the 3d image. + :param pool_size: the pool_size parameter used in the max pooling operation. + :param n_filters: Number of filters used by the last node in a given level. + :param depth: The number of levels down in the U-shaped model a given node is. + :return: 5D vector of the shape of the output node + """ + output_image_shape = np.asarray(np.divide(image_shape, np.power(pool_size, depth)), dtype=np.int32).tolist() + return tuple([None, n_filters] + output_image_shape) + + +def get_up_convolution(n_filters, pool_size, kernel_size=(2, 2, 2), strides=(2, 2, 2), + deconvolution=False): + if deconvolution: + return Deconvolution3D(filters=n_filters, kernel_size=kernel_size, + strides=strides) + else: + return UpSampling3D(size=pool_size) diff --git a/keras/downstream_tasks/utils.py b/keras/downstream_tasks/utils.py new file mode 100755 index 0000000..f678ac7 --- /dev/null +++ b/keras/downstream_tasks/utils.py @@ -0,0 +1,289 @@ +import os +import random +import copy +import keras +import shutil +import math +import numpy as np +import tensorflow as tf +import matplotlib.pyplot as plt +from tqdm import tqdm +from keras import backend as K +from sklearn import metrics +from skimage.transform import resize +from keras.callbacks import LambdaCallback,TensorBoard,ReduceLROnPlateau + +def augment_rician_noise(data_sample, noise_variance=(0, 0.1)): + variance = random.uniform(noise_variance[0], noise_variance[1]) + data_sample = np.sqrt( + (data_sample + np.random.normal(0.0, variance, size=data_sample.shape)) ** 2 + + np.random.normal(0.0, variance, size=data_sample.shape) ** 2) + return data_sample + +def augment_gaussian_noise(data_sample, noise_variance=(0, 0.1)): + if noise_variance[0] == noise_variance[1]: + variance = noise_variance[0] + else: + variance = random.uniform(noise_variance[0], noise_variance[1]) + data_sample = data_sample + np.random.normal(0.0, variance, size=data_sample.shape) + return data_sample + +###### +# Module: Evaluation metric +###### +def mean_iou(y_true, y_pred): + prec = [] + for t in np.arange(0.5, 1.0, 0.05): + y_pred_ = tf.to_int32(y_pred > t) + score, up_opt = tf.metrics.mean_iou(y_true, y_pred_, 2) + K.get_session().run(tf.local_variables_initializer()) + with tf.control_dependencies([up_opt]): + score = tf.identity(score) + prec.append(score) + return K.mean(K.stack(prec), axis=0) + +def dice_coef(y_true, y_pred, smooth=1.): + y_true_f = K.flatten(y_true) + y_pred_f = K.flatten(y_pred) + intersection = K.sum(y_true_f * y_pred_f) + return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth) + +def dice_coef_loss(y_true, y_pred): + return 1. - dice_coef(y_true, y_pred) + +def bce_dice_loss(y_true, y_pred): + return 0.5 * keras.losses.binary_crossentropy(y_true, y_pred) - dice_coef(y_true, y_pred) + +def iou(im1, im2): + overlap = (im1>0.5) * (im2>0.5) + union = (im1>0.5) + (im2>0.5) + return overlap.sum()/float(union.sum()) + +def dice(im1, im2, empty_score=1.0): + im1 = np.asarray(im1>0.5).astype(np.bool) + im2 = np.asarray(im2>0.5).astype(np.bool) + + if im1.shape != im2.shape: + raise ValueError("Shape mismatch: im1 and im2 must have the same shape.") + + im_sum = im1.sum() + im2.sum() + if im_sum == 0: + return empty_score + + intersection = np.logical_and(im1, im2) + + return 2. * intersection.sum() / im_sum + + + +###### +# Module: model setup +###### +def classification_model_compile(model, config): + if config.num_classes <= 2: + model.compile(optimizer=config.optimizer, + loss="binary_crossentropy", + metrics=['accuracy','binary_crossentropy'], + ) + else: + model.compile(optimizer=config.optimizer, + loss="categorical_crossentropy", + metrics=['categorical_accuracy','categorical_crossentropy'], + ) + return model + +def segmentation_model_compile(model, config): + model.compile(optimizer=config.optimizer, + loss=dice_coef_loss, + metrics=[mean_iou, + dice_coef], + ) + return model + +def model_setup(model, config, task=None): + if task == 'segmentation': + model = segmentation_model_compile(model, config) + elif task == 'classification': + model = classification_model_compile(model, config) + else: + raise + + if os.path.exists(os.path.join(config.model_path, config.exp_name+".txt")): + os.remove(os.path.join(config.model_path, config.exp_name+".txt")) + with open(os.path.join(config.model_path, config.exp_name+".txt"),'w') as fh: + model.summary(print_fn=lambda x: fh.write(x + '\n')) + + shutil.rmtree(os.path.join(config.logs_path, config.exp_name), ignore_errors=True) + if not os.path.exists(os.path.join(config.logs_path, config.exp_name)): + os.makedirs(os.path.join(config.logs_path, config.exp_name)) + tbCallBack = TensorBoard(log_dir=os.path.join(config.logs_path, config.exp_name), + histogram_freq=0, + write_graph=True, + write_images=True, + ) + tbCallBack.set_model(model) + + early_stopping = keras.callbacks.EarlyStopping(monitor='val_loss', + patience=config.patience, + verbose=config.verbose, + mode='min', + ) + check_point = keras.callbacks.ModelCheckpoint(os.path.join(config.model_path, config.exp_name+".h5"), + monitor='val_loss', + verbose=config.verbose, + save_best_only=True, + mode='min', + ) + lrate_scheduler = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=6, + min_delta=0.0001, min_lr=1e-6, verbose=1) + callbacks = [check_point, early_stopping, tbCallBack, lrate_scheduler] + return model, callbacks + +def classification_model_evaluation(model, config, x, y, note=None): + model = classification_model_compile(model, config) + p = model.predict(x, verbose=config.verbose, batch_size=config.batch_size) + if note is not None: + print("[INFO] {}".format(note)) + print("x: {} | {:.1f} ~ {:.1f}".format(x.shape, np.min(x), np.max(x))) + print("y: {} | {:.1f} ~ {:.1f}".format(y.shape, np.min(y), np.max(y))) + print("p: {} | {:.1f} ~ {:.1f}".format(p.shape, np.min(p), np.max(p))) + + fpr, tpr, thresholds = metrics.roc_curve(y, p, pos_label=1) + + print("[EVAL] AUC = {:.2f}%".format(100.0 * metrics.auc(fpr, tpr))) + + return p + +def segmentation_model_evaluation(model, config, x, y, note=None): + model.compile(optimizer=config.optimizer, + loss=dice_coef_loss, + metrics=[mean_iou, + dice_coef], + ) + p = model.predict(x, verbose=config.verbose, batch_size=config.batch_size) + eva = model.evaluate(x, y, verbose=config.verbose, batch_size=config.batch_size) + if note is not None: + print("[INFO] {}".format(note)) + print("x: {} | {:.1f} ~ {:.1f}".format(x.shape, np.min(x), np.max(x))) + print("y: {} | {:.1f} ~ {:.1f}".format(y.shape, np.min(y), np.max(y))) + print("p: {} | {:.1f} ~ {:.1f}".format(p.shape, np.min(p), np.max(p))) + print("[BIN] Dice = {:.2f}%".format(100.0 * dice(p, y))) + print("[BIN] IoU = {:.2f}%".format(100.0 * iou(p, y))) + print("[EVAL] Dice = {:.2f}%".format(100.0 * eva[-1])) + print("[EVAL] IoU = {:.2f}%".format(100.0 * eva[-2])) + + return p + +def plot_image_truth_prediction(x, y, p): + x, y, p = np.squeeze(x), np.squeeze(y), np.squeeze(p>0.5) + rows, cols = 12, 12 + plt.rcParams.update({'font.size': 30}) + plt.figure(figsize=(25*3, 25)) + + large_image = np.zeros((rows*x.shape[0], cols*x.shape[1])) + for b in range(rows*cols): + large_image[(b//rows)*x.shape[0]:(b//rows+1)*x.shape[0], + (b%cols)*x.shape[1]:(b%cols+1)*x.shape[1]] = np.transpose(np.squeeze(x[:, :, b])) + plt.subplot(1, 3, 1) + plt.imshow(large_image, cmap='gray', vmin=0, vmax=1); plt.axis('off') + + large_image = np.zeros((rows*x.shape[0], cols*x.shape[1])) + for b in range(rows*cols): + large_image[(b//rows)*y.shape[0]:(b//rows+1)*y.shape[0], + (b%cols)*y.shape[1]:(b%cols+1)*y.shape[1]] = np.transpose(np.squeeze(y[:, :, b])) + plt.subplot(1, 3, 2) + plt.imshow(large_image, cmap='gray', vmin=0, vmax=1); plt.axis('off') + + large_image = np.zeros((rows*p.shape[0], cols*p.shape[1])) + for b in range(rows*cols): + large_image[(b//rows)*p.shape[0]:(b//rows+1)*p.shape[0], + (b%cols)*p.shape[1]:(b%cols+1)*p.shape[1]] = np.transpose(np.squeeze(p[:, :, b])) + plt.subplot(1, 3, 3) + plt.imshow(large_image, cmap='gray', vmin=0, vmax=1); plt.axis('off') + + plt.show() + +def predict_on_test_image(x, model, config): + rows, cols, deps = x.shape[0], x.shape[1], x.shape[2] + _resize = False + + p = np.zeros((rows, cols, deps), dtype='float') + n = np.ones((rows, cols, deps), dtype='float') + + nb_rows = int( math.floor( (rows-config.crop_rows) / config.step_pixel_size) ) + 1 + nb_cols = int( math.floor( (cols-config.crop_cols) / config.step_pixel_size) ) + 1 + nb_deps = int( math.floor( (deps-config.crop_deps) / config.step_pixel_size) ) + 1 + row_list = [x*config.step_pixel_size for x in range(nb_rows)] + col_list = [x*config.step_pixel_size for x in range(nb_cols)] + dep_list = [x*config.step_pixel_size for x in range(nb_deps)] + + for i in row_list: + for j in col_list: + for k in dep_list: + im = x[i:i+config.crop_rows, j:j+config.crop_cols, k:k+config.crop_deps] + im = resize(im, (config.input_rows, config.input_cols, config.input_deps), preserve_range=True) + im = np.expand_dims(np.expand_dims(im, axis=0), axis=0) + pr = np.squeeze(model.predict(im, verbose=0)) + pr = resize(pr, (config.crop_rows, config.crop_cols, config.crop_deps), preserve_range=True) + p[i:i+config.crop_rows, j:j+config.crop_cols, k:k+config.crop_deps] += pr + n[i:i+config.crop_rows, j:j+config.crop_cols, k:k+config.crop_deps] += 1 + + im = x[i:i+config.crop_rows, j:j+config.crop_cols, deps-config.crop_deps:deps] + im = resize(im, (config.input_rows, config.input_cols, config.input_deps), preserve_range=True) + im = np.expand_dims(np.expand_dims(im, axis=0), axis=0) + pr = np.squeeze(model.predict(im, verbose=0)) + pr = resize(pr, (config.crop_rows, config.crop_cols, config.crop_deps), preserve_range=True) + p[i:i+config.crop_rows, j:j+config.crop_cols, deps-config.crop_deps:deps] += pr + n[i:i+config.crop_rows, j:j+config.crop_cols, deps-config.crop_deps:deps] += 1 + + im = x[i:i+config.crop_rows, cols-config.crop_cols:cols, deps-config.crop_deps:deps] + im = resize(im, (config.input_rows, config.input_cols, config.input_deps), preserve_range=True) + im = np.expand_dims(np.expand_dims(im, axis=0), axis=0) + pr = np.squeeze(model.predict(im, verbose=0)) + pr = resize(pr, (config.crop_rows, config.crop_cols, config.crop_deps), preserve_range=True) + p[i:i+config.crop_rows, cols-config.crop_cols:cols, deps-config.crop_deps:deps] += pr + n[i:i+config.crop_rows, cols-config.crop_cols:cols, deps-config.crop_deps:deps] += 1 + + im = x[rows-config.crop_rows:rows, cols-config.crop_cols:cols, deps-config.crop_deps:deps] + im = resize(im, (config.input_rows, config.input_cols, config.input_deps), preserve_range=True) + im = np.expand_dims(np.expand_dims(im, axis=0), axis=0) + pr = np.squeeze(model.predict(im, verbose=0)) + pr = resize(pr, (config.crop_rows, config.crop_cols, config.crop_deps), preserve_range=True) + p[rows-config.crop_rows:rows, cols-config.crop_cols:cols, deps-config.crop_deps:deps] += pr + n[rows-config.crop_rows:rows, cols-config.crop_cols:cols, deps-config.crop_deps:deps] += 1 + + p = 1.0 * p / n + + return p + +###### +# Module: Visualization +###### +def plot_case(case_id=None, mris=None, segs=None, rows=10, cols=10, increment=38): + assert case_id is not None + assert mris is not None + assert segs is not None + font = {'family' : 'times', + 'weight' : 'bold', + 'size' : 22} + plt.rc('font', **font) + + print("\n\n[INFO] case id {}".format(case_id)) + + # plot the patient MRI + plt.figure(figsize=(cols*1, rows*1)) + plt.subplots_adjust(wspace=0.01, hspace=0.1) + for i in range(rows*cols): + plt.subplot(rows, cols, i+1) + plt.imshow(np.transpose(mris[case_id, 0, :, :, i+increment]), cmap="gray", vmin=0, vmax=1) + plt.axis('off') + plt.show() + + # plot the segmentation mask + plt.figure(figsize=(cols*1, rows*1)) + plt.subplots_adjust(wspace=0.01, hspace=0.1) + for i in range(rows*cols): + plt.subplot(rows, cols, i+1) + plt.imshow(np.transpose(segs[case_id, 0, :, :, i+increment]), cmap="gray", vmin=0, vmax=1) + plt.axis('off') + plt.show() \ No newline at end of file