{"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":"# **IMPORTING LIBRARIES**","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nimport tifffile as tiff \nimport cv2\n\nimport tensorflow as tf\nfrom tensorflow.keras import layers\nfrom keras import backend as K\n\nfrom skimage.transform import resize\nfrom sklearn.model_selection import train_test_split","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-07-16T19:10:50.861489Z","iopub.execute_input":"2022-07-16T19:10:50.862258Z","iopub.status.idle":"2022-07-16T19:10:58.563332Z","shell.execute_reply.started":"2022-07-16T19:10:50.862136Z","shell.execute_reply":"2022-07-16T19:10:58.562380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **DATA GENERATOR**","metadata":{}},{"cell_type":"code","source":"class imageDataGen(tf.keras.utils.Sequence):\n    def __init__(self, df, shuffle=True, training=True, imageSize=(512,512), batchSize = 8):\n        self.df = df\n        self.shuffle = shuffle\n        self.training = training\n        self.imageSize = imageSize\n        self.batchSize = batchSize\n        self.N = len(self.df)\n        \n        \n    def on_epoch_end(self):\n        \"\"\"\n            This functions runs at end of every epoch.\n        \"\"\"\n        if self.shuffle:\n            self.df = self.df.sample(frac=1).reset_index(drop=True)\n            \n            \n    def __getitem__(self, index):\n        \"\"\"\n            input  : index value of batch\n            output : returns the batch of training images and target images\n        \"\"\"\n        batchDF = self.df[index*self.batchSize : (index + 1)*self.batchSize]\n        X = self.__getInput(batchDF.id)\n        Y = self.__getOutput(batchDF[['rle', 'img_width', 'img_height']])\n        return (X, Y)\n    \n    \n    def __len__(self):\n        \"\"\"\n            Calculates the length of data with batch size. \n        \"\"\"\n        return self.N // self.batchSize\n        \n        \n    # Public helper functions.    \n    def mask2rle(self, img):\n        \"\"\"\n            input  : image\n            output : return the run length encoding of given image\n        \"\"\"\n        pixels= img.T.flatten() \n        pixels = np.concatenate([[0], pixels, [0]])\n        runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n        runs[1::2] -= runs[::2]\n        return ' '.join(str(x) for x in runs)\n\n    \n    def rle2img(self, mask_rle, width, height):\n        \"\"\"\n            input  : run length encoding\n            output : return the image of given run length encoding.\n        \"\"\"\n        shape = (width, height)\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        img = img.reshape(shape).T.reshape(shape[0], shape[1], 1)\n        return resize(img, self.imageSize)\n    \n    \n    # Private helper functions\n    def __loadImage(self, imgId):\n        \"\"\"\n            input  : image id\n            output : return the array of tiff image\n        \"\"\"\n        img = tiff.imread(\"../input/hubmap-organ-segmentation/train_images/\" + str(imgId) + \".tiff\")\n        img = resize(img, self.imageSize)\n        img = tf.image.rgb_to_grayscale(img)\n        return img.numpy()\n    \n    \n    def __augument(self, image):\n        \"\"\"\n            input  : image\n            output : augumented image\n        \"\"\"\n        pass\n                \n\n    def __getInput(self, imageIds): \n        \"\"\"\n            input  : image ids of batch data \n            output : return the batch of training images\n        \"\"\"\n        images = imageIds.map(self.__loadImage)\n        images = np.stack(images)\n        if self.training:\n            #images = images.map(self.__augument)\n            pass\n        return images\n    \n    \n    def __getOutput(self, masksDf):\n        \"\"\"\n            input  : RLE of batch data \n            output : return the batch of training label images\n        \"\"\"\n        maskImages = masksDf.apply(lambda x: self.rle2img(x['rle'], x['img_width'], x['img_height']), axis=1)\n        maskImages = np.stack(maskImages)\n        return maskImages\n        ","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:10:58.565429Z","iopub.execute_input":"2022-07-16T19:10:58.566269Z","iopub.status.idle":"2022-07-16T19:10:58.590916Z","shell.execute_reply.started":"2022-07-16T19:10:58.566222Z","shell.execute_reply":"2022-07-16T19:10:58.588340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **U-Net MArchitecture**","metadata":{}},{"cell_type":"markdown","source":"It is the U-Net architecture with using same padding on all convolutional layers.\n<br>\nThe input is in grayscale and output layer is with the sigmoid activation function.\n<br><br>\nInput shape of model  : (512,512,1)\n<br>\nOutput shape of model : (512,512,1)","metadata":{}},{"cell_type":"code","source":"def buildModel():\n    Input = layers.Input(shape=(512,512,1))\n    \n    # Feature extraction layers by conv layers\n    conv1 = layers.Conv2D(64, (3, 3), (1, 1), padding=\"same\", activation='relu')(Input)\n    conv1 = layers.Conv2D(64, (3, 3), (1, 1), padding=\"same\", activation='relu')(conv1)\n    pool1 = layers.MaxPooling2D ()(conv1)\n    \n    conv2 = layers.Conv2D(128, (3, 3), (1, 1), padding=\"same\", activation='relu')(pool1)\n    conv2 = layers.Conv2D(128, (3, 3), (1, 1), padding=\"same\", activation='relu')(conv2)\n    pool2 = layers.MaxPooling2D()(conv2)\n    \n    conv3 = layers.Conv2D(256, (3, 3), (1, 1), padding=\"same\", activation='relu')(pool2)\n    conv3 = layers.Conv2D(256, (3, 3), (1, 1), padding=\"same\", activation='relu')(conv3)\n    pool3 = layers.MaxPooling2D()(conv3)\n    \n    conv4 = layers.Conv2D(512, (3, 3), (1, 1), padding=\"same\", activation='relu')(pool3)\n    conv4 = layers.Conv2D(512, (3, 3), (1, 1), padding=\"same\", activation='relu')(conv4)\n    pool4 = layers.MaxPooling2D()(conv4)\n    \n    conv5 = layers.Conv2D(1024, (3, 3), (1, 1), padding=\"same\", activation='relu')(pool4)\n    conv5 = layers.Conv2D(1024, (3, 3), (1, 1), padding=\"same\", activation='relu')(conv5)\n    \n    # Creating a represented mask by deconv layers\n    dconv4 = layers.Conv2DTranspose(512, (3, 3), (2, 2), padding=\"same\", activation='relu')(conv5)\n    uconv4 = layers.Concatenate()([dconv4, conv4])\n    uconv4 = layers.Conv2D(512, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv4)\n    uconv4 = layers.Conv2D(512, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv4)\n    \n    dconv3 = layers.Conv2DTranspose(256, (3, 3), (2, 2), padding=\"same\", activation='relu')(uconv4)\n    uconv3 = layers.Concatenate()([dconv3, conv3])\n    uconv3 = layers.Conv2D(256, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv3)\n    uconv3 = layers.Conv2D(256, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv3)\n    \n    dconv2 = layers.Conv2DTranspose(128, (3, 3), (2, 2), padding=\"same\", activation='relu')(uconv3)\n    uconv2 = layers.Concatenate()([dconv2, conv2])\n    uconv2 = layers.Conv2D(128, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv2)\n    uconv2 = layers.Conv2D(128, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv2)\n    \n    dconv1 = layers.Conv2DTranspose(64, (3, 3), (2, 2), padding=\"same\", activation='relu')(uconv2)\n    uconv1 = layers.Concatenate()([dconv1, conv1])\n    uconv1 = layers.Conv2D(64, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv1)\n    uconv1 = layers.Conv2D(64, (3, 3), (1, 1), padding=\"same\", activation='relu')(uconv1)\n    \n    # Final output layer\n    Output = layers.Conv2D(1, (3, 3), (1, 1), padding=\"same\", activation='sigmoid')(uconv1)\n\n    model = tf.keras.Model(inputs=[Input], outputs=[Output])\n    return model","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:10:58.592586Z","iopub.execute_input":"2022-07-16T19:10:58.593391Z","iopub.status.idle":"2022-07-16T19:10:58.617837Z","shell.execute_reply.started":"2022-07-16T19:10:58.593356Z","shell.execute_reply":"2022-07-16T19:10:58.616863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **DATA LOADING**","metadata":{}},{"cell_type":"code","source":"DF = pd.read_csv(\"../input/hubmap-organ-segmentation/train.csv\")\n\n# Splitting the data for training and validation\ntrainDF,validDF = train_test_split(DF,test_size=0.2)\n\n# Creating a train and validation generator\ntrainGen = imageDataGen(trainDF)\nvalidGen = imageDataGen(validDF)","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:10:58.621944Z","iopub.execute_input":"2022-07-16T19:10:58.622595Z","iopub.status.idle":"2022-07-16T19:10:58.901335Z","shell.execute_reply.started":"2022-07-16T19:10:58.622558Z","shell.execute_reply":"2022-07-16T19:10:58.900371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **DATA VISUALIZATION**","metadata":{}},{"cell_type":"code","source":"# Generating data from the data generator\nbatch1 = trainGen.__getitem__(1)","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:10:58.902729Z","iopub.execute_input":"2022-07-16T19:10:58.903060Z","iopub.status.idle":"2022-07-16T19:11:15.771707Z","shell.execute_reply.started":"2022-07-16T19:10:58.903025Z","shell.execute_reply":"2022-07-16T19:11:15.770458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x = batch1[0][1]\ny = batch1[1][1]\n\nprint(f\"Training images shape : {x.shape}\")\nprint(f\"Target images shape : {y.shape}\")","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:11:15.773399Z","iopub.execute_input":"2022-07-16T19:11:15.773762Z","iopub.status.idle":"2022-07-16T19:11:15.779529Z","shell.execute_reply.started":"2022-07-16T19:11:15.773724Z","shell.execute_reply":"2022-07-16T19:11:15.778519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(5,5))\nplt.imshow(x)\nplt.imshow(y, cmap='coolwarm', alpha=0.5)","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:11:15.780662Z","iopub.execute_input":"2022-07-16T19:11:15.781239Z","iopub.status.idle":"2022-07-16T19:11:16.066993Z","shell.execute_reply.started":"2022-07-16T19:11:15.781205Z","shell.execute_reply":"2022-07-16T19:11:16.066115Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **LOSS FUNCTION**","metadata":{}},{"cell_type":"code","source":"class DiceLoss(tf.keras.losses.Loss):\n    def __init__(self):\n        super().__init__()\n        \n    def call(self, y_true, y_pred):\n        smooth = 1.0\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.0 * K.sum(intersection) + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)\n        return 1.0 - score","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:11:16.068021Z","iopub.execute_input":"2022-07-16T19:11:16.068348Z","iopub.status.idle":"2022-07-16T19:11:16.077147Z","shell.execute_reply.started":"2022-07-16T19:11:16.068316Z","shell.execute_reply":"2022-07-16T19:11:16.076130Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **MODEL INTIALIZATION**","metadata":{}},{"cell_type":"code","source":"EPOCHS = 36\nLEARNING_RATE = 1e-3","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:11:16.078789Z","iopub.execute_input":"2022-07-16T19:11:16.079420Z","iopub.status.idle":"2022-07-16T19:11:16.086681Z","shell.execute_reply.started":"2022-07-16T19:11:16.079382Z","shell.execute_reply":"2022-07-16T19:11:16.085593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = buildModel()\n\nopt = tf.keras.optimizers.Adam(LEARNING_RATE)\nmodel.compile(optimizer=opt, loss=DiceLoss(), metrics=[tf.keras.metrics.MeanIoU(num_classes=2)])","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:11:16.090535Z","iopub.execute_input":"2022-07-16T19:11:16.090931Z","iopub.status.idle":"2022-07-16T19:11:16.340636Z","shell.execute_reply.started":"2022-07-16T19:11:16.090903Z","shell.execute_reply":"2022-07-16T19:11:16.339708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callback0 = tf.keras.callbacks.ModelCheckpoint(f\"BestModel.h5\", \n               monitor='loss',save_best_only=True, verbose=1)","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:11:16.342098Z","iopub.execute_input":"2022-07-16T19:11:16.342428Z","iopub.status.idle":"2022-07-16T19:11:16.348302Z","shell.execute_reply.started":"2022-07-16T19:11:16.342396Z","shell.execute_reply":"2022-07-16T19:11:16.346984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **MODEL TRAINING**","metadata":{}},{"cell_type":"code","source":"model.fit(trainGen, validation_data=validGen, epochs=EPOCHS, callbacks=[callback0])","metadata":{"execution":{"iopub.status.busy":"2022-07-16T19:11:16.349960Z","iopub.execute_input":"2022-07-16T19:11:16.350305Z","iopub.status.idle":"2022-07-16T19:12:58.933244Z","shell.execute_reply.started":"2022-07-16T19:11:16.350272Z","shell.execute_reply":"2022-07-16T19:12:58.930898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}