{"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":"**This is a starter notebook for [HuBMAP + HPA - Hacking the Human Body](https://www.kaggle.com/competitions/hubmap-organ-segmentation) using FPN with InceptionV3 as backbone.**\n\n![](https://i.postimg.cc/s24PHJDV/Screenshot-2022-06-26-at-03-05-59-Hu-BMAP-HPA-Hacking-the-Human-Body-Kaggle.png)\n","metadata":{}},{"cell_type":"markdown","source":"I used the Docker File of 2020-11-18 in this notebook, I did this by forking from another notebook created using that Docker File. You might need to fork this notebook or something equivalent to get the same Docker File in order to run this code. \n\n<h3><font color='red'> If you like this notebook then please upvote.</h3>","metadata":{}},{"cell_type":"markdown","source":"**INSTALLING REQUIREMENTS**","metadata":{}},{"cell_type":"code","source":"!pip install -U ../input/kerasapplications/Keras_Applications-1.0.8-py3-none-any.whl\n!pip install ../input/qubvel/efficientnet-1.0.0-py3-none-any.whl\n!pip install ../input/qubvel/image_classifiers-1.0.0-py3-none-any.whl\n!pip install ../input/qubvel-segmentation-model-keras-v101/segmentation_models-master\n\n%env SM_FRAMEWORK=tf.keras","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-06-28T04:09:48.374512Z","iopub.execute_input":"2022-06-28T04:09:48.375068Z","iopub.status.idle":"2022-06-28T04:11:46.210468Z","shell.execute_reply.started":"2022-06-28T04:09:48.375031Z","shell.execute_reply":"2022-06-28T04:11:46.209101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport gc\nimport cv2\nimport glob\nfrom tqdm import notebook\nimport tifffile as tiff \nimport numpy as np \nimport pandas as pd \nimport tensorflow.keras.backend as K\nimport tensorflow as tf\nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:46.213765Z","iopub.execute_input":"2022-06-28T04:11:46.214497Z","iopub.status.idle":"2022-06-28T04:11:52.262241Z","shell.execute_reply.started":"2022-06-28T04:11:46.214446Z","shell.execute_reply":"2022-06-28T04:11:52.261171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_csv = pd.read_csv(\"../input/hubmap-organ-segmentation/train.csv\")\ntest_csv = pd.read_csv(\"../input/hubmap-organ-segmentation/test.csv\")\nsample_submission = pd.read_csv(\"../input/hubmap-organ-segmentation/sample_submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:52.26406Z","iopub.execute_input":"2022-06-28T04:11:52.264511Z","iopub.status.idle":"2022-06-28T04:11:52.658239Z","shell.execute_reply.started":"2022-06-28T04:11:52.264465Z","shell.execute_reply":"2022-06-28T04:11:52.657248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_csv.head(10)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:52.660837Z","iopub.execute_input":"2022-06-28T04:11:52.661606Z","iopub.status.idle":"2022-06-28T04:11:52.69715Z","shell.execute_reply.started":"2022-06-28T04:11:52.661555Z","shell.execute_reply":"2022-06-28T04:11:52.695975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Setting up Seeds for reproducibility","metadata":{}},{"cell_type":"code","source":"SEED = 42\nos.environ['PYTHONHASHSEED'] = str(SEED)\nnp.random.seed = SEED\nK.set_random_seed = SEED\ntf.random.set_seed= SEED","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:52.702524Z","iopub.execute_input":"2022-06-28T04:11:52.702843Z","iopub.status.idle":"2022-06-28T04:11:52.708652Z","shell.execute_reply.started":"2022-06-28T04:11:52.702811Z","shell.execute_reply":"2022-06-28T04:11:52.707427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_SIZE = 480","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:52.712022Z","iopub.execute_input":"2022-06-28T04:11:52.712538Z","iopub.status.idle":"2022-06-28T04:11:52.719509Z","shell.execute_reply.started":"2022-06-28T04:11:52.712488Z","shell.execute_reply":"2022-06-28T04:11:52.717899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**IMAGE AUGMENTATIONS**","metadata":{}},{"cell_type":"markdown","source":"I am only using `HorizontalFlip`, `VerticalFlip`, `RandomRotate90` and `RandomBrightnessContrast` here but feel free to try out other augmentation techniques like `GridDistortion` and `OpticalDistortion` .","metadata":{}},{"cell_type":"code","source":"from albumentations import *\n\ntransforms = Compose([\n             HorizontalFlip(),\n             VerticalFlip(),\n             RandomRotate90(),\n             RandomBrightnessContrast(),\n             ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=15, p=0.9, \n                              border_mode=cv2.BORDER_REFLECT),\n\n                     ], p=1.0)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:52.721934Z","iopub.execute_input":"2022-06-28T04:11:52.722635Z","iopub.status.idle":"2022-06-28T04:11:54.046882Z","shell.execute_reply.started":"2022-06-28T04:11:52.722477Z","shell.execute_reply":"2022-06-28T04:11:54.045917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**LOAD DATA**","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/code/paulorzp/rle-functions-run-lenght-encode-decode\n\ndef mask2rle(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels= img.T.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n \ndef rle2mask(mask_rle, shape):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:54.049946Z","iopub.execute_input":"2022-06-28T04:11:54.050546Z","iopub.status.idle":"2022-06-28T04:11:54.064666Z","shell.execute_reply.started":"2022-06-28T04:11:54.050501Z","shell.execute_reply":"2022-06-28T04:11:54.063742Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In this demonstration I loaded the data into numpy(because I managed to fit them) but ITS ALWAYS BETTER TO USE `tf.data` in data loading cases. Because it's fast and also convenient for using other functions. <br>I will add this in later commits.","metadata":{}},{"cell_type":"code","source":"imgs = [] \nmasks = []\nviz = False\n\nfor each_id in notebook.tqdm(train_csv.id.values, total=train_csv.shape[0]):\n    info = train_csv[train_csv.id==each_id]\n    img_path = \"../input/hubmap-organ-segmentation/train_images/{}.tiff\".format(each_id)\n    \n    img = tiff.imread(img_path)\n    msk = rle2mask(mask_rle=info['rle'].values[0], \n                   shape=(info['img_height'].values[0], info['img_width'].values[0])\n                  )\n    sample = transforms(image = img, mask = msk)\n    aug_img = sample['image']\n    aug_msk = sample['mask']\n    aug_img = cv2.resize(aug_img, (IMG_SIZE, IMG_SIZE))\n    aug_msk = cv2.resize(aug_msk, (IMG_SIZE, IMG_SIZE))\n    aug_img = aug_img/255.0\n    \n    imgs.append( aug_img )\n    masks.append( aug_msk )\n    \n    #img = cv2.resize(img, (IMG_SIZE, IMG_SIZE)) \n    #msk = cv2.resize(msk, (IMG_SIZE, IMG_SIZE))\n    #img = img/255.0\n    \n    #imgs.append( img )\n    #masks.append( msk )\n    \n    if viz:\n        fig, ax = plt.subplots(1, 2, figsize=(12, 8))\n        ax[0].imshow(aug_img)\n        ax[1].imshow(aug_msk)\n        plt.show()\n\n    \nimgs = np.array(imgs).reshape(-1, IMG_SIZE, IMG_SIZE, 3).astype(np.float32)\nmasks = np.array(masks).reshape(-1, IMG_SIZE, IMG_SIZE)\n\nprint(imgs.shape, masks.shape)\nprint(np.min(imgs), np.max(imgs), np.min(masks), np.max(masks))","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:11:54.066333Z","iopub.execute_input":"2022-06-28T04:11:54.066638Z","iopub.status.idle":"2022-06-28T04:14:35.392815Z","shell.execute_reply.started":"2022-06-28T04:11:54.066583Z","shell.execute_reply":"2022-06-28T04:14:35.390457Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Let's see some images**","metadata":{}},{"cell_type":"code","source":"no_imgs = 5\n\nfor _ in range(no_imgs):\n    idx = np.random.randint(low=0, high=imgs.shape[0]-1)\n    fig, ax = plt.subplots(1, 2, figsize=(10, 5))\n    \n    ax[0].imshow(imgs[idx])\n    ax[0].set_title('Image')\n    ax[1].imshow(masks[idx])\n    ax[1].set_title('GT Mask')\n    plt.show()\n    ","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:14:35.395969Z","iopub.execute_input":"2022-06-28T04:14:35.396739Z","iopub.status.idle":"2022-06-28T04:14:37.656938Z","shell.execute_reply.started":"2022-06-28T04:14:35.396689Z","shell.execute_reply":"2022-06-28T04:14:37.65585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_imgs, val_imgs, train_masks, val_masks = train_test_split(imgs, masks, \n                                                                shuffle=True, test_size=0.20, \n                                                                random_state=SEED)\nprint(train_imgs.shape, train_masks.shape, val_imgs.shape, val_masks.shape)\n\ndel imgs, masks\n_ = gc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:14:37.658705Z","iopub.execute_input":"2022-06-28T04:14:37.659432Z","iopub.status.idle":"2022-06-28T04:14:38.269405Z","shell.execute_reply.started":"2022-06-28T04:14:37.659382Z","shell.execute_reply":"2022-06-28T04:14:38.268177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**DEFINE THE MODEL**","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/code/queyrusi/vanilla-submission-seresnext50\n\ndef dice_coeff(y_true, y_pred, epsilon=1.):\n    \n    \"\"\"\n    Calculates dice coefficient\n\n    Arguments: \n            y_true : tensor of ground truth values.\n            y_pred : tensor of predicted values.\n            epsilon : constant to avoid divide by 0 errors.\n    \n    Returns:\n            dice_coefficient\n    \"\"\"\n    \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    score = (2. * intersection + epsilon) / (K.sum(y_true_f) + K.sum(y_pred_f) + epsilon)\n    return score","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:14:38.271255Z","iopub.execute_input":"2022-06-28T04:14:38.271972Z","iopub.status.idle":"2022-06-28T04:14:38.28204Z","shell.execute_reply.started":"2022-06-28T04:14:38.271922Z","shell.execute_reply":"2022-06-28T04:14:38.281135Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%env SM_FRAMEWORK=tf.keras\nfrom segmentation_models import FPN\n\nmodel = FPN('inceptionv3', input_shape=(IMG_SIZE, IMG_SIZE, 3), classes=1, activation='sigmoid',\n            encoder_weights=\n            '../input/keras-pretrained-imagenet-weights/inceptionv3_imagenet_1000_no_top.h5'\n           )\n\nmodel.compile(loss='binary_crossentropy', optimizer='adam', metrics = [dice_coeff]) ","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:14:38.284094Z","iopub.execute_input":"2022-06-28T04:14:38.28464Z","iopub.status.idle":"2022-06-28T04:14:46.928341Z","shell.execute_reply.started":"2022-06-28T04:14:38.284588Z","shell.execute_reply":"2022-06-28T04:14:46.927164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Start Training**","metadata":{}},{"cell_type":"code","source":"%%time\n\ncp_callback = tf.keras.callbacks.ModelCheckpoint('/kaggle/working/best_model/',\n                                                 monitor='val_dice_coeff',\n                                                 verbose=1,\n                                                 save_best_only=True,\n                                                 save_weights_only=False,\n                                                 mode='max',\n                                                 save_freq='epoch',\n                                                )                                 \nhistory = model.fit(train_imgs, train_masks, \n                    epochs=15, batch_size=8,\n                    validation_data=(val_imgs, val_masks),\n                    callbacks=[cp_callback]\n                    )\n\ndel train_imgs, train_masks\n_ = gc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:14:46.930041Z","iopub.execute_input":"2022-06-28T04:14:46.930463Z","iopub.status.idle":"2022-06-28T04:15:20.033505Z","shell.execute_reply.started":"2022-06-28T04:14:46.930418Z","shell.execute_reply":"2022-06-28T04:15:20.032217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.DataFrame(history.history).plot(figsize=(8, 6))\nplt.show();","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:15:20.035645Z","iopub.execute_input":"2022-06-28T04:15:20.036057Z","iopub.status.idle":"2022-06-28T04:15:20.073676Z","shell.execute_reply.started":"2022-06-28T04:15:20.036022Z","shell.execute_reply":"2022-06-28T04:15:20.07192Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Let's look at some Predictions by our model**","metadata":{}},{"cell_type":"markdown","source":"Here, I used the same model but trained on 30 epochs.","metadata":{}},{"cell_type":"code","source":"model = tf.keras.models.load_model('/kaggle/working/best_model', custom_objects={'dice_coeff':dice_coeff})\nprint(\"Best Model Loaded!\")","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:15:24.298149Z","iopub.execute_input":"2022-06-28T04:15:24.298549Z","iopub.status.idle":"2022-06-28T04:16:21.202121Z","shell.execute_reply.started":"2022-06-28T04:15:24.298506Z","shell.execute_reply":"2022-06-28T04:16:21.200898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"no_imgs = 5\n\nfor _ in range(no_imgs):\n    idx = np.random.randint(low=0, high=val_imgs.shape[0]-1)\n    fig, ax = plt.subplots(1, 3, figsize=(10, 5))\n\n    ax[0].imshow(val_imgs[idx])\n    ax[0].set_title('Image')\n    \n    pred = model.predict(np.expand_dims(val_imgs[idx], 0))[0, :, :, 0]\n    pred[pred>=0.5] = 1\n    pred[pred<0.5] = 0\n    ax[1].imshow(pred)\n    ax[1].set_title('Predicted Mask')\n\n    ax[2].imshow(val_masks[idx])\n    ax[2].set_title('GT Mask')\n    plt.show()\n","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:16:21.204566Z","iopub.execute_input":"2022-06-28T04:16:21.205321Z","iopub.status.idle":"2022-06-28T04:16:26.691658Z","shell.execute_reply.started":"2022-06-28T04:16:21.205273Z","shell.execute_reply":"2022-06-28T04:16:26.690487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**SUBMISSION**","metadata":{}},{"cell_type":"code","source":"### Let's delete Val Images and Masks since we don't need them to do submission.\n\ndel val_imgs, val_masks\n_ = gc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:16:26.693313Z","iopub.execute_input":"2022-06-28T04:16:26.693949Z","iopub.status.idle":"2022-06-28T04:16:27.230875Z","shell.execute_reply.started":"2022-06-28T04:16:26.693903Z","shell.execute_reply":"2022-06-28T04:16:27.22947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ids = []\npreds = []\n\nfor each_id in sample_submission.id.values:\n    print(each_id)\n    img_path = \"../input/hubmap-organ-segmentation/test_images/{}.tiff\".format(each_id)\n    img = tiff.imread(img_path)\n    if img==[]:\n        ids.append(each_id)\n        preds.append('')\n    else:\n        img_real_shape  = img.shape\n        img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n        \n        ###Prediction\n        img = np.expand_dims(img, 0)\n        img = img/255.0\n        pred_mask = model.predict(img)[0, :, :, 0]\n        pred_mask = cv2.resize(pred_mask, (img_real_shape[1], img_real_shape[0]))\n        pred_mask[pred_mask>=0.5] = 1\n        pred_mask[pred_mask<0.5] = 0\n        \n        pred_rle  = mask2rle(pred_mask)\n        ids.append(each_id)\n        preds.append(pred_rle)\n        ","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:16:27.233267Z","iopub.execute_input":"2022-06-28T04:16:27.233912Z","iopub.status.idle":"2022-06-28T04:16:27.861188Z","shell.execute_reply.started":"2022-06-28T04:16:27.233859Z","shell.execute_reply":"2022-06-28T04:16:27.859906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub = pd.DataFrame({'id':ids,'rle':preds})\nsub.to_csv('/kaggle/working/submission.csv', index=False)\nsub.head(5)","metadata":{"execution":{"iopub.status.busy":"2022-06-28T04:16:27.863798Z","iopub.execute_input":"2022-06-28T04:16:27.864493Z","iopub.status.idle":"2022-06-28T04:16:28.235085Z","shell.execute_reply.started":"2022-06-28T04:16:27.864445Z","shell.execute_reply":"2022-06-28T04:16:28.233923Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Thank You for reading.**\n","metadata":{}}]}