{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# imports\nimport os\nimport random\n\n# Data analysis and manipulation\nimport numpy as np\nimport pandas as pd\n\n# Data visualization\nfrom matplotlib import animation\nimport matplotlib.pyplot as plt\nfrom IPython import display\nimport seaborn as sns\nimport plotly\n\n# ML, DL & Modelling\n# from sklearn import \nimport tensorflow as tf","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:20:29.765696Z","iopub.execute_input":"2023-09-13T08:20:29.766094Z","iopub.status.idle":"2023-09-13T08:20:48.463612Z","shell.execute_reply.started":"2023-09-13T08:20:29.766046Z","shell.execute_reply":"2023-09-13T08:20:48.462487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **0. Loading observations from the dataset and normalizing to build X_train and y_train**","metadata":{}},{"cell_type":"markdown","source":"**0.1 Loading observations from the dataset**","metadata":{}},{"cell_type":"code","source":"%%time\n# Loading a fraction of the dataset\n# Starting with 2 observations\n\nBASE_DIR = '/kaggle/input/google-research-identify-contrails-reduce-global-warming/train'\nnumber_observation = 500\n\n# Building list of record_ids\nrecord_ids = os.listdir(BASE_DIR)\n\n# Randomly selecting 2 observations\nsample_record_ids = random.sample(record_ids, number_observation)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:20:48.466519Z","iopub.execute_input":"2023-09-13T08:20:48.467089Z","iopub.status.idle":"2023-09-13T08:20:48.654617Z","shell.execute_reply.started":"2023-09-13T08:20:48.467059Z","shell.execute_reply":"2023-09-13T08:20:48.65363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**0.2 Normalizing data** ","metadata":{}},{"cell_type":"code","source":"def normalize_range(data, bounds):\n    \"\"\"Maps data to the range [0, 1].\"\"\"\n    return (data - bounds[0]) / (bounds[1] - bounds[0])","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:20:48.656238Z","iopub.execute_input":"2023-09-13T08:20:48.656628Z","iopub.status.idle":"2023-09-13T08:20:48.662366Z","shell.execute_reply.started":"2023-09-13T08:20:48.656594Z","shell.execute_reply":"2023-09-13T08:20:48.660903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**0.3 Building X_train and y_train from loaded observations and scaling them**","metadata":{}},{"cell_type":"code","source":"%%time\n\n# Building the X_init and y_init array, only keeping observations with contrails \ntarget_suffix = 'human_pixel_masks.npy'\nband_choice = 'band_11.npy'\n\n#['band_11.npy','band_14.npy','band_15.npy']\n\nN_TIMES_BEFORE = 4\nrecord_array_list = []\ntarget_array_list = []\n\nfor sample_id in sample_record_ids:\n    target_path = os.path.join(BASE_DIR, sample_id, target_suffix)\n    target = np.load(open(target_path, 'rb'))\n#     print(target.shape) \n#     print(target.shape)\n    if target.sum() == 0:\n        continue \n    else:\n        record_band_path = os.path.join(BASE_DIR, sample_id, band_choice)\n        band = np.load(open(record_band_path, 'rb'))[:,:,N_TIMES_BEFORE]\n#     print(band.shape)\n        band = np.expand_dims(band, axis=-1)\n#     print(band.shape)\n        record_array_list.append(band)\n        target_array_list.append(target)\n\nX_init = np.stack(record_array_list, axis=0)\ny_init = np.stack(target_array_list, axis=0).astype(float)\ny_init_test = y_init[:,:,:,0]\n\nupper_bound = X_init.max()\nlower_bound = X_init.min()\nband_bounds = (lower_bound, upper_bound)\n\nX_init_scaled = normalize_range(X_init, band_bounds)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:20:48.665932Z","iopub.execute_input":"2023-09-13T08:20:48.66665Z","iopub.status.idle":"2023-09-13T08:21:04.987672Z","shell.execute_reply.started":"2023-09-13T08:20:48.666614Z","shell.execute_reply":"2023-09-13T08:21:04.986475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_init_scaled.shape","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:04.989258Z","iopub.execute_input":"2023-09-13T08:21:04.989889Z","iopub.status.idle":"2023-09-13T08:21:04.999042Z","shell.execute_reply.started":"2023-09-13T08:21:04.989851Z","shell.execute_reply":"2023-09-13T08:21:04.997686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_init.mean()","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.000786Z","iopub.execute_input":"2023-09-13T08:21:05.001586Z","iopub.status.idle":"2023-09-13T08:21:05.021394Z","shell.execute_reply.started":"2023-09-13T08:21:05.001549Z","shell.execute_reply":"2023-09-13T08:21:05.020368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Building a np.array with record ids\nsample_ids_array = np.array(sample_record_ids)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.02287Z","iopub.execute_input":"2023-09-13T08:21:05.023284Z","iopub.status.idle":"2023-09-13T08:21:05.028542Z","shell.execute_reply.started":"2023-09-13T08:21:05.023252Z","shell.execute_reply":"2023-09-13T08:21:05.027524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Checking all shapes\nprint(\"X_init shape is:\", X_init.shape)\nprint(\"y_init shape is:\", y_init.shape)\nprint(\"y_init_test shape is:\", y_init_test.shape)\nprint(\"sample_ids_array shape is:\", sample_ids_array.shape)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.03028Z","iopub.execute_input":"2023-09-13T08:21:05.030903Z","iopub.status.idle":"2023-09-13T08:21:05.042017Z","shell.execute_reply.started":"2023-09-13T08:21:05.030866Z","shell.execute_reply":"2023-09-13T08:21:05.040881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_test = X_init_scaled[5]\ny_init_image = y_init[5]","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.043789Z","iopub.execute_input":"2023-09-13T08:21:05.044213Z","iopub.status.idle":"2023-09-13T08:21:05.05861Z","shell.execute_reply.started":"2023-09-13T08:21:05.044172Z","shell.execute_reply":"2023-09-13T08:21:05.057604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plotting random image \n\nplt.imshow(image_test)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.065388Z","iopub.execute_input":"2023-09-13T08:21:05.065932Z","iopub.status.idle":"2023-09-13T08:21:05.506029Z","shell.execute_reply.started":"2023-09-13T08:21:05.065856Z","shell.execute_reply":"2023-09-13T08:21:05.505115Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plotting mask associated \n\nplt.imshow(y_init_image)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.507106Z","iopub.execute_input":"2023-09-13T08:21:05.507472Z","iopub.status.idle":"2023-09-13T08:21:05.799409Z","shell.execute_reply.started":"2023-09-13T08:21:05.507426Z","shell.execute_reply":"2023-09-13T08:21:05.798388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_init_image.sum()","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.801071Z","iopub.execute_input":"2023-09-13T08:21:05.801769Z","iopub.status.idle":"2023-09-13T08:21:05.809566Z","shell.execute_reply.started":"2023-09-13T08:21:05.801732Z","shell.execute_reply":"2023-09-13T08:21:05.808629Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **I. Building the dice metric for the model loss function**","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nimport numpy as np","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.811117Z","iopub.execute_input":"2023-09-13T08:21:05.812192Z","iopub.status.idle":"2023-09-13T08:21:05.818853Z","shell.execute_reply.started":"2023-09-13T08:21:05.81215Z","shell.execute_reply":"2023-09-13T08:21:05.817973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def proba_to_pixel(y):\n    return tf.where(y > 0.5, tf.ones_like(y),tf.zeros_like(y))\n\n# à ajouter après le predict pour pouvoir afficher le imshow","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.820343Z","iopub.execute_input":"2023-09-13T08:21:05.82069Z","iopub.status.idle":"2023-09-13T08:21:05.83466Z","shell.execute_reply.started":"2023-09-13T08:21:05.820646Z","shell.execute_reply":"2023-09-13T08:21:05.831598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#@tf.function\n\ndef dice_metric(y_true, y_pred):\n    #with tf.GradientTape() as tape:\n        #converting y_pred probas to pixels (between 0 and 1)\n        y_pred = proba_to_pixel(y_pred)\n        y_true = proba_to_pixel(y_true)\n\n        # Define epsilon to prevent division by zero\n        smooth = 1e-5 \n\n        # Calculate the sum of y_true and y_pred for each class\n        y_true_sum = tf.reduce_sum(y_true)\n        y_pred_sum = tf.reduce_sum(y_pred)\n\n        # Calculate the intersection and union of y_true and y_pred\n        intersection = tf.reduce_sum(y_true * y_pred)\n        union = y_true_sum + y_pred_sum\n\n        # Calculate the Dice coefficient for each class\n        dice = (2. * intersection + smooth) / (union + smooth)\n\n        return dice","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.836118Z","iopub.execute_input":"2023-09-13T08:21:05.836573Z","iopub.status.idle":"2023-09-13T08:21:05.84623Z","shell.execute_reply.started":"2023-09-13T08:21:05.836529Z","shell.execute_reply":"2023-09-13T08:21:05.845345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def dice_loss(y_true, y_pred):\n    #with tf.GradientTape() as tape:\n        #converting y_pred probas to pixels (between 0 and 1)\n        #y_pred = proba_to_pixel(y_pred)\n        #y_true = proba_to_pixel(y_true)\n\n        # Define epsilon to prevent division by zero\n        smooth = 1e-5 \n\n        # Calculate the sum of y_true and y_pred for each class\n        y_true_sum = tf.reduce_sum(y_true)\n        y_pred_sum = tf.reduce_sum(y_pred)\n\n        # Calculate the intersection and union of y_true and y_pred\n        intersection = tf.reduce_sum(y_true * y_pred)\n        union = y_true_sum + y_pred_sum\n\n        # Calculate the Dice coefficient for each class\n        dice = (2. * intersection + smooth) / (union + smooth)\n\n        return (-1) * dice","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.84819Z","iopub.execute_input":"2023-09-13T08:21:05.848546Z","iopub.status.idle":"2023-09-13T08:21:05.858519Z","shell.execute_reply.started":"2023-09-13T08:21:05.848514Z","shell.execute_reply":"2023-09-13T08:21:05.857632Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#do not use \n#def dice_coeff(y_true, y_pred):\n #   smooth = 100\n#  # Flatten\n# y_true_f = tf.cast(tf.reshape(y_true, [-1]),'float32')\n#y_pred_f = tf.cast(tf.reshape(y_pred > 0.5, [-1]),'float32')\n\n  #  intersection = tf.reduce_sum(tf.math.multiply(y_true_f,y_pred_f))\n  #  score = (2. * intersection + smooth) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + smooth)\n   # return (-1) * score","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.859628Z","iopub.execute_input":"2023-09-13T08:21:05.860132Z","iopub.status.idle":"2023-09-13T08:21:05.875088Z","shell.execute_reply.started":"2023-09-13T08:21:05.860099Z","shell.execute_reply":"2023-09-13T08:21:05.87398Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Defining the dice_closs as loss function used for the model \n# Generalized Dice coefficient potentially better? ","metadata":{"execution":{"iopub.status.busy":"2023-09-12T14:19:14.189237Z","iopub.execute_input":"2023-09-12T14:19:14.190287Z","iopub.status.idle":"2023-09-12T14:19:14.198677Z","shell.execute_reply.started":"2023-09-12T14:19:14.190242Z","shell.execute_reply":"2023-09-12T14:19:14.197384Z"}}},{"cell_type":"code","source":"# Testing the dice loss function \n\npredictions_test = np.array([0.3, 1.5])\ntrue_set = np.array([1.0, 1.0])\n\ndice_loss(true_set, predictions_test)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:05.876943Z","iopub.execute_input":"2023-09-13T08:21:05.877289Z","iopub.status.idle":"2023-09-13T08:21:12.124483Z","shell.execute_reply.started":"2023-09-13T08:21:05.877257Z","shell.execute_reply":"2023-09-13T08:21:12.123483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# II. Building a first simple CNN model ","metadata":{}},{"cell_type":"markdown","source":"Our first model architecture will have **2 building blocks**: \n* **Downsampling path / Decoder** = convolutional layers extracting features from the image while reducing it size\n* **Upsampling / Decoder** = expanding the size of the image using Transpose convolution to reach an output (the mask) with same size as input image","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.models import Sequential\nfrom tensorflow.keras import layers","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:12.126108Z","iopub.execute_input":"2023-09-13T08:21:12.126475Z","iopub.status.idle":"2023-09-13T08:21:12.132145Z","shell.execute_reply.started":"2023-09-13T08:21:12.126425Z","shell.execute_reply":"2023-09-13T08:21:12.131154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = Sequential()\n\n# Encoder \nmodel.add(layers.Conv2D(16, (3,3), input_shape=(256, 256, 3), padding='same', activation=\"relu\"))\nmodel.add(layers.MaxPool2D(pool_size=(2,2)))\n\nmodel.add(layers.Conv2D(32, (2,2), padding='same', activation=\"relu\"))\nmodel.add(layers.MaxPool2D(pool_size=(2,2)))\n\n# Decoder \nmodel.add(layers.Conv2DTranspose(32, (2,2), padding='same', activation=\"relu\", strides=(2,2)))\nmodel.add(layers.Conv2DTranspose(1, (2,2), padding='same', activation=\"sigmoid\", strides=(2,2)))\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:12.133612Z","iopub.execute_input":"2023-09-13T08:21:12.134356Z","iopub.status.idle":"2023-09-13T08:21:12.493701Z","shell.execute_reply.started":"2023-09-13T08:21:12.134323Z","shell.execute_reply":"2023-09-13T08:21:12.49289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\noptimizer = tf.keras.optimizers.Adam(\n    learning_rate=0.05,\n    beta_1=0.9,\n    beta_2=0.999,\n    epsilon=1e-07,\n    amsgrad=False,\n    weight_decay=None,\n    clipnorm=None,\n    clipvalue=None,\n    global_clipnorm=None,\n    use_ema=False,\n    ema_momentum=0.99,\n    ema_overwrite_frequency=None,\n    jit_compile=True,\n    name='Adam')\n\n# 2. Compile\nmodel.compile(optimizer=optimizer,\n                  loss=dice_loss,\n                  metrics=dice_metric)\n\n# 3. Fit \nfrom tensorflow.keras import callbacks\nes = callbacks.EarlyStopping(patience=30)\n\nhistory_base_model = model.fit(X_init_scaled, y_init,\n          batch_size=16, # Batch size -too small--> no generalization\n          epochs=10,    #            -too large--> slow computations\n          validation_split=0.3,\n          callbacks=[es],\n          verbose=1)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:22:08.143647Z","iopub.execute_input":"2023-09-13T08:22:08.14412Z","iopub.status.idle":"2023-09-13T08:22:08.430508Z","shell.execute_reply.started":"2023-09-13T08:22:08.14408Z","shell.execute_reply":"2023-09-13T08:22:08.429386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = model.predict(X_init)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:13.571208Z","iopub.execute_input":"2023-09-13T08:21:13.571608Z","iopub.status.idle":"2023-09-13T08:21:13.984835Z","shell.execute_reply.started":"2023-09-13T08:21:13.571555Z","shell.execute_reply":"2023-09-13T08:21:13.982225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred[5, :, :, 0].max()","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:13.986259Z","iopub.status.idle":"2023-09-13T08:21:13.987049Z","shell.execute_reply.started":"2023-09-13T08:21:13.986749Z","shell.execute_reply":"2023-09-13T08:21:13.986776Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_init[5, :, :, 0]","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:13.989156Z","iopub.status.idle":"2023-09-13T08:21:13.989697Z","shell.execute_reply.started":"2023-09-13T08:21:13.989451Z","shell.execute_reply":"2023-09-13T08:21:13.989476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred.shape","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:13.99159Z","iopub.status.idle":"2023-09-13T08:21:13.99207Z","shell.execute_reply.started":"2023-09-13T08:21:13.99183Z","shell.execute_reply":"2023-09-13T08:21:13.991853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(y_init[5, :, :, 0])","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:13.99396Z","iopub.status.idle":"2023-09-13T08:21:13.994446Z","shell.execute_reply.started":"2023-09-13T08:21:13.994189Z","shell.execute_reply":"2023-09-13T08:21:13.994212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(proba_to_pixel(y_pred[5, :, :, 0]))","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:13.997019Z","iopub.status.idle":"2023-09-13T08:21:13.998026Z","shell.execute_reply.started":"2023-09-13T08:21:13.997762Z","shell.execute_reply":"2023-09-13T08:21:13.997785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history_base_model.__dict__","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:13.999263Z","iopub.status.idle":"2023-09-13T08:21:14.000791Z","shell.execute_reply.started":"2023-09-13T08:21:14.000542Z","shell.execute_reply":"2023-09-13T08:21:14.000566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_history(history, title='', axs=None, exp_name=\"\"):\n    if axs is not None:\n        ax1, ax2 = axs\n    else:\n        f, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n    \n    if len(exp_name) > 0 and exp_name[0] != '_':\n        exp_name = '_' + exp_name\n    ax1.plot(history.history['loss'], label = 'train' + exp_name)\n    ax1.plot(history.history['val_loss'], label = 'val' + exp_name)\n    ax1.set_title('loss')\n    ax1.legend()\n\n    ax2.plot(history.history['dice_loss'], label='train dice_loss'  + exp_name)\n    ax2.plot(history.history['val_dice_loss'], label='val dice_loss'  + exp_name)\n    ax2.set_title('Dice')\n    ax2.legend()\n    return (ax1, ax2)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:14.002362Z","iopub.status.idle":"2023-09-13T08:21:14.002852Z","shell.execute_reply.started":"2023-09-13T08:21:14.002607Z","shell.execute_reply":"2023-09-13T08:21:14.002628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history_base_model)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:14.004789Z","iopub.status.idle":"2023-09-13T08:21:14.005258Z","shell.execute_reply.started":"2023-09-13T08:21:14.005023Z","shell.execute_reply":"2023-09-13T08:21:14.005046Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# III. Building an advanced Unet model","metadata":{}},{"cell_type":"code","source":"# 1. Building the Unet model \n\ndef build_model(input_layer, start_neurons):\n    \n    # Downsampling path / Decoder = convolutional layers extracting features from the image while \n    # reducing it size\n    conv1 = layers.Conv2D(start_neurons * 1, (3, 3), activation=\"relu\", padding=\"same\")(input_layer)\n    conv1 = layers.Conv2D(start_neurons * 1, (3, 3), activation=\"relu\", padding=\"same\")(conv1)\n    pool1 = layers.MaxPooling2D((2, 2))(conv1)\n    pool1 = layers.Dropout(0.25)(pool1)\n\n    conv2 = layers.Conv2D(start_neurons * 2, (3, 3), activation=\"relu\", padding=\"same\")(pool1)\n    conv2 = layers.Conv2D(start_neurons * 2, (3, 3), activation=\"relu\", padding=\"same\")(conv2)\n    pool2 = layers.MaxPooling2D((2, 2))(conv2)\n    pool2 = layers.Dropout(0.5)(pool2)\n\n    conv3 = layers.Conv2D(start_neurons * 4, (3, 3), activation=\"relu\", padding=\"same\")(pool2)\n    conv3 = layers.Conv2D(start_neurons * 4, (3, 3), activation=\"relu\", padding=\"same\")(conv3)\n    pool3 = layers.MaxPooling2D((2, 2))(conv3)\n    pool3 = layers.Dropout(0.5)(pool3)\n\n    conv4 = layers.Conv2D(start_neurons * 8, (3, 3), activation=\"relu\", padding=\"same\")(pool3)\n    conv4 = layers.Conv2D(start_neurons * 8, (3, 3), activation=\"relu\", padding=\"same\")(conv4)\n    pool4 = layers.MaxPooling2D((2, 2))(conv4)\n    pool4 = layers.Dropout(0.5)(pool4)\n\n    # Middle path / Bottleneck = CNN with large number of layers to extract the image's most important /\n    # complex features\n    convm = layers.Conv2D(start_neurons * 16, (3, 3), activation=\"relu\", padding=\"same\")(pool4)\n    convm = layers.Conv2D(start_neurons * 16, (3, 3), activation=\"relu\", padding=\"same\")(convm)\n    \n    # Upsampling / Decoder using Transpose convolution = expanding the size of the image to reach an output \n    # (the mask) with same size as input image \n    \n    # Skip connections: it helps the model learn both detailed information from the \n    # downsampling / decoder and high-level info from the upsampling / decoder \n    \n    # In practice, after the transposed convolution, the image is upsized from 28x28x1024 → 56x56x512\n    # this image is then concatenated with the corresponding image from the downsampling path \n    # and together makes an image of size 56x56x1024. \n    \n    # upsamppling \n    deconv4 = layers.Conv2DTranspose(start_neurons * 8, (3, 3), strides=(2, 2), padding=\"same\")(convm)\n    # skip-connection\n    uconv4 = layers.concatenate([deconv4, conv4])\n    uconv4 = layers.Dropout(0.5)(uconv4)\n    uconv4 = layers.Conv2D(start_neurons * 8, (3, 3), activation=\"relu\", padding=\"same\")(uconv4)\n    uconv4 = layers.Conv2D(start_neurons * 8, (3, 3), activation=\"relu\", padding=\"same\")(uconv4)\n\n    deconv3 = layers.Conv2DTranspose(start_neurons * 4, (3, 3), strides=(2, 2), padding=\"same\")(uconv4)\n    uconv3 = layers.concatenate([deconv3, conv3])\n    uconv3 = layers.Dropout(0.5)(uconv3)\n    uconv3 = layers.Conv2D(start_neurons * 4, (3, 3), activation=\"relu\", padding=\"same\")(uconv3)\n    uconv3 = layers.Conv2D(start_neurons * 4, (3, 3), activation=\"relu\", padding=\"same\")(uconv3)\n\n    deconv2 = layers.Conv2DTranspose(start_neurons * 2, (3, 3), strides=(2, 2), padding=\"same\")(uconv3)\n    uconv2 = layers.concatenate([deconv2, conv2])\n    uconv2 = layers.Dropout(0.5)(uconv2)\n    uconv2 = layers.Conv2D(start_neurons * 2, (3, 3), activation=\"relu\", padding=\"same\")(uconv2)\n    uconv2 = layers.Conv2D(start_neurons * 2, (3, 3), activation=\"relu\", padding=\"same\")(uconv2)\n\n    deconv1 = layers.Conv2DTranspose(start_neurons * 1, (3, 3), strides=(2, 2), padding=\"same\")(uconv2)\n    uconv1 = layers.concatenate([deconv1, conv1])\n    uconv1 = layers.Dropout(0.5)(uconv1)\n    uconv1 = layers.Conv2D(start_neurons * 1, (3, 3), activation=\"relu\", padding=\"same\")(uconv1)\n    uconv1 = layers.Conv2D(start_neurons * 1, (3, 3), activation=\"relu\", padding=\"same\")(uconv1)\n    \n    output_layer = layers.Conv2D(1, (1,1), padding=\"same\", activation=\"sigmoid\")(uconv1)\n    \n    return output_layer","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:14.013787Z","iopub.status.idle":"2023-09-13T08:21:14.014211Z","shell.execute_reply.started":"2023-09-13T08:21:14.01397Z","shell.execute_reply":"2023-09-13T08:21:14.013993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Defining img_size and number of neurons for the CNN layers \n\nimg_size_target = 256\nnumber_channels_target = 1\nstart_neurons = 16\n\ninput_layer = layers.Input((img_size_target, img_size_target, number_channels_target))\noutput_layer = build_model(input_layer, start_neurons)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:14.015938Z","iopub.status.idle":"2023-09-13T08:21:14.016734Z","shell.execute_reply.started":"2023-09-13T08:21:14.016485Z","shell.execute_reply":"2023-09-13T08:21:14.01651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# unet model with Keras Functional API\nunet_model = tf.keras.Model(input_layer, output_layer, name=\"U-Net\")","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:14.018145Z","iopub.status.idle":"2023-09-13T08:21:14.018962Z","shell.execute_reply.started":"2023-09-13T08:21:14.018692Z","shell.execute_reply":"2023-09-13T08:21:14.018716Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time \n# 2. Compile\nunet_model.compile(optimizer='adam',\n                  loss=dice_loss,\n                  metrics=\"accuracy\")\n\n# 3. Fit \nfrom tensorflow.keras import callbacks\nes = callbacks.EarlyStopping(patience=30)\n\nhistory_unet_model = unet_model.fit(X_init, y_init,\n          batch_size=8, # Batch size -too small--> no generalization\n          epochs=10,    #            -too large--> slow computations\n          validation_split=0.3,\n          callbacks=[es],\n          verbose=1)","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:14.020378Z","iopub.status.idle":"2023-09-13T08:21:14.021188Z","shell.execute_reply.started":"2023-09-13T08:21:14.020937Z","shell.execute_reply":"2023-09-13T08:21:14.02096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history_unet_model.__dict__","metadata":{"execution":{"iopub.status.busy":"2023-09-13T08:21:14.022619Z","iopub.status.idle":"2023-09-13T08:21:14.023413Z","shell.execute_reply.started":"2023-09-13T08:21:14.023163Z","shell.execute_reply":"2023-09-13T08:21:14.023187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### plot_history(history_unet_model)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-09-12T15:40:17.871994Z","iopub.status.idle":"2023-09-12T15:40:17.872937Z","shell.execute_reply.started":"2023-09-12T15:40:17.87267Z","shell.execute_reply":"2023-09-12T15:40:17.872693Z"}}}],"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"}}