{"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":"import pandas as pd\n\nfrom tensorflow.keras.models import *\nfrom tensorflow.keras.layers import *\nfrom tensorflow.keras.optimizers import *\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nfrom tensorflow.keras import backend as keras\n#from tensorflow import keras\nimport cv2 as cv\nfrom tensorflow.keras import backend as K\n\n# for path related functionalities\nimport os\n# for array operations\nimport numpy as np\n# tensorflow framework\nimport tensorflow as tf\n# keras API for deep learning\nfrom tensorflow import keras\n# for image visulaizations\nimport matplotlib.pyplot as plt\n# for viewing iteration status\nfrom tqdm import tqdm\nimport wandb\nimport random\nfrom IPython.display import clear_output","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-06-10T12:08:11.828973Z","iopub.execute_input":"2023-06-10T12:08:11.829549Z","iopub.status.idle":"2023-06-10T12:08:20.707558Z","shell.execute_reply.started":"2023-06-10T12:08:11.829506Z","shell.execute_reply":"2023-06-10T12:08:20.706629Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# CONSTANT","metadata":{}},{"cell_type":"code","source":"IMAGE_WIDTH = 256\nIMAGE_HEIGHT = 256\n\nTRAIN_DIR = '/kaggle/input/bkai-igh-neopolyp/train/train/'\nTRAIN_MASK_DIR = '/kaggle/input/bkai-igh-neopolyp/train_gt/train_gt/'\nTEST_DIR = '/kaggle/input/bkai-igh-neopolyp/test/test/'\n\nN_CLASS = 3\n\nBATCH_SIZE = 32\nNUM_EPOCHS = 100\nNUM_WORKERS = 4\nLEARNING_RATE = 0.0001 # 1e - 4\n\nBUFF_SIZE = 1000\n\nTRAIN_STEPS = 800//BATCH_SIZE\nVALIDATION_STEPS = 200//BATCH_SIZE","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:28.811045Z","iopub.execute_input":"2023-06-10T12:08:28.811639Z","iopub.status.idle":"2023-06-10T12:08:28.817871Z","shell.execute_reply.started":"2023-06-10T12:08:28.811603Z","shell.execute_reply":"2023-06-10T12:08:28.816885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# GET IMAGE","metadata":{}},{"cell_type":"markdown","source":"## Get path","metadata":{}},{"cell_type":"code","source":"# a list to collect paths of 1000 images\nimage_path = []\nfor root, dirs, files in os.walk(TRAIN_DIR):\n    # iterate over 1000 images\n    for file in files:\n        # create path\n        path = os.path.join(root,file)\n        # add path to list\n        image_path.append(path)\nlen(image_path)","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:31.573956Z","iopub.execute_input":"2023-06-10T12:08:31.574309Z","iopub.status.idle":"2023-06-10T12:08:32.123073Z","shell.execute_reply.started":"2023-06-10T12:08:31.574278Z","shell.execute_reply":"2023-06-10T12:08:32.122185Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# a list to collect paths of 1000 masks\nmask_path = []\nfor root, dirs, files in os.walk(TRAIN_MASK_DIR):\n    #iterate over 1000 masks\n    for file in files:\n        # obtain the path\n        path = os.path.join(root,file)\n        # add path to the list\n        mask_path.append(path)\nlen(mask_path)","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:33.512178Z","iopub.execute_input":"2023-06-10T12:08:33.512792Z","iopub.status.idle":"2023-06-10T12:08:34.041231Z","shell.execute_reply.started":"2023-06-10T12:08:33.512756Z","shell.execute_reply":"2023-06-10T12:08:34.040294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Get list images - chanel = 3","metadata":{}},{"cell_type":"code","source":"def read_image(image_path):\n    image = cv.imread(image_path)\n    image = cv.cvtColor(image, cv.COLOR_BGR2RGB)\n    image = cv.resize(image, (IMAGE_WIDTH, IMAGE_HEIGHT))\n    image = image/255.0\n    image = image.astype(np.float32)\n    return image","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:35.577863Z","iopub.execute_input":"2023-06-10T12:08:35.578231Z","iopub.status.idle":"2023-06-10T12:08:35.584314Z","shell.execute_reply.started":"2023-06-10T12:08:35.578201Z","shell.execute_reply":"2023-06-10T12:08:35.583293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(read_image(image_path[588]))\nread_image(image_path[588]).shape","metadata":{"execution":{"iopub.status.busy":"2023-06-10T10:06:42.037071Z","iopub.execute_input":"2023-06-10T10:06:42.038102Z","iopub.status.idle":"2023-06-10T10:06:42.505183Z","shell.execute_reply.started":"2023-06-10T10:06:42.038055Z","shell.execute_reply":"2023-06-10T10:06:42.504144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Get list mask - chanel = 1","metadata":{}},{"cell_type":"code","source":"def read_mask(mask_path):\n    image = cv.imread(mask_path)\n    image = cv.resize(image, (IMAGE_WIDTH, IMAGE_HEIGHT))\n    image = cv.cvtColor(image, cv.COLOR_BGR2HSV)\n    # lower boundary RED color range values; Hue (0 - 10)\n    lower1 = np.array([0, 100, 20])\n    upper1 = np.array([10, 255, 255])\n    # upper boundary RED color range values; Hue (160 - 180)\n    lower2 = np.array([160,100,20])\n    upper2 = np.array([179,255,255])\n    lower_mask = cv.inRange(image, lower1, upper1)\n    upper_mask = cv.inRange(image, lower2, upper2)\n\n    red_mask = lower_mask + upper_mask;\n    red_mask[red_mask != 0] = 2\n    \n    # boundary GREEN color range values; Hue (36 - 70)\n    green_mask = cv.inRange(image, (36, 25, 25), (70, 255,255))\n    green_mask[green_mask != 0] = 1\n    \n    full_mask = cv.bitwise_or(red_mask, green_mask)\n    full_mask = full_mask.astype(np.uint8)\n    return full_mask","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:37.894465Z","iopub.execute_input":"2023-06-10T12:08:37.894870Z","iopub.status.idle":"2023-06-10T12:08:37.909626Z","shell.execute_reply.started":"2023-06-10T12:08:37.894835Z","shell.execute_reply":"2023-06-10T12:08:37.908509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(read_mask(mask_path[588]).astype(np.uint8), cmap='nipy_spectral')\nread_mask(mask_path[588]).shape","metadata":{"execution":{"iopub.status.busy":"2023-06-10T09:58:24.091862Z","iopub.execute_input":"2023-06-10T09:58:24.092292Z","iopub.status.idle":"2023-06-10T09:58:24.440003Z","shell.execute_reply.started":"2023-06-10T09:58:24.092257Z","shell.execute_reply":"2023-06-10T09:58:24.438689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# BUILD MODEL","metadata":{}},{"cell_type":"code","source":"def double_conv_block(input, num_filters):\n    x = Conv2D(filters=num_filters, kernel_size=3, padding='same')(input)\n    x = BatchNormalization()(x)\n    x = Activation('relu')(x)\n    \n    x = Conv2D(filters=num_filters, kernel_size=3, padding='same')(x)\n    x = BatchNormalization()(x)\n    x = Activation('relu')(x)\n    return x\n\ndef downsample_block(x, n_filters):\n   f = double_conv_block(x, n_filters)\n   p = MaxPool2D(2)(f)\n   p = Dropout(0.3)(p)\n   return f, p\n\ndef upsample_block(x, skip_features, n_filters):\n   # upsample\n   x = Conv2DTranspose(n_filters, (2,2), 2, padding=\"same\")(x)\n   # concatenate\n   x = Concatenate()([x, skip_features])\n   # dropout\n   x = Dropout(0.3)(x)\n   # Conv2D twice with ReLU activation\n   x = double_conv_block(x, n_filters)\n   return x","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:41.001689Z","iopub.execute_input":"2023-06-10T12:08:41.002048Z","iopub.status.idle":"2023-06-10T12:08:41.010158Z","shell.execute_reply.started":"2023-06-10T12:08:41.002015Z","shell.execute_reply":"2023-06-10T12:08:41.009234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_unet_model(input_shape=(256, 256, 3)):\n    # inputs\n    inputs = Input(shape=input_shape)\n    # encoder: contracting path - downsample\n    # 1 - downsample\n    f1, p1 = downsample_block(inputs, 64)\n    # 2 - downsample\n    f2, p2 = downsample_block(p1, 128)\n    # 3 - downsample\n    f3, p3 = downsample_block(p2, 256)\n    # 4 - downsample\n    f4, p4 = downsample_block(p3, 512)\n    # 5 - bottleneck\n    bottleneck = double_conv_block(p4, 1024)\n    # decoder: expanding path - upsample\n    # 6 - upsample\n    u6 = upsample_block(bottleneck, f4, 512)\n    # 7 - upsample\n    u7 = upsample_block(u6, f3, 256)\n    # 8 - upsample\n    u8 = upsample_block(u7, f2, 128)\n    # 9 - upsample\n    u9 = upsample_block(u8, f1, 64)\n    # outputs\n    outputs = Conv2D(N_CLASS, 1, padding=\"same\", activation = \"softmax\")(u9)\n    # unet model with Keras Functional API\n    unet_model = Model(inputs, outputs, name=\"U-Net\")\n    return unet_model","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:43.958683Z","iopub.execute_input":"2023-06-10T12:08:43.959048Z","iopub.status.idle":"2023-06-10T12:08:43.966476Z","shell.execute_reply.started":"2023-06-10T12:08:43.959018Z","shell.execute_reply":"2023-06-10T12:08:43.965416Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unet = build_unet_model((IMAGE_HEIGHT, IMAGE_WIDTH, 3))","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:46.572936Z","iopub.execute_input":"2023-06-10T12:08:46.573308Z","iopub.status.idle":"2023-06-10T12:08:50.026543Z","shell.execute_reply.started":"2023-06-10T12:08:46.573276Z","shell.execute_reply":"2023-06-10T12:08:50.025565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"keras.utils.plot_model(unet, show_shapes=True)","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:08:51.328494Z","iopub.execute_input":"2023-06-10T12:08:51.328852Z","iopub.status.idle":"2023-06-10T12:08:52.136439Z","shell.execute_reply.started":"2023-06-10T12:08:51.328819Z","shell.execute_reply":"2023-06-10T12:08:52.135209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Define Dataset","metadata":{}},{"cell_type":"code","source":"# plot an image\nplt.subplot(1,2,1)\nplt.imshow(read_image(image_path[588]))\n\n#plot a mask\nplt.subplot(1,2,2)\nplt.imshow(read_mask(mask_path[588]), cmap='nipy_spectral')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-06-10T09:58:33.054137Z","iopub.execute_input":"2023-06-10T09:58:33.054611Z","iopub.status.idle":"2023-06-10T09:58:33.516235Z","shell.execute_reply.started":"2023-06-10T09:58:33.054558Z","shell.execute_reply":"2023-06-10T09:58:33.514874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_X, val_X, train_y, val_y = train_test_split(image_path, mask_path, test_size=0.2, random_state=42)","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:12.306892Z","iopub.execute_input":"2023-06-10T12:09:12.307348Z","iopub.status.idle":"2023-06-10T12:09:12.816930Z","shell.execute_reply.started":"2023-06-10T12:09:12.307309Z","shell.execute_reply":"2023-06-10T12:09:12.815808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def convert2TfDataset(x, y, batch_size=8):\n    def preprocess(image_path, mask_path):\n        def f(image_path, mask_path):\n            image_path = image_path.decode()\n            mask_path = mask_path.decode()\n            image = read_image(image_path)\n            mask = read_mask(mask_path)\n            return image, mask\n\n        image, mask = tf.numpy_function(f, [image_path, mask_path], [tf.float32, tf.uint8])\n        mask = tf.one_hot(mask, N_CLASS, dtype=tf.uint8)\n        image.set_shape([IMAGE_HEIGHT, IMAGE_WIDTH, 3])\n        mask.set_shape([IMAGE_HEIGHT, IMAGE_WIDTH, 3])\n        return image, mask\n\n    dataset = tf.data.Dataset.from_tensor_slices((x, y))\n    dataset = dataset.shuffle(buffer_size=BUFF_SIZE)\n    dataset = dataset.map(preprocess)\n    dataset = dataset.batch(batch_size)\n    dataset = dataset.repeat()\n    dataset = dataset.prefetch(2)\n    return dataset","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:14.363856Z","iopub.execute_input":"2023-06-10T12:09:14.364263Z","iopub.status.idle":"2023-06-10T12:09:14.373502Z","shell.execute_reply.started":"2023-06-10T12:09:14.364230Z","shell.execute_reply":"2023-06-10T12:09:14.372497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = convert2TfDataset(train_X, train_y, BATCH_SIZE)\nval_dataset = convert2TfDataset(val_X, val_y, BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:16.905095Z","iopub.execute_input":"2023-06-10T12:09:16.905525Z","iopub.status.idle":"2023-06-10T12:09:17.151306Z","shell.execute_reply.started":"2023-06-10T12:09:16.905491Z","shell.execute_reply":"2023-06-10T12:09:17.150295Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model Compile","metadata":{}},{"cell_type":"code","source":"def dice_coef(y_true, y_pred):\n    return (2. * K.sum(y_true * y_pred) + 1.) / (K.sum(y_true) + K.sum(y_pred) + 1.)","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:18.854945Z","iopub.execute_input":"2023-06-10T12:09:18.855311Z","iopub.status.idle":"2023-06-10T12:09:18.860191Z","shell.execute_reply.started":"2023-06-10T12:09:18.855279Z","shell.execute_reply":"2023-06-10T12:09:18.859260Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"unet.compile(optimizer=keras.optimizers.Adam(lr = LEARNING_RATE), loss='categorical_crossentropy', metrics=[dice_coef, \"accuracy\"])","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:20.701212Z","iopub.execute_input":"2023-06-10T12:09:20.701578Z","iopub.status.idle":"2023-06-10T12:09:20.723596Z","shell.execute_reply.started":"2023-06-10T12:09:20.701547Z","shell.execute_reply":"2023-06-10T12:09:20.722701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint\n\nfilepath = 'model.h5'\ncheckpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='min')","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:23.753991Z","iopub.execute_input":"2023-06-10T12:09:23.754367Z","iopub.status.idle":"2023-06-10T12:09:23.759255Z","shell.execute_reply.started":"2023-06-10T12:09:23.754328Z","shell.execute_reply":"2023-06-10T12:09:23.758316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training \n","metadata":{}},{"cell_type":"code","source":"if len(train_X) % BATCH_SIZE != 0:\n    STEPS_PER_EPOCH += 1\n\nif len(val_X) % BATCH_SIZE != BATCH_SIZE:\n    VALIDATION_STEPS += 1","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:26.123106Z","iopub.execute_input":"2023-06-10T12:09:26.123764Z","iopub.status.idle":"2023-06-10T12:09:26.128418Z","shell.execute_reply.started":"2023-06-10T12:09:26.123728Z","shell.execute_reply":"2023-06-10T12:09:26.127550Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nhist_1 = unet.fit(train_dataset,\n                   validation_data=val_dataset,\n                   epochs=NUM_EPOCHS,\n                   batch_size = BATCH_SIZE,\n                   workers=NUM_WORKERS,\n                   verbose=1,\n                   steps_per_epoch=TRAIN_STEPS,\n                   validation_steps=VALIDATION_STEPS,\n                   callbacks=[checkpoint])","metadata":{"execution":{"iopub.status.busy":"2023-06-10T12:09:28.523594Z","iopub.execute_input":"2023-06-10T12:09:28.523958Z","iopub.status.idle":"2023-06-10T13:21:25.253361Z","shell.execute_reply.started":"2023-06-10T12:09:28.523925Z","shell.execute_reply":"2023-06-10T13:21:25.252281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig = plt.figure()\nplt.plot(np.arange(0, NUM_EPOCHS), hist_1.history['loss'], label='training loss')\nplt.plot(np.arange(8, NUM_EPOCHS), hist_1.history['val_loss'][8:NUM_EPOCHS], label='validation loss')\nplt.plot(np.arange(0, NUM_EPOCHS), hist_1.history['accuracy'], label='accuracy')\nplt.plot(np.arange(0, NUM_EPOCHS), hist_1.history['val_accuracy'], label='validation accuracy')\nplt.title('Accuracy and Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss|Accuracy')\nplt.legend()","metadata":{"execution":{"iopub.status.busy":"2023-06-10T13:35:05.910009Z","iopub.execute_input":"2023-06-10T13:35:05.910689Z","iopub.status.idle":"2023-06-10T13:35:06.269986Z","shell.execute_reply.started":"2023-06-10T13:35:05.910654Z","shell.execute_reply":"2023-06-10T13:35:06.269063Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predictions","metadata":{}},{"cell_type":"code","source":"colors = np.array([[ 0, 0, 0],\n                   [ 0, 255, 0],\n                   [ 255, 0, 0]])\ntest_images = [os.path.join(TEST_DIR, f'{x}') for x in os.listdir(TEST_DIR)]\n\ndef show_example(image, mask):\n    plt.figure(figsize=(18,15))\n    plt.subplot(1,3,1)\n    plt.imshow(image, cmap='bone')\n    plt.axis('off')\n    plt.title('Image')\n\n    plt.subplot(1,3,2)\n    plt.imshow(mask.astype(np.uint8), cmap='nipy_spectral')\n    plt.axis('off')\n    plt.title('Mask')\n\n    image = image*255\n    plt.subplot(1,3,3)\n    plt.imshow(image[...,1].astype(np.uint8), cmap='bone')\n    plt.imshow(mask.astype(np.uint8), alpha=0.5, cmap='nipy_spectral')\n    plt.axis('off')\n    plt.title('Overlay')\n\n    plt.show()\n\nfor image in tqdm(test_images[0:20]):\n    '''\n    We need segent 3 classes:\n        + 0 if the pixel is part of the image background (denoted by black color);\n        + 1 if the pixel is part of a non-neoplastic polyp (denoted by green color);\n        + 2 if the pixel is part of a neoplastic polyp (denoted by red color).\n    '''\n#     original_image = cv2.imread(image)\n#     original_image = cv.cvtColor(original_image, cv.COLOR_BGR2RGB)\n#     h, w, c = original_image.shape\n    x = read_image(image)\n    p = unet.predict(np.expand_dims(x, axis=0))[0]  #256,256,3\n\n    p = np.argmax(p, axis=-1)\n    rgb = np.zeros((*p.shape, 3))\n    for label, color in enumerate(colors):\n        rgb[p == label] = color\n    show_example(x, rgb)","metadata":{"execution":{"iopub.status.busy":"2023-06-10T13:50:19.480378Z","iopub.execute_input":"2023-06-10T13:50:19.480760Z","iopub.status.idle":"2023-06-10T13:50:32.983704Z","shell.execute_reply.started":"2023-06-10T13:50:19.480724Z","shell.execute_reply":"2023-06-10T13:50:32.981731Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# NOTE\n- Đang có vấn đề với hàm softmax khi xuất ra - trả về kết quả xác xuất \n- mà ở dưới lại dùng hàm loss ","metadata":{}}]}