{"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":"code","source":"print(\"\\n... IMPORTS STARTING ...\\n\")\n\nprint(\"\\n... PIP/APT INSTALLS AND DOWNLOADS/ZIP STARTING ...\")\n!pip install -q pandarallel\n!pip install -q tensorflow_model_optimization\n!pip install -q --upgrade tensorflow_datasets\n!pip install -q neural-structured-learning\nprint(\"... PIP/APT INSTALLS COMPLETE ...\\n\")\n\nprint(\"\\n\\tVERSION INFORMATION\")\n# Machine Learning and Data Science Imports\nimport tensorflow as tf; print(f\"\\t\\t– TENSORFLOW VERSION: {tf.__version__}\");\nimport tensorflow_addons as tfa; print(f\"\\t\\t– TENSORFLOW ADDONS VERSION: {tfa.__version__}\");\nimport pandas as pd; pd.options.mode.chained_assignment = None;\nimport numpy as np; print(f\"\\t\\t– NUMPY VERSION: {np.__version__}\");\nimport sklearn; print(f\"\\t\\t– SKLEARN VERSION: {sklearn.__version__}\");\nfrom sklearn.preprocessing import RobustScaler, PolynomialFeatures\nfrom pandarallel import pandarallel; pandarallel.initialize();\nfrom sklearn.model_selection import GroupKFold;\n\n# Built In Imports\nfrom kaggle_datasets import KaggleDatasets\nfrom collections import Counter\nfrom datetime import datetime\nfrom glob import glob\nimport warnings\nimport requests\nimport hashlib\nimport imageio\nimport IPython\nimport sklearn\nimport urllib\nimport zipfile\nimport pickle\nimport random\nimport shutil\nimport string\nimport json\nimport math\nimport time\nimport gzip\nimport ast\nimport sys\nimport io\nimport os\nimport gc\nimport re\n\n# Visualization Imports\nfrom matplotlib.colors import ListedColormap\nimport matplotlib.patches as patches\nimport plotly.graph_objects as go\nimport matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm; tqdm.pandas();\nimport plotly.express as px\nimport seaborn as sns\nfrom PIL import Image, ImageEnhance\nimport matplotlib; print(f\"\\t\\t– MATPLOTLIB VERSION: {matplotlib.__version__}\");\nimport plotly\nimport PIL\nimport cv2\n\n\ndef seed_it_all(seed=7):\n    \"\"\" Attempt to be Reproducible \"\"\"\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    random.seed(seed)\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n\n    \nprint(\"\\n\\n... IMPORTS COMPLETE ...\\n\")\n    \nprint(\"\\n... EFFICIENTDET SETUP STARTING ...\")\n\n# SET LIBRARY DIRECTORY\nLIB_DIR = \"/kaggle/input/google-automl-efficientdetefficientnet-oct-2021\"\n\n# To give access to automl files\nsys.path.insert(0, LIB_DIR)\nsys.path.insert(0, os.path.join(LIB_DIR, \"automl-master\"))\nsys.path.insert(0, os.path.join(LIB_DIR, \"automl-master\", \"efficientdet\"))\nsys.path.insert(0, os.path.join(LIB_DIR, \"automl-master\", \"efficientdet\", \"tf2\"))\n    ","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:21:21.902899Z","iopub.execute_input":"2021-11-01T23:21:21.903233Z","iopub.status.idle":"2021-11-01T23:22:05.166728Z","shell.execute_reply.started":"2021-11-01T23:21:21.903147Z","shell.execute_reply":"2021-11-01T23:22:05.165848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# The name you gave to the TPU to use\nTPU_WORKER = 'my-tpu-name'\n\n# or you can also specify the grpc path directly\n# TPU_WORKER = 'grpc://xxx.xxx.xxx.xxx:8470'\n\n# The zone you chose when you created the TPU to use on GCP.\nZONE = 'us-east1-b'\n\n# The name of the GCP project where you created the TPU to use on GCP.\nPROJECT = 'my-tpu-project'\n\ntpu = tf.distribute.cluster_resolver.TPUClusterResolver(tpu=TPU_WORKER, zone=ZONE, project=PROJECT)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:05.168545Z","iopub.execute_input":"2021-11-01T23:22:05.168964Z","iopub.status.idle":"2021-11-01T23:22:05.175353Z","shell.execute_reply.started":"2021-11-01T23:22:05.168926Z","shell.execute_reply":"2021-11-01T23:22:05.174658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"\\n... ACCELERATOR SETUP STARTING ...\\n\")\n\n# Detect hardware, return appropriate distribution strategy\ntry:\n    # TPU detection. No parameters necessary if TPU_NAME environment variable is set. On Kaggle this is always the case.\n    TPU = tf.distribute.cluster_resolver.TPUClusterResolver()  \nexcept ValueError:\n    TPU = None\n\nif TPU:\n    print(f\"\\n... RUNNING ON TPU - {TPU.master()}...\")\n    tf.config.experimental_connect_to_cluster(TPU)\n    tf.tpu.experimental.initialize_tpu_system(TPU)\n    strategy = tf.distribute.experimental.TPUStrategy(TPU)\nelse:\n    print(f\"\\n... RUNNING ON CPU/GPU ...\")\n    # Yield the default distribution strategy in Tensorflow\n    #   --> Works on CPU and single GPU.\n    strategy = tf.distribute.get_strategy() \n\n# What Is a Replica?\n#    --> A single Cloud TPU device consists of FOUR chips, each of which has TWO TPU cores. \n#    --> Therefore, for efficient utilization of Cloud TPU, a program should make use of each of the EIGHT (4x2) cores. \n#    --> Each replica is essentially a copy of the training graph that is run on each core and \n#        trains a mini-batch containing 1/8th of the overall batch size\nN_REPLICAS = strategy.num_replicas_in_sync\n    \nprint(f\"... # OF REPLICAS: {N_REPLICAS} ...\\n\")\n\nprint(f\"\\n... ACCELERATOR SETUP COMPLTED ...\\n\")","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:05.176230Z","iopub.execute_input":"2021-11-01T23:22:05.176461Z","iopub.status.idle":"2021-11-01T23:22:05.201245Z","shell.execute_reply.started":"2021-11-01T23:22:05.176430Z","shell.execute_reply":"2021-11-01T23:22:05.200521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"\\n... DATA ACCESS SETUP STARTED ...\\n\")\n\nif TPU:\n    # Google Cloud Dataset path to training and validation images\n    DATA_DIR = KaggleDatasets().get_gcs_path('sartorius-cell-instance-segmentation')\n    save_locally = tf.saved_model.SaveOptions(experimental_io_device='/job:localhost')\nelse:\n    # Local path to training and validation images\n    DATA_DIR = \"/kaggle/input/sartorius-cell-instance-segmentation\"\n    save_locally = None\n    \nprint(f\"\\n... DATA DIRECTORY PATH IS:\\n\\t--> {DATA_DIR}\")\n\nprint(f\"\\n... IMMEDIATE CONTENTS OF DATA DIRECTORY IS:\")\nfor file in tf.io.gfile.glob(os.path.join(DATA_DIR, \"*\")): print(f\"\\t--> {file}\")\n\n    \nprint(\"\\n\\n... DATA ACCESS SETUP COMPLETED ...\\n\")","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:05.202432Z","iopub.execute_input":"2021-11-01T23:22:05.202670Z","iopub.status.idle":"2021-11-01T23:22:05.217353Z","shell.execute_reply.started":"2021-11-01T23:22:05.202637Z","shell.execute_reply":"2021-11-01T23:22:05.216710Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"\\n... XLA OPTIMIZATIONS STARTING ...\\n\")\n\nprint(f\"\\n... CONFIGURE JIT (JUST IN TIME) COMPILATION ...\\n\")\n# enable XLA optmizations (10% speedup when using @tf.function calls)\ntf.config.optimizer.set_jit(True)\n\nprint(f\"\\n... XLA OPTIMIZATIONS COMPLETED ...\\n\")","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:05.219342Z","iopub.execute_input":"2021-11-01T23:22:05.219515Z","iopub.status.idle":"2021-11-01T23:22:05.407716Z","shell.execute_reply.started":"2021-11-01T23:22:05.219494Z","shell.execute_reply":"2021-11-01T23:22:05.406979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## تعريفات البيانات الأساسية وتهيئتها","metadata":{}},{"cell_type":"code","source":"print(\"\\n... BASIC DATA SETUP STARTING ...\\n\\n\")\n\nprint(\"\\n... SET PATH INFORMATION ..\\n\")\nSEG_DIR = \"/kaggle/input/sartorius-segmentation-train-mask-dataset-npz\"\nLC_DIR = os.path.join(DATA_DIR, \"LIVECell_dataset_2021\")\nLC_ANN_DIR = os.path.join(LC_DIR, \"annotations\")\nLC_IMG_DIR = os.path.join(LC_DIR, \"images\")\nTRAIN_DIR = os.path.join(DATA_DIR, \"train\")\nTEST_DIR = os.path.join(DATA_DIR, \"test\")\nSEMI_DIR = os.path.join(DATA_DIR, \"train_semi_supervised\")\n\nprint(\"\\n... TRAIN DATAFRAME ...\\n\")\n\n# FIX THE TRAIN DATAFRAME (GROUP THE RLEs TOGETHER)\nTRAIN_CSV = os.path.join(DATA_DIR, \"train.csv\")\ntrain_df = pd.read_csv(TRAIN_CSV)\ndisplay(train_df)\n\nprint(\"\\n... SS DATAFRAME ..\\n\")\nSS_CSV = os.path.join(DATA_DIR, \"sample_submission.csv\")\nss_df = pd.read_csv(SS_CSV)\nss_df[\"img_path\"] = ss_df[\"id\"].apply(lambda x: os.path.join(TEST_DIR, x+\".png\")) # Capture Image Path As Well\ndisplay(ss_df)\n\nCELL_TYPES = list(train_df.cell_type.unique())\nFIRST_SHSY5Y_IDX = 0\nFIRST_ASTRO_IDX  = 1\nFIRST_CORT_IDX   = 2\n\n# This is required for plotting so that the smaller distributions get plotted on top\nARB_SORT_MAP = {\"astro\":0, \"shsy5y\":1, \"cort\":2}\n\nprint(\"\\n... CELL TYPES ..\")\nfor x in CELL_TYPES: print(f\"\\t--> {x}\")\n    \nprint(\"\\n\\n... BASIC DATA SETUP FINISHING ...\\n\")","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:05.409053Z","iopub.execute_input":"2021-11-01T23:22:05.409474Z","iopub.status.idle":"2021-11-01T23:22:05.959414Z","shell.execute_reply.started":"2021-11-01T23:22:05.409436Z","shell.execute_reply":"2021-11-01T23:22:05.958738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### وظائف وفصول المساعد","metadata":{}},{"cell_type":"code","source":"# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\n# modified from: https://www.kaggle.com/inversion/run-length-decoding-quick-start\ndef rle_decode(mask_rle, shape, color=1):\n    \"\"\" TBD\n    \n    Args:\n        mask_rle (str): run-length as string formated (start length)\n        shape (tuple of ints): (height,width) of array to return \n    \n    Returns: \n        Mask (np.array)\n            - 1 indicating mask\n            - 0 indicating background\n\n    \"\"\"\n    # Split the string by space, then convert it into a integer array\n    s = np.array(mask_rle.split(), dtype=int)\n\n    # Every even value is the start, every odd value is the \"run\" length\n    starts = s[0::2] - 1\n    lengths = s[1::2]\n    ends = starts + lengths\n\n    # The image image is actually flattened since RLE is a 1D \"run\"\n    if len(shape)==3:\n        h, w, d = shape\n        img = np.zeros((h * w, d), dtype=np.float32)\n    else:\n        h, w = shape\n        img = np.zeros((h * w,), dtype=np.float32)\n\n    # The color here is actually just any integer you want!\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = color\n        \n    # Don't forget to change the image back to the original shape\n    return img.reshape(shape)\n\n# https://www.kaggle.com/namgalielei/which-reshape-is-used-in-rle\ndef rle_decode_top_to_bot_first(mask_rle, shape):\n    \"\"\" TBD\n    \n    Args:\n        mask_rle (str): run-length as string formated (start length)\n        shape (tuple of ints): (height,width) of array to return \n    \n    Returns:\n        Mask (np.array)\n            - 1 indicating mask\n            - 0 indicating background\n\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[1], shape[0]), order='F').T  # Reshape from top -> bottom first\n\n# ref.: https://www.kaggle.com/stainsby/fast-tested-rle\ndef rle_encode(img):\n    \"\"\" TBD\n    \n    Args:\n        img (np.array): \n            - 1 indicating mask\n            - 0 indicating background\n    \n    Returns: \n        run length as string formated\n    \"\"\"\n    \n    pixels = img.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\n\ndef flatten_l_o_l(nested_list):\n    \"\"\" Flatten a list of lists \"\"\"\n    return [item for sublist in nested_list for item in sublist]\n\n\ndef load_json_to_dict(json_path):\n    \"\"\" tbd \"\"\"\n    with open(json_path) as json_file:\n        data = json.load(json_file)\n    return data\n\n# https://github.com/PyImageSearch/imutils/blob/master/imutils/convenience.py\ndef grab_contours(cnts):\n    \"\"\" TBD \"\"\"\n    \n    # if the length the contours tuple returned by cv2.findContours\n    # is '2' then we are using either OpenCV v2.4, v4-beta, or\n    # v4-official\n    if len(cnts) == 2:\n        cnts = cnts[0]\n\n    # if the length of the contours tuple is '3' then we are using\n    # either OpenCV v3, v4-pre, or v4-alpha\n    elif len(cnts) == 3:\n        cnts = cnts[1]\n\n    # otherwise OpenCV has changed their cv2.findContours return\n    # signature yet again and I have no idea WTH is going on\n    else:\n        raise Exception((\"Contours tuple must have length 2 or 3, \"\n            \"otherwise OpenCV changed their cv2.findContours return \"\n            \"signature yet again. Refer to OpenCV's documentation \"\n            \"in that case\"))\n\n    # return the actual contours array\n    return cnts\n\ndef get_contour_bbox(msk):\n    \"\"\" Function to return the bounding box (tl, br) for a given mask \"\"\"\n    \n    # Get contour(s) --> There should be only one\n    cnts = cv2.findContours(msk.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n\n    contour = grab_contours(cnts)\n    \n    if len(contour)==0:\n        return None\n    else:\n        contour = contour[0]\n    \n    # Get extreme coordinates\n    tl = (tuple(contour[contour[:, :, 0].argmin()][0])[0], \n          tuple(contour[contour[:, :, 1].argmin()][0])[1])\n    br = (tuple(contour[contour[:, :, 0].argmax()][0])[0], \n          tuple(contour[contour[:, :, 1].argmax()][0])[1])\n    return tl, br\n\ndef tf_load_png(img_path):\n    return tf.image.decode_png(tf.io.read_file(img_path), channels=3)\n\ndef get_img_and_mask(img_path, annotation, width, height, mask_only=False, rle_fn=rle_decode):\n    \"\"\" Capture the relevant image array as well as the image mask \"\"\"\n    img_mask = np.zeros((height, width), dtype=np.uint8)\n    for i, annot in enumerate(annotation): \n        img_mask = np.where(rle_fn(annot, (height, width))!=0, i, img_mask)\n    \n    # Early Exit\n    if mask_only:\n        return img_mask\n    \n    # Else Return images\n    img = tf_load_png(img_path)[..., 0]\n    return img, img_mask\n\ndef plot_img_and_mask(img, mask, bboxes=None, invert_img=True, boost_contrast=True):\n    \"\"\" Function to take an image and the corresponding mask and plot\n    \n    Args:\n        img (np.arr): 1 channel np arr representing the image of cellular structures\n        mask (np.arr): 1 channel np arr representing the instance masks (incrementing by one)\n        bboxes (list of tuples, optional): (tl, br) coordinates of enclosing bboxes\n        invert_img (bool, optional): Whether or not to invert the base image\n        boost_contrast (bool, optional): Whether or not to boost contrast of the base image\n        \n    Returns:\n        None; Plots the two arrays and overlays them to create a merged image\n    \"\"\"\n    plt.figure(figsize=(20,10))\n    \n    plt.subplot(1,3,1)\n    _img = np.tile(np.expand_dims(img, axis=-1), 3)\n    \n    # Flip black-->white ... white-->black\n    if invert_img:\n        _img = _img.max()-_img\n    \n    if boost_contrast:\n        _img = np.asarray(ImageEnhance.Contrast(Image.fromarray(_img)).enhance(16))\n    \n    if bboxes:\n        for i, bbox in enumerate(bboxes):\n            mask = cv2.rectangle(mask, bbox[0], bbox[1], (i+1, 0, 0), thickness=2)\n    \n    plt.imshow(_img)\n    plt.axis(False)\n    plt.title(\"Cell Image\", fontweight=\"bold\")\n    \n    plt.subplot(1,3,2)\n    _mask = np.zeros_like(_img)\n    _mask[..., 0] = mask\n    plt.imshow(mask, cmap=\"inferno\")\n    plt.axis(False)\n    plt.title(\"Instance Segmentation Mask\", fontweight=\"bold\")\n    \n    merged = cv2.addWeighted(_img, 0.75, np.clip(_mask, 0, 1)*255, 0.25, 0.0,)\n    plt.subplot(1,3,3)\n    plt.imshow(merged)\n    plt.axis(False)\n    plt.title(\"Cell Image w/ Instance Segmentation Mask Overlay\", fontweight=\"bold\")\n    \n    plt.tight_layout()\n    plt.show()\n    \ndef pd_get_bboxes(row):\n    \"\"\" Get all bboxes for a given row/cell-image \"\"\"\n    mask = get_img_and_mask(row.img_path, row.annotation, row.width, row.height, mask_only=True)\n    return [get_contour_bbox(np.where(mask==i, 1, 0).astype(np.uint8)) for i in range(1, mask.max()+1)]\n\ndef get_bbox_stats(bbox_list, style=\"area\"): \n    \"\"\" TBD \n    \n    Args:\n        bbox_list(): TBD\n        style (str, optional): TBD\n    Returns:\n        TBD\n        \"\"\"\n    bbox_stats = []\n    for box in bbox_list:\n        try:\n            if style==\"area\":\n                bbox_stats.append(float((box[1][0]-box[0][0])*(box[1][1]-box[0][1])))\n            elif style==\"width\":\n                bbox_stats.append(float(box[1][0]-box[0][0]))\n            else:\n                bbox_stats.append(float(box[1][1]-box[0][1]))\n        except:\n            bbox_stats.append(0.0)\n    return bbox_stats","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:05.960868Z","iopub.execute_input":"2021-11-01T23:22:05.961520Z","iopub.status.idle":"2021-11-01T23:22:05.997334Z","shell.execute_reply.started":"2021-11-01T23:22:05.961489Z","shell.execute_reply":"2021-11-01T23:22:05.996579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## إنشاء واستكشاف قواعد البيانات","metadata":{}},{"cell_type":"markdown","source":"`# قم بتحديث إطار بيانات القطار `","metadata":{}},{"cell_type":"code","source":"# Aggregate under training \ntrain_df[\"img_path\"] = train_df[\"id\"].apply(lambda x: os.path.join(TRAIN_DIR, x+\".png\")) # Capture Image Path As Well\ntmp_df = train_df.drop_duplicates(subset=[\"id\", \"img_path\"]).reset_index(drop=True)\ntmp_df[\"annotation\"] = train_df.groupby(\"id\")[\"annotation\"].agg(list).reset_index(drop=True)\ntrain_df = tmp_df.copy()\ntrain_df[\"seg_path\"] = train_df.id.apply(lambda x: os.path.join(SEG_DIR, f\"{x}.npz\"))\ndisplay(train_df)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:05.998658Z","iopub.execute_input":"2021-11-01T23:22:05.998936Z","iopub.status.idle":"2021-11-01T23:22:06.239621Z","shell.execute_reply.started":"2021-11-01T23:22:05.998899Z","shell.execute_reply":"2021-11-01T23:22:06.238935Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## تصور بيانات القطار","metadata":{}},{"cell_type":"code","source":"for i in range(2, 70, 8):\n    print(f\"\\n\\n\\n\\n... RELEVANT DATAFRAME ROW - INDEX={i} ...\\n\")\n    display(train_df.iloc[i:i+1])\n    img, msk = get_img_and_mask(**train_df[[\"img_path\", \"annotation\", \"width\", \"height\"]].iloc[i].to_dict())\n    plot_img_and_mask(img, msk)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:06.240837Z","iopub.execute_input":"2021-11-01T23:22:06.242615Z","iopub.status.idle":"2021-11-01T23:22:14.396572Z","shell.execute_reply.started":"2021-11-01T23:22:06.242585Z","shell.execute_reply":"2021-11-01T23:22:14.395914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x1 = rle_decode_top_to_bot_first(train_df.iloc[0].annotation[0], (train_df.iloc[0].height, train_df.iloc[0].width))\nx2 = rle_decode(train_df.iloc[0].annotation[0], (train_df.iloc[0].height, train_df.iloc[0].width))\n\nplt.figure(figsize=(15,6))\nplt.subplot(1,2,1)\nplt.imshow(x1, cmap=\"inferno\")\nplt.axis(False)\nplt.title(\"NamGalielei RLE Decode Function\", fontweight=\"bold\")\nplt.subplot(1,2,2)\nplt.imshow(x2, cmap=\"inferno\")\nplt.axis(False)\nplt.title(\"Original RLE Decode Function\", fontweight=\"bold\")\nplt.tight_layout()\nplt.show()\nprint(f\"\\n... THERE ARE {(x1!=x2).sum()} PIXELS IN DISAGREEMENT WHEN USING THE TWO FUNCTIONS ON A SINGLE CELL...\\n\")\n\nimg1, msk1 = get_img_and_mask(**train_df[[\"img_path\", \"annotation\", \"width\", \"height\"]].iloc[0].to_dict())\nimg2, msk2 = get_img_and_mask(**train_df[[\"img_path\", \"annotation\", \"width\", \"height\"]].iloc[0].to_dict(), rle_fn=rle_decode_top_to_bot_first)\n\nplot_img_and_mask(img1, msk1)\nplot_img_and_mask(img2, msk2)\n\nprint(f\"\\n... THERE ARE {(msk2!=msk1).sum()} PIXELS IN DISAGREEMENT WHEN USING THE TWO FUNCTIONS ON ALL CELL MASK ...\\n\")","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:14.397688Z","iopub.execute_input":"2021-11-01T23:22:14.398026Z","iopub.status.idle":"2021-11-01T23:22:16.432767Z","shell.execute_reply.started":"2021-11-01T23:22:14.397993Z","shell.execute_reply":"2021-11-01T23:22:16.432148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"\\n\\n... WIDTH VALUE COUNTS ...\")\nfor k,v in train_df.width.value_counts().items():\n    print(f\"\\t--> There are {v} images with WIDTH={k}\")\n\nprint(\"\\n\\n... HEIGHT VALUE COUNTS ...\")\nfor k,v in train_df.height.value_counts().items():\n    print(f\"\\t--> There are {v} images with HEIGHT={k}\")\n\nprint(\"\\n\\n... AREA COUNTS ...\")\nfor k,v in (train_df.width*train_df.height).value_counts().items():\n    print(f\"\\t--> There are {v} images with AREA={k}\")\n\nprint(\"\\n\\n... NOTE: ALL THE IMAGES ARE THE SAME SIZE ...\\n\")\n\nprint(\"\\n\\n... PLATE TIME VALUE COUNTS ...\")\nfor k,v in train_df.plate_time.value_counts().items():\n    print(f\"\\t--> There are {v} images with PLATE_TIME={k}\")\nfig = px.histogram(train_df, x=\"plate_time\", color=\"cell_type\", title=\"<b>Plate Time Histogram</b>\")\nfig.show()\n\nprint(\"\\n\\n... SAMPLE DATE VALUE COUNTS ...\")\nfor k,v in train_df.sample_date.value_counts().items():\n    print(f\"\\t--> There are {v} images with SAMPLE_DATE={k}\")\nfig = px.histogram(train_df, train_df.sample_date.apply(lambda x: x.replace(\"-\", \"_\")), color=\"cell_type\", title=\"<b>Sample Date Value Histogram</b>\")\nfig.show()\n\nprint(\"\\n\\n... ELAPSED TIME DELTA VALUE COUNTS ...\")\nfor k,v in train_df.elapsed_timedelta.value_counts().items():\n    print(f\"\\t--> There are {v} images with SAMPLE_DATE={k}\")\nfig = px.histogram(train_df, \"elapsed_timedelta\", color=\"cell_type\", title=\"<b>Elapsed Time Delta Value Histogram</b>\")\nfig.show()\n    \nprint(\"\\n\\n... SAMPLE ID VALUE COUNTS (>1) ...\")\nprint(f\"\\t--> There are {len(train_df[train_df.sample_id.isin([x for x,v in train_df.sample_id.value_counts().items() if v>1])])} SAMPLE_IDs with more than one image\\n\")\nfor k,v in train_df[train_df.sample_id.isin([x for x,v in train_df.sample_id.value_counts().items() if v>1])].reset_index()[\"sample_id\"].value_counts().items():\n    print(f\"\\t--> There are {v} images with SAMPLE_ID={k}\")\nfig = px.histogram(train_df[train_df.sample_id.isin([x for x,v in train_df.sample_id.value_counts().items() if v>1])].reset_index(), \"sample_id\", color=\"cell_type\", title=\"<b>Sample ID Value Histogram</b>\")\nfig.show()\n\n    \nprint(\"\\n\\n... CELL TYPE VALUE COUNTS ...\")\nfor k,v in train_df.cell_type.value_counts().items():\n    print(f\"\\t--> There are {v} images with CELL_TYPE={k}\")\n    \nfig = px.histogram(train_df, x=\"cell_type\", title=\"<b>Cell Type Histogram</b>\")\nfig.show()\n\nfor ct in CELL_TYPES:\n    print(f\"\\n\\n... SHOWING THREE EXAMPLES OF CELL TYPE {ct.upper()} ...\\n\")\n    for i in range(3):\n        img, msk = get_img_and_mask(**train_df[train_df.cell_type==ct][[\"img_path\", \"annotation\", \"width\", \"height\"]].sample(3).reset_index(drop=True).iloc[i].to_dict())\n        plot_img_and_mask(img, msk)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:16.434706Z","iopub.execute_input":"2021-11-01T23:22:16.434964Z","iopub.status.idle":"2021-11-01T23:22:23.841745Z","shell.execute_reply.started":"2021-11-01T23:22:16.434931Z","shell.execute_reply":"2021-11-01T23:22:23.841053Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DEFER = True\n\nif not DEFER:\n    LC_CELL_TYPES = os.listdir(os.path.join(LC_ANN_DIR, \"LIVECell_single_cells\"))\n\n    print(\"\\n... LOADING TRAIN COCO JSON ...\\n\")\n    LC_COCO_TRAIN = os.path.join(LC_ANN_DIR, \"LIVECell\", \"livecell_coco_train.json\")\n\n    print(\"\\n... LOADING VALIDATION COCO JSON ...\\n\")\n    LC_COCO_VAL = os.path.join(LC_ANN_DIR, \"LIVECell\", \"livecell_coco_val.json\")\n\n    print(\"\\n... LOADING TEST COCO JSON ...\\n\")\n    LC_COCO_TEST = os.path.join(LC_ANN_DIR, \"LIVECell\", \"livecell_coco_test.json\")\n\n    LC_SC_TRAIN = {\n        lc_ct:os.path.join(LC_ANN_DIR, \"LIVECell_single_cells\", lc_ct, f\"livecell_{lc_ct}_train.json\") \\\n        for lc_ct in LC_CELL_TYPES\n    }\n    LC_SC_VAL = {\n        lc_ct:os.path.join(LC_ANN_DIR, \"LIVECell_single_cells\", lc_ct, f\"livecell_{lc_ct}_val.json\") \\\n        for lc_ct in LC_CELL_TYPES\n    }\n    LC_SC_TEST = {\n        lc_ct:os.path.join(LC_ANN_DIR, \"LIVECell_single_cells\", lc_ct, f\"livecell_{lc_ct}_test.json\") \\\n        for lc_ct in LC_CELL_TYPES\n    }\n\n    print(LC_SC_TRAIN)\n    print(LC_SC_VAL)\n    print(LC_SC_TEST)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:23.842799Z","iopub.execute_input":"2021-11-01T23:22:23.843028Z","iopub.status.idle":"2021-11-01T23:22:23.857707Z","shell.execute_reply.started":"2021-11-01T23:22:23.842998Z","shell.execute_reply":"2021-11-01T23:22:23.857058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"semi_df = pd.DataFrame()\n\nsemi_df[\"cell_type\"] = [x.split(\"[\", 1)[0] for x in tf.io.gfile.listdir(SEMI_DIR)]\nsemi_df[\"compound\"] = [x.split(\"]\", 1)[0].split(\"[\", 1)[-1] for x in tf.io.gfile.listdir(SEMI_DIR)]\nsemi_df[\"img_path\"] = tf.io.gfile.glob(os.path.join(SEMI_DIR, \"**\"))\n\nfig = px.histogram(semi_df, \"cell_type\", color=\"compound\")\nfig.show()\n\nfig = px.histogram(semi_df, \"compound\", color=\"cell_type\")\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:23.859149Z","iopub.execute_input":"2021-11-01T23:22:23.859678Z","iopub.status.idle":"2021-11-01T23:22:24.616585Z","shell.execute_reply.started":"2021-11-01T23:22:23.859641Z","shell.execute_reply":"2021-11-01T23:22:24.615944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(20,26))\nfor i, img_path in zip(range(15), semi_df.img_path.to_list()):\n    plt.subplot(5,3,i+1)\n    plt.imshow((255-np.asarray(ImageEnhance.Contrast(Image.fromarray(tf_load_png(img_path).numpy())).enhance(16))), cmap=\"inferno\")\n    plt.axis(False)\n    plt.title(img_path.rsplit(\"/\", 1)[-1].rsplit(\".\", 1)[0], fontweight=\"bold\")\n    \nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:24.620253Z","iopub.execute_input":"2021-11-01T23:22:24.620720Z","iopub.status.idle":"2021-11-01T23:22:28.459398Z","shell.execute_reply.started":"2021-11-01T23:22:24.620683Z","shell.execute_reply":"2021-11-01T23:22:28.457181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DEMO_IDX = 11\nimg, msk = get_img_and_mask(**train_df[[\"img_path\", \"annotation\", \"width\", \"height\"]].iloc[DEMO_IDX].to_dict())\nplot_img_and_mask(img, msk)\n\nplt.figure(figsize=(20, min(80, msk.max()//2)))\nfor i in range(1, msk.max()+1):\n    plt.subplot(10,10,i)\n    tl, br = get_contour_bbox(np.where(msk==i, 1, 0).astype(np.uint8))\n    plt.imshow(np.asarray(ImageEnhance.Contrast(Image.fromarray(255-img.numpy())).enhance(16))[tl[1]:br[1], tl[0]:br[0]], cmap=\"magma\")\n    plt.axis(False)\n    plt.title(f\"{i}\", fontweight=\"bold\")\n    if i==100:\n        break\n    \nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:28.460854Z","iopub.execute_input":"2021-11-01T23:22:28.461357Z","iopub.status.idle":"2021-11-01T23:22:35.005693Z","shell.execute_reply.started":"2021-11-01T23:22:28.461299Z","shell.execute_reply":"2021-11-01T23:22:35.004937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Takes about 1 minute\nprint(\"\\n... CREATE FULL SCALE BBOXES ...\\n\")\ntrain_df[\"bboxes\"] = train_df.parallel_apply(pd_get_bboxes, axis=1)\ndisplay(train_df.head())\n\nprint(\"\\n... CREATE SCALED DOWN (0-1) BBOXES ...\\n\")\nIMG_O_W, IMG_O_H = train_df.iloc[0].width, train_df.iloc[0].height\ntrain_df[\"scaled_bboxes\"] = train_df.bboxes.progress_apply(lambda box_list: [((box[0][0]/IMG_O_W, box[0][1]/IMG_O_H), (box[1][0]/IMG_O_W,box[1][1]/IMG_O_H)) if box else None for box in box_list])\n\n# CORT\nimg, msk = get_img_and_mask(**train_df[[\"img_path\", \"annotation\", \"width\", \"height\"]].iloc[FIRST_SHSY5Y_IDX].to_dict())\nplot_img_and_mask(img, msk, bboxes=train_df.iloc[FIRST_SHSY5Y_IDX].bboxes)\n\n# ASTRO\nimg, msk = get_img_and_mask(**train_df[[\"img_path\", \"annotation\", \"width\", \"height\"]].iloc[FIRST_ASTRO_IDX].to_dict())\nplot_img_and_mask(img, msk, bboxes=train_df.iloc[FIRST_ASTRO_IDX].bboxes)\n\n# SHSY5Y\nimg, msk = get_img_and_mask(**train_df[[\"img_path\", \"annotation\", \"width\", \"height\"]].iloc[FIRST_CORT_IDX].to_dict())\nplot_img_and_mask(img, msk, bboxes=train_df.iloc[FIRST_CORT_IDX].bboxes)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:22:35.007289Z","iopub.execute_input":"2021-11-01T23:22:35.007766Z","iopub.status.idle":"2021-11-01T23:23:59.182281Z","shell.execute_reply.started":"2021-11-01T23:22:35.007731Z","shell.execute_reply":"2021-11-01T23:23:59.179285Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df[\"bbox_widths\"] = train_df.bboxes.apply(lambda x: get_bbox_stats(x, style=\"width\"))\ntrain_df[\"bbox_heights\"] = train_df.bboxes.apply(lambda x: get_bbox_stats(x, style=\"height\"))\ntrain_df[\"bbox_areas\"] = train_df.bboxes.apply(lambda x: get_bbox_stats(x, style=\"area\"))\n\ntrain_df[\"scaled_bbox_widths\"] = train_df.scaled_bboxes.apply(lambda x: get_bbox_stats(x, style=\"width\"))\ntrain_df[\"scaled_bbox_heights\"] = train_df.scaled_bboxes.apply(lambda x: get_bbox_stats(x, style=\"height\"))\ntrain_df[\"scaled_bbox_areas\"] = train_df.scaled_bboxes.apply(lambda x: get_bbox_stats(x, style=\"area\"))\n\ndisplay(train_df.head())\n\n# Plot\npx.scatter(train_df.sort_values(by=\"cell_type\", key=lambda x: x.map(ARB_SORT_MAP))[[\"cell_type\", \"bbox_widths\", \"bbox_heights\", \"bbox_areas\"]].explode(column=[\"bbox_widths\",\"bbox_heights\", \"bbox_areas\"]), x=\"bbox_widths\", y=\"bbox_heights\", color=\"cell_type\", title=\"<b>Cell Bounding Box Sizes (WxH)</b>\")","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:23:59.183962Z","iopub.execute_input":"2021-11-01T23:23:59.184470Z","iopub.status.idle":"2021-11-01T23:24:00.958429Z","shell.execute_reply.started":"2021-11-01T23:23:59.184429Z","shell.execute_reply":"2021-11-01T23:24:00.957737Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Trining UNet","metadata":{}},{"cell_type":"code","source":"from pathlib import Path\nimport cv2\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.layers.experimental import preprocessing\n\nfrom IPython.display import clear_output\nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:00.959767Z","iopub.execute_input":"2021-11-01T23:24:00.960214Z","iopub.status.idle":"2021-11-01T23:24:00.965791Z","shell.execute_reply.started":"2021-11-01T23:24:00.960177Z","shell.execute_reply":"2021-11-01T23:24:00.965211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# paths\n# input\nDIR = '../input/sartorius-cell-instance-segmentation'\ntrain_csv = os.path.join(DIR,'train.csv') \ntrain_path =  os.path.join(DIR, 'train/')\ntest_path = os.path.join(DIR, 'test/')\n\n# output \ncsv_output = os.path.join('./', 'submission.csv') \nmodel_output = os.path.join('./', 'unet_keras_model.h5')","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:00.966941Z","iopub.execute_input":"2021-11-01T23:24:00.967753Z","iopub.status.idle":"2021-11-01T23:24:00.975291Z","shell.execute_reply.started":"2021-11-01T23:24:00.967716Z","shell.execute_reply":"2021-11-01T23:24:00.974623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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) of array to return \n    Returns numpy array, 1 - mask, 0 - background.\n    ref: https://www.kaggle.com/inversion/run-length-decoding-quick-start\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.float32)\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = color\n    return img.reshape(shape)\n\n\ndef rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    ref: https://www.kaggle.com/dragonzhang/positive-score-with-detectron-3-3-inference\n    '''\n    pixels = img.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\n\ndef get_mask(image_id, df):\n    '''\n    Uses rle_decode() to get ndarray from mask using image_id in dataframe (df).\n    ref: https://www.kaggle.com/barteksadlej123/sartors-tf-starter\n    '''\n    current = df[df[\"id\"] == image_id]\n    labels = current[\"annotation\"].tolist()\n    \n    mask = np.zeros((HEIGHT, WIDTH))\n    for label in labels:\n        mask += rle_decode(label, (HEIGHT, WIDTH))\n    mask = mask.clip(0, 1)\n    \n    return mask\n\n\n#  fix overlaps: \n\ndef check_overlap(msk):\n    '''\n    Checks if there are overlap in a mask (msk).\n    ref: https://www.kaggle.com/awsaf49/sartorius-fix-overlap\n    '''\n    msk = msk.astype(np.bool).astype(np.uint8)\n    return np.any(np.sum(msk, axis=-1)>1)\n\n\ndef fix_overlap(msk):\n    '''\n    Args:\n        mask: multi-channel mask, each channel is an instance of cell, shape:(520,704,None)\n    Returns:\n        multi-channel mask with non-overlapping values, shape:(520,704,None) \n    ref: https://www.kaggle.com/awsaf49/sartorius-fix-overlap\n    '''\n    msk = np.array(msk)\n    msk = np.pad(msk, [[0,0],[0,0],[1,0]])\n    ins_len = msk.shape[-1]\n    msk = np.argmax(msk,axis=-1)\n    msk = tf.keras.utils.to_categorical(msk, num_classes=ins_len)\n    msk = msk[...,1:]\n    msk = msk[...,np.any(msk, axis=(0,1))]\n    return msk","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:00.976861Z","iopub.execute_input":"2021-11-01T23:24:00.977131Z","iopub.status.idle":"2021-11-01T23:24:00.996169Z","shell.execute_reply.started":"2021-11-01T23:24:00.977098Z","shell.execute_reply":"2021-11-01T23:24:00.995481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# make predictions for test set: \n\ndef make_predictions(dataset, num, keras_model):\n    '''\n    For a tf.Dataset, makes predictions for n=num (num =-1 or all_images takes all images in the dataset), \n    images using a keras_model. Returns a list of predicted masks, each as ndarray. \n    '''\n    predictions = []\n    if dataset:\n        for image in dataset.take(num):\n            image = image[None]\n            pred_mask = keras_model.predict(image)\n            # changes shape from (1,512,512,1) to (512,512)\n            pred_mask = pred_mask[0, :, :, 0]\n            # fix overlaps\n            if check_overlap(msk=pred_mask)==True:\n                pred_mask = pred_mask[None]\n                pred_mask = fix_overlap(msk=pred_mask)\n            # transforms ndarray values to 0s and 1s\n            pred_mask =  np.where( pred_mask > 0.5, 1, 0)\n            predictions.append(pred_mask)\n    return predictions","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:00.998437Z","iopub.execute_input":"2021-11-01T23:24:00.998634Z","iopub.status.idle":"2021-11-01T23:24:01.010797Z","shell.execute_reply.started":"2021-11-01T23:24:00.998610Z","shell.execute_reply":"2021-11-01T23:24:01.009879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# constants\n\nDEBUG = False\n\nSEED = 123\nWIDTH, HEIGHT = 704, 520\nRESIZE_WIDTH, RESIZE_HEIGHT = 512, 512\nBATCH_SIZE = 32\nBUFFER_SIZE = 32\n\nVAL_SPLIT = 0.2\n\nAUTO = tf.data.AUTOTUNE\n\nEPOCHS = 20","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:01.012372Z","iopub.execute_input":"2021-11-01T23:24:01.012990Z","iopub.status.idle":"2021-11-01T23:24:01.023897Z","shell.execute_reply.started":"2021-11-01T23:24:01.012852Z","shell.execute_reply":"2021-11-01T23:24:01.023110Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train and validation split\ntrain = pd.read_csv(train_csv)\ntrain.head()\n\nn_ids = train.id.nunique()\n\nif DEBUG:\n    unique_ids_train = list(set(train['id'].tolist()))[:BATCH_SIZE]\n    unique_ids_valid = list(set(train['id'].tolist()))[BATCH_SIZE:2*BATCH_SIZE]\nelse:\n    unique_ids_train = list(set(train['id'].tolist()))[:int(n_ids * (1 - VAL_SPLIT))]\n    unique_ids_valid = list(set(train['id'].tolist()))[int(n_ids * (1 - VAL_SPLIT)):]\n\n\ntemp = pd.DataFrame()\nfor sample_id in unique_ids_train:\n    query = train[train.id == sample_id]\n    temp = pd.concat([temp, query])\ntrain = temp\ntrain = train.reset_index(drop=True)\n\ntemp = pd.DataFrame()\nfor sample_id in unique_ids_valid:\n    query = train[train.id == sample_id]\n    temp = pd.concat([temp, query])\nvalid = temp\nvalid = train.reset_index(drop=True)\n    \nTRAIN_LENGTH = train['id'].nunique()\nSTEPS_PER_EPOCH = TRAIN_LENGTH // BATCH_SIZE\n\nVALID_LENGTH = valid['id'].nunique()\nVALIDATION_STEPS = VALID_LENGTH // BATCH_SIZE\n# training data generator \ndef train_generator(df):\n    image_ids = set(df['id'].tolist())\n    \n    for image_id in image_ids:\n        image = cv2.imread(os.path.join(train_path, image_id) + '.png') \n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        mask = get_mask(image_id, df)\n        \n        image = cv2.resize(image, (RESIZE_HEIGHT, RESIZE_WIDTH))\n        mask = cv2.resize(mask, (RESIZE_HEIGHT, RESIZE_WIDTH))\n        mask = mask.reshape((*mask.shape, 1))\n        \n        image = image.astype(np.float32)\n        mask = mask.astype(np.int32)\n        \n        yield image, mask","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:01.025140Z","iopub.execute_input":"2021-11-01T23:24:01.026161Z","iopub.status.idle":"2021-11-01T23:24:09.278178Z","shell.execute_reply.started":"2021-11-01T23:24:01.025320Z","shell.execute_reply":"2021-11-01T23:24:09.277400Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# use the generator to get training and validation sets\ntrain_ds = tf.data.Dataset.from_generator(\n    lambda : train_generator(train), \n    output_types=(tf.float32, tf.int32),\n    output_shapes=((RESIZE_HEIGHT, RESIZE_WIDTH, 3), (RESIZE_HEIGHT, RESIZE_WIDTH, 1)))\n\nvalid_ds = tf.data.Dataset.from_generator(\n    lambda : train_generator(valid), \n    output_types=(tf.float32, tf.int32),\n    output_shapes=((RESIZE_HEIGHT, RESIZE_WIDTH, 3), (RESIZE_HEIGHT, RESIZE_WIDTH, 1)))","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:09.279511Z","iopub.execute_input":"2021-11-01T23:24:09.279757Z","iopub.status.idle":"2021-11-01T23:24:09.346761Z","shell.execute_reply.started":"2021-11-01T23:24:09.279725Z","shell.execute_reply":"2021-11-01T23:24:09.346091Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# \"the following class performs a simple augmentation by randomly-flipping an image\"\nclass Augment(tf.keras.layers.Layer):\n    def __init__(self, seed=SEED):\n        super().__init__()\n        \n        self.augment_inputs = preprocessing.RandomFlip('horizontal', seed=seed)\n        self.augment_labels = preprocessing.RandomFlip('horizontal', seed=seed)\n        \n    def call(self, inputs, labels):\n        inputs = self.augment_inputs(inputs)\n        labels = self.augment_labels(labels)\n        return inputs, labels","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:09.348066Z","iopub.execute_input":"2021-11-01T23:24:09.348462Z","iopub.status.idle":"2021-11-01T23:24:09.354768Z","shell.execute_reply.started":"2021-11-01T23:24:09.348427Z","shell.execute_reply":"2021-11-01T23:24:09.354132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# \"build the input pipeline, applying the augmentation after batching the inputs\"\n\ntrain_ds = (\n    train_ds\n    .shuffle(BUFFER_SIZE)\n    .batch(BATCH_SIZE)\n    .repeat()\n    .map(Augment())\n    .prefetch(AUTO))\n\nvalid_ds = (\n    valid_ds\n    .batch(BATCH_SIZE)\n    .repeat()\n    .prefetch(AUTO))","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:09.356079Z","iopub.execute_input":"2021-11-01T23:24:09.356464Z","iopub.status.idle":"2021-11-01T23:24:09.510725Z","shell.execute_reply.started":"2021-11-01T23:24:09.356432Z","shell.execute_reply":"2021-11-01T23:24:09.509972Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# \"visualize an image example and its corresponding mask from the dataset\"\n\ndef display(display_list):\n    plt.figure(figsize=(20, 20))\n\n    title = ['Input Image', 'True Mask', 'Predicted Mask']\n\n    for i in range(len(display_list)):\n        plt.subplot(1, len(display_list), i+1)\n        plt.title(title[i])\n        plt.imshow(tf.keras.preprocessing.image.array_to_img(display_list[i]))\n        plt.axis('off')\n    plt.show()\n    \nfor images, masks in train_ds.take(2):\n    sample_image, sample_mask = images[0], masks[0]\n    display([sample_image, sample_mask])","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:09.512132Z","iopub.execute_input":"2021-11-01T23:24:09.512401Z","iopub.status.idle":"2021-11-01T23:24:21.140982Z","shell.execute_reply.started":"2021-11-01T23:24:09.512355Z","shell.execute_reply":"2021-11-01T23:24:21.140150Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# base model and encoder (down_stack)\n\nbase_model = tf.keras.applications.MobileNetV2(input_shape=[RESIZE_HEIGHT, RESIZE_WIDTH, 3], include_top=False)\n\n# use the activations of these layers\nlayer_names = [\n    'block_1_expand_relu',   # 64x64\n    'block_3_expand_relu',   # 32x32\n    'block_6_expand_relu',   # 16x16\n    'block_13_expand_relu',  # 8x8\n    'block_16_project',      # 4x4\n]\n\nbase_model_outputs = [base_model.get_layer(name).output for name in layer_names]\n\n# create the feature extraction model\ndown_stack = tf.keras.Model(inputs=base_model.input, outputs=base_model_outputs)\ndown_stack.trainable = False","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:21.143393Z","iopub.execute_input":"2021-11-01T23:24:21.143629Z","iopub.status.idle":"2021-11-01T23:24:22.317633Z","shell.execute_reply.started":"2021-11-01T23:24:21.143597Z","shell.execute_reply":"2021-11-01T23:24:22.316909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# decoder / upsampler\n\ndef upsample(filters, size, apply_dropout=False):\n    '''\n    filters: Integer, the dimensionality of the output space (i.e. the number of output filters in the convolution). \n    size: An integer or tuple/list of 2 integers, specifying the height and width of the 2D convolution window. \n    Can be a single integer to specify the same value for all spatial dimensions. \n    return: 4+D tensor with shape: batch_shape + (channels, rows, cols) if data_format='channels_first' \n    or 4+D tensor with shape: batch_shape + (rows, cols, channels) if data_format='channels_last\n    ref: https://www.tensorflow.org/tutorials/generative/pix2pix?hl=nb\n    '''\n    initializer = tf.random_normal_initializer(0., 0.02)\n    result = tf.keras.Sequential()\n    result.add(\n    tf.keras.layers.Conv2DTranspose(filters, size, strides=2,\n                                    padding='same',\n                                    kernel_initializer=initializer,\n                                    use_bias=False))\n    result.add(tf.keras.layers.BatchNormalization())\n    if apply_dropout:\n        result.add(tf.keras.layers.Dropout(0.5))\n    result.add(tf.keras.layers.ReLU())\n    return result\n\n\nup_stack = [\n    upsample(512, 3),  # 4x4 -> 8x8\n    upsample(256, 3),  # 8x8 -> 16x16\n    upsample(128, 3),  # 16x16 -> 32x32\n    upsample(64, 3),   # 32x32 -> 64x64\n]","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:22.318890Z","iopub.execute_input":"2021-11-01T23:24:22.319154Z","iopub.status.idle":"2021-11-01T23:24:22.348295Z","shell.execute_reply.started":"2021-11-01T23:24:22.319120Z","shell.execute_reply":"2021-11-01T23:24:22.347640Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# U-Net model \ndef unet_model(output_channels : int):\n    inputs = tf.keras.layers.Input(shape=[RESIZE_HEIGHT , RESIZE_WIDTH, 3])\n    # \"downsampling through the model\"\n    skips = down_stack(inputs)\n    x = skips[-1]\n    skips = reversed(skips[:-1])\n    # \"sampling and establishing the skip connections\"\n    for up, skip in zip(up_stack, skips):\n        x = up(x)\n        concat = tf.keras.layers.Concatenate()\n        x = concat([x, skip])\n    # \"this is the last layer of the model\"\n    last = tf.keras.layers.Conv2DTranspose(\n        filters=output_channels, kernel_size=3, strides=2,\n        padding='same', activation='sigmoid') #64x64 -> 128x128\n    \n    x = last(x)\n    \n    return tf.keras.Model(inputs=inputs, outputs=x)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:22.349704Z","iopub.execute_input":"2021-11-01T23:24:22.349970Z","iopub.status.idle":"2021-11-01T23:24:22.357792Z","shell.execute_reply.started":"2021-11-01T23:24:22.349935Z","shell.execute_reply":"2021-11-01T23:24:22.357004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# compile model \n## in a segmentation task each pixel is given a class \n## OUTPUT_CLASSES: number of classes that can be assigned to each pixel \n\nOUTPUT_CLASSES = 1\n\nmodel = unet_model(output_channels=OUTPUT_CLASSES)\n\nopt = keras.optimizers.Adam(learning_rate=0.01)\n\nmodel.compile(optimizer=opt,\n              loss=tf.keras.losses.BinaryCrossentropy(from_logits=False),\n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:22.359132Z","iopub.execute_input":"2021-11-01T23:24:22.359394Z","iopub.status.idle":"2021-11-01T23:24:23.075191Z","shell.execute_reply.started":"2021-11-01T23:24:22.359360Z","shell.execute_reply":"2021-11-01T23:24:23.074447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# visualize model architecture \ntf.keras.utils.plot_model(model, show_shapes=True)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:23.076359Z","iopub.execute_input":"2021-11-01T23:24:23.076608Z","iopub.status.idle":"2021-11-01T23:24:23.993861Z","shell.execute_reply.started":"2021-11-01T23:24:23.076573Z","shell.execute_reply":"2021-11-01T23:24:23.993074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# try out the model to check what it predicts before training\n\ndef create_mask(pred_mask):\n    pred_mask = tf.where(pred_mask > 0.5,1,0)\n    return pred_mask\n\n\ndef show_predictions(dataset=None, num=1):\n    if dataset:\n        for image, mask in dataset.take(num):\n            pred_mask = model.predict(image)\n            display([image[0], mask[0], create_mask(pred_mask[1])])\n    else:\n        display([sample_image, sample_mask,\n                 create_mask(model.predict(sample_image[tf.newaxis, ...])[0])])\n\n        \nshow_predictions(train_ds)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:24:23.995782Z","iopub.execute_input":"2021-11-01T23:24:23.996277Z","iopub.status.idle":"2021-11-01T23:24:46.461760Z","shell.execute_reply.started":"2021-11-01T23:24:23.996227Z","shell.execute_reply":"2021-11-01T23:24:46.461004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# training\n\n# \"observe how the model improves while it is training\"\nclass DisplayCallback(tf.keras.callbacks.Callback):\n    def __init__(self):\n        super().__init__()\n    def on_epoch_end(self, epoch, logs=None):\n        clear_output(wait=False)\n        show_predictions()\n        print ('\\nSample Prediction after epoch {}\\n'.format(epoch+1))\n# display callback defined above\ndisplay_cb = DisplayCallback()\n\n# \"save the Keras model or model weights at some frequency\"\nmodel_checkpoint = tf.keras.callbacks.ModelCheckpoint(\n    model_output,\n    save_best_only=True,\n    save_weights_only=True,\n)\n\n# \"reduce learning rate when a metric has stopped improving\"\n# documentation: https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/ReduceLROnPlateau\nlr_reduce = tf.keras.callbacks.ReduceLROnPlateau( monitor='val_loss', factor=0.1, patience=10, verbose=0,\n    mode='auto', min_delta=0.0001, cooldown=0, min_lr=0)\n\nmodel_history = model.fit(train_ds, epochs=EPOCHS,\n                          steps_per_epoch=STEPS_PER_EPOCH,\n                          validation_steps=VALIDATION_STEPS,\n                          validation_data=valid_ds,\n                          callbacks=[display_cb, model_checkpoint, lr_reduce])","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:31:54.145128Z","iopub.execute_input":"2021-11-01T23:31:54.145700Z","iopub.status.idle":"2021-11-01T23:55:20.283649Z","shell.execute_reply.started":"2021-11-01T23:31:54.145660Z","shell.execute_reply":"2021-11-01T23:55:20.282705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plot training curve\nloss = model_history.history['loss']\nval_loss = model_history.history['val_loss']\nplt.figure()\nplt.plot(model_history.epoch, loss, 'r', label='Training loss')\nplt.plot(model_history.epoch, val_loss, 'bo', label='Validation loss')\nplt.title('Training and Validation Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss Value')\nplt.ylim([0, 1])\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:56:05.319927Z","iopub.execute_input":"2021-11-01T23:56:05.320794Z","iopub.status.idle":"2021-11-01T23:56:05.535646Z","shell.execute_reply.started":"2021-11-01T23:56:05.320748Z","shell.execute_reply":"2021-11-01T23:56:05.534958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test data generator \ntest_ids = [  os.path.join(test_path, each)  for each in os.listdir(test_path) if each.endswith('.png')]\ndef test_generator(image_ids):\n    for image_id in image_ids:\n        image = cv2.imread(image_id) \n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)        \n        image = cv2.resize(image, (RESIZE_HEIGHT, RESIZE_WIDTH))\n        image = image.astype(np.float32)\n        yield image","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:56:08.315805Z","iopub.execute_input":"2021-11-01T23:56:08.316099Z","iopub.status.idle":"2021-11-01T23:56:08.329755Z","shell.execute_reply.started":"2021-11-01T23:56:08.316053Z","shell.execute_reply":"2021-11-01T23:56:08.328579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test dataset from test data generator \ntest_ds = tf.data.Dataset.from_generator(\n    lambda : test_generator(test_ids), \n    output_types=(tf.float32),\n    output_shapes=((RESIZE_HEIGHT, RESIZE_WIDTH, 3)) )","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:56:10.365689Z","iopub.execute_input":"2021-11-01T23:56:10.365951Z","iopub.status.idle":"2021-11-01T23:56:10.762863Z","shell.execute_reply.started":"2021-11-01T23:56:10.365920Z","shell.execute_reply":"2021-11-01T23:56:10.762134Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test image ids and predictions\ntest_predictions = make_predictions(dataset=test_ds, num=len(test_ids), keras_model=model)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:56:12.381838Z","iopub.execute_input":"2021-11-01T23:56:12.382329Z","iopub.status.idle":"2021-11-01T23:56:12.702927Z","shell.execute_reply.started":"2021-11-01T23:56:12.382290Z","shell.execute_reply":"2021-11-01T23:56:12.702130Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# encode predections in the RL format\ntest_predictions = [rle_encode(mask) for mask in test_predictions] ","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:56:15.270482Z","iopub.execute_input":"2021-11-01T23:56:15.271180Z","iopub.status.idle":"2021-11-01T23:56:15.281282Z","shell.execute_reply.started":"2021-11-01T23:56:15.271141Z","shell.execute_reply":"2021-11-01T23:56:15.280480Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# transform full image paths to ids \ntest_ids = [Path(ID).stem for ID in test_ids]","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:56:18.288915Z","iopub.execute_input":"2021-11-01T23:56:18.289192Z","iopub.status.idle":"2021-11-01T23:56:18.294565Z","shell.execute_reply.started":"2021-11-01T23:56:18.289161Z","shell.execute_reply":"2021-11-01T23:56:18.293774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# generate submission data frame \nsubmisssion = pd.DataFrame.from_dict({'id': test_ids, 'predicted': test_predictions} )\nsubmisssion = submisssion.sort_values( ['id'], ascending=True )\nprint(submisssion.head(), 'n')\nsubmisssion.to_csv(csv_output, index=False)","metadata":{"execution":{"iopub.status.busy":"2021-11-01T23:56:24.415536Z","iopub.execute_input":"2021-11-01T23:56:24.416301Z","iopub.status.idle":"2021-11-01T23:56:24.430892Z","shell.execute_reply.started":"2021-11-01T23:56:24.416261Z","shell.execute_reply":"2021-11-01T23:56:24.430066Z"},"trusted":true},"execution_count":null,"outputs":[]}]}