{"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":"# Import","metadata":{}},{"cell_type":"code","source":"from PIL import Image\nimport numpy as np\nimport os\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nfrom tensorflow import keras\nprint(\"tensorflow\" + tf.__version__)\nimport tensorflow.keras.layers as tfl\nfrom keras.utils import load_img, img_to_array\nfrom tensorflow.keras.layers.experimental.preprocessing import RandomFlip, RandomRotation, RandomContrast\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nimport shutil\nimport zipfile\nfrom tensorflow.keras.layers import Input\nfrom tensorflow.keras.layers import Conv2D\nfrom tensorflow.keras.layers import MaxPooling2D\nfrom tensorflow.keras.layers import Dropout \nfrom tensorflow.keras.layers import Conv2DTranspose\nfrom tensorflow.keras.layers import concatenate\nfrom tensorflow.keras import backend as K","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-10-04T15:06:45.739107Z","iopub.execute_input":"2023-10-04T15:06:45.739888Z","iopub.status.idle":"2023-10-04T15:06:54.713317Z","shell.execute_reply.started":"2023-10-04T15:06:45.739858Z","shell.execute_reply":"2023-10-04T15:06:54.712225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.autograph.set_verbosity(0) # Silences warnings","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:06:54.718735Z","iopub.execute_input":"2023-10-04T15:06:54.719442Z","iopub.status.idle":"2023-10-04T15:06:54.727606Z","shell.execute_reply.started":"2023-10-04T15:06:54.719398Z","shell.execute_reply":"2023-10-04T15:06:54.726754Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Utils","metadata":{}},{"cell_type":"code","source":"def getZippedFilePaths():\n    zip_file_names = []\n    for dirname, _, filenames in os.walk('/kaggle/input'):\n        for filename in filenames:\n            if filename.split('.')[-1] == 'zip':\n                zip_file_names.append((os.path.join(dirname, filename)))\n    return zip_file_names\n\ndef preprocess_image(file_path):\n    # Load and decode the image\n    img = tf.io.read_file(file_path)\n    # You can adjust channels based on your images (3 for RGB)\n    img = tf.image.decode_jpeg(img, channels=3) # Returned as uint8\n    # Normalize the pixel values to [0, 1]\n    img = tf.image.convert_image_dtype(img, tf.float32)\n    # Resize the image to your desired dimensions\n    img = tf.image.resize(img, [96, 128], method = 'nearest')\n    return img\n\ndef preprocess_target(file_path):\n    # Load and decode the image\n    mask = tf.io.read_file(file_path)\n    # Normalizing to between 0 and 1 (only two classes)\n    mask = tf.image.decode_image(mask, expand_animations=False, dtype=tf.float32)\n    # Get only one value for the 3rd channel\n    mask = tf.math.reduce_max(mask, axis=-1, keepdims=True)\n    # Resize the image to your desired dimensions\n    mask = tf.image.resize(mask, [96, 128], method = 'nearest')\n    return mask\n\ndef dice_coef(y_true, y_pred, smooth=10e-6):\n    y_true_f = K.flatten(y_true)\n    y_pred_f = K.flatten(y_pred)\n    intersection = K.sum(y_true_f * y_pred_f)\n    dice = (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)\n    return dice\n\ndef dice_loss(y_true, y_pred):\n    return 1 - dice_coef(y_true, y_pred)\n\ndef display(display_list):\n    plt.figure(figsize=(15, 15))\n\n    title = ['Input Image', 'True Mask', 'Predicted Mask']\n\n    for i in range(len(display_list)):\n        plt.subplot(1, len(display_list), i+1)\n        plt.title(title[i])\n        plt.imshow(tf.keras.preprocessing.image.array_to_img(display_list[i]))\n        plt.axis('off')\n    plt.show()\n    \ndef create_mask(pred_mask):\n    mask = pred_mask[..., -1] >= 0.5\n    pred_mask[..., -1] = tf.where(mask, 1, 0)\n    # Return only first mask of batch\n    return pred_mask[0]\n\ndef show_predictions(model, dataset=None, num=1):\n    \"\"\"\n    Displays the first image of each of the num batches\n    \"\"\"\n    if dataset:\n        for image, mask in dataset.take(num):\n            pred_mask = model.predict(image)\n            display([image[0], mask[0], create_mask(pred_mask)])\n    else:\n        display([sample_image, sample_mask,\n             create_mask(model.predict(sample_image[tf.newaxis, ...]))])","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:06:54.732218Z","iopub.execute_input":"2023-10-04T15:06:54.735997Z","iopub.status.idle":"2023-10-04T15:06:54.754969Z","shell.execute_reply.started":"2023-10-04T15:06:54.735965Z","shell.execute_reply":"2023-10-04T15:06:54.754003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Unzip files (this will take a few minutes)","metadata":{}},{"cell_type":"code","source":"zip_file_names = getZippedFilePaths()\n\nitems_to_remove = ['/kaggle/input/carvana-image-masking-challenge/train.zip', \n                   '/kaggle/input/carvana-image-masking-challenge/test.zip']\n     \nzip_file_names = [item for item in zip_file_names if item not in items_to_remove]\n\nfor zip_file_path in zip_file_names:\n    with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:\n        zip_ref.extractall()","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:06:54.759822Z","iopub.execute_input":"2023-10-04T15:06:54.762599Z","iopub.status.idle":"2023-10-04T15:11:06.692748Z","shell.execute_reply.started":"2023-10-04T15:06:54.762569Z","shell.execute_reply":"2023-10-04T15:11:06.691788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Exploration","metadata":{}},{"cell_type":"markdown","source":"## Looking at images","metadata":{}},{"cell_type":"code","source":"# Appending all path names to a sorted list\ntrain_hq_dir = '/kaggle/working/train_hq/'\ntrain_masks_dir = '/kaggle/working/train_masks/'\ntest_hq_dir = '/kaggle/working/test_hq/'\n\nX_train_id = sorted([os.path.join(train_hq_dir, filename) for filename in os.listdir(train_hq_dir)], key=lambda x: x.split('/')[-1].split('.')[0])\ny_train = sorted([os.path.join(train_masks_dir, filename) for filename in os.listdir(train_masks_dir)], key=lambda x: x.split('/')[-1].split('.')[0])\nX_test_id = sorted([os.path.join(test_hq_dir, filename) for filename in os.listdir(test_hq_dir)], key=lambda x: x.split('/')[-1].split('.')[0])\n\nX_train_id = X_train_id[:1000]\ny_train = y_train[:1000]\nX_train, X_val, y_train, y_val = train_test_split(X_train_id, y_train, test_size=0.2, random_state=42)\n\n# Create Dataset objects from the list of file paths\nX_train = tf.data.Dataset.from_tensor_slices(X_train)\ny_train = tf.data.Dataset.from_tensor_slices(y_train)\n\nX_val = tf.data.Dataset.from_tensor_slices(X_val)\ny_val = tf.data.Dataset.from_tensor_slices(y_val)\n\nX_test = tf.data.Dataset.from_tensor_slices(X_test_id)\n\nimg_height = 96\nimg_width = 128\nnum_channels = 3\n\nimg_size = (img_height, img_width)\n\n# Apply preprocessing\nX_train = X_train.map(preprocess_image)\ny_train = y_train.map(preprocess_target)\n\nX_val = X_val.map(preprocess_image)\ny_val = y_val.map(preprocess_target)\n\nX_test = X_test.map(preprocess_image)\n\n# Add labels to dataframe objects (one-hot-encoded)\ntrain_dataset = tf.data.Dataset.zip((X_train, y_train))\nval_dataset = tf.data.Dataset.zip((X_val, y_val))\n\nBATCH_SIZE = 32\nbatched_train_dataset = train_dataset.batch(BATCH_SIZE)\nbatched_val_dataset = val_dataset.batch(BATCH_SIZE)\nbatched_test_dataset = X_test.batch(BATCH_SIZE)\n\n# Adding autotune for pre-fetching\nAUTOTUNE = tf.data.experimental.AUTOTUNE\nbatched_train_dataset = batched_train_dataset.prefetch(buffer_size=AUTOTUNE)\nbatched_val_dataset = batched_val_dataset.prefetch(buffer_size=AUTOTUNE)\nbatched_test_dataset = batched_test_dataset.prefetch(buffer_size=AUTOTUNE)","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:11:06.694165Z","iopub.execute_input":"2023-10-04T15:11:06.694809Z","iopub.status.idle":"2023-10-04T15:11:11.038289Z","shell.execute_reply.started":"2023-10-04T15:11:06.694777Z","shell.execute_reply":"2023-10-04T15:11:11.037228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# View images and associated labels\nfor images, masks in batched_val_dataset.take(1):\n    car_number = 0\n    for image_slot in range(16):\n        ax = plt.subplot(4, 4, image_slot + 1)\n        if image_slot % 2 == 0:\n            plt.imshow((images[car_number])) \n            class_name = 'Image'\n        else:\n            plt.imshow(masks[car_number], cmap = 'gray')\n            plt.colorbar()\n            class_name = 'Mask'\n            car_number += 1            \n        plt.title(class_name)\n        plt.axis(\"off\")","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:11:11.039685Z","iopub.execute_input":"2023-10-04T15:11:11.040208Z","iopub.status.idle":"2023-10-04T15:11:17.279162Z","shell.execute_reply.started":"2023-10-04T15:11:11.040177Z","shell.execute_reply":"2023-10-04T15:11:17.278349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Augmentation","metadata":{}},{"cell_type":"code","source":"data_augmentation = tf.keras.Sequential([\n        tfl.RandomFlip(mode=\"horizontal\", seed=42),\n        tfl.RandomRotation(factor=0.01, seed=42),\n        tfl.RandomContrast(factor=0.2, seed=42)\n])","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:11:17.281828Z","iopub.execute_input":"2023-10-04T15:11:17.282131Z","iopub.status.idle":"2023-10-04T15:11:17.373798Z","shell.execute_reply.started":"2023-10-04T15:11:17.282102Z","shell.execute_reply":"2023-10-04T15:11:17.372899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Custom Model","metadata":{}},{"cell_type":"code","source":"def get_model(img_size):\n    inputs = Input(shape=img_size + (3,))\n    x = data_augmentation(inputs)\n    \n    # Contracting path\n    x = tfl.Conv2D(64, 3, strides=2, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x) \n    x = tfl.Conv2D(64, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x) \n    x = tfl.Conv2D(128, 3, strides=2, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x) \n    x = tfl.Conv2D(128, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x) \n    x = tfl.Conv2D(256, 3, strides=2, padding=\"same\", activation=\"relu\", kernel_initializer='he_normal')(x) \n    x = tfl.Conv2D(256, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x)\n    \n    # Expanding path\n    x = tfl.Conv2DTranspose(256, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x)\n    x = tfl.Conv2DTranspose(256, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal', strides=2)(x)\n    x = tfl.Conv2DTranspose(128, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x)\n    x = tfl.Conv2DTranspose(128, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal', strides=2)(x)\n    x = tfl.Conv2DTranspose(64, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal')(x)\n    x = tfl.Conv2DTranspose(64, 3, activation=\"relu\", padding=\"same\", kernel_initializer='he_normal', strides=2)(x)\n\n    outputs = tfl.Conv2D(1, 3, activation=\"sigmoid\", padding=\"same\")(x)\n    model = keras.Model(inputs, outputs) \n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:11:17.374993Z","iopub.execute_input":"2023-10-04T15:11:17.375534Z","iopub.status.idle":"2023-10-04T15:11:17.816690Z","shell.execute_reply.started":"2023-10-04T15:11:17.375502Z","shell.execute_reply":"2023-10-04T15:11:17.815681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_model = get_model(img_size=img_size) \ncustom_model.summary()","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:11:17.817952Z","iopub.execute_input":"2023-10-04T15:11:17.818902Z","iopub.status.idle":"2023-10-04T15:11:18.258357Z","shell.execute_reply.started":"2023-10-04T15:11:17.818844Z","shell.execute_reply":"2023-10-04T15:11:18.257635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001,\n                                                        epsilon=1e-06), \n                                                        loss=[dice_loss], \n                                                        metrics=[dice_coef])\n\ncallbacks_list = [\n    keras.callbacks.EarlyStopping(\n        monitor=\"val_loss\",\n        patience=2,\n    ),\n    keras.callbacks.ModelCheckpoint(\n        filepath=\"best-custom-model\",\n        monitor=\"val_loss\",\n        save_best_only=True,\n    )\n]\n\nhistory = custom_model.fit(batched_train_dataset, epochs=20,\n                    callbacks=callbacks_list,\n                    validation_data=batched_val_dataset)","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:11:18.259334Z","iopub.execute_input":"2023-10-04T15:11:18.259657Z","iopub.status.idle":"2023-10-04T15:14:48.955429Z","shell.execute_reply.started":"2023-10-04T15:11:18.259625Z","shell.execute_reply":"2023-10-04T15:14:48.952743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_model = keras.models.load_model(\"/kaggle/working/best-custom-model\", custom_objects={'dice_coef': dice_coef, 'dice_loss': dice_loss})\n\nshow_predictions(model = custom_model, dataset = batched_train_dataset, num = 6)","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:14:48.956574Z","iopub.status.idle":"2023-10-04T15:14:48.957096Z","shell.execute_reply.started":"2023-10-04T15:14:48.956872Z","shell.execute_reply":"2023-10-04T15:14:48.956893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Using U-Net","metadata":{}},{"cell_type":"code","source":"def contracting_block(inputs=None, n_filters=64, dropout_prob=0, max_pooling=True):\n    conv = Conv2D(n_filters,  \n                  3,   \n                  activation='relu',\n                  padding='same',\n                  kernel_initializer='he_normal')(inputs)\n    conv = Conv2D(n_filters,  \n                  3,   \n                  activation='relu',\n                  padding='same',\n                  kernel_initializer='he_normal')(conv)\n\n    if dropout_prob > 0:\n        conv = Dropout(dropout_prob)(conv)\n\n    if max_pooling:\n        next_layer = MaxPooling2D(pool_size=(2, 2))(conv)\n\n    else:\n        next_layer = conv\n\n    skip_connection = conv\n\n    return next_layer, skip_connection\n\ndef expanding_block(expansive_input, contractive_input, n_filters=64):\n    up = Conv2DTranspose(\n        n_filters,    \n        3,    \n        strides=(2, 2),\n        padding='same',\n        kernel_initializer='he_normal')(expansive_input)\n\n    # Merge the previous output and the contractive_input\n    merge = concatenate([up, contractive_input], axis=3)\n\n    conv = Conv2D(n_filters,   \n                  3,     \n                  activation='relu',\n                  padding='same',\n                  kernel_initializer='he_normal')(merge)\n    conv = Conv2D(n_filters,   \n                  3,     \n                  activation='relu',\n                  padding='same',\n                  kernel_initializer='he_normal')(conv)\n\n    return conv\n\ndef unet_model(input_size=(96, 128, 3), n_filters=64, n_classes=1):\n    inputs = Input(input_size)\n    \n    inputs = data_augmentation(inputs)\n\n    # Contracting Path (encoding)\n    cblock1 = contracting_block(inputs, n_filters)\n    cblock2 = contracting_block(cblock1[0], n_filters*2)\n    cblock3 = contracting_block(cblock2[0], n_filters*4)\n    cblock4 = contracting_block(cblock3[0], n_filters*8, dropout_prob=0.3)\n\n    # Bottleneck Layer\n    cblock5 = contracting_block(cblock4[0], n_filters*16, dropout_prob=0.3, max_pooling=False)\n    \n    # Expanding Path (decoding)\n    ublock6 = expanding_block(cblock5[0], cblock4[1],  n_filters*8)\n    ublock7 = expanding_block(ublock6, cblock3[1],  n_filters*4)\n    ublock8 = expanding_block(ublock7, cblock2[1],  n_filters*2)\n    ublock9 = expanding_block(ublock8, cblock1[1],  n_filters)\n\n    conv9 = Conv2D(n_filters,\n                   3,\n                   activation='relu',\n                   padding='same',\n                   kernel_initializer='he_normal')(ublock9)\n\n    conv10 = Conv2D(n_classes, 1, padding='same', activation=\"sigmoid\")(conv9)\n\n    model = tf.keras.Model(inputs=inputs, outputs=conv10)\n\n    return model","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:14:48.958651Z","iopub.status.idle":"2023-10-04T15:14:48.959243Z","shell.execute_reply.started":"2023-10-04T15:14:48.959000Z","shell.execute_reply":"2023-10-04T15:14:48.959021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unet = unet_model(input_size=(img_height, img_width, num_channels), n_filters=64, n_classes=1)\nunet.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001, epsilon=1e-06),\n             loss=[dice_loss], \n             metrics=[dice_coef])\n\nunet.summary()","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:14:48.960483Z","iopub.status.idle":"2023-10-04T15:14:48.960906Z","shell.execute_reply.started":"2023-10-04T15:14:48.960690Z","shell.execute_reply":"2023-10-04T15:14:48.960710Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks_list = [\n    keras.callbacks.EarlyStopping(\n        monitor=\"val_loss\",\n        patience=2,\n    ),\n    keras.callbacks.ModelCheckpoint(\n        filepath=\"best-u_net-model\",\n        monitor=\"val_loss\",\n        save_best_only=True,\n    )\n]\n\nhistory = unet.fit(batched_train_dataset, epochs=20,\n                    callbacks=callbacks_list,\n                    validation_data=batched_val_dataset)","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:14:48.962284Z","iopub.status.idle":"2023-10-04T15:14:48.963826Z","shell.execute_reply.started":"2023-10-04T15:14:48.963617Z","shell.execute_reply":"2023-10-04T15:14:48.963638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unet = keras.models.load_model(\"/kaggle/working/best-u_net-model\", custom_objects={'dice_coef': dice_coef, 'dice_loss': dice_loss})\n\nshow_predictions(model = unet, dataset = batched_train_dataset, num = 6)","metadata":{"execution":{"iopub.status.busy":"2023-10-04T15:14:48.964907Z","iopub.status.idle":"2023-10-04T15:14:48.970568Z","shell.execute_reply.started":"2023-10-04T15:14:48.970356Z","shell.execute_reply":"2023-10-04T15:14:48.970377Z"},"trusted":true},"execution_count":null,"outputs":[]}]}