{"metadata":{"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":61446,"databundleVersionId":6962461,"sourceType":"competition"},{"sourceId":7407720,"sourceType":"datasetVersion","datasetId":4308295},{"sourceId":7415742,"sourceType":"datasetVersion","datasetId":4308607},{"sourceId":160138952,"sourceType":"kernelVersion"},{"sourceId":6191,"sourceType":"modelInstanceVersion","modelInstanceId":4655}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.12"},"papermill":{"default_parameters":{},"duration":3846.080383,"end_time":"2024-01-14T04:20:19.064569","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-01-14T03:16:12.984186","version":"2.4.0"},"widgets":{"application/vnd.jupyter.widget-state+json":{"state":{"08983a9c6aff42578980f4f7113c3ee2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_4411aefc021d46d0ada7b645eb53ec48","placeholder":"​","style":"IPY_MODEL_09a10a8cf9334c51857397ed50398c8e","value":"Searching best thr : 100%"}},"09a10a8cf9334c51857397ed50398c8e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"1f3989a0c01248328e16875075e9d1c4":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_08983a9c6aff42578980f4f7113c3ee2","IPY_MODEL_22cfcc0a7cc6455fbf3bb7c788c8a4e1","IPY_MODEL_c8392e8075224e3b8a020a16c1a08447"],"layout":"IPY_MODEL_6cec9a2c2fac450d87248aed8dd62f86"}},"22cfcc0a7cc6455fbf3bb7c788c8a4e1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_dffe80502d954bdea0bbb6353dbf5515","max":20,"min":0,"orientation":"horizontal","style":"IPY_MODEL_7ce1b34a4f864a42a6619eec82311eb0","value":20}},"4411aefc021d46d0ada7b645eb53ec48":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6cec9a2c2fac450d87248aed8dd62f86":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"7ce1b34a4f864a42a6619eec82311eb0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"83fe40a0b8f047cc8602206909d42361":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9384babdb7054d55aecdf3e989ddc926":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"c8392e8075224e3b8a020a16c1a08447":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_83fe40a0b8f047cc8602206909d42361","placeholder":"​","style":"IPY_MODEL_9384babdb7054d55aecdf3e989ddc926","value":" 20/20 [04:34&lt;00:00, 12.66s/it]"}},"dffe80502d954bdea0bbb6353dbf5515":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}},"version_major":2,"version_minor":0}}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<center><img src=\"https://keras.io/img/logo-small.png\" alt=\"Keras logo\" width=\"100\"><br/>\nThis starter notebook is provided by the Keras team.</center>","metadata":{"execution":{"iopub.execute_input":"2024-01-10T05:24:31.308329Z","iopub.status.busy":"2024-01-10T05:24:31.307595Z","iopub.status.idle":"2024-01-10T05:24:31.313088Z","shell.execute_reply":"2024-01-10T05:24:31.312113Z","shell.execute_reply.started":"2024-01-10T05:24:31.308287Z"},"papermill":{"duration":0.011755,"end_time":"2024-01-14T03:16:16.447481","exception":false,"start_time":"2024-01-14T03:16:16.435726","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# SenNet + HOA - Exploring 3D Human Vasculature Segmentation with [KerasCV](https://github.com/keras-team/keras-cv) and [Keras](https://github.com/keras-team/keras)\n\n> The objective of this competition is to accurately segment blood vessels in the human kidney.\n\nThis notebook guides you through inferring a trained model, specifically DeepLabV3+, using KerasCV on the competition dataset. This notebook utilizes a **sliding window** mechanism to infer on large images (e.g. `1320 x 920` or `2024 x 1024`) even though the model was trained on much smaller images (`384 x 384`). Since we are using a fully convolutional model, we can also increase our input image size (e.g. `1024 x 1024`) without any trade-off, as it won't affect the model weights. You can find the **training noteobook** [here](https://www.kaggle.com/code/awsaf49/sennet-hoa-kerascv-starter-notebook-train).","metadata":{}},{"cell_type":"markdown","source":"# 🛠 | Install Libraries  \n\nSince internet access is **disabled** during inference, we cannot install libraries in the usual `!pip install <lib_name>` manner. Instead, we need to install libraries from local files. In the following cell, we will install libraries from our local files. The installation code stays very similar - we just use the `filepath` instead of the `filename` of the library. So now the code is `!pip install <local_filepath>`. \n\n> The `filepath` of these local libraries look quite complicated, but don't be intimidated! Also `--no-deps` argument ensures that we are not installing any additional libraries.","metadata":{"papermill":{"duration":0.011416,"end_time":"2024-01-14T03:16:16.470167","exception":false,"start_time":"2024-01-14T03:16:16.458751","status":"completed"},"tags":[]}},{"cell_type":"code","source":"!pip install -q /kaggle/input/kerasv3-lib-ds/keras_cv-0.8.1-py3-none-any.whl --no-deps\n!pip install -q /kaggle/input/kerasv3-lib-ds/tensorflow-2.15.0.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl --no-deps\n!pip install -q /kaggle/input/kerasv3-lib-ds/keras-3.0.2-py3-none-any.whl --no-deps\n!pip install -q /kaggle/input/kerasv3-lib-ds/tensorflow_io-0.35.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl --no-deps","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-01-19T18:35:11.459921Z","iopub.execute_input":"2024-01-19T18:35:11.460785Z","iopub.status.idle":"2024-01-19T18:37:24.466213Z","shell.execute_reply.started":"2024-01-19T18:35:11.460748Z","shell.execute_reply":"2024-01-19T18:37:24.465132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📚 | Import Libraries ","metadata":{"papermill":{"duration":0.010878,"end_time":"2024-01-14T03:17:49.510159","exception":false,"start_time":"2024-01-14T03:17:49.499281","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import os\nos.environ[\"KERAS_BACKEND\"] = \"jax\" # you can also use tensorflow or torch\n\nimport keras\nfrom keras import ops\nimport keras_cv\nimport tensorflow as tf\nimport tensorflow_io as tfio\n\nimport cv2\nimport pandas as pd\nimport numpy as np\nfrom glob import glob\nfrom tqdm.notebook import tqdm\nimport gc\n\nimport matplotlib.pyplot as plt ","metadata":{"papermill":{"duration":10.671979,"end_time":"2024-01-14T03:18:00.193134","exception":false,"start_time":"2024-01-14T03:17:49.521155","status":"completed"},"tags":[],"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-01-19T18:37:24.468481Z","iopub.execute_input":"2024-01-19T18:37:24.469186Z","iopub.status.idle":"2024-01-19T18:37:34.021836Z","shell.execute_reply.started":"2024-01-19T18:37:24.469146Z","shell.execute_reply":"2024-01-19T18:37:34.021049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Library Versions","metadata":{"papermill":{"duration":0.010958,"end_time":"2024-01-14T03:18:00.215704","exception":false,"start_time":"2024-01-14T03:18:00.204746","status":"completed"},"tags":[]}},{"cell_type":"code","source":"print(\"TensorFlow:\", tf.__version__)\nprint(\"Keras:\", keras.__version__)\nprint(\"KerasCV:\", keras_cv.__version__)","metadata":{"papermill":{"duration":0.019435,"end_time":"2024-01-14T03:18:00.246368","exception":false,"start_time":"2024-01-14T03:18:00.226933","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.022947Z","iopub.execute_input":"2024-01-19T18:37:34.023454Z","iopub.status.idle":"2024-01-19T18:37:34.028381Z","shell.execute_reply.started":"2024-01-19T18:37:34.023428Z","shell.execute_reply":"2024-01-19T18:37:34.027405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ⚙️ | Configuration","metadata":{"papermill":{"duration":0.010922,"end_time":"2024-01-14T03:18:00.26855","exception":false,"start_time":"2024-01-14T03:18:00.257628","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class CFG:\n    verbose = 1  # Verbosity\n    seed = 42  # Random seed\n    preset = \"deeplab_v3_plus_resnet50_pascalvoc\"  # Name of pretrained models\n    image_size = [1024, 1024]  # Input image size\n    epochs = 15 # Training epochs\n    batch_size = 12  # Batch size\n    drop_remainder = True  # Drop incomplete batches\n    num_classes = 1\n    cache = True\n    ckpt_dir = \"/kaggle/input/sennet-hoa-kerascv-starter-notebook-train\" # Folder of ckpt","metadata":{"papermill":{"duration":0.018795,"end_time":"2024-01-14T03:18:00.298534","exception":false,"start_time":"2024-01-14T03:18:00.279739","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.030972Z","iopub.execute_input":"2024-01-19T18:37:34.031635Z","iopub.status.idle":"2024-01-19T18:37:34.052249Z","shell.execute_reply.started":"2024-01-19T18:37:34.031608Z","shell.execute_reply":"2024-01-19T18:37:34.051405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ♻️ | Reproducibility \nSets value for random seed to produce similar result in each run.","metadata":{"papermill":{"duration":0.010907,"end_time":"2024-01-14T03:18:00.32063","exception":false,"start_time":"2024-01-14T03:18:00.309723","status":"completed"},"tags":[]}},{"cell_type":"code","source":"keras.utils.set_random_seed(CFG.seed)","metadata":{"papermill":{"duration":0.018371,"end_time":"2024-01-14T03:18:00.350074","exception":false,"start_time":"2024-01-14T03:18:00.331703","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.053416Z","iopub.execute_input":"2024-01-19T18:37:34.053998Z","iopub.status.idle":"2024-01-19T18:37:34.06203Z","shell.execute_reply.started":"2024-01-19T18:37:34.053966Z","shell.execute_reply":"2024-01-19T18:37:34.061147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📁 | Dataset Path ","metadata":{"papermill":{"duration":0.010888,"end_time":"2024-01-14T03:18:00.372053","exception":false,"start_time":"2024-01-14T03:18:00.361165","status":"completed"},"tags":[]}},{"cell_type":"code","source":"BASE_PATH = \"/kaggle/input/blood-vessel-segmentation\"","metadata":{"papermill":{"duration":0.017704,"end_time":"2024-01-14T03:18:00.400852","exception":false,"start_time":"2024-01-14T03:18:00.383148","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.063111Z","iopub.execute_input":"2024-01-19T18:37:34.063399Z","iopub.status.idle":"2024-01-19T18:37:34.072051Z","shell.execute_reply.started":"2024-01-19T18:37:34.063376Z","shell.execute_reply":"2024-01-19T18:37:34.071314Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📖 | Metadata\n\nAs the actual test data is hidden and we have only access to few files, to properly infer using 2.5D method we will upsample the test data. But, after `submission` when we encounter actual dataset we will not upsample the test data.","metadata":{"papermill":{"duration":0.011434,"end_time":"2024-01-14T03:18:00.472401","exception":false,"start_time":"2024-01-14T03:18:00.460967","status":"completed"},"tags":[]}},{"cell_type":"code","source":"image_paths = sorted(glob(f\"{BASE_PATH}/test/*/images/*tif\"))\ntest_df = pd.DataFrame({\"image_path\":image_paths})\ntest_df['dataset'] = test_df.image_path.map(lambda x: x.split('/')[-3])\ntest_df['slice'] = test_df.image_path.map(lambda x: x.split('/')[-1].replace(\".tif\",\"\"))\ntest_df[\"id\"] = test_df[\"dataset\"] + \"_\" + test_df[\"slice\"]\n\n# Upsample test data when we are comitting only (not submitting)\nif len(test_df) < 7:\n    test_df = test_df.sample(18, replace=True) \n    test_df = test_df.sort_values(by=[\"dataset\",\"slice\"]).reset_index(drop=True)\n    \ntest_df.head()","metadata":{"papermill":{"duration":0.86264,"end_time":"2024-01-14T03:18:01.346487","exception":false,"start_time":"2024-01-14T03:18:00.483847","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.073241Z","iopub.execute_input":"2024-01-19T18:37:34.073629Z","iopub.status.idle":"2024-01-19T18:37:34.120285Z","shell.execute_reply.started":"2024-01-19T18:37:34.073599Z","shell.execute_reply":"2024-01-19T18:37:34.119481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Updating for 2.5D Data\n\nIn this notebook, we will use `2.5D` images. So what exactly are `2.5D` images?\n\n- `2.5D` is a method that uses the channel dimension to encode temporal information. \n- Specifically, each channel contains a 2D slice from the 3D volume.\n- This allows us to leverage pretrained 2D models, unlike pure 3D approaches. \n- But unlike pure 2D, we gain spatial context across adjacent slices.\n- In our notebook, we will use `3` `CHANNELS` that are spaced `3` slices (`STRIDES`) apart from each other.","metadata":{"papermill":{"duration":0.011802,"end_time":"2024-01-14T03:18:01.370567","exception":false,"start_time":"2024-01-14T03:18:01.358765","status":"completed"},"tags":[]}},{"cell_type":"code","source":"CHANNELS = 3 # take 3 slices to use \"ImageNet\" weights which require 3 channels\nSTRIDE = 3 # gap between each 2D slice\n\nfor i in range(CHANNELS):\n    test_df[f'image_path_{i:02}'] = test_df.groupby(['dataset'])['image_path'].shift(-i*STRIDE).ffill()\ntest_df['image_paths'] = test_df[[f'image_path_{i:02d}' for i in range(CHANNELS)]].values.tolist()\ntest_df.image_paths[0]","metadata":{"papermill":{"duration":0.051334,"end_time":"2024-01-14T03:18:01.433862","exception":false,"start_time":"2024-01-14T03:18:01.382528","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.121271Z","iopub.execute_input":"2024-01-19T18:37:34.121561Z","iopub.status.idle":"2024-01-19T18:37:34.139067Z","shell.execute_reply.started":"2024-01-19T18:37:34.121539Z","shell.execute_reply":"2024-01-19T18:37:34.138277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🍚 | DataLoader\n\nThis dataloader reads 3 `.tif` image files and stacks them along the channel dimension. It then applies `MinMax` scaling to normalize the values.","metadata":{"papermill":{"duration":0.011843,"end_time":"2024-01-14T03:18:01.457956","exception":false,"start_time":"2024-01-14T03:18:01.446113","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def build_decoder(with_labels=True, target_size=CFG.image_size, augment=False):\n    def decode_image(paths):\n        img_array = tf.TensorArray(dtype=tf.uint8, size=len(paths))\n        for i in range(len(paths)):\n            file_bytes = tf.io.read_file(paths[i])\n            img0 = tfio.experimental.image.decode_tiff(file_bytes)[..., 0]\n            img_array = img_array.write(i, img0)\n        img = tf.transpose(img_array.stack(), perm=(1, 2, 0))\n        img = tf.cast(img, tf.float32)\n        img -= tf.reduce_min(img)\n        img /= tf.reduce_max(img) + 0.001\n        del img_array\n        return img\n    \n    def decode_mask(mask_path):\n        file_bytes = tf.io.read_file(mask_path)\n        msk = tfio.experimental.image.decode_tiff(file_bytes)[...,0:1]\n        msk = tf.cast(msk, tf.float32) / 255.0\n        return msk\n\n    def decode_without_labels(img_path):\n        img = decode_image(img_path)\n        return img\n    \n    def decode_with_labels(img_path, msk_path):\n        img_msk = tf.concat([decode_image(img_path), decode_mask(msk_path)], axis=-1)\n        img_msk = tf.image.random_crop(img_msk, [*target_size, 4])\n        if augment:\n            img_msk = apply_augmentations(img_msk)\n        img = tf.reshape(img_msk[...,0:3], [*target_size, 3])\n        msk = tf.reshape(img_msk[...,3:4], [*target_size, 1])\n        return (img, msk)\n    \n    def apply_augmentations(img):\n        img = tf.image.random_flip_left_right(img)\n        img = tf.image.random_flip_up_down(img)\n        img = tf.image.rot90(img, k=np.random.randint(-3, 3))\n        return img\n    \n    return decode_with_labels if with_labels else decode_without_labels\n\n\ndef build_dataset(img_paths, msk_paths=None, batch_size=32, cache=True,\n                  decode_fn=None, augment_fn=None,\n                  augment=True, repeat=True, shuffle=1024, \n                  cache_dir=\"\", drop_remainder=False):\n    if cache_dir != \"\" and cache is True:\n        os.makedirs(cache_dir, exist_ok=True)\n    \n    if decode_fn is None:\n        decode_fn = build_decoder(msk_paths is not None, augment=augment)\n    \n    AUTO = tf.data.experimental.AUTOTUNE\n    slices = img_paths if msk_paths is None else (img_paths, msk_paths)\n    \n    ds = tf.data.Dataset.from_tensor_slices(slices)\n    ds = ds.map(decode_fn, num_parallel_calls=AUTO)\n    ds = ds.cache(cache_dir) if cache else ds\n    ds = ds.repeat() if repeat else ds\n    if shuffle: \n        ds = ds.shuffle(shuffle, seed=CFG.seed)\n        opt = tf.data.Options()\n        opt.experimental_deterministic = False\n        ds = ds.with_options(opt)\n    ds = ds.batch(batch_size, drop_remainder=drop_remainder)\n    ds = ds.prefetch(AUTO)\n    return ds","metadata":{"papermill":{"duration":0.039133,"end_time":"2024-01-14T03:18:01.509017","exception":false,"start_time":"2024-01-14T03:18:01.469884","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.140597Z","iopub.execute_input":"2024-01-19T18:37:34.140933Z","iopub.status.idle":"2024-01-19T18:37:34.15825Z","shell.execute_reply.started":"2024-01-19T18:37:34.140903Z","shell.execute_reply":"2024-01-19T18:37:34.157544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Build Test Dataset\n\nWe are using `batch_size = 1` as we will be using **sliding window** mechanism on each images.","metadata":{"papermill":{"duration":0.011875,"end_time":"2024-01-14T03:18:01.611955","exception":false,"start_time":"2024-01-14T03:18:01.60008","status":"completed"},"tags":[]}},{"cell_type":"code","source":"test_image_paths = test_df.image_paths.tolist()\ntest_ds = build_dataset(test_image_paths, batch_size=1,\n                         cache=False, repeat=False, shuffle=False, augment=False)","metadata":{"papermill":{"duration":1.049545,"end_time":"2024-01-14T03:18:02.673433","exception":false,"start_time":"2024-01-14T03:18:01.623888","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.161536Z","iopub.execute_input":"2024-01-19T18:37:34.161776Z","iopub.status.idle":"2024-01-19T18:37:34.668718Z","shell.execute_reply.started":"2024-01-19T18:37:34.161755Z","shell.execute_reply":"2024-01-19T18:37:34.667861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset Check","metadata":{"papermill":{"duration":0.011529,"end_time":"2024-01-14T03:18:02.697067","exception":false,"start_time":"2024-01-14T03:18:02.685538","status":"completed"},"tags":[]}},{"cell_type":"code","source":"img = test_ds.take(1).get_single_element()\nplt.imshow(img[0])","metadata":{"papermill":{"duration":35.790198,"end_time":"2024-01-14T03:18:38.498991","exception":false,"start_time":"2024-01-14T03:18:02.708793","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:34.66982Z","iopub.execute_input":"2024-01-19T18:37:34.670105Z","iopub.status.idle":"2024-01-19T18:37:35.451705Z","shell.execute_reply.started":"2024-01-19T18:37:34.670081Z","shell.execute_reply":"2024-01-19T18:37:35.450748Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🤖 | Modeling","metadata":{"papermill":{"duration":0.016849,"end_time":"2024-01-14T03:18:38.613991","exception":false,"start_time":"2024-01-14T03:18:38.597142","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## Build Segmentation `Head`\n\nAs our pretrained `DeepLabV3+` model is trained on the `PASCAL VOC` dataset which contained `21` classes, we need to modify it for our dataset which contains only `1` class. Therefore, we will only use the pretrained weights for the layers before the segmentation `Head`, and declare a new `Head` layer suited for our dataset. \n\n> Note that we are using a `sigmoid` activation for the final layer, whereas the original model used `softmax` activation.","metadata":{"papermill":{"duration":0.015693,"end_time":"2024-01-14T03:18:38.645855","exception":false,"start_time":"2024-01-14T03:18:38.630162","status":"completed"},"tags":[]}},{"cell_type":"code","source":"segmentation_head = keras.Sequential(\n    [\n        keras.layers.Conv2D(\n            filters=32,\n            kernel_size=1,\n            padding=\"same\",\n            use_bias=False,\n        ),\n        keras.layers.BatchNormalization(),\n        keras.layers.ReLU(),\n        keras.layers.UpSampling2D(size=(4, 4), interpolation=\"bilinear\"),\n        keras.layers.Conv2D(\n            filters=CFG.num_classes,\n            kernel_size=1,\n            use_bias=False,\n            padding=\"same\",\n            activation=\"sigmoid\",\n            dtype=\"float32\",\n        ),\n    ], name=\"segmentation_head\",\n)","metadata":{"papermill":{"duration":0.029818,"end_time":"2024-01-14T03:18:38.691799","exception":false,"start_time":"2024-01-14T03:18:38.661981","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2024-01-19T18:37:35.452791Z","iopub.execute_input":"2024-01-19T18:37:35.453046Z","iopub.status.idle":"2024-01-19T18:37:35.463228Z","shell.execute_reply.started":"2024-01-19T18:37:35.453023Z","shell.execute_reply":"2024-01-19T18:37:35.462317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Build and Load trained `Model`","metadata":{"papermill":{"duration":0.0158,"end_time":"2024-01-14T03:18:38.723891","exception":false,"start_time":"2024-01-14T03:18:38.708091","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Load the full DeepLabV3+ model\nbackbone = keras_cv.models.DeepLabV3Plus.from_preset(\n    CFG.preset,\n    input_shape=[*CFG.image_size, 3],\n)\n\n# Take only layers from backbone before head\nneck_layer_name = backbone.layers[-2].name\nout = backbone.get_layer(neck_layer_name).output\n\n# Use newly defined head for segmentation\nout = segmentation_head(out)\n\n# Create a new model\nmodel = keras.models.Model(inputs=backbone.input, outputs=out)\n\n# Load best model weights\nmodel.load_weights(f\"{CFG.ckpt_dir}/best_model.keras\")\n\n# Model Sumamry\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-01-19T18:37:35.464217Z","iopub.execute_input":"2024-01-19T18:37:35.464533Z","iopub.status.idle":"2024-01-19T18:37:56.177582Z","shell.execute_reply.started":"2024-01-19T18:37:35.464509Z","shell.execute_reply":"2024-01-19T18:37:56.176711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🧪 | Prediction","metadata":{"papermill":{"duration":0.693309,"end_time":"2024-01-14T04:15:05.731839","exception":false,"start_time":"2024-01-14T04:15:05.03853","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## Utilites","metadata":{}},{"cell_type":"code","source":"def rle_encode(mask):\n    \"\"\"Encodes a mask into RLE format for submission.\"\"\"\n\n    pixel = mask.flatten()\n    pixel = np.concatenate([[0], pixel, [0]])\n    run = np.where(pixel[1:] != pixel[:-1])[0] + 1\n    run[1::2] -= run[::2]\n    rle = \" \".join(str(r) for r in run)\n    if rle == \"\":\n        rle = \"1 0\"\n    return rle\n\n\ndef apply_tta(window):\n    \"\"\"Applies test time augmentations to a window.\"\"\"\n\n    window_tta = []\n    window_tta.append(window)\n    window_tta.append(window[:, ::-1, :, :])\n    window_tta.append(window[:, :, ::-1, :])\n    window_tta.append(window[:, ::-1, ::-1, :])\n    return ops.concatenate(window_tta, axis=0)\n\n\ndef reverse_tta(window):\n    \"\"\"Reverses test time augmentations and aggregates predictions.\"\"\"\n\n    window[0] = window[0]\n    window[1] = window[1, ::-1, :, :]\n    window[2] = window[2, :, ::-1, :]\n    window[3] = window[3, ::-1, ::-1, :]\n    return window.mean(axis=0)\n\n\ndef pad_image(img):\n    \"\"\"Pads an image to be divisible by 32 for model.\"\"\"\n\n    # Pad height\n    PAD_H = (32 - img.shape[1] % 32) % 32\n    PAD_H = [PAD_H // 2, PAD_H // 2 + PAD_H % 2]\n\n    # Pad width\n    PAD_W = (32 - img.shape[2] % 32) % 32\n    PAD_W = [PAD_W // 2, PAD_W // 2 + PAD_W % 2]\n\n    img = ops.pad(\n        img,\n        ((0, 0), (PAD_H[0], PAD_H[1]), (PAD_W[0], PAD_W[1]), (0, 0)),\n        mode=\"constant\",\n    )\n    return img, PAD_H, PAD_W\n\n\ndef unpad_image(img, PAD_H, PAD_W):\n    \"\"\"Remove padding from image after inference .\"\"\"\n\n    if PAD_H[1] > 0 and PAD_W[1] > 0:\n        img = img[PAD_H[0] : -PAD_H[1], PAD_W[0] : -PAD_W[1]]\n    elif PAD_H[1] > 0:\n        img = img[PAD_H[0] : -PAD_H[1], :]\n    elif PAD_W[1] > 0:\n        img = img[:, PAD_W[0] : -PAD_W[1]]\n    else:\n        img = img\n\n    return img","metadata":{"execution":{"iopub.status.busy":"2024-01-19T18:37:56.178832Z","iopub.execute_input":"2024-01-19T18:37:56.179492Z","iopub.status.idle":"2024-01-19T18:37:56.193767Z","shell.execute_reply.started":"2024-01-19T18:37:56.179455Z","shell.execute_reply":"2024-01-19T18:37:56.192797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Infer Using Sliding Window","metadata":{}},{"cell_type":"code","source":"THR = 0.1 # threshold for converting prediction to binary mask\nWIN_SIZE = CFG.image_size[0] # size of the sliding window\nSTRIDE = CFG.image_size[0] // 2 # steps between two windows\n\nresult_imgs = []\nresult_msks = []\nrles = []\n\nfor img in tqdm(test_ds, total=len(test_df)):\n\n    img = ops.convert_to_tensor(img)\n    msk = np.zeros_like(img[0, ..., 0], dtype=\"uint8\")\n\n    # Sliding through the image\n    for i in range(0, img.shape[1] - WIN_SIZE + STRIDE, STRIDE):\n        for j in range(0, img.shape[2] - WIN_SIZE + STRIDE, STRIDE):\n\n            # Extract window\n            window = img[:, i : i + WIN_SIZE, j : j + WIN_SIZE, :]\n\n            # Apply padding so that image is divisible by 32\n            window_padded, PAD_H, PAD_W = pad_image(window)\n\n            # Apply test time augmentations\n            window_padded = apply_tta(window_padded)\n\n            # Make prediction\n            preds_padded = model.predict(window_padded, verbose=0)\n\n            # Reverse test time augmentations and merge predictions\n            preds_padded = reverse_tta(preds_padded).squeeze()\n\n            # Remove padding from predictions\n            preds = unpad_image(preds_padded, PAD_H, PAD_W)\n\n            # Store predictions as mask\n            msk[i : i + WIN_SIZE, j : j + WIN_SIZE] += (preds > THR).astype(\n                \"uint8\"\n            )\n\n            # Delete intermediate variables\n            del window, window_padded, preds, preds_padded\n            gc.collect()\n\n    # Binarize final mask\n    msk = (msk > 0).astype(\"uint8\")\n\n    # Encode mask into RLE format for submission\n    rles.append(rle_encode(msk))\n\n    # Save first two images and masks\n    if len(result_imgs) < 2:\n        result_imgs.append(img)\n        result_msks.append(msk)\n\n    # Delete intermediate variables\n    del img, msk\n    gc.collect()","metadata":{"execution":{"iopub.status.busy":"2024-01-19T18:39:18.115683Z","iopub.execute_input":"2024-01-19T18:39:18.116034Z","iopub.status.idle":"2024-01-19T18:39:44.392719Z","shell.execute_reply.started":"2024-01-19T18:39:18.116009Z","shell.execute_reply":"2024-01-19T18:39:44.391835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n\n\n\n## Check Prediction","metadata":{}},{"cell_type":"code","source":"for idx in range(2):\n    plt.figure(figsize=(8, 6))\n    \n    plt.subplot(121)\n    plt.imshow(result_imgs[idx].squeeze())\n\n    plt.subplot(122)\n    plt.imshow(result_msks[idx].squeeze())\n\n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-01-19T18:39:44.394173Z","iopub.execute_input":"2024-01-19T18:39:44.394529Z","iopub.status.idle":"2024-01-19T18:39:45.867037Z","shell.execute_reply.started":"2024-01-19T18:39:44.394503Z","shell.execute_reply":"2024-01-19T18:39:45.866158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📩 | Submission","metadata":{}},{"cell_type":"code","source":"test_df['rle'] = rles\nsub_df = test_df[[\"id\",\"rle\"]].copy()\nsub_df.to_csv(\"submission.csv\",index=False)\nsub_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-01-19T18:39:45.868332Z","iopub.execute_input":"2024-01-19T18:39:45.868733Z","iopub.status.idle":"2024-01-19T18:39:45.882836Z","shell.execute_reply.started":"2024-01-19T18:39:45.868698Z","shell.execute_reply":"2024-01-19T18:39:45.881917Z"},"trusted":true},"execution_count":null,"outputs":[]}]}