{"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":"https://www.tensorflow.org/tutorials/images/segmentation","metadata":{}},{"cell_type":"code","source":"%%capture\n!pip install git+https://github.com/tensorflow/examples.git","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:54:22.579348Z","iopub.execute_input":"2021-10-17T19:54:22.580359Z","iopub.status.idle":"2021-10-17T19:54:39.186797Z","shell.execute_reply.started":"2021-10-17T19:54:22.580230Z","shell.execute_reply":"2021-10-17T19:54:39.185868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nimport os\nimport cv2\n\nimport tensorflow as tf\nfrom tensorflow.keras.layers.experimental import preprocessing\n\nfrom tensorflow_examples.models.pix2pix import pix2pix\n\nfrom IPython.display import clear_output\nimport matplotlib.pyplot as plt","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-10-17T19:54:39.188854Z","iopub.execute_input":"2021-10-17T19:54:39.189117Z","iopub.status.idle":"2021-10-17T19:54:43.781415Z","shell.execute_reply.started":"2021-10-17T19:54:39.189084Z","shell.execute_reply":"2021-10-17T19:54:43.780565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DEBUG = False\n\ntrain_path = '../input/sartorius-cell-instance-segmentation/train/'\n\nSEED = 42\nWIDTH, HEIGHT = 704, 520\n# RESIZE_WIDTH, RESIZE_HEIGHT = 128, 128\nRESIZE_WIDTH, RESIZE_HEIGHT = 512, 512\nBATCH_SIZE = 32\nBUFFER_SIZE = 32\n\nVAL_SPLIT = 0.2\n\nAUTO = tf.data.AUTOTUNE","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:54:43.782534Z","iopub.execute_input":"2021-10-17T19:54:43.782785Z","iopub.status.idle":"2021-10-17T19:54:43.792498Z","shell.execute_reply.started":"2021-10-17T19:54:43.782754Z","shell.execute_reply":"2021-10-17T19:54:43.791320Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = pd.read_csv('../input/sartorius-cell-instance-segmentation/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","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:54:43.794187Z","iopub.execute_input":"2021-10-17T19:54:43.794412Z","iopub.status.idle":"2021-10-17T19:54:51.894331Z","shell.execute_reply.started":"2021-10-17T19:54:43.794382Z","shell.execute_reply":"2021-10-17T19:54:51.893445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ref: https://www.kaggle.com/inversion/run-length-decoding-quick-start\n\ndef 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\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\ndef get_mask(image_id, df):\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","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:54:51.895778Z","iopub.execute_input":"2021-10-17T19:54:51.896045Z","iopub.status.idle":"2021-10-17T19:54:51.904827Z","shell.execute_reply.started":"2021-10-17T19:54:51.896009Z","shell.execute_reply":"2021-10-17T19:54:51.904037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def 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-10-17T19:54:51.906085Z","iopub.execute_input":"2021-10-17T19:54:51.906428Z","iopub.status.idle":"2021-10-17T19:54:51.920704Z","shell.execute_reply.started":"2021-10-17T19:54:51.906392Z","shell.execute_reply":"2021-10-17T19:54:51.920038Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_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)))\n","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:20.789984Z","iopub.execute_input":"2021-10-17T19:57:20.790267Z","iopub.status.idle":"2021-10-17T19:57:20.828898Z","shell.execute_reply.started":"2021-10-17T19:57:20.790237Z","shell.execute_reply":"2021-10-17T19:57:20.828214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class 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-10-17T19:57:21.410306Z","iopub.execute_input":"2021-10-17T19:57:21.410551Z","iopub.status.idle":"2021-10-17T19:57:21.416801Z","shell.execute_reply.started":"2021-10-17T19:57:21.410523Z","shell.execute_reply":"2021-10-17T19:57:21.415795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_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-10-17T19:57:21.828587Z","iopub.execute_input":"2021-10-17T19:57:21.828899Z","iopub.status.idle":"2021-10-17T19:57:21.941310Z","shell.execute_reply.started":"2021-10-17T19:57:21.828865Z","shell.execute_reply":"2021-10-17T19:57:21.940472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def 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","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:22.732716Z","iopub.execute_input":"2021-10-17T19:57:22.732965Z","iopub.status.idle":"2021-10-17T19:57:22.738701Z","shell.execute_reply.started":"2021-10-17T19:57:22.732937Z","shell.execute_reply":"2021-10-17T19:57:22.737892Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for images, masks in train_ds.take(2):\n    sample_image, sample_mask = images[0], masks[0]\n    display([sample_image, sample_mask])\n","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:54:54.314767Z","iopub.execute_input":"2021-10-17T19:54:54.315271Z","iopub.status.idle":"2021-10-17T19:55:06.555264Z","shell.execute_reply.started":"2021-10-17T19:54:54.315236Z","shell.execute_reply":"2021-10-17T19:55:06.554483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.max(sample_mask)","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:55:06.557073Z","iopub.execute_input":"2021-10-17T19:55:06.557362Z","iopub.status.idle":"2021-10-17T19:55:06.565968Z","shell.execute_reply.started":"2021-10-17T19:55:06.557329Z","shell.execute_reply":"2021-10-17T19:55:06.565193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_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\ndown_stack = tf.keras.Model(inputs=base_model.input, outputs=base_model_outputs)\n\ndown_stack.trainable = False","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:27.448365Z","iopub.execute_input":"2021-10-17T19:57:27.448640Z","iopub.status.idle":"2021-10-17T19:57:28.387481Z","shell.execute_reply.started":"2021-10-17T19:57:27.448611Z","shell.execute_reply":"2021-10-17T19:57:28.386717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"up_stack = [\n    pix2pix.upsample(512, 3),  # 4x4 -> 8x8\n    pix2pix.upsample(256, 3),  # 8x8 -> 16x16\n    pix2pix.upsample(128, 3),  # 16x16 -> 32x32\n    pix2pix.upsample(64, 3),   # 32x32 -> 64x64\n]","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:28.389240Z","iopub.execute_input":"2021-10-17T19:57:28.389490Z","iopub.status.idle":"2021-10-17T19:57:28.412597Z","shell.execute_reply.started":"2021-10-17T19:57:28.389456Z","shell.execute_reply":"2021-10-17T19:57:28.411966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def unet_model(output_channels : int):\n    inputs = tf.keras.layers.Input(shape=[RESIZE_HEIGHT , RESIZE_WIDTH, 3])\n    \n    skips = down_stack(inputs)\n    x = skips[-1]\n    skips = reversed(skips[:-1])\n    \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    \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-10-17T19:57:28.413946Z","iopub.execute_input":"2021-10-17T19:57:28.414238Z","iopub.status.idle":"2021-10-17T19:57:28.421410Z","shell.execute_reply.started":"2021-10-17T19:57:28.414180Z","shell.execute_reply":"2021-10-17T19:57:28.420499Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.losses import binary_crossentropy\nimport tensorflow.keras.backend as K\n\ndef dice_loss(y_true, y_pred):\n    smooth = 1.\n    y_true_f = K.flatten(y_true)\n    y_pred_f = K.flatten(y_pred)\n    intersection = y_true_f * y_pred_f\n    score = (2. * K.sum(intersection) + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)\n    return 1. - score\n\ndef bce_dice_loss(y_true, y_pred):\n    return binary_crossentropy(tf.cast(y_true, tf.float32), y_pred) + 0.5 * dice_loss(tf.cast(y_true, tf.float32), y_pred)","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:28.639700Z","iopub.execute_input":"2021-10-17T19:57:28.640431Z","iopub.status.idle":"2021-10-17T19:57:28.647266Z","shell.execute_reply.started":"2021-10-17T19:57:28.640389Z","shell.execute_reply":"2021-10-17T19:57:28.646146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"OUTPUT_CLASSES = 1\n\nmodel = unet_model(output_channels=OUTPUT_CLASSES)\nmodel.compile(optimizer='adam',\n              loss=bce_dice_loss,\n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:28.947870Z","iopub.execute_input":"2021-10-17T19:57:28.948085Z","iopub.status.idle":"2021-10-17T19:57:29.401062Z","shell.execute_reply.started":"2021-10-17T19:57:28.948061Z","shell.execute_reply":"2021-10-17T19:57:29.400335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.keras.utils.plot_model(model, show_shapes=True)\n","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:29.402793Z","iopub.execute_input":"2021-10-17T19:57:29.403047Z","iopub.status.idle":"2021-10-17T19:57:29.657272Z","shell.execute_reply.started":"2021-10-17T19:57:29.403012Z","shell.execute_reply":"2021-10-17T19:57:29.656464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_mask(pred_mask):\n    pred_mask = tf.where(pred_mask > 0.5,1,0)\n#     pred_mask = pred_mask[..., tf.newaxis]\n    return pred_mask\n","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:29.730757Z","iopub.execute_input":"2021-10-17T19:57:29.731011Z","iopub.status.idle":"2021-10-17T19:57:29.735740Z","shell.execute_reply.started":"2021-10-17T19:57:29.730977Z","shell.execute_reply":"2021-10-17T19:57:29.735040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def 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[0])])\n    else:\n        display([sample_image, sample_mask,\n                 create_mask(model.predict(sample_image[tf.newaxis, ...])[0])])","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:30.130350Z","iopub.execute_input":"2021-10-17T19:57:30.130957Z","iopub.status.idle":"2021-10-17T19:57:30.136234Z","shell.execute_reply.started":"2021-10-17T19:57:30.130923Z","shell.execute_reply":"2021-10-17T19:57:30.135323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_predictions(train_ds)","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:30.488052Z","iopub.execute_input":"2021-10-17T19:57:30.488680Z","iopub.status.idle":"2021-10-17T19:57:39.860086Z","shell.execute_reply.started":"2021-10-17T19:57:30.488644Z","shell.execute_reply":"2021-10-17T19:57:39.859173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DisplayCallback(tf.keras.callbacks.Callback):\n    def __init__(self):\n        super().__init__()\n    \n    def on_epoch_end(self, epoch, logs=None):\n#         clear_output(wait=True)\n        show_predictions()\n        print ('\\nSample Prediction after epoch {}\\n'.format(epoch+1))\n","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:57:39.862636Z","iopub.execute_input":"2021-10-17T19:57:39.862920Z","iopub.status.idle":"2021-10-17T19:57:39.868151Z","shell.execute_reply.started":"2021-10-17T19:57:39.862885Z","shell.execute_reply":"2021-10-17T19:57:39.867458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS = 100\n\ndisplay_cb = DisplayCallback()\nmodel_checkpoint = tf.keras.callbacks.ModelCheckpoint(\n    'best_model/',\n    save_best_only=True,\n    save_weights_only=False,\n)\nlr_reduce = tf.keras.callbacks.ReduceLROnPlateau()\nes = tf.keras.callbacks.EarlyStopping(patience=15)\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, es])\n","metadata":{"execution":{"iopub.status.busy":"2021-10-17T19:58:20.738610Z","iopub.execute_input":"2021-10-17T19:58:20.739515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}