{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## EDA\n#### Looking at the shape and layout of the raw DICOM data","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport matplotlib.pyplot as plt \nimport os, glob, random, cv2, glob, pydicom","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.601132Z","iopub.execute_input":"2022-01-10T15:25:27.601438Z","iopub.status.idle":"2022-01-10T15:25:27.879237Z","shell.execute_reply.started":"2022-01-10T15:25:27.601361Z","shell.execute_reply":"2022-01-10T15:25:27.878547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.880958Z","iopub.execute_input":"2022-01-10T15:25:27.881227Z","iopub.status.idle":"2022-01-10T15:25:27.895489Z","shell.execute_reply.started":"2022-01-10T15:25:27.881194Z","shell.execute_reply":"2022-01-10T15:25:27.894847Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.shape","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.896665Z","iopub.execute_input":"2022-01-10T15:25:27.896907Z","iopub.status.idle":"2022-01-10T15:25:27.905400Z","shell.execute_reply.started":"2022-01-10T15:25:27.896875Z","shell.execute_reply":"2022-01-10T15:25:27.903704Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.907398Z","iopub.execute_input":"2022-01-10T15:25:27.907864Z","iopub.status.idle":"2022-01-10T15:25:27.922895Z","shell.execute_reply.started":"2022-01-10T15:25:27.907827Z","shell.execute_reply":"2022-01-10T15:25:27.922274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.MGMT_value.value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.924951Z","iopub.execute_input":"2022-01-10T15:25:27.925615Z","iopub.status.idle":"2022-01-10T15:25:27.934539Z","shell.execute_reply.started":"2022-01-10T15:25:27.925579Z","shell.execute_reply":"2022-01-10T15:25:27.933737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_sample_path = '../input/rsna-miccai-brain-tumor-radiogenomic-classification/train'\nlen(os.listdir(train_sample_path)), df.BraTS21ID.nunique()","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.936550Z","iopub.execute_input":"2022-01-10T15:25:27.937148Z","iopub.status.idle":"2022-01-10T15:25:27.984209Z","shell.execute_reply.started":"2022-01-10T15:25:27.937112Z","shell.execute_reply":"2022-01-10T15:25:27.983466Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_dicom_xray(path):\n    data = pydicom.read_file(path).pixel_array\n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    return data","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.985181Z","iopub.execute_input":"2022-01-10T15:25:27.985532Z","iopub.status.idle":"2022-01-10T15:25:27.990210Z","shell.execute_reply.started":"2022-01-10T15:25:27.985496Z","shell.execute_reply":"2022-01-10T15:25:27.989487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# following function took from: https://www.kaggle.com/ihelon/brain-tumor-eda-with-animations-and-modeling?scriptVersionId=68202876&cellId=11\ndef visualize_sample(\n    brats21id, \n    mgmt_value,\n    slice_i,\n    types=(\"FLAIR\", \"T1w\", \"T1wCE\", \"T2w\")\n):\n    plt.figure(figsize=(16, 5))\n    patient_path = os.path.join(\n        train_sample_path, \n        str(brats21id).zfill(5),\n    )\n    for i, t in enumerate(types, 1):\n        t_paths = sorted(\n            glob.glob(os.path.join(patient_path, t, \"*\")), \n            key=lambda x: int(x[:-4].split(\"-\")[-1]),\n        )\n        data = read_dicom_xray(t_paths[int(len(t_paths) * slice_i)])\n        plt.subplot(1, 4, i)\n        plt.imshow(data, cmap=\"gray\")\n        plt.title(f\"{t}\", fontsize=16)\n        plt.axis(\"off\")\n\n    plt.suptitle(f\"MGMT_value: {mgmt_value}\", fontsize=16)\n    plt.show()\n    \n    \nfor i in random.sample(range(df.shape[0]), 2):\n    visualize_sample(df.iloc[i][\"BraTS21ID\"], df.iloc[i][\"MGMT_value\"], slice_i=0.5)","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:27.991540Z","iopub.execute_input":"2022-01-10T15:25:27.991978Z","iopub.status.idle":"2022-01-10T15:25:29.047643Z","shell.execute_reply.started":"2022-01-10T15:25:27.991885Z","shell.execute_reply":"2022-01-10T15:25:29.046986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Preprocessing\n\nI used a little bit from different Kaggle notebooks to create the training and validation generator, similar to how we did the assignments for CS 190. Creating these generators are probably the most complex part of this notebook, but essentially the goal here is to create a generator which provides 2D slices of 312 x 312 pixel data from each of the four sequences (T1 precontrast, T1 postcontrast, T2, and FLAIR). Here, I set the batch size to 3, so we might want to try out GroupNorm instead of BatchNorm in the DenseNet implementation because the batch size is very small. I also used some code from a notebook which randomly selects a 2D slice from the middle 5 layers of the 3D DICOM data, so that the 2D CNN can use the best 2D slice as input. This is what the fold_generator() function does which uses the scikit-learn StratifiedKFold to basically random sample a 2D slice from the middle 5 2D slices of the MRI data. The final data shape of an output from the train generator is (3, 312, 312, 4) corresponding to a batch size of 3, an image size of 312 x 312, and the 4 MRI sequences (T1 pre, T1 post, T2, and FLAIR). Also, the preoprocessing_image() and get_data_generator() functions perform data augmentation to basically remove some of the excess black pixels around the MRI imagery. There is some manual preprocessing done in the preproceessing_image() function, but most of it is handled by the keras Data Augmentation layers (RandomRotation, RandomTranslation). Similar thing is done for the validation generator. ","metadata":{}},{"cell_type":"code","source":"# Data Preprocessing DICOM into 2D Slices as Generator\nimport tensorflow as tf\nimport tensorflow_addons as tfa\nfrom tensorflow.keras.layers.experimental.preprocessing import RandomFlip,RandomRotation,RandomTranslation\n\n# Keras Data Augmentation\naugmentation_layers = tf.keras.Sequential(\n    [\n        RandomRotation(factor=0.01),\n        RandomTranslation(height_factor=0.0, width_factor=0.1),\n    ],\n    name='keras_augment_layers'\n)\n\n# More manual data augmentation\ndef preprocessing_image(img, augment=True):   \n    img = tf.cast(img, tf.float32) / 255.0\n\n    # only true for train set \n    if augment:\n        # augment each slices \n        # todo: integrate better technique \n        splitted_img = tf.split(img, input_depth, axis=-1)\n\n        augment_img = []\n        for each_img in splitted_img:\n            img = tf.repeat(each_img, repeats=3, axis=-1)\n            img = tf.image.random_flip_left_right(img)\n            img = tf.image.random_saturation(img, 0.9, 1.3)\n            img = tf.image.random_contrast(img, 0.8, 1.2)\n            img = tf.image.random_brightness(img, 0.2)\n            img, _, _ = tf.split(img, 3, axis=-1)\n            img = tfa.image.random_cutout(tf.expand_dims(img, 0),\n                                          mask_size=(20, 20), \n                                          constant_values=0)\n            augment_img.append(img)\n            \n        img = tf.concat(augment_img, axis=-1)\n    img = tf.reshape(img, [input_height, input_width, input_depth])\n    return img\n\ndef get_data_generator(data, is_train=False, shuffle=True, augment=False, repeat=True, batch_size=32):\n    if repeat: \n        data = data.repeat()\n    \n    if shuffle:\n        data = data.shuffle(batch_size * 10)\n        \n    data = data.map(lambda x, y: (preprocessing_image(x, augment), y), num_parallel_calls=AUTO)\n    data = data.batch(batch_size, drop_remainder=is_train)\n    \n    if shuffle:\n        data = data.map(lambda x, y: (augmentation_layers(x), y), num_parallel_calls=AUTO) \n    \n    data = data.prefetch(AUTO)\n    return data ","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:29.048905Z","iopub.execute_input":"2022-01-10T15:25:29.049283Z","iopub.status.idle":"2022-01-10T15:25:36.339696Z","shell.execute_reply.started":"2022-01-10T15:25:29.049246Z","shell.execute_reply":"2022-01-10T15:25:36.338969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# data loader \nclass BrainTumorGenerator(tf.keras.utils.Sequence):\n    def __init__(self, dicom_path, data, is_train=True):\n        self.is_train = is_train # to control training/validation/inference part         \n        self.data = data\n        self.dicom_path = dicom_path\n        self.label = self.data['MGMT_value']\n  \n    def __len__(self):\n        return self.data['BraTS21ID'].shape[0]\n    \n    def __getitem__(self, index):\n        patient_ids = f\"{self.dicom_path}/{str(self.data['BraTS21ID'][index]).zfill(5)}/\"\n   \n        channel = []\n        for t in (\"FLAIR\", \"T1w\", \"T1wCE\", \"T2w\"): \n            t_paths = sorted(\n                glob.glob(os.path.join(patient_ids, t, \"*\")), \n                key=lambda x: int(x[:-4].split(\"-\")[-1]),\n            )\n            \n            # pick 15 slices \n            K = 15\n            # computing strt, and end index \n            strt_idx = (len(t_paths) // 2) - (K // 2)\n            end_idx = (len(t_paths) // 2) + (K // 2)\n            # slicing extracting elements with 3 intervals \n            r = t_paths[strt_idx + 3: end_idx + 3: 3]\n    \n            # removing black borders \n            # and add multi-modal features maps / channel depth\n            threshold = 0\n            for i in r:\n                image = self.read_dicom_xray(i)\n                temp_image = image\n                \n                rows = np.where(np.max(temp_image, 0) > threshold)[0]\n                if rows.size:\n                    cols = np.where(np.max(temp_image, 1) > threshold)[0]\n                    image = image[cols[0]: cols[-1] + 1, rows[0]: rows[-1] + 1]\n                else:\n                    image = image[:1, :1]\n                \n                channel.append(cv2.resize(image, (input_height, input_width)))\n                break # remove it for r-times frames for each series\n                    \n        if self.is_train:\n            return np.array(channel).T, self.label.iloc[index,]\n        else:\n            return np.array(channel).T\n    \n    def read_dicom_xray(self, path):\n        data = pydicom.read_file(path).pixel_array\n        data = data - np.min(data)\n        data = data / np.max(data)\n        data = (data * 255).astype(np.uint8)\n        return data","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:36.343623Z","iopub.execute_input":"2022-01-10T15:25:36.345547Z","iopub.status.idle":"2022-01-10T15:25:36.364418Z","shell.execute_reply.started":"2022-01-10T15:25:36.345507Z","shell.execute_reply":"2022-01-10T15:25:36.363176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import StratifiedKFold\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\nfor index, (train_index, val_index) in enumerate(skf.split(X=df.index, \n                                                           y=df.MGMT_value)):\n    df.loc[val_index, 'fold'] = index\n    \nprint(df.groupby(['fold', df.MGMT_value]).size())","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:36.369244Z","iopub.execute_input":"2022-01-10T15:25:36.371747Z","iopub.status.idle":"2022-01-10T15:25:37.014235Z","shell.execute_reply.started":"2022-01-10T15:25:36.371705Z","shell.execute_reply":"2022-01-10T15:25:37.012595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# params \nAUTO = tf.data.AUTOTUNE\ninput_height = 128\ninput_width = 128\ninput_depth = 4\nbatch_size = 3\nfold = 0\n\ndef fold_generator(fold):\n    # for way one - data generator\n    train_labels = df[df.fold != fold].reset_index(drop=True)\n    val_labels = df[df.fold == fold].reset_index(drop=True)\n    \n    return (\n        BrainTumorGenerator(train_sample_path, train_labels),\n        BrainTumorGenerator(train_sample_path, val_labels)\n    )\n\n# first fold \ntrain_gen, val_gen = fold_generator(fold)","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:37.015648Z","iopub.execute_input":"2022-01-10T15:25:37.015917Z","iopub.status.idle":"2022-01-10T15:25:37.025631Z","shell.execute_reply.started":"2022-01-10T15:25:37.015881Z","shell.execute_reply":"2022-01-10T15:25:37.024945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = tf.data.Dataset.from_generator(\n    lambda: map(tuple, train_gen),\n    (tf.float32, tf.float32),\n    (\n        tf.TensorShape([input_height, input_width, input_depth]),\n        tf.TensorShape([]),\n    ),\n)\n\n# generate train sets \ntrain_generator = get_data_generator(train_data, is_train=True, repeat=False, shuffle=True, augment=True, batch_size=batch_size)","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:37.027085Z","iopub.execute_input":"2022-01-10T15:25:37.027335Z","iopub.status.idle":"2022-01-10T15:25:39.071888Z","shell.execute_reply.started":"2022-01-10T15:25:37.027299Z","shell.execute_reply":"2022-01-10T15:25:39.071169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train generator visualization \nx, y = next(iter(train_generator))\nprint(x.shape, y.shape)  \nplt.figure(figsize=(35, 15))\nfor i in range(input_depth):\n    plt.subplot(1, input_depth, i + 1)\n    plt.imshow(x[1 ,:, :, i], cmap=\"gray\")\n    plt.axis(\"off\")\n    plt.title(y[1].numpy())","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:39.075760Z","iopub.execute_input":"2022-01-10T15:25:39.076348Z","iopub.status.idle":"2022-01-10T15:25:47.865198Z","shell.execute_reply.started":"2022-01-10T15:25:39.076316Z","shell.execute_reply":"2022-01-10T15:25:47.864491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Validation data generator visualization\nval_data = tf.data.Dataset.from_generator(\n    lambda: map(tuple, val_gen),\n    (tf.float32, tf.float32),\n    (\n        tf.TensorShape([input_height, input_width, input_depth]),\n        tf.TensorShape([]),\n    ),\n)\n\n# generate validation sets \nvalid_generator = get_data_generator(val_data, is_train=True, \n                                     shuffle=False, repeat=False, augment=False, \n                                     batch_size=batch_size)\n\n# visualization \nx, y = next(iter(valid_generator))\nprint(x.shape, y.shape)  \nplt.figure(figsize=(35, 15))\nfor i in range(input_depth):\n    plt.subplot(1, input_depth, i + 1)\n    plt.imshow(x[0 ,:, :, i], cmap=\"gray\")\n    plt.axis(\"off\")\n    plt.title(y[0].numpy())","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:47.866437Z","iopub.execute_input":"2022-01-10T15:25:47.866805Z","iopub.status.idle":"2022-01-10T15:25:48.949208Z","shell.execute_reply.started":"2022-01-10T15:25:47.866770Z","shell.execute_reply":"2022-01-10T15:25:48.948526Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2D CNN DenseNet Implementation","metadata":{}},{"cell_type":"markdown","source":"I basically used the standard Keras DenseNet implementation shown on the documentation. I added a final Conv2D layer and a Sigmoid layer after the DenseNet so that we can get softmax output values. Even with this simple DenseNet implementation, we already have nearly 7 million trainable params, so we will definitely have to try condensing a U-Net ensemble model or try pretraining weights since we will have way too many parameters to train. Also, I did not set any pre-trained weights for this DenseNet implementation, but if we did we could probably greatly improve the model. I didn't add any pre-trained weights because this is our benchmark anyway, so its better to assume we use the simplest possible model we can. The other hyperparameters are the standard values (Adam optimizer, Learning Rate = 0.001, Loss=BinaryCrossEntropy). I also saved the model as a .h5 file like we did for CS 190, so if you guys want to use this pre-trained model baseline directly later on, we have that option. Also, I didn't train this model for too long, since there aren't many samples in the dataset anyway and I didn't want to overfit, so I just did 5 epochs. ","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras import Input, Model \nfrom tensorflow.keras.layers import Conv2D, GlobalAveragePooling2D, Dense\nfrom tensorflow.keras.applications import *\n\ninput_dim = (input_height, input_width, input_depth)\ninput_tensor = Input(input_dim, name='input2d')\nefnet = DenseNet121(weights=None, \n                       include_top = False, \n                       input_shape=(input_height, input_width, 3))\nmapping3feat = Conv2D(3, (3, 3), padding='same', use_bias=False)(input_tensor)\n\noutput = efnet(mapping3feat)\noutput = GlobalAveragePooling2D()(output)\noutput = Dense(1, activation='sigmoid')(output)\n\ntf.keras.backend.clear_session()\nmodel = Model(input_tensor, output)\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:48.952871Z","iopub.execute_input":"2022-01-10T15:25:48.953554Z","iopub.status.idle":"2022-01-10T15:25:51.684921Z","shell.execute_reply.started":"2022-01-10T15:25:48.953511Z","shell.execute_reply":"2022-01-10T15:25:51.684234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow import keras \nfrom tensorflow.keras.optimizers import Adam, SGD, RMSprop\nfrom tensorflow_addons.optimizers import RectifiedAdam, Lookahead\n\n# compiling \n\nmodel.compile(\n    loss=tf.keras.losses.BinaryCrossentropy(from_logits=False),\n    optimizer=Adam(learning_rate=1e-3),\n    metrics=[tf.keras.metrics.AUC(), \n             tf.keras.metrics.BinaryAccuracy(name='bacc')],\n)\n\n# define callbacks.\ncheckpoint_cb = keras.callbacks.ModelCheckpoint(\n    \"model.h5\", monitor='val_auc', \n    mode='max', save_best_only=True\n)\n\n\n# fitting the model \n#epochs = 5\n#model.fit(\n    #train_generator, \n    #epochs=epochs,\n    #validation_data=valid_generator, \n    #callbacks=[checkpoint_cb]\n#)\n","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:51.686316Z","iopub.execute_input":"2022-01-10T15:25:51.687185Z","iopub.status.idle":"2022-01-10T15:25:51.718479Z","shell.execute_reply.started":"2022-01-10T15:25:51.687146Z","shell.execute_reply":"2022-01-10T15:25:51.717812Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Our final training AUC is 0.5236 and our final validation AUC is 0.5280 which is around what the AUC is for a solution ranked \\#600 on the leaderboard (~55\\% percentile), so around the average solution. The training and validation AUCs are starting to diverge after 5 epochs, so this is probably the optimal training length before we start overfitting. I think this is a pretty good result for just a benchmark 2D CNN, so this looks promising for a complex U-Net Ensemble. ","metadata":{}},{"cell_type":"markdown","source":"# U-Net Implementation","metadata":{}},{"cell_type":"code","source":"from tensorflow import losses, optimizers\nfrom tensorflow.keras import Input, Model, models, layers\n# --- Define model\n\n# I will be implementing a 2D U-Net architecture with the following modifications:\n#     1) An Inception modification to the contracting / expanding backbone\n#     2) Modification of the skip connection to include additional convolution operations\n\n# --- Define lambda functions\nconv = lambda x, filters,kernel_size, strides : layers.Conv2D(\n    filters=filters, \n    kernel_size=kernel_size,\n    strides=strides, \n    padding='same')(x)\nnorm = lambda x : layers.BatchNormalization()(x)\nrelu = lambda x : layers.ReLU()(x)\npool = lambda x : layers.MaxPool2D(pool_size=(3, 3), strides=1, padding='same')(x)\nconv2 = lambda filters, x : relu(norm(conv(x, filters, kernel_size=(3,3),strides=(2, 2))))\n\n# --- Define 1x1, 3x3 and 5x5 convs\nconv1 = lambda filters, x : relu(norm(conv(x, filters, kernel_size=(1, 1),strides=1)))\nconv3 = lambda filters, x : relu(norm(conv(x, filters, kernel_size=(3, 3),strides=1)))\nconv5 = lambda filters, x : relu(norm(conv(x, filters, kernel_size=(5, 5),strides=1)))\nmpool = lambda x : relu(norm(pool(x)))\n\n# --- Define projection\nproj = lambda filters, x : layers.Conv2D(\n    filters=filters, \n    strides=1, \n    kernel_size=(1, 1),\n    padding='same')(x)\n\n# --- Define single transpose\ntran = lambda x, filters, kernel_size, strides : layers.Conv2DTranspose(\n    filters=filters, \n    kernel_size=kernel_size,\n    strides=strides,\n    padding='same')(x)\n\n# --- Define transpose block\ntran2 = lambda filters, x : relu(norm(tran(x, filters, kernel_size=(3,3), strides=(2, 2))))\n\n# --- Define concat function\nconcat = lambda a, b : layers.Concatenate()([a, b])\n\n# --- Define inception function\ndef inception(filters, prev_layer):\n    # --- Define four different paths\n    b1 = proj(filters, prev_layer)\n    p1 = conv1(filters, prev_layer)\n    p2 = conv3(filters, b1)\n    p3 = conv5(filters, b1)\n    p4 = proj(filters, mpool(prev_layer))\n    # --- Concatenate\n    return layers.Concatenate()([p1,p2,p3,p4])","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:51.719785Z","iopub.execute_input":"2022-01-10T15:25:51.720168Z","iopub.status.idle":"2022-01-10T15:25:51.734183Z","shell.execute_reply.started":"2022-01-10T15:25:51.720133Z","shell.execute_reply":"2022-01-10T15:25:51.733477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# --- Define contracting layers\nl1 = conv1(32, input_tensor)\nl2 = inception(16, conv2(32, l1))\nl3 = inception(32, conv2(64, l2))\nl4 = inception(64, conv2(128, l3))\n\n# --- Define expanding layers\n# I'm modifying the skip connection by performing a convolution operation on the \n# concat to introduce additional convolution operations in the skip connections \nl5 = tran2(128, l4)\nl6  = tran2(64, inception(64, conv3(128,concat(l3, l5))))\nl7 = tran2(32, inception(32, conv3(64, concat(l2, l6))))\n#l8 = tran2(8, inception(4, conv3(16, concat(l2,l8))))\nl8 = inception(4, l7)\n\n# --- Create logits\noutput = layers.Conv2D(filters=2, kernel_size=(3, 3),padding='same')(l8)\noutput = GlobalAveragePooling2D()(output)\noutput = Dense(1, activation='sigmoid')(output)\n\n# --- Create model\nmodel = Model(inputs=input_tensor, outputs=output)","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:51.735599Z","iopub.execute_input":"2022-01-10T15:25:51.735859Z","iopub.status.idle":"2022-01-10T15:25:52.579256Z","shell.execute_reply.started":"2022-01-10T15:25:51.735825Z","shell.execute_reply":"2022-01-10T15:25:52.578432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:25:52.580412Z","iopub.execute_input":"2022-01-10T15:25:52.580790Z","iopub.status.idle":"2022-01-10T15:25:52.662914Z","shell.execute_reply.started":"2022-01-10T15:25:52.580755Z","shell.execute_reply":"2022-01-10T15:25:52.662179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# --- Compile model\n\ncheckpoint_filepath = 'best_model.h5'\nmodel_checkpoint_callback = keras.callbacks.ModelCheckpoint(\n\"best_model.h5\",\nmonitor='val_auc',\nmode='max',\nsave_best_only=True)\n\nearlyStopping = keras.callbacks.EarlyStopping(monitor='val_loss', patience = 5)\n\nmodel.compile(\n    optimizer=optimizers.Adam(learning_rate=1e-3),\n    loss=tf.keras.losses.BinaryCrossentropy(from_logits=False),\n    metrics=[tf.keras.metrics.AUC(), \n             tf.keras.metrics.BinaryAccuracy(name='bacc')],\n)\n\nmodel.fit(\n    train_generator, \n    epochs=50,\n    validation_data=valid_generator, \n    callbacks=[model_checkpoint_callback, earlyStopping]\n)","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:32:29.014124Z","iopub.execute_input":"2022-01-10T15:32:29.014387Z","iopub.status.idle":"2022-01-10T15:34:35.009711Z","shell.execute_reply.started":"2022-01-10T15:32:29.014360Z","shell.execute_reply":"2022-01-10T15:34:35.008938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TYPES = [\"FLAIR\", \"T1w\", \"T2w\", \"T1wCE\"]\nWHITE_THRESHOLD = 10 # out of 255\nEXCLUDE = [109, 123, 709]\ntrain_df = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv\")\ntest_df = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/sample_submission.csv')\ntrain_df = train_df[~train_df.BraTS21ID.isin(EXCLUDE)]\ndef load_dicom(path, size = 224):\n    ''' \n    Reads a DICOM image, standardizes so that the pixel values are between 0 and 1, then rescales to 0 and 255\n    \n    Note super sure if this kind of scaling is appropriate, but everyone seems to do it. \n    '''\n    dicom = pydicom.read_file(path)\n    data = dicom.pixel_array\n    if np.max(data) != 0:\n        data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    return cv2.resize(data, (size, size))\n\ndef get_all_image_paths(brats21id, image_type, folder='train'): \n    '''\n    Returns an arry of all the images of a particular type for a particular patient ID\n    '''\n    assert(image_type in TYPES)\n    \n    patient_path = os.path.join(\n        \"../input/rsna-miccai-brain-tumor-radiogenomic-classification/%s/\" % folder, \n        str(brats21id).zfill(5),\n    )\n\n    paths = sorted(\n        glob.glob(os.path.join(patient_path, image_type, \"*\")), \n        key=lambda x: int(x[:-4].split(\"-\")[-1]),\n    )\n    \n    num_images = len(paths)\n    \n    start = int(num_images * 0.25)\n    end = int(num_images * 0.75)\n\n    interval = 3\n    \n    if num_images < 10: \n        interval = 1\n    \n    return np.array(paths[start:end:interval])\n\ndef get_all_images(brats21id, image_type, folder='train', size=225):\n    return [load_dicom(path, size) for path in get_all_image_paths(brats21id, image_type, folder)]\nIMAGE_SIZE = 128\n\ndef get_all_data_for_train(image_type):\n    global train_df\n    \n    X = []\n    y = []\n    train_ids = []\n\n    for i in tqdm(train_df.index):\n        x = train_df.loc[i]\n        images = get_all_images(int(x['BraTS21ID']), image_type, 'train', IMAGE_SIZE)\n        label = x['MGMT_value']\n\n        X += images\n        y += [label] * len(images)\n        train_ids += [int(x['BraTS21ID'])] * len(images)\n        assert(len(X) == len(y))\n    return np.array(X), np.array(y), np.array(train_ids)\n\ndef get_all_data_for_test(image_type):\n    global test_df\n    \n    X = []\n    test_ids = []\n\n    for i in tqdm(test_df.index):\n        x = test_df.loc[i]\n        images = get_all_images(int(x['BraTS21ID']), image_type, 'test', IMAGE_SIZE)\n        X += images\n        test_ids += [int(x['BraTS21ID'])] * len(images)\n\n    return np.array(X), np.array(test_ids)","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:30:40.658204Z","iopub.execute_input":"2022-01-10T15:30:40.658611Z","iopub.status.idle":"2022-01-10T15:30:40.706017Z","shell.execute_reply.started":"2022-01-10T15:30:40.658564Z","shell.execute_reply":"2022-01-10T15:30:40.705315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tqdm.notebook import tqdm\nX_test, testidt = get_all_data_for_test('T1wCE')\nfile_path = 'best_model.h5'\nmodel_best = tf.keras.models.load_model(filepath=file_path)\nsample = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/sample_submission.csv')\n\n#y_pred = model_best.predict(X_test)\n\n#pred = np.argmax(y_pred, axis=1)\n\n#result=pd.DataFrame(testidt)\n#result[1]=pred\n\n#result.columns=['BraTS21ID','MGMT_value']\n#result2 = result.groupby('BraTS21ID',as_index=False).mean()\n#result2['BraTS21ID'] = sample['BraTS21ID']\n# result2['MGMT_value'] = result2['MGMT_value'].apply(lambda x:round(x*10)/10)\n#result2.to_csv('submission.csv',index=False)\n#result2","metadata":{"execution":{"iopub.status.busy":"2022-01-10T15:32:14.297921Z","iopub.execute_input":"2022-01-10T15:32:14.298570Z","iopub.status.idle":"2022-01-10T15:32:20.529536Z","shell.execute_reply.started":"2022-01-10T15:32:14.298528Z","shell.execute_reply":"2022-01-10T15:32:20.528376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}