{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":30201,"databundleVersionId":2750748,"sourceType":"competition"}],"dockerImageVersionId":30153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Imports","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom tqdm.notebook import tqdm\nfrom matplotlib import pyplot as plt\nimport cv2\nfrom sklearn.preprocessing import Binarizer\nimport tensorflow as tf\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.utils import plot_model\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.layers import Input, Conv2D, Conv2DTranspose, MaxPool2D, SpatialDropout2D, Concatenate, LeakyReLU","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-02-27T06:19:34.262139Z","iopub.execute_input":"2024-02-27T06:19:34.262417Z","iopub.status.idle":"2024-02-27T06:19:40.539563Z","shell.execute_reply.started":"2024-02-27T06:19:34.262337Z","shell.execute_reply":"2024-02-27T06:19:40.538824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Constants and Configuration","metadata":{}},{"cell_type":"code","source":"RANDOM_STATE = 7\nINPUT_IMG_SHAPE = (520, 704)\nTARGET_IMG_SHAPE = (512,  704)\nPOWER = 2\nVAL_SIZE = 0.1\nLEARNING_RATE = 1e-4\nBATCH_SIZE = 4\nEPOCHS = 100\nPLOTS_DPI = 150\nPATIENCE = 6\n\nnp.random.seed(RANDOM_STATE)","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:20:50.025010Z","iopub.execute_input":"2024-02-27T06:20:50.025587Z","iopub.status.idle":"2024-02-27T06:20:50.031970Z","shell.execute_reply.started":"2024-02-27T06:20:50.025549Z","shell.execute_reply":"2024-02-27T06:20:50.031241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## EDA","metadata":{}},{"cell_type":"markdown","source":"### Loading training data","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('../input/sartorius-cell-instance-segmentation/train.csv')\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:20:55.494252Z","iopub.execute_input":"2024-02-27T06:20:55.495008Z","iopub.status.idle":"2024-02-27T06:20:56.094420Z","shell.execute_reply.started":"2024-02-27T06:20:55.494974Z","shell.execute_reply":"2024-02-27T06:20:56.093110Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.shape","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:02.514645Z","iopub.execute_input":"2024-02-27T06:21:02.515396Z","iopub.status.idle":"2024-02-27T06:21:02.520598Z","shell.execute_reply.started":"2024-02-27T06:21:02.515356Z","shell.execute_reply":"2024-02-27T06:21:02.519890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Null check","metadata":{}},{"cell_type":"code","source":"train_df.isnull().sum().sum()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:05.139550Z","iopub.execute_input":"2024-02-27T06:21:05.140294Z","iopub.status.idle":"2024-02-27T06:21:05.198779Z","shell.execute_reply.started":"2024-02-27T06:21:05.140251Z","shell.execute_reply":"2024-02-27T06:21:05.197956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Number of unique images","metadata":{}},{"cell_type":"code","source":"train_df[\"id\"].nunique()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:09.429037Z","iopub.execute_input":"2024-02-27T06:21:09.429794Z","iopub.status.idle":"2024-02-27T06:21:09.445418Z","shell.execute_reply.started":"2024-02-27T06:21:09.429759Z","shell.execute_reply":"2024-02-27T06:21:09.444722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Unique cell types","metadata":{}},{"cell_type":"code","source":"train_df[\"cell_type\"].unique()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:14.409247Z","iopub.execute_input":"2024-02-27T06:21:14.409867Z","iopub.status.idle":"2024-02-27T06:21:14.421234Z","shell.execute_reply.started":"2024-02-27T06:21:14.409828Z","shell.execute_reply":"2024-02-27T06:21:14.420488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Image sizes\nAll images defined in `train_df` are of the same size - 520 * 704","metadata":{}},{"cell_type":"code","source":"train_df[[\"height\", \"width\"]].describe()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:18.784091Z","iopub.execute_input":"2024-02-27T06:21:18.784824Z","iopub.status.idle":"2024-02-27T06:21:18.810885Z","shell.execute_reply.started":"2024-02-27T06:21:18.784783Z","shell.execute_reply":"2024-02-27T06:21:18.810137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Number of annotations\nNumber of annotations per image are very varied with the minimum being 4 and maximum being 790","metadata":{}},{"cell_type":"code","source":"annot_counts = train_df.groupby('id')[['annotation']].count().sort_values('annotation')\nannot_counts","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:22.144200Z","iopub.execute_input":"2024-02-27T06:21:22.144914Z","iopub.status.idle":"2024-02-27T06:21:22.179197Z","shell.execute_reply.started":"2024-02-27T06:21:22.144879Z","shell.execute_reply":"2024-02-27T06:21:22.178440Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"annot_counts.describe()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:22.989034Z","iopub.execute_input":"2024-02-27T06:21:22.989679Z","iopub.status.idle":"2024-02-27T06:21:23.002916Z","shell.execute_reply.started":"2024-02-27T06:21:22.989637Z","shell.execute_reply":"2024-02-27T06:21:23.002128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.style.use('ggplot')\nplt.figure(figsize = (10, 6))\nplt.hist(annot_counts, bins = 50, alpha = 0.8)\nplt.xlabel(\"Number of annotations\")\nplt.ylabel(\"Count\")\nplt.title(\"Number of annotations per image\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:24.139359Z","iopub.execute_input":"2024-02-27T06:21:24.139765Z","iopub.status.idle":"2024-02-27T06:21:24.491290Z","shell.execute_reply.started":"2024-02-27T06:21:24.139725Z","shell.execute_reply":"2024-02-27T06:21:24.490543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Mask generation and pixel distribution\n\n5 sample images have been chosen for visualization:\n- Random image of cell type `shsy5y`\n- Random image of cell type `astro`\n- Random image of cell type `cort`\n- Image with least number of annotations\n- Image with most number of annotations","metadata":{}},{"cell_type":"code","source":"def rle_decode(mask_rle, shape, color = 1):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height, width, channels) of array to return \n    color: color for the mask\n    Returns numpy array (mask)\n    '''\n    s = mask_rle.split()\n    \n    starts = list(map(lambda x: int(x) - 1, s[0::2]))\n    lengths = list(map(int, s[1::2]))\n    ends = [x + y for x, y in zip(starts, lengths)]\n    \n    img = np.zeros((shape[0] * shape[1], shape[2]), dtype = np.float32)\n            \n    for start, end in zip(starts, ends):\n        img[start : end] = color\n    \n    return img.reshape(shape)\n\ndef get_grayscale_mask(image_id, annots):\n    grayscale_mask = np.zeros((*INPUT_IMG_SHAPE, 1))\n    \n    for annot in annots:\n            grayscale_mask += rle_decode(annot, shape = (*INPUT_IMG_SHAPE, 1))\n    \n    return grayscale_mask.clip(0, 1)\n\ndef get_rgb_mask(image_id, annots):\n    rgb_mask = np.zeros((*INPUT_IMG_SHAPE, 3))\n    \n    for annot in annots:\n        rgb_mask += rle_decode(annot, shape = (*INPUT_IMG_SHAPE, 3), color = np.random.rand(3))\n    \n    return rgb_mask.clip(0, 1)\n\ndef get_image(image_id):\n    image = cv2.imread(f\"../input/sartorius-cell-instance-segmentation/train/{image_id}.png\", cv2.IMREAD_GRAYSCALE)\n    return image.reshape(*INPUT_IMG_SHAPE, 1)\n\ndef plot_images(image_ids):\n    n = len(image_ids)\n    grayscale_masks = []\n    rgb_masks = []\n    images = []\n    celltypes = []\n    \n    for img_id in image_ids:\n        row = train_df[train_df[\"id\"] == img_id]\n\n        annots = row[\"annotation\"].tolist()\n        celltypes.append(row[\"cell_type\"].tolist()[0])\n    \n        grayscale_masks.append(get_grayscale_mask(img_id, annots))\n        rgb_masks.append(get_rgb_mask(img_id, annots))\n        \n        images.append(get_image(img_id))\n    \n    plt.figure(figsize = (20 , 4 * n))\n    \n    for i in range(n):\n        \n        plt.subplot(n, 4, (i * 4) + 1)\n        plt.imshow(images[i], cmap = 'gray')\n        plt.title(f'{image_ids[i]} - {celltypes[i]}', fontsize = 16)\n        plt.axis(\"off\")\n\n        plt.subplot(n, 4, (i * 4) + 2)\n        plt.imshow(images[i] * grayscale_masks[i], cmap = 'gray')\n        plt.title('Input image with mask', fontsize = 16)\n        plt.axis(\"off\")\n\n        plt.subplot(n, 4, (i * 4) + 3)\n        plt.imshow(rgb_masks[i])\n        plt.title('RGB mask', fontsize = 16)\n        plt.axis(\"off\")\n        \n        plt.subplot(n, 4, (i * 4) + 4)\n        plt.hist(images[i].flatten(), bins = 255, range = (0, 255))\n        plt.title('Pixel distribution', fontsize = 16)\n    \n    plt.suptitle(\"Sample images, masks and their pixel distributions\", fontsize = 24)\n    plt.tight_layout(rect = [0, 0, 0.90, 1])\n    plt.show()\n    return grayscale_masks, rgb_masks, images\n\nsample_ids = ['0030fd0e6378','0140b3c8f445','01ae5a43a2ab', 'e92c56871769', 'c4121689002f']\n_, _, images = plot_images(sample_ids)","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:24.492934Z","iopub.execute_input":"2024-02-27T06:21:24.493222Z","iopub.status.idle":"2024-02-27T06:21:31.698940Z","shell.execute_reply.started":"2024-02-27T06:21:24.493178Z","shell.execute_reply":"2024-02-27T06:21:31.697943Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Image transformation\nImages have very less contrast as all pixel values are very close together. Pixel values have been updated to rectify that.","metadata":{}},{"cell_type":"markdown","source":"### Transforming input images","metadata":{}},{"cell_type":"code","source":"def transform_image(img_data, power = 2):\n    img_data_mask = np.ones_like(img_data, dtype = np.int16)\n    img_data_mask[img_data < 127.5] = -1\n    \n    img_data_transformed = img_data.astype(np.int16) - 127.5\n    img_data_transformed[img_data_transformed > 0] = np.power(img_data_transformed[img_data_transformed > 0], 1 / power)\n    img_data_transformed[img_data_transformed < 0] = np.power(-img_data_transformed[img_data_transformed < 0], 1 / power)\n    img_data_transformed = ((img_data_transformed * img_data_mask) / (2 * np.power(127.5, 1 / power))) + 0.5\n    \n    return img_data_transformed\n\ndef plot_transformed_images(images, transformed_images):\n    n = len(images)\n    \n    plt.figure(figsize = (20 , 4 * n))\n    \n    for i in range(n):\n        plt.subplot(n, 4, (i * 4) + 1)\n        plt.imshow(images[i], cmap = 'gray')\n        plt.title(f'{sample_ids[i]} - Original', fontsize = 16)\n        plt.axis(\"off\")\n        \n        plt.subplot(n, 4, (i * 4) + 2)\n        plt.hist(images[i].flatten() / 255, bins = 255, range = (0, 1))\n        plt.title('Original pixel distribution', fontsize = 16)\n        \n        plt.subplot(n, 4, (i * 4) + 3)\n        plt.imshow(transformed_images[i], cmap = 'gray')\n        plt.title('Transformed image', fontsize = 16)\n        plt.axis(\"off\")\n        \n        plt.subplot(n, 4, (i * 4) + 4)\n        plt.hist(transformed_images[i].flatten(), bins = 255, range = (0, 1))\n        plt.title('Pixel distribution after transformation', fontsize = 16)\n\n    plt.suptitle(\"Image transformation\", fontsize = 24)\n    plt.tight_layout(rect = [0, 0, 0.90, 1])\n    plt.show()\n    \nplot_transformed_images(images, [transform_image(image) for image in images])","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:21:50.349237Z","iopub.execute_input":"2024-02-27T06:21:50.349836Z","iopub.status.idle":"2024-02-27T06:21:58.374200Z","shell.execute_reply.started":"2024-02-27T06:21:50.349787Z","shell.execute_reply":"2024-02-27T06:21:58.373173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Effect of transformation for different values of power","metadata":{}},{"cell_type":"code","source":"n = len(images)\nplt.figure(figsize = (20 , 4.5 * n))\n\nfor i in range(n):\n    plt.subplot(n, 4, (i * 4) + 1)\n    plt.imshow(images[i], cmap = 'gray')\n    plt.title(f'{sample_ids[i]} - Original', fontsize = 16)\n    plt.axis(\"off\")\n    \n    plt.subplot(n, 4, (i * 4) + 2)\n    plt.imshow(transform_image(images[i], 2), cmap = 'gray')\n    plt.title('Power = 2', fontsize = 16)\n    plt.axis(\"off\")\n    \n    plt.subplot(n, 4, (i * 4) + 3)\n    plt.imshow(transform_image(images[i], 3), cmap = 'gray')\n    plt.title('Power = 3', fontsize = 16)\n    plt.axis(\"off\")\n    \n    plt.subplot(n, 4, (i * 4) + 4)\n    plt.imshow(transform_image(images[i], 4), cmap = 'gray')\n    plt.title('Power = 4', fontsize = 16)\n    plt.axis(\"off\")\n    \nplt.suptitle(\"Effect of power on image transformation\", fontsize = 24)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:22:24.839227Z","iopub.execute_input":"2024-02-27T06:22:24.839787Z","iopub.status.idle":"2024-02-27T06:22:27.372038Z","shell.execute_reply.started":"2024-02-27T06:22:24.839748Z","shell.execute_reply":"2024-02-27T06:22:27.371280Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data preparation","metadata":{}},{"cell_type":"markdown","source":"### Loading and transforming the input images and their corresponding grayscale masks","metadata":{}},{"cell_type":"code","source":"X = []\ny = []\n\nimage_ids = train_df[\"id\"].unique()\nnp.random.shuffle(image_ids)\n\nfor img_id in tqdm(image_ids, unit = \" images\", desc = \"Loading transformed images and their masks in grayscale\"):\n    X.append(cv2.resize(transform_image(get_image(img_id), POWER), (TARGET_IMG_SHAPE[1], TARGET_IMG_SHAPE[0])).reshape(*TARGET_IMG_SHAPE, 1))\n    \n    annots = train_df[train_df[\"id\"] == img_id][\"annotation\"].tolist()\n    y.append(cv2.resize(get_grayscale_mask(img_id, annots), (TARGET_IMG_SHAPE[1], TARGET_IMG_SHAPE[0])).reshape(*TARGET_IMG_SHAPE, 1))\n    \nX = np.array(X)\ny = np.array(y)\ny = Binarizer().transform(y.reshape(-1, 1)).reshape(y.shape)\n\nX.shape, y.shape","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:23:14.759059Z","iopub.execute_input":"2024-02-27T06:23:14.759600Z","iopub.status.idle":"2024-02-27T06:24:19.228582Z","shell.execute_reply.started":"2024-02-27T06:23:14.759567Z","shell.execute_reply":"2024-02-27T06:24:19.227856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Sample input images and output masks","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (20 , 13))\n\nfor i, j in enumerate(np.random.randint(len(image_ids), size = 6)):\n    plt.subplot(3, 4, (i * 2) + 1)\n    plt.imshow(X[j], cmap = 'gray')\n    plt.title(f'Input image - {image_ids[j]}', fontsize = 16)\n    plt.axis(\"off\")\n    \n    plt.subplot(3, 4, (i * 2) + 2)\n    plt.imshow(y[j], cmap = 'gray')\n    plt.title(f'Output mask - {image_ids[j]}', fontsize = 16)\n    plt.axis(\"off\")\n    \nplt.suptitle(\"Sample inputs and outputs\", fontsize = 24)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:24:26.689209Z","iopub.execute_input":"2024-02-27T06:24:26.689503Z","iopub.status.idle":"2024-02-27T06:24:27.906876Z","shell.execute_reply.started":"2024-02-27T06:24:26.689470Z","shell.execute_reply":"2024-02-27T06:24:27.906128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"markdown","source":"### Model Building","metadata":{}},{"cell_type":"code","source":"def unet_model():\n    input_layer = Input(shape = (*TARGET_IMG_SHAPE, 1), name = 'Input_Layer')\n    \n    conv_1 = Conv2D(16, 5, padding = 'same', activation = LeakyReLU(), name = 'Conv_1')(input_layer)\n    pool_1 = MaxPool2D(name = 'Max_Pool_1')(conv_1)\n    spd_1 = SpatialDropout2D(0.1, name = 'SPD_1')(pool_1)\n    \n    conv_2 = Conv2D(32, 4, padding = 'same', activation = LeakyReLU(), name = 'Conv_2')(spd_1)\n    pool_2 = MaxPool2D(name = 'Max_Pool_2')(conv_2)  \n    conv_3 = Conv2D(64, 4, padding = 'same', activation = LeakyReLU(), name = 'Conv_3')(pool_2)\n    pool_3 = MaxPool2D(name = 'Max_Pool_3')(conv_3)\n    spd_2 = SpatialDropout2D(0.1, name = 'SPD_2')(pool_3)\n    \n    conv_4 = Conv2D(128, 3, padding = 'same', activation = LeakyReLU(), name = 'Conv_4')(spd_2)\n    pool_4 = MaxPool2D(name = 'Max_Pool_4')(conv_4)\n    conv_5 = Conv2D(256, 3, padding = 'same', activation = LeakyReLU(), name = 'Conv_5')(pool_4)\n    pool_5 = MaxPool2D(name = 'Max_Pool_5')(conv_5)\n    spd_3 = SpatialDropout2D(0.1, name = 'SPD_3')(pool_5)\n    \n    conv_6 = Conv2D(512, 2, padding = 'same', activation = LeakyReLU(), name = 'Conv_6')(spd_3)\n    pool_6 = MaxPool2D(name = 'Max_Pool_6')(conv_6)\n    \n    conv_t_1 = Conv2DTranspose(256, 1, padding = 'same', strides = 2, activation = LeakyReLU(), name = 'Conv_T_1')(pool_6)\n    concat_1 = Concatenate(name = 'Concat_1')([conv_t_1, spd_3])\n    spd_4 = SpatialDropout2D(0.1, name = 'SPD_4')(concat_1)\n    \n    conv_t_2 = Conv2DTranspose(128, 3, padding = 'same', strides = 2, activation = LeakyReLU(), name = 'Conv_T_2')(spd_4)\n    conv_t_3 = Conv2DTranspose(64, 3, padding = 'same', strides = 2, activation = LeakyReLU(), name = 'Conv_T_3')(conv_t_2)\n    concat_2 = Concatenate(name = 'Concat_2')([conv_t_3, spd_2])\n    spd_5 = SpatialDropout2D(0.1, name = 'SPD_5')(concat_2)\n    \n    conv_t_4 = Conv2DTranspose(32, 4, padding = 'same', strides = 2, activation = LeakyReLU(), name = 'Conv_T_4')(spd_5)\n    conv_t_5 = Conv2DTranspose(16, 4, padding = 'same', strides = 2, activation = LeakyReLU(), name = 'Conv_T_5')(conv_t_4)\n    concat_3 = Concatenate(name = 'Concat_3')([conv_t_5, spd_1])\n    spd_6 = SpatialDropout2D(0.1, name = 'SPD_6')(concat_3)\n    \n    conv_t_6 = Conv2DTranspose(8, 5, padding = 'same', strides = 2, activation = LeakyReLU(), name = 'Conv_T_6')(spd_6)\n    \n    output_layer = Conv2DTranspose(1, 5, padding = 'same', activation = 'sigmoid', name = 'Output_Layer')(conv_t_6)\n    \n    return Model(inputs = input_layer, outputs = output_layer, name = 'Sartorius')\n\nmodel = unet_model()\nmodel.compile(optimizer = Adam(LEARNING_RATE), loss = 'binary_crossentropy', metrics = ['accuracy'])\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:24:56.596426Z","iopub.execute_input":"2024-02-27T06:24:56.596987Z","iopub.status.idle":"2024-02-27T06:24:59.443051Z","shell.execute_reply.started":"2024-02-27T06:24:56.596944Z","shell.execute_reply":"2024-02-27T06:24:59.442404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_model(model, to_file = 'model.jpg', show_shapes = True, dpi = PLOTS_DPI)","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:25:11.314465Z","iopub.execute_input":"2024-02-27T06:25:11.314756Z","iopub.status.idle":"2024-02-27T06:25:12.485386Z","shell.execute_reply.started":"2024-02-27T06:25:11.314724Z","shell.execute_reply":"2024-02-27T06:25:12.484375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Training","metadata":{}},{"cell_type":"code","source":"%%time\n\nearly_stop = EarlyStopping(monitor = 'val_loss', patience = PATIENCE, restore_best_weights = True)\n\nhistory = model.fit(\n    X, y,\n    batch_size = BATCH_SIZE,\n    epochs = EPOCHS,\n    validation_split = VAL_SIZE,\n    callbacks = [early_stop]\n)","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:25:37.015226Z","iopub.execute_input":"2024-02-27T06:25:37.015968Z","iopub.status.idle":"2024-02-27T06:37:42.292678Z","shell.execute_reply.started":"2024-02-27T06:25:37.015919Z","shell.execute_reply":"2024-02-27T06:37:42.291911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Metrics","metadata":{}},{"cell_type":"code","source":"loss = history.history['loss']\nval_loss = history.history['val_loss']\n\naccuracy = history.history['accuracy']\nval_accuracy = history.history['val_accuracy']\n\nepochs_range = history.epoch\n\nplt.figure(figsize = (18, 6))\n\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, loss, label = 'Training Loss')\nplt.plot(epochs_range, val_loss, label = 'Validation Loss')\nplt.legend(loc = 'upper right', fontsize = 14)\nplt.ylim(0, None)\nplt.title('Loss', fontsize = 20)\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, accuracy, label = 'Training Accuracy')\nplt.plot(epochs_range, val_accuracy, label = 'Validation Accuracy')\nplt.legend(loc = 'lower right', fontsize = 14)\nplt.title('Accuracy', fontsize = 20)\n\nplt.suptitle(\"Evaluation Metrics\", fontsize = 24)\nplt.savefig('loss_and_accuracy.jpg', dpi = PLOTS_DPI, bbox_inches = 'tight')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:37:50.960567Z","iopub.execute_input":"2024-02-27T06:37:50.960957Z","iopub.status.idle":"2024-02-27T06:38:05.057843Z","shell.execute_reply.started":"2024-02-27T06:37:50.960911Z","shell.execute_reply":"2024-02-27T06:38:05.057116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Predictions","metadata":{}},{"cell_type":"markdown","source":"### Getting smaple predictions","metadata":{}},{"cell_type":"code","source":"num_preds = 5\nsample_pred_ids = np.random.randint(len(X), size = num_preds)\n\npreds = model.predict(X[sample_pred_ids])\n\npreds.shape","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:38:14.859244Z","iopub.execute_input":"2024-02-27T06:38:14.859884Z","iopub.status.idle":"2024-02-27T06:38:15.543985Z","shell.execute_reply.started":"2024-02-27T06:38:14.859853Z","shell.execute_reply":"2024-02-27T06:38:15.543253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Finding optimal threshold for creating a binary mask","metadata":{}},{"cell_type":"code","source":"threshold_ranges = np.arange(0.25, 0.76, 0.05)\n\naccuracies = []\n\nfor threshold in threshold_ranges:\n    pred_mask = Binarizer(threshold = threshold).transform(preds.reshape(-1, 1)).reshape(preds.shape)\n    accuracies.append((pred_mask == y[sample_pred_ids]).sum() / pred_mask.size)\n\nthreshold_results_df = pd.DataFrame({\n    'threshold': threshold_ranges,\n    'accuracy': accuracies\n}).round(3).sort_values('accuracy', ascending = False)\n\nthreshold_results_df","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:38:18.674221Z","iopub.execute_input":"2024-02-27T06:38:18.674844Z","iopub.status.idle":"2024-02-27T06:38:18.828196Z","shell.execute_reply.started":"2024-02-27T06:38:18.674803Z","shell.execute_reply":"2024-02-27T06:38:18.827463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualizing Predictions","metadata":{}},{"cell_type":"code","source":"pred_mask = Binarizer(threshold = threshold_results_df['threshold'].iloc[0]).transform(preds.reshape(-1, 1)).reshape(preds.shape)\n\nplt.figure(figsize = (20 , 20))\nfor i in range(num_preds):\n    plt.subplot(num_preds, 4, (4 * i) + 1)\n    plt.imshow(X[sample_pred_ids[i]], cmap = 'gray')\n    plt.axis('off')\n    plt.title(f'Input image - {image_ids[sample_pred_ids[i]]}', fontsize = 16)\n    \n    plt.subplot(num_preds, 4, (4 * i) + 2)\n    plt.imshow(y[sample_pred_ids[i]], cmap = 'gray')\n    plt.axis('off')\n    plt.title('Expected output mask', fontsize = 16)\n    \n    plt.subplot(num_preds, 4, (4 * i) + 3)\n    plt.imshow(preds[i], cmap = 'gray')\n    plt.axis('off')\n    plt.title('Predicted mask', fontsize = 16)\n    \n    plt.subplot(num_preds, 4, (4 * i) + 4)\n    plt.imshow(pred_mask[i], cmap = 'gray')\n    plt.axis('off')\n    plt.title('Binarized mask', fontsize = 16)\n    \nplt.suptitle(\"Sample inputs and outputs\", fontsize = 24)\nplt.tight_layout(rect = [0, 0, 0.90, 1])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-02-27T06:38:21.149316Z","iopub.execute_input":"2024-02-27T06:38:21.150060Z","iopub.status.idle":"2024-02-27T06:38:22.822599Z","shell.execute_reply.started":"2024-02-27T06:38:21.150024Z","shell.execute_reply":"2024-02-27T06:38:22.821842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}