{"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":"# RSNA MICCAI Brain Tumor Radiogenomic Classification\n\n[<img src=\"https://storage.googleapis.com/kaggle-competitions/kaggle/29653/logos/header.png?t=2021-07-07-17-26-56\">](http://google.com.au/)\n\nIn this notebook I will try to classify the images using differente EfficientNet models. To deal with 3D data I will try several method:\n* Aggregating data along the first axis\n* Start with a 1x1 convolution to reduce dimensionality\n* The 3D version of EfficientNet\n* One model proposed [here](http://www.ajnr.org/content/42/5/845)\n\n## Importing necessary libraries","metadata":{}},{"cell_type":"code","source":"# Basic libraries\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# Neural network libraries\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom keras import layers\nfrom keras.callbacks import EarlyStopping\n\n# Reading images and creating video libraries\nimport cv2\nfrom IPython.display import HTML\nfrom base64 import b64encode\nimport matplotlib.animation as animation\nimport os\n\nimport SimpleITK as sitk","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-07-15T10:43:02.79723Z","iopub.execute_input":"2021-07-15T10:43:02.797592Z","iopub.status.idle":"2021-07-15T10:43:02.804101Z","shell.execute_reply.started":"2021-07-15T10:43:02.797556Z","shell.execute_reply":"2021-07-15T10:43:02.803303Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Utility functions to visualize the images\n\nI display a video with a collection of the images of each folder.","metadata":{}},{"cell_type":"code","source":"def play(filename):\n    html = ''\n    video = open(filename,'rb').read()\n    src = 'data:video/mp4;base64,' + b64encode(video).decode()\n    html += '<video width=500 controls autoplay loop><source src=\"%s\" type=\"video/mp4\"></video>' % src \n    return HTML(html)\n\ndef create_video(imgs, output='/kaggle/working/predicted.mp4', duration=30, subplot=True, \n                frame_delay=200):\n    fig, ax = plt.subplots(figsize=(15, 10))\n    ims = []\n    if not subplot:\n        shape = imgs.shape[0]\n        for i in range(duration):\n            im = ax.imshow(imgs[i % shape], animated=True)\n            ims.append([im])\n        plt.close(fig)\n    else:\n        shapes = [imgs[views[0]].shape[0], imgs[views[1]].shape[0], \n                  imgs[views[2]].shape[0], imgs[views[3]].shape[0]]\n        fig, ax = plt.subplots(2,2, figsize=(10,10))\n        for k in range(duration):\n            im_ = []\n            for i in range(2):\n                for j in range(2):\n                    im = ax[i,j].imshow(imgs[views[2*i+j]][k % shapes[2*i+j]], animated=True)\n                    im_.append(im)\n                    ax[i,j].set_title(views[2*i+j])\n                    plt.close()\n            ims.append(im_)\n\n    ani = animation.ArtistAnimation(fig, ims, interval=frame_delay, blit=True, repeat_delay=1000)\n\n    ani.save(output)","metadata":{"execution":{"iopub.status.busy":"2021-07-15T10:43:02.805577Z","iopub.execute_input":"2021-07-15T10:43:02.806017Z","iopub.status.idle":"2021-07-15T10:43:02.819328Z","shell.execute_reply.started":"2021-07-15T10:43:02.805981Z","shell.execute_reply":"2021-07-15T10:43:02.818464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Labels","metadata":{}},{"cell_type":"code","source":"target = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')\npreds = pd.read_csv('../input/rsna-miccai-brain-tumor-radiogenomic-classification/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2021-07-15T10:43:02.821958Z","iopub.execute_input":"2021-07-15T10:43:02.822219Z","iopub.status.idle":"2021-07-15T10:43:02.842613Z","shell.execute_reply.started":"2021-07-15T10:43:02.822194Z","shell.execute_reply":"2021-07-15T10:43:02.841801Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Read images utility function","metadata":{}},{"cell_type":"code","source":"# specify your image path\nviews = ['FLAIR', 'T1w', 'T1wCE', 'T2w']\ndef load_imgs(idx, ignore_zeros=True, train=True):\n    imgs = {}\n    for view in views:\n        save_ds = []\n        if train:\n            dir_path = os.walk(os.path.join(\n            '../input/rsna-miccai-png/train/', idx, view\n        ))\n        else:\n            dir_path = os.walk(os.path.join(\n            '../input/rsna-miccai-png/test/', idx, view\n        ))\n        for path, subdirs, files in dir_path:\n            for name in files:\n                image_path = os.path.join(path, name) \n                ds = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n                save_ds.append(np.array(ds))\n        if len(save_ds) == 0:\n            save_ds = np.zeros((1,256,256))\n        imgs[view] = np.array(save_ds)\n    return imgs","metadata":{"execution":{"iopub.status.busy":"2021-07-15T10:43:02.843786Z","iopub.execute_input":"2021-07-15T10:43:02.844122Z","iopub.status.idle":"2021-07-15T10:43:02.852243Z","shell.execute_reply.started":"2021-07-15T10:43:02.844087Z","shell.execute_reply":"2021-07-15T10:43:02.851255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Here we try loading 32 images to see how much it takes. This will be the base to set the batch size later on so that each iteration is less expensive in time.","metadata":{}},{"cell_type":"code","source":"%%time\nfor i in range(32):\n    idx = str(target.BraTS21ID[i]).zfill(5)\n    imgs = load_imgs(idx)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Also, there are some folders without images. For those we simply define a zero-valued image so that the models work fine.","metadata":{}},{"cell_type":"code","source":"# Pathological one\nidx = str(109).zfill(5)\nimgs = load_imgs(idx)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Example of Image Visualization","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(2,2, figsize=(10,10))\nfor i in range(2):\n    for j in range(2):\n        m = ax[i,j].imshow(imgs[views[2*i+j]].mean(axis=0))\n        ax[i,j].set_title(views[2*i+j])\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Example of Video Visualization","metadata":{}},{"cell_type":"code","source":"create_video(imgs, duration=60, subplot=True, frame_delay=300)\nplay('predicted.mp4')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## DataGenerator\n\nSince the data is massive, and it is a good practice to use them, I have created the data loaders for the models. The only thing to highlight is that we use N4BiasFieldCorrectionImageFilter to correct the bias of the images as shown in the paper I mentioned at the beginning.","metadata":{}},{"cell_type":"code","source":"class DataGenerator(keras.utils.Sequence):\n    'Generates data for Keras'\n    def __init__(self, list_IDs, labels=None, batch_size=256, dim=(512,512), n_channels=4,\n                 n_classes=2, shuffle=True, is_train=True):\n        'Initialization'\n        self.dim = dim\n        self.batch_size = batch_size\n        self.labels = labels\n        self.is_train = (labels is not None)\n        self.list_IDs = list_IDs\n        self.n_channels = n_channels\n        self.n_classes = n_classes\n        self.shuffle = shuffle\n        self.on_epoch_end()\n\n    def __len__(self):\n        'Denotes the number of batches per epoch'\n        return int(np.floor(len(self.list_IDs) / self.batch_size))\n\n    def __getitem__(self, index):\n        'Generate one batch of data'\n        # Generate indexes of the batch\n        list_IDs_temp = self.list_IDs[index*self.batch_size:(index+1)*self.batch_size]\n\n        X = self.__data_generation(list_IDs_temp)\n        # Generate data\n        if self.is_train:\n            y = self.labels[index*self.batch_size:(index+1)*self.batch_size]\n            return np.array(X), np.array(y)\n        else:\n            return np.array(X)\n\n    def on_epoch_end(self):\n        'Updates indexes after each epoch'\n        self.indexes = np.arange(len(self.list_IDs))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n\n    def __data_generation(self, list_IDs_temp):\n        'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)\n        # Initialization\n        X = np.empty((self.batch_size, *self.dim, self.n_channels))\n\n        # Generate data\n        for i, ID in enumerate(list_IDs_temp):\n            # Store sample\n            idx = str(ID).zfill(5)\n            imgs = load_imgs(idx, ignore_zeros=False, train=self.is_train)\n            new_imgs = []\n            for ii in range(2):\n                for jj in range(2):\n                    img_ = imgs[views[2*ii+jj]].mean(axis=0)\n                    img_ = cv2.resize(img_, dsize=self.dim, interpolation=cv2.INTER_LINEAR)\n                    img_ = np.array(img_, dtype='float32') \n                    \n                    # Removing radiofrequency inhomogeneity using N4 Bias Field Correction \n                    inputImage = sitk.GetImageFromArray(img_)\n                    maskImage = sitk.GetImageFromArray((img_ > 0.1) * 1)\n                    inputImage = sitk.Cast(inputImage, sitk.sitkFloat32)\n                    maskImage = sitk.Cast(maskImage, sitk.sitkUInt8)\n                    corrector = sitk.N4BiasFieldCorrectionImageFilter()\n                    numberFittingLevels = 4\n                    maxIter = 100\n                    if maxIter is not None:\n                        corrector.SetMaximumNumberOfIterations([maxIter]\n                                                               * numberFittingLevels)\n                    corrected_image = corrector.Execute(inputImage, maskImage)\n                    img_ = sitk.GetArrayFromImage(corrected_image)\n                    new_imgs.append(img_)\n            new_imgs = np.array(new_imgs).transpose(1,2,0)\n            X[i,] = new_imgs\n        \n        return X","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Usual train-validation split","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_val, y_train, y_val = train_test_split(target.BraTS21ID, target.MGMT_value,\n                                                 test_size=0.2, random_state=0,\n                                                 stratify=target.MGMT_value)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dim = (256,256)\ntrain_dataset = DataGenerator(X_train, y_train, batch_size=8, dim=dim)\nval_dataset = DataGenerator(X_val, y_val, batch_size=8, dim=dim)\ntest_dataset = DataGenerator(preds.BraTS21ID, batch_size=8, dim=dim)","metadata":{"execution":{"iopub.status.busy":"2021-07-15T10:44:50.684071Z","iopub.execute_input":"2021-07-15T10:44:50.684488Z","iopub.status.idle":"2021-07-15T10:44:50.694343Z","shell.execute_reply.started":"2021-07-15T10:44:50.684456Z","shell.execute_reply":"2021-07-15T10:44:50.693477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### EfficientNet","metadata":{}},{"cell_type":"code","source":"!pip install efficientnet","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model #1\n\nWe use a convolutional layer to change the number of channels to 3 as it is needed by the EfficientNet model. We use early stopping but each iteration takes so long that until now I haven't managed to make it converge. Apart from that, the model is saved at each epoch. For this approach, no more than 0.55 in AUC was achieved.","metadata":{}},{"cell_type":"code","source":"import efficientnet.keras as efn\n\nwith tf.device('/gpu:0'):\n    model = keras.Sequential([\n        layers.Conv2D(3, kernel_size=1, input_shape=(*dim, 4), padding='same'),\n        efn.EfficientNetB0(include_top=False, pooling='avg'),\n        layers.Dense(1, activation='sigmoid')\n    ])\n    \n    earlyStopping = EarlyStopping(patience=2, min_delta=0.001, verbose=1)\n    \n    checkpoint_path = \"training_/cp.ckpt\"\n    checkpoint_dir = os.path.dirname(checkpoint_path)\n    #model.load_weights(checkpoint_path)\n\n    # Create a callback that saves the model's weights\n    cp_callback = keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n                                                 save_weights_only=True,\n                                                 verbose=1)\n    \n    model.compile(\n        optimizer='adam', \n        loss='binary_crossentropy',\n        metrics=[keras.metrics.AUC()]\n        )\n    \n    #history = model.fit(train_dataset, validation_data=val_dataset,\n                                 #epochs=10, callbacks=[earlyStopping, cp_callback])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.applications.resnet import ResNet50\n\nwith tf.device('/gpu:0'):\n    model = keras.Sequential([\n        layers.Conv2D(3, kernel_size=1, input_shape=(*dim, 4), padding='same'),\n        ResNet50(include_top=False, pooling='avg'),\n        layers.Dense(1, activation='sigmoid')\n    ])\n    \n    earlyStopping = EarlyStopping(patience=2, min_delta=0.001, verbose=1)\n    \n    checkpoint_path = \"training_resnet/cp.ckpt\"\n    checkpoint_dir = os.path.dirname(checkpoint_path)\n    #model.load_weights(checkpoint_path)\n\n    # Create a callback that saves the model's weights\n    cp_callback = keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n                                                 save_weights_only=True,\n                                                 verbose=1)\n    \n    model.compile(\n        optimizer='adam', \n        loss='binary_crossentropy',\n        metrics=[keras.metrics.AUC()]\n        )\n    \n    #history = model.fit(train_dataset, validation_data=val_dataset,\n                                 #epochs=10, callbacks=[earlyStopping, cp_callback])","metadata":{"execution":{"iopub.status.busy":"2021-07-15T10:46:42.516808Z","iopub.execute_input":"2021-07-15T10:46:42.517136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## DataGenerator3D\n\nIn this data generator we don't apply the mean to reduce dimensionality and we normalize the data to be zero-mean and unit-variance.","metadata":{}},{"cell_type":"code","source":"from sklearn.preprocessing import StandardScaler\n\nclass DataGenerator3D(keras.utils.Sequence):\n    'Generates data for Keras'\n    def __init__(self, list_IDs, labels=None, batch_size=256, dim=(512,512,512), n_channels=4,\n                 n_classes=2, shuffle=True, is_train=True):\n        'Initialization'\n        self.dim = dim\n        self.batch_size = batch_size\n        self.labels = labels\n        self.is_train = (labels is not None)\n        self.list_IDs = list_IDs\n        self.n_channels = n_channels\n        self.n_classes = n_classes\n        self.shuffle = shuffle\n        self.on_epoch_end()\n\n    def __len__(self):\n        'Denotes the number of batches per epoch'\n        return int(np.floor(len(self.list_IDs) / self.batch_size))\n\n    def __getitem__(self, index):\n        'Generate one batch of data'\n        # Generate indexes of the batch\n        list_IDs_temp = self.list_IDs[index*self.batch_size:(index+1)*self.batch_size]\n\n        X = self.__data_generation(list_IDs_temp)\n        # Generate data\n        if self.is_train:\n            y = self.labels[index*self.batch_size:(index+1)*self.batch_size]\n            return np.array(X), np.array(y)\n        else:\n            return np.array(X)\n\n    def on_epoch_end(self):\n        'Updates indexes after each epoch'\n        self.indexes = np.arange(len(self.list_IDs))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n\n    def __data_generation(self, list_IDs_temp):\n        'Generates data containing batch_size samples' # X : (n_samples, *dim, n_channels)\n        # Initialization\n        X = np.empty((self.batch_size, *self.dim, self.n_channels))\n\n        # Generate data\n        for i, ID in enumerate(list_IDs_temp):\n            # Store sample\n            idx = str(ID).zfill(5)\n            imgs = load_imgs(idx, ignore_zeros=False, train=self.is_train)\n            new_imgs = []\n            for ii in range(2):\n                for jj in range(2):\n                    img_ = imgs[views[2*ii+jj]]\n                    img_ = np.array([cv2.resize(img_[i], dsize=(self.dim[1],self.dim[0]), interpolation=cv2.INTER_LINEAR) for i in range(img_.shape[0])])\n                    img_ = np.array([cv2.resize(img_.transpose(1,2,0)[i], dsize=(self.dim[2],self.dim[1]), interpolation=cv2.INTER_LINEAR) for i in range(self.dim[0])])\n                    \n                    # Removing radiofrequency inhomogeneity using N4 Bias Field Correction \n                    for p in range(len(img_)):\n                        inputImage = sitk.GetImageFromArray(img_[p])\n                        maskImage = sitk.GetImageFromArray((img_[p] >0.1) * 1)\n                        inputImage = sitk.Cast(inputImage, sitk.sitkFloat32)\n                        maskImage = sitk.Cast(maskImage, sitk.sitkUInt8)\n                        corrector = sitk.N4BiasFieldCorrectionImageFilter()\n                        numberFittingLevels = 4\n                        maxIter = 100\n                        if maxIter is not None:\n                            corrector.SetMaximumNumberOfIterations([maxIter]\n                                                                   * numberFittingLevels)\n                        corrected_image = corrector.Execute(inputImage, maskImage)\n                        img_[p] = sitk.GetArrayFromImage(corrected_image)\n                        \n                    # Normalization\n                    sc = StandardScaler()\n                    img_ = np.array([sc.fit_transform(img_[i]) for i in range(img_.shape[0])])\n\n                    new_imgs.append(img_)\n            new_imgs = np.concatenate(new_imgs).transpose(1,2,0).reshape((*self.dim,-1))\n            X[i,] = new_imgs\n        \n        return X","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Again train-validation split","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_val, y_train, y_val = train_test_split(target.BraTS21ID, target.MGMT_value,\n                                                 test_size=0.2, random_state=0,\n                                                 stratify=target.MGMT_value)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = DataGenerator3D(X_train, y_train, batch_size=4, dim=(64,64,16))\nval_dataset = DataGenerator3D(X_val, y_val, batch_size=4, dim=(64,64,16))\ntest_dataset = DataGenerator3D(preds.BraTS21ID, batch_size=4, dim=(64,64,16))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model #2\n\nInstead of aggregating by one axis, apply a 2D convolutional layer to infer that aggregation and use EfficientNet as before.","metadata":{}},{"cell_type":"code","source":"with tf.device('/gpu:0'):\n    model = keras.Sequential([\n        layers.InputLayer(input_shape=(128,128,128,4)),\n        layers.Reshape((128,128,-1)),\n        layers.Conv2D(3, kernel_size=1, padding='same'),\n        efn.EfficientNetB0(include_top=False, pooling='avg'),\n        layers.Dense(32, activation='relu'),\n        layers.Dense(1, activation='sigmoid')\n    ])\n    \n    earlyStopping = EarlyStopping(patience=2, min_delta=0.001, verbose=1)\n    \n    checkpoint_path = \"training_0/cp.ckpt\"\n    checkpoint_dir = os.path.dirname(checkpoint_path)\n    #model.load_weights(checkpoint_path)\n\n    # Create a callback that saves the model's weights\n    cp_callback = keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n                                                 save_weights_only=True,\n                                                 verbose=1)\n    \n    model.compile(\n        optimizer='adam', \n        loss='binary_crossentropy',\n        metrics=[keras.metrics.AUC()]\n        )\n    \n    #history = model.fit(train_dataset, validation_data=val_dataset,\n                                 #epochs=10, callbacks=[earlyStopping, cp_callback])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install efficientnet_3D","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model #3\n\nUse the 3D version of EfficientNet, no other operation used.","metadata":{}},{"cell_type":"code","source":"import efficientnet_3D.tfkeras as efn3d\n\nwith tf.device('/gpu:0'):\n    model = keras.Sequential([\n        layers.InputLayer(input_shape=(64,64,16,4)),\n        layers.Conv3D(3, kernel_size=1, padding='same'),\n        efn3d.EfficientNetB0(include_top=False, input_shape=(64,64,16,3), pooling='avg'),\n        layers.Dense(64, activation='relu'),\n        layers.Dense(1, activation='sigmoid')\n    ])\n    \n    earlyStopping = EarlyStopping(patience=2, min_delta=0.001, verbose=1)\n    \n    checkpoint_path = \"training_1/cp.ckpt\"\n    checkpoint_dir = os.path.dirname(checkpoint_path)\n\n    # Create a callback that saves the model's weights\n    cp_callback = keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n                                                 save_weights_only=True,\n                                                 verbose=1)\n\n    model.compile(\n        optimizer='adam', \n        loss='binary_crossentropy',\n        metrics=[keras.metrics.AUC()]\n        )\n    \n    #history = model.fit(train_dataset, validation_data=val_dataset,\n                                 #epochs=10, callbacks=[earlyStopping, cp_callback])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Model #4\n\nThis is a version similar to that presented in the paper.","metadata":{}},{"cell_type":"code","source":"with tf.device('/gpu:0'):\n    def blockTD(inp):\n        x = layers.BatchNormalization()(inp)\n        x = layers.Activation('relu')(x)\n        x = layers.Conv3D(16, kernel_size=5, padding='same')(x)\n        x = layers.Dropout(0.2)(x)\n        out = layers.MaxPooling3D(2)(x)\n        return out\n    \n    def blockTU(inp):\n        x = layers.BatchNormalization()(inp)\n        x = layers.Activation('relu')(x)\n        x = layers.Conv3DTranspose(16, kernel_size=5, strides=2, padding='same')(x)\n        out = layers.Dropout(0.2)(x)\n        return out\n    \n    def blockDense_(inp):\n        x = layers.BatchNormalization()(inp)\n        x = layers.Activation('relu')(x)\n        x = layers.Conv3D(16, kernel_size=5, padding='same')(x)\n        out = layers.Dropout(0.2)(x)\n        return out\n    \n    def blockDense(inp):\n        y = blockDense_(inp)\n        x = layers.Concatenate()([inp, y])\n        out = y\n        for _ in range(3):\n            y = blockDense_(x)\n            out = layers.Concatenate()([out, y])\n            x = layers.Concatenate()([x, y])\n        out = layers.Concatenate()([out, x])\n        y = blockDense_(x)\n        out = layers.Concatenate()([out, y])\n        return out\n        \n    def build_model():\n        inp = keras.Input(shape=(64,64,16,4))\n        y = blockDense(inp)\n        x = layers.Concatenate()([inp, y])\n        x1 = tf.identity(x)\n        \n        x = blockTD(x)\n        y = blockDense(x)\n        x = layers.Concatenate()([x, y])\n        x0 = tf.identity(x)\n        \n        x = blockTD(x)\n        y = blockDense(x)\n        x = layers.Concatenate()([x, y])\n        \n        y = blockTD(x)\n        y = blockDense(y)\n        y = blockTU(y)\n        x = layers.Concatenate()([x, y])\n        \n        y = blockTU(x)\n        y = blockDense(y)\n        x = layers.Concatenate()([x0, y])\n        \n        y = blockTU(x)\n        y = blockDense(y)\n        x = layers.Concatenate()([x1, y])\n        \n        y = blockDense(x)\n        y = layers.GlobalMaxPooling3D()(y)\n        y = layers.Dense(32, activation='relu')(y)\n        out = layers.Dense(1, activation='sigmoid')(y)\n        return keras.Model(inputs = inp, outputs = out)\n    \n    model = build_model()\n    \n    earlyStopping = EarlyStopping(patience=2, min_delta=0.001, verbose=1)\n    \n    checkpoint_path = \"training_2/cp.ckpt\"\n    checkpoint_dir = os.path.dirname(checkpoint_path)\n    #model.load_weights(checkpoint_path)\n\n    # Create a callback that saves the model's weights\n    cp_callback = keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n                                                 save_weights_only=True,\n                                                 verbose=1)\n    \n    model.compile(\n        optimizer=keras.optimizers.Adam(lr=1e-4), \n        loss='binary_crossentropy',\n        metrics=[keras.metrics.AUC()]\n        )\n    \n    #history = model.fit(train_dataset, validation_data=val_dataset,\n                                 #epochs=10, callbacks=[earlyStopping, cp_callback])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with tf.device('/gpu:0'):\n    model = build_model()\n    \n    checkpoint_path = \"training_2/cp.ckpt\"\n    checkpoint_dir = os.path.dirname(checkpoint_path)\n    #model.load_weights(checkpoint_path)\n    \n    model.compile(\n        optimizer='adam', \n        loss='binary_crossentropy',\n        metrics=[keras.metrics.AUC()]\n        )\n    \n    #preds = model.predict(test_dataset)","metadata":{},"execution_count":null,"outputs":[]}]}