{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":52279,"databundleVersionId":5822112,"sourceType":"competition"},{"sourceId":8380012,"sourceType":"datasetVersion","datasetId":4983219},{"sourceId":8577811,"sourceType":"datasetVersion","datasetId":5129583}],"dockerImageVersionId":30665,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"!pip install -U segmentation-models","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:25.388919Z","iopub.execute_input":"2024-06-01T12:12:25.390173Z","iopub.status.idle":"2024-06-01T12:12:41.439831Z","shell.execute_reply.started":"2024-06-01T12:12:25.390116Z","shell.execute_reply":"2024-06-01T12:12:41.438508Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport pickle\nimport json, math\nimport numpy as np\nimport random, time\nimport pandas as pd\nfrom PIL import Image\nimport seaborn as sns\nimport shutil, sys, os, gc\nfrom datetime import datetime\nfrom tqdm.notebook import tqdm\nimport matplotlib.pyplot as plt\n\n\nimport tensorflow as tf\nimport albumentations as A\nfrom tensorflow.keras.utils import Sequence\nfrom sklearn.model_selection import train_test_split\nfrom imblearn.over_sampling import RandomOverSampler\nfrom tensorflow.keras.callbacks import ModelCheckpoint\n\n\nos.environ['SM_FRAMEWORK'] = 'tf.keras'\nimport segmentation_models as sm","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:41.442456Z","iopub.execute_input":"2024-06-01T12:12:41.442881Z","iopub.status.idle":"2024-06-01T12:12:56.067117Z","shell.execute_reply.started":"2024-06-01T12:12:41.442844Z","shell.execute_reply":"2024-06-01T12:12:56.066092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Configs","metadata":{}},{"cell_type":"code","source":"class CFG:\n    # PATHS\n    tile_fpath = \"/kaggle/input/hubmap-human-vasculature-dataset-512512/HuPMap/kidney_tiles.csv\"\n    masks_dir = \"/kaggle/input/hubmap-human-vasculature-dataset-512512/HuPMap/masks/\"\n    images_dir = \"/kaggle/input/hubmap-human-vasculature-dataset-512512/HuPMap/images/\"\n\n    # Seeding for reproducibility\n    seed = 42\n\n    # Image, Mask\n    _shape = 512\n    mask_channel = 1 # 1 for blood_vessels only, 2 for unsure as well, any other value returns 512, 512, 3 mask\n    image_size = (_shape, _shape)\n    \n    # optimizer\n    lr=2e-3\n    \n    # Batch Size & Epochs\n    epochs = 20\n    batch_size = 16\n\n    # Image prediction prob cutoff\n    cutoff = 0.6    \n    \n    # Model data\n    base_model = \"Unet\"\n    encoder = \"efficientnetb5\" \n    model_name = \"{}_{}\".format(base_model, encoder)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.068272Z","iopub.execute_input":"2024-06-01T12:12:56.068820Z","iopub.status.idle":"2024-06-01T12:12:56.075277Z","shell.execute_reply.started":"2024-06-01T12:12:56.068792Z","shell.execute_reply":"2024-06-01T12:12:56.074179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Utility Functions","metadata":{}},{"cell_type":"code","source":" def process_image(X, Y, clhe=False):\n    processing = A.Compose([\n        A.CLAHE(clip_limit=2.0, tile_grid_size=(8, 8), p=1.0),\n     ])\n    \n    if not clhe:\n        return X, Y\n        \n    processed_set = processing(image=X, mask=Y)\n    return processed_set['image'], processed_set['mask']\n\ndef augment(X, Y):\n    size = X.shape[0]\n    \n    augmentation = A.Compose([\n            A.HorizontalFlip(p=0.5),\n            A.VerticalFlip(p=0.5),\n            A.RandomRotate90(p=1.0),\n            A.Affine(translate_percent=(0.0, 0.2), p=0.5),\n            A.RandomBrightnessContrast(p=0.75),\n            A.OneOf([\n                    A.GaussNoise(var_limit=[10, 50]),\n                    A.GaussianBlur(),\n                    A.MotionBlur(),\n                    ], p=0.4),\n            A.GridDistortion(num_steps=5, distort_limit=0.3, p=0.5),\n        ])\n    \n    augmented_set = augmentation(image=X, mask=Y)\n    return augmented_set['image'], augmented_set['mask']\n\ndef augment_batch(X_batch, Y_batch, augment, show_progress=False):\n    augmented_X_batch, augmented_Y_batch = [], []\n    for X, Y in tqdm(zip(X_batch, Y_batch), total=X_batch.shape[0], disable=not show_progress, desc=\"processing\"):\n        augmented_X, augmented_Y = augment(X, Y)\n        augmented_X_batch.append(augmented_X)\n        augmented_Y_batch.append(augmented_Y)\n        \n    return np.array(augmented_X_batch), np.array(augmented_Y_batch)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.078150Z","iopub.execute_input":"2024-06-01T12:12:56.078547Z","iopub.status.idle":"2024-06-01T12:12:56.112167Z","shell.execute_reply.started":"2024-06-01T12:12:56.078512Z","shell.execute_reply":"2024-06-01T12:12:56.111326Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_mask(index, channel=CFG.mask_channel):\n    # loading mask\n    mask = np.load(f\"{CFG.masks_dir}{index}.npy\")\n    \n    # Select the specified channels\n    if channel == 1:\n        mask = mask[:, :, 0] # to consider only blood vessels\n    elif channel == 2:\n        selected_channels = mask[:, :, [0, 2]]\n        mask = np.sum(selected_channels, axis=2)\n    else:\n        pass\n    \n    # expanding dimension\n    if len(mask.shape) != 3:\n        mask = np.expand_dims(mask, axis=-1)\n        mask = np.where(mask > 0, 1, 0).astype(np.uint8)\n\n    return mask\n\n# to read data\ndef read_image_mask(df, processing=process_image, processing_batch=augment_batch):\n    # Loading data\n    indexes = df['id'].to_numpy()\n    x = np.array([np.load(CFG.images_dir + index + \".npy\") for index in tqdm(indexes, desc=\"Loading images\")])\n    y = np.array([read_mask(index) for index in tqdm(indexes, desc=\"Loading masks\")])\n    \n    if processing:\n        x, y = processing_batch(x, y, processing, show_progress=True)\n    \n    gc.collect()\n    return x, y","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.113307Z","iopub.execute_input":"2024-06-01T12:12:56.113677Z","iopub.status.idle":"2024-06-01T12:12:56.125982Z","shell.execute_reply.started":"2024-06-01T12:12:56.113646Z","shell.execute_reply":"2024-06-01T12:12:56.124977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Generates data on which model trains on\nclass DataGenerator(Sequence):\n    def __init__(self, df, normalization, batch_size=CFG.batch_size,\n                 transform=None, processing=None, processing_batch=augment_batch,\n                 images_dir=CFG.images_dir, masks_dir=CFG.masks_dir, **kwargs):\n        super().__init__(**kwargs)\n        \n        self.df = df\n        \n        self.masks_dir = masks_dir\n        self.images_dir = images_dir\n        self.batch_size = batch_size\n        \n        self.transform = transform\n        self.processing = processing\n        self.normalization = normalization\n        self.processing_batch = processing_batch\n\n    def __len__(self):\n        return self.df.shape[0] // self.batch_size\n\n    def read_mask(self, index, channel=CFG.mask_channel):\n        # loading mask\n        mask = np.load(f\"{self.masks_dir}{index}.npy\")\n\n        # Select the specified channels\n        if channel == 1:\n            mask = mask[:, :, 0] # to consider only blood vessels\n        elif channel == 2:\n            selected_channels = mask[:, :, [0, 2]]\n            mask = np.sum(selected_channels, axis=2)\n        else:\n            pass\n\n        # expanding dimension\n        if len(mask.shape) != 3:\n            mask = np.expand_dims(mask, axis=-1)\n            mask = np.where(mask > 0, 1, 0).astype(np.uint8)\n\n        return mask\n    \n    def __getitem__(self, index):\n        # Load images, and masks\n        batch_df = self.df[index * self.batch_size: (index + 1) * self.batch_size]\n        X = np.array([np.load(self.images_dir + row['id'] + \".npy\") for i, row in batch_df.iterrows()])\n        y = np.array([self.read_mask(row['id']) for i, row in batch_df.iterrows()], dtype=np.float32)\n\n        # processing\n        if self.processing:\n             X, y = self.processing_batch(X, y, self.processing)\n            \n        # augmentation\n        if self.transform:\n            X, y = self.processing_batch(X, y, self.transform)\n            \n        # preprocessing\n        if self.normalization:\n            X = self.normalization(X)\n            \n        gc.collect()\n        return X, y","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.127607Z","iopub.execute_input":"2024-06-01T12:12:56.127875Z","iopub.status.idle":"2024-06-01T12:12:56.142602Z","shell.execute_reply.started":"2024-06-01T12:12:56.127853Z","shell.execute_reply":"2024-06-01T12:12:56.141771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Usage example save_history(HISTORY, 'history.json')\ndef save_history(history, file_path):\n    with open(file_path, 'w') as file:\n        json.dump(history, file)\n\n# Usage example loaded_history = load_history('history.json') \ndef load_history(file_path):\n    with open(file_path, 'r') as file:\n        history = json.load(file)\n    return history\n        \n# to plot model hsitory\ndef plot_history(history, targets=[]):\n    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))\n\n    # Plot loss\n    ax1.plot(history[targets[2]], label=targets[2], color=\"tab:blue\")\n    ax1.plot(history[targets[3]], label=targets[3], color=\"tab:orange\")\n    ax1.set_xlabel('Epoch')\n    ax1.set_ylabel('Loss')\n    ax1.tick_params(axis='y')\n    ax1.legend(loc=\"upper left\")\n\n    # Plot IoU\n    ax2.plot(history[targets[0]], label=targets[0], color=\"tab:green\")\n    ax2.plot(history[targets[1]], label=targets[1], color=\"tab:red\")\n    ax2.set_ylabel('Metric')\n    ax2.tick_params(axis='y')\n    ax2.legend(loc=\"upper right\")\n\n    fig.tight_layout()  # Ensure the labels do not overlap\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.143870Z","iopub.execute_input":"2024-06-01T12:12:56.144729Z","iopub.status.idle":"2024-06-01T12:12:56.156143Z","shell.execute_reply.started":"2024-06-01T12:12:56.144697Z","shell.execute_reply":"2024-06-01T12:12:56.155180Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load DataFrame","metadata":{}},{"cell_type":"code","source":"# read csv file\ntile_df = pd.read_csv(CFG.tile_fpath)\n\n# ignore blank masks, and select some features\ntile_df = tile_df[tile_df['annotated'] == 1]\nif CFG.mask_channel == 1:\n    tile_df = tile_df[tile_df['blood_vessel'] > 0]\n    \ntile_df = tile_df[['id', 'source_wsi', 'dataset', 'dataset_wsi', 'blood_vessel', 'glomerulus', 'unsure']]\n\nprint(tile_df.shape)\ntile_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.157199Z","iopub.execute_input":"2024-06-01T12:12:56.157575Z","iopub.status.idle":"2024-06-01T12:12:56.234199Z","shell.execute_reply.started":"2024-06-01T12:12:56.157530Z","shell.execute_reply":"2024-06-01T12:12:56.233250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Plotting samples","metadata":{}},{"cell_type":"code","source":" # To overlay mask onto its image\ndef overlay_mask(image, mask, opacity=0.90):\n    if np.max(mask) == 0:\n        return image.astype(np.uint8)  # Return the original image if the mask is blank (all zeros)\n    \n    alpha = mask[:, :, 0] * opacity  # Extract the single channel from the mask & Adjust the opacity by multiplying with a factor\n    alpha = alpha[:, :, np.newaxis]   # Add a third dimension to make it compatible with the image\n    result = alpha * mask + (1 - alpha) * image\n    \n    return result.astype(np.uint8)\n\n# Displaying image, mask, and mask overlayed onto image.\ndef show_random_sample(df):\n    fig, ax = plt.subplots(1,3, figsize = (10, 10))\n    \n    #getting random image     \n    _idx = df['id'].to_numpy()[random.randint(0, df.shape[0] - 1)]\n    _img =  np.load(CFG.images_dir + _idx + \".npy\")\n    _mask = read_mask(_idx)\n    _img, _mask = process_image(_img, _mask)\n    _overlay = overlay_mask(_img, _mask)\n\n    ax[0].imshow(_img)\n    ax[1].imshow(_overlay)\n    ax[2].imshow(_mask, cmap='gray')\n\n    ax[0].set_title(\"Image ({})\".format(_idx))\n    ax[1].set_title(\"Overlayed Image\")\n    ax[2].set_title(\"pixel wise label\")","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.235717Z","iopub.execute_input":"2024-06-01T12:12:56.236550Z","iopub.status.idle":"2024-06-01T12:12:56.246835Z","shell.execute_reply.started":"2024-06-01T12:12:56.236515Z","shell.execute_reply":"2024-06-01T12:12:56.245858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Displaying random image\nshow_random_sample(tile_df)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:56.250442Z","iopub.execute_input":"2024-06-01T12:12:56.250759Z","iopub.status.idle":"2024-06-01T12:12:57.175410Z","shell.execute_reply.started":"2024-06-01T12:12:56.250721Z","shell.execute_reply":"2024-06-01T12:12:57.174327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Displaying random image\nshow_random_sample(tile_df)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:57.176810Z","iopub.execute_input":"2024-06-01T12:12:57.177130Z","iopub.status.idle":"2024-06-01T12:12:58.045462Z","shell.execute_reply.started":"2024-06-01T12:12:57.177102Z","shell.execute_reply":"2024-06-01T12:12:58.044460Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Exploratory data analysis. (E.D.A.)","metadata":{}},{"cell_type":"code","source":"# To dispaly data distribution\ndef plot_bar(df, select):\n    sum_data_df = df[select].groupby(select[-1]).count()\n    sum_data_df.plot(kind = \"bar\", title = \"count of (dataset, source wsi)\", color=[\"#4682B4\", \"#4682B4\"])\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:58.046779Z","iopub.execute_input":"2024-06-01T12:12:58.047231Z","iopub.status.idle":"2024-06-01T12:12:58.053373Z","shell.execute_reply.started":"2024-06-01T12:12:58.047198Z","shell.execute_reply":"2024-06-01T12:12:58.052175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# To dispaly data distribution\nselect = [\"dataset\", \"source_wsi\", \"dataset_wsi\"]\nplot_bar(tile_df, select)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:58.054777Z","iopub.execute_input":"2024-06-01T12:12:58.055046Z","iopub.status.idle":"2024-06-01T12:12:58.327616Z","shell.execute_reply.started":"2024-06-01T12:12:58.055023Z","shell.execute_reply":"2024-06-01T12:12:58.326608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# To dispaly data distribution\nselect = [\"id\", \"source_wsi\"]\nplot_bar(tile_df, select)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:58.328956Z","iopub.execute_input":"2024-06-01T12:12:58.329688Z","iopub.status.idle":"2024-06-01T12:12:58.614613Z","shell.execute_reply.started":"2024-06-01T12:12:58.329650Z","shell.execute_reply":"2024-06-01T12:12:58.613328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# To dispaly data distribution\nselect = [\"id\", \"dataset\"]\nplot_bar(tile_df, select)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:58.615920Z","iopub.execute_input":"2024-06-01T12:12:58.616237Z","iopub.status.idle":"2024-06-01T12:12:58.909700Z","shell.execute_reply.started":"2024-06-01T12:12:58.616210Z","shell.execute_reply":"2024-06-01T12:12:58.908552Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data preparation","metadata":{}},{"cell_type":"code","source":"# model backbone\npreprocess_input = sm.get_preprocessing(CFG.encoder)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:58.911214Z","iopub.execute_input":"2024-06-01T12:12:58.912258Z","iopub.status.idle":"2024-06-01T12:12:58.917850Z","shell.execute_reply.started":"2024-06-01T12:12:58.912216Z","shell.execute_reply":"2024-06-01T12:12:58.916643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# spliting data and perserving the same ratio of each class\nX_train, X_val = train_test_split(tile_df, test_size=0.2, random_state=CFG.seed, stratify=tile_df['dataset_wsi'])\nprint(X_train.shape, X_val.shape)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:58.919220Z","iopub.execute_input":"2024-06-01T12:12:58.919571Z","iopub.status.idle":"2024-06-01T12:12:58.932727Z","shell.execute_reply.started":"2024-06-01T12:12:58.919542Z","shell.execute_reply":"2024-06-01T12:12:58.931497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nfrom sklearn.utils import shuffle\n\ndef oversample_data_generator(x, y, batch_size=4500, random_state=123):\n    # Identify the minority class samples (assuming label 1 is the minority class)\n    minority_indices = np.where(y == 1)[0]\n    \n    while True:\n        # Set the random seed\n        np.random.seed(random_state)\n\n        # Randomly oversample the minority class to match the number of majority class samples\n        oversampled_minority_indices = np.random.choice(minority_indices, size=batch_size // 2, replace=True)\n        \n        # Combine oversampled minority and majority indices\n        selected_indices = np.concatenate([oversampled_minority_indices, np.where(y == 0)[0]])\n\n        # Shuffle the combined indices\n        selected_indices = shuffle(selected_indices, random_state=random_state)\n\n        for i in range(0, len(selected_indices), batch_size):\n            batch_indices = selected_indices[i:i + batch_size]\n            X_batch = x.iloc[batch_indices]\n\n            yield X_batch","metadata":{"execution":{"iopub.status.busy":"2024-05-31T14:43:59.030721Z","iopub.execute_input":"2024-05-31T14:43:59.031059Z","iopub.status.idle":"2024-05-31T14:43:59.038283Z","shell.execute_reply.started":"2024-05-31T14:43:59.031030Z","shell.execute_reply":"2024-05-31T14:43:59.037467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"_, y_train = read_image_mask(X_train, processing=None)\nX_resampled = next(oversample_data_generator(X_train, y_train))\nX_combined = pd.DataFrame(np.concatenate([X_train, X_resampled]), columns=X_train.columns)\n\ndel _\ndel y_train\ndel X_resampled\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2024-05-31T14:44:00.173467Z","iopub.execute_input":"2024-05-31T14:44:00.173817Z","iopub.status.idle":"2024-05-31T14:45:12.259498Z","shell.execute_reply.started":"2024-05-31T14:44:00.173790Z","shell.execute_reply":"2024-05-31T14:45:12.258475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(X_combined.shape, X_train.shape, X_val.shape)","metadata":{"execution":{"iopub.status.busy":"2024-05-31T14:45:12.261554Z","iopub.execute_input":"2024-05-31T14:45:12.262333Z","iopub.status.idle":"2024-05-31T14:45:12.267296Z","shell.execute_reply.started":"2024-05-31T14:45:12.262297Z","shell.execute_reply":"2024-05-31T14:45:12.266283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# creating data generator instances\ntrain_generator = DataGenerator(X_combined, transform=augment, processing=process_image, processing_batch=augment_batch, normalization=preprocess_input)\nval_generator = DataGenerator(X_val, processing=process_image, processing_batch=augment_batch, normalization=preprocess_input)","metadata":{"execution":{"iopub.status.busy":"2024-05-31T14:30:51.193967Z","iopub.execute_input":"2024-05-31T14:30:51.194328Z","iopub.status.idle":"2024-05-31T14:30:51.234818Z","shell.execute_reply.started":"2024-05-31T14:30:51.194299Z","shell.execute_reply":"2024-05-31T14:30:51.233662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Display samples of the DataGenerator images\nfig, axes = plt.subplots(1, 2, figsize=(10, 6))\nx, y = val_generator[0]\nprint(x.shape, y.shape)\n\n# Display the input image\naxes[0].imshow(x[0])\naxes[0].set_title(\"Input Image\")\naxes[0].axis('off')\n\n# Display the label image\naxes[1].imshow(y[0])\naxes[1].set_title(\"Label Image\")\naxes[1].axis('off')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-30T10:22:15.071629Z","iopub.execute_input":"2024-05-30T10:22:15.071966Z","iopub.status.idle":"2024-05-30T10:22:16.445319Z","shell.execute_reply.started":"2024-05-30T10:22:15.071942Z","shell.execute_reply":"2024-05-30T10:22:16.444534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# U-NET Model","metadata":{}},{"cell_type":"code","source":"HISTORY = {}\nBEST_MODEL_PATH=F\"{CFG.model_name}_weights.keras\"\nTARGETS = ['iou_score', 'val_iou_score', 'loss', 'val_loss']\n\n# model history\nfor target in TARGETS:\n    HISTORY[target] = []","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:12:58.936525Z","iopub.execute_input":"2024-06-01T12:12:58.936887Z","iopub.status.idle":"2024-06-01T12:12:58.942409Z","shell.execute_reply.started":"2024-06-01T12:12:58.936853Z","shell.execute_reply":"2024-06-01T12:12:58.941340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Instantiate model\nmodel = sm.Unet(CFG.encoder, encoder_weights='imagenet', decoder_use_batchnorm=True, classes=1, activation='sigmoid')\n\n# Compile model\n# lr_schedule = tf.keras.optimizers.schedules.CosineDecay(initial_learning_rate=CFG.lr, decay_steps=CFG.epochs, alpha=CFG.min_lr)\nmodel.compile(\n    tf.keras.optimizers.AdamW(learning_rate=CFG.lr),\n    loss=sm.losses.dice_loss,\n    metrics=[sm.metrics.iou_score],\n)\n\n# Callback functions\nsave_best_weights = ModelCheckpoint(BEST_MODEL_PATH, monitor='val_loss', verbose=1, save_best_only=True, mode='min')\n\n# Loading weights\nmodel.load_weights(\"/kaggle/input/weights/Unet_efficientnetb5_weights.keras\")\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:13:26.506372Z","iopub.execute_input":"2024-06-01T12:13:26.507297Z","iopub.status.idle":"2024-06-01T12:14:06.959829Z","shell.execute_reply.started":"2024-06-01T12:13:26.507262Z","shell.execute_reply":"2024-06-01T12:14:06.958786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model Training","metadata":{}},{"cell_type":"code","source":"# HISTORY = load_history('/kaggle/input/unet-weights/training_history.json')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# fit model\nmodel.fit(\n    train_generator,\n    batch_size=CFG.batch_size,\n    epochs=CFG.epochs,\n    validation_data=val_generator,\n    callbacks=[save_best_weights]\n)","metadata":{"execution":{"iopub.status.busy":"2024-05-30T10:23:25.765690Z","iopub.execute_input":"2024-05-30T10:23:25.765995Z","iopub.status.idle":"2024-05-30T10:24:11.320821Z","shell.execute_reply.started":"2024-05-30T10:23:25.765968Z","shell.execute_reply":"2024-05-30T10:24:11.319656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# saving model history\nfor key in TARGETS:\n    HISTORY[key].extend(model.history.history[key])\n\nsave_history(HISTORY, 'training_history.json')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plotting model history loss, and metric\nplot_history(HISTORY, TARGETS)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model Evaluation","metadata":{}},{"cell_type":"code","source":"# model.predict method\ndef predict_masks(model, images):\n    # Ensure the input image has the right shape for prediction\n    if len(images.shape) == 3:\n        images = np.expand_dims(images, axis=0)  # Add batch dimension if needed\n\n    # Predict the probabilities for the input image\n    images = preprocess_input(images)\n    prob = model.predict(images)\n\n    # Return the predicted mask\n    return prob\n\n# model.predict method\ndef predict_masks(model, images):\n    # Ensure the input image has the right shape for prediction\n    if len(images.shape) == 3:\n        images = np.expand_dims(images, axis=0)  # Add batch dimension if needed\n\n    # Predict the probabilities for the input image\n    images = preprocess_input(images)\n    prob = model.predict(images)\n\n    # Return the predicted mask\n    return prob\n\ndef calculate_metrics(y_true, y_pred, threshold):\n    y_pred_binary = (y_pred > threshold).astype(np.uint8)\n\n    # True Positives, False Positives, False Negatives, True Negatives\n    TP = np.sum((y_true == 1) & (y_pred_binary == 1))\n    FP = np.sum((y_true == 0) & (y_pred_binary == 1))\n    TN = np.sum((y_true == 0) & (y_pred_binary == 0))\n    FN = np.sum((y_true == 1) & (y_pred_binary == 0))\n\n    # Dice coefficient\n    dice_denominator = 2 * TP + FP + FN\n    dice = (2 * TP) / dice_denominator if dice_denominator != 0 else 1\n\n    # Intersection over Union (IoU)\n    iou_denominator = TP + FP + FN\n    iou = TP / iou_denominator if iou_denominator != 0 else 1\n\n    # Precision\n    precision = TP / (TP + FP) if (TP + FP) != 0 else 1\n\n    # Recall\n    recall = TP / (TP + FN) if (TP + FN) != 0 else 1\n    \n    # F1 Score\n    f1_score = 2 * ((precision * recall) / (precision + recall)) if (precision + recall) != 0 else 1\n\n    # Confidence\n    binary_mask = y_pred > threshold\n    confidence_scores = y_pred.flatten()\n    binary_mask_flat = binary_mask.flatten()\n    blood_vessel_confidences = confidence_scores[binary_mask_flat]\n    confidence = np.mean(blood_vessel_confidences)\n\n    return dice, iou, precision, recall, f1_score, confidence\n\n\ndef metrics_dataframe(Y, Y_hat, threshold=CFG.cutoff):\n    n_val = len(Y)\n    df_object = {}\n    df_object['dice'] = []\n    df_object['iou'] = []\n    df_object['precision'] = []\n    df_object['recall'] = []    \n    df_object['f1_score'] = []\n    df_object['confidence'] = []\n    df_object['threshold'] = threshold\n\n    for i in tqdm(range(n_val), total=n_val):\n        metrics = calculate_metrics(Y[i], Y_hat[i], threshold)\n        df_object['dice'].append(metrics[0])\n        df_object['iou'].append(metrics[1])\n        df_object['precision'].append(metrics[2])\n        df_object['recall'].append(metrics[3])        \n        df_object['f1_score'].append(metrics[4])\n        df_object['confidence'].append(metrics[5])\n        \n    return pd.DataFrame(df_object)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:14:12.721960Z","iopub.execute_input":"2024-06-01T12:14:12.722604Z","iopub.status.idle":"2024-06-01T12:14:12.740614Z","shell.execute_reply.started":"2024-06-01T12:14:12.722564Z","shell.execute_reply":"2024-06-01T12:14:12.739446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# load best model weights\nmodel.load_weights(f\"/kaggle/working/{BEST_MODEL_PATH}\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# loading validation data\nX, Y = read_image_mask(X_val)\n\n# making prediction\nY_hat = predict_masks(model, X)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:14:14.769151Z","iopub.execute_input":"2024-06-01T12:14:14.769678Z","iopub.status.idle":"2024-06-01T12:16:17.932709Z","shell.execute_reply.started":"2024-06-01T12:14:14.769645Z","shell.execute_reply":"2024-06-01T12:16:17.931501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def print_metrics(threshold=CFG.cutoff):\n    n = len(Y)\n    iou, dice = [], []\n    \n    for i in tqdm(range(n)):\n        metrics = calculate_metrics(Y[i], Y_hat[i], threshold)\n        iou.append(metrics[1])\n        dice.append(metrics[0])\n    \n    iou = np.round(np.mean(iou ) * 100, 4)\n    dice = np.round(np.mean(dice) * 100, 4)\n    \n    print(\"threshold {}% - IoU score {}% - Dice coefficient {}%\"\n          .format(threshold*100, np.mean(iou),np.mean(dice)))   \n    \n    return threshold, dice\n    \nmax_dice = -1\nbest_threshold = 0\nfor i in range(50, 100, 5):\n    threshold, dice = print_metrics(i / 100)\n    if dice > max_dice:\n        max_dice = dice\n        best_threshold = threshold","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:16:17.935431Z","iopub.execute_input":"2024-06-01T12:16:17.935888Z","iopub.status.idle":"2024-06-01T12:16:23.142265Z","shell.execute_reply.started":"2024-06-01T12:16:17.935848Z","shell.execute_reply":"2024-06-01T12:16:23.141201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"metrics_df = metrics_dataframe(Y, Y_hat, best_threshold)\nmetrics_df.to_csv('metrics_dataframe.csv', index=False)\nmetrics_df.mean()","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:16:23.143830Z","iopub.execute_input":"2024-06-01T12:16:23.144302Z","iopub.status.idle":"2024-06-01T12:16:23.700047Z","shell.execute_reply.started":"2024-06-01T12:16:23.144256Z","shell.execute_reply":"2024-06-01T12:16:23.698989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# IOU boxplot using Seaborn\nsns.boxplot(x=metrics_df['iou'])\n\n# Show the plot\nplt.title('IOU Scores Boxplot')\nplt.xlabel('IOU Scores')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:16:23.701972Z","iopub.execute_input":"2024-06-01T12:16:23.702300Z","iopub.status.idle":"2024-06-01T12:16:23.867367Z","shell.execute_reply.started":"2024-06-01T12:16:23.702272Z","shell.execute_reply":"2024-06-01T12:16:23.866242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Dice boxplot using Seaborn\nsns.boxplot(x=metrics_df['dice'])\n\n# Show the plot\nplt.title('Dice Scores Boxplot')\nplt.xlabel('Dice Scores')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:16:23.869135Z","iopub.execute_input":"2024-06-01T12:16:23.869751Z","iopub.status.idle":"2024-06-01T12:16:24.036049Z","shell.execute_reply.started":"2024-06-01T12:16:23.869712Z","shell.execute_reply":"2024-06-01T12:16:24.034672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Plotting Predictions","metadata":{}},{"cell_type":"code","source":"def plot_result(X, Y_true, Y_pred, cutoff=CFG.cutoff):\n    \n    N = X.shape[0]\n    \n    fig, ax = plt.subplots(N,4, figsize = (10, 3*N))\n    \n    for k in range(N):\n        \n        cutoff_img1 = (Y_pred[k,:,:,0] > cutoff).astype(int)\n\n        true_img = np.zeros((512, 512, 3), dtype = np.uint8)\n        true_img[:,:,1] = Y_true[k,:,:,0]*200\n        \n        cutoff1 = np.zeros((512, 512, 3), dtype = np.uint8)\n        \n        cutoff1[:,:,0] = cutoff_img1*230\n        \n        cutoff1[:,:,1] = cutoff_img1*50\n        cutoff1[:,:,2] = cutoff_img1*50\n        \n        diff_photo1 = cutoff1.copy()\n        diff_photo1[:,:,1] += (Y_true[k,:,:,0]*200).astype(np.uint8)\n        \n        ax[k, 0].imshow(X[k])\n        ax[k, 1].imshow(true_img, cmap = \"gray\")\n        ax[k, 2].imshow(cutoff1, cmap = \"gray\")\n        ax[k, 3].imshow(diff_photo1)\n        \n        for j in range(4):\n            ax[k,j].set_xticks([])\n            ax[k,j].set_yticks([])\n    \n        if k == 0:\n            ax[k, 0].set_title(\"val img\")\n            ax[k, 1].set_title(\"true label\")\n            ax[k, 2].set_title(\"model (cutoff at {})\".format(cutoff))\n            ax[k, 3].set_title(\"Compare (Y:tp)\")","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:16:41.294888Z","iopub.execute_input":"2024-06-01T12:16:41.295269Z","iopub.status.idle":"2024-06-01T12:16:41.307858Z","shell.execute_reply.started":"2024-06-01T12:16:41.295240Z","shell.execute_reply":"2024-06-01T12:16:41.306911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_val = len(X)\nnp.random.seed(CFG.seed)\nval_sample = np.random.choice(n_val, 20)\nplot_result(X[val_sample], Y[val_sample], Y_hat[val_sample], cutoff=best_threshold)","metadata":{"execution":{"iopub.status.busy":"2024-06-01T12:16:41.679687Z","iopub.execute_input":"2024-06-01T12:16:41.680356Z","iopub.status.idle":"2024-06-01T12:16:50.430279Z","shell.execute_reply.started":"2024-06-01T12:16:41.680327Z","shell.execute_reply":"2024-06-01T12:16:50.429143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}