{"cells":[{"metadata":{},"cell_type":"markdown","source":"**General information**\n\nThis is my first published Kernel :)\nIf there are any Mistakes or Errors please let met notice.\nDescriptions of each part will follow soon, as well as a training pipeline.\nWith the Descriptions the aknowledgements will follow.\nBut I want to go ahead and say thank you to xhlulu and Andrew for their amazing Kernels.\n"},{"metadata":{},"cell_type":"markdown","source":"# Imports"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import os\nimport json\n\nimport albumentations as albu\nimport cv2\nimport keras\nfrom keras import backend as K\nfrom keras.models import Model\nfrom keras.layers import Input\nfrom keras.layers.convolutional import Conv2D, Conv2DTranspose\nfrom keras.layers.pooling import MaxPooling2D\nfrom keras.layers.merge import concatenate\nfrom keras.losses import binary_crossentropy\nfrom keras.callbacks import Callback, ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\nfrom skimage.exposure import adjust_gamma\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom sklearn.model_selection import train_test_split\nfrom keras.layers import LeakyReLU\nfrom keras.layers import Input, Conv2D, Conv2DTranspose, MaxPooling2D, concatenate, Dropout,BatchNormalization\nfrom keras.layers import Conv2D, Concatenate, MaxPooling2D\nfrom keras.layers import UpSampling2D, Dropout, BatchNormalization\nfrom keras import optimizers\nfrom keras.legacy import interfaces\nfrom keras.utils.generic_utils import get_custom_objects\n\nfrom keras.engine.topology import Input\nfrom keras.engine.training import Model\nfrom keras.layers.convolutional import Conv2D, UpSampling2D, Conv2DTranspose\nfrom keras.layers.core import Activation, SpatialDropout2D\nfrom keras.layers.merge import concatenate\nfrom keras.layers.normalization import BatchNormalization\nfrom keras.layers.pooling import MaxPooling2D\nfrom keras.layers import Input,Dropout,BatchNormalization,Activation,Add\nfrom keras.regularizers import l2\nfrom keras.layers.core import Dense, Lambda\nfrom keras.layers.merge import concatenate, add\nfrom keras.layers import GlobalAveragePooling2D, Reshape, Dense, multiply, Permute\nfrom keras.optimizers import SGD\nfrom keras.preprocessing.image import ImageDataGenerator","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"!pip install ../input/efficientnet-keras-source-code/repository/qubvel-efficientnet-c993591","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Helper Functions"},{"metadata":{},"cell_type":"markdown","source":"taken from Andrews Kernel: https://www.kaggle.com/artgor/segmentation-in-pytorch-using-convenient-tools"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"def post_process(probability, threshold, min_size):\n    \"\"\"\n    Post processing of each predicted mask, components with lesser number of pixels\n    than `min_size` are ignored\n    \"\"\"\n    \n    mask = cv2.threshold(probability, threshold, 1, cv2.THRESH_BINARY)[1]\n    \n    num_component, component = cv2.connectedComponents(mask.astype(np.uint8))\n    predictions = np.zeros((350, 525), np.float32)\n    num = 0\n    for c in range(1, num_component):\n        p = (component == c)\n        if p.sum() > min_size:\n            predictions[p] = 1\n            num += 1\n    return predictions, num\n\ndef np_resize(img, input_shape):\n    \"\"\"\n    Reshape a numpy array, which is input_shape=(height, width), \n    as opposed to input_shape=(width, height) for cv2\n    \"\"\"\n    height, width = input_shape\n    return cv2.resize(img, (width, height))\n    \ndef mask2rle(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\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\ndef rle2mask(rle, input_shape):\n    width, height = input_shape[:2]\n    \n    mask= np.zeros( width*height ).astype(np.uint8)\n    \n    array = np.asarray([int(x) for x in rle.split()])\n    starts = array[0::2]\n    lengths = array[1::2]\n\n    current_position = 0\n    for index, start in enumerate(starts):\n        mask[int(start):int(start+lengths[index])] = 1\n        current_position += lengths[index]\n        \n    return mask.reshape(height, width).T\n\ndef build_masks(rles, input_shape, reshape=None):\n    depth = len(rles)\n    if reshape is None:\n        masks = np.zeros((*input_shape, depth))\n    else:\n        masks = np.zeros((*reshape, depth))\n    \n    for i, rle in enumerate(rles):\n        if type(rle) is str:\n            if reshape is None:\n                masks[:, :, i] = rle2mask(rle, input_shape)\n            else:\n                mask = rle2mask(rle, input_shape)\n                reshaped_mask = np_resize(mask, reshape)\n                masks[:, :, i] = reshaped_mask\n    \n    return masks\n\ndef build_rles(masks, reshape=None):\n    width, height, depth = masks.shape\n    \n    rles = []\n    \n    for i in range(depth):\n        mask = masks[:, :, i]\n        \n        if reshape:\n            mask = mask.astype(np.float32)\n            mask = np_resize(mask, reshape).astype(np.int64)\n        \n        rle = mask2rle(mask)\n        rles.append(rle)\n        \n    return rles","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preprocessing"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/understanding_cloud_organization/train.csv')\ntrain_df['ImageId'] = train_df['Image_Label'].apply(lambda x: x.split('_')[0])\ntrain_df['ClassId'] = train_df['Image_Label'].apply(lambda x: x.split('_')[1])\ntrain_df['hasMask'] = ~ train_df['EncodedPixels'].isna()\n\nprint(train_df.shape)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mask_count_df = train_df.groupby('ImageId').agg(np.sum).reset_index()\nmask_count_df.sort_values('hasMask', ascending=False, inplace=True)\nprint(mask_count_df.shape)\nmask_count_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df = pd.read_csv('../input/understanding_cloud_organization/sample_submission.csv')\nsub_df['ImageId'] = sub_df['Image_Label'].apply(lambda x: x.split('_')[0])\ntest_imgs = pd.DataFrame(sub_df['ImageId'].unique(), columns=['ImageId'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# DataGenerator"},{"metadata":{},"cell_type":"markdown","source":"Data Generator taken from Yirun Zhang: https://www.kaggle.com/gogo827jz/resunet-keras-with-some-new-ideas\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"class DataGenerator(keras.utils.Sequence):\n    'Generates data for Keras'\n    def __init__(self, list_IDs, df, target_df=None, mode='fit',\n                 base_path='../input/understanding_cloud_organization/train_images',\n                 batch_size=32, dim=(1400, 2100), n_channels=3, reshape=None, gamma=None,\n                 augment=False, n_classes=4, random_state=2019, shuffle=True):\n        self.dim = dim\n        self.batch_size = batch_size\n        self.df = df\n        self.mode = mode\n        self.base_path = base_path\n        self.target_df = target_df\n        self.list_IDs = list_IDs\n        self.reshape = reshape\n        self.gamma = gamma\n        self.n_channels = n_channels\n        self.augment = augment\n        self.n_classes = n_classes\n        self.shuffle = shuffle\n        self.random_state = random_state\n        \n        self.on_epoch_end()\n        np.random.seed(self.random_state)\n\n    def __len__(self):\n        'Denotes the number of batches per epoch'\n        return int(np.floor(len(self.list_IDs) / self.batch_size))\n\n    def __getitem__(self, index):\n        'Generate one batch of data'\n        # Generate indexes of the batch\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n\n        # Find list of IDs\n        list_IDs_batch = [self.list_IDs[k] for k in indexes]\n        \n        X = self.__generate_X(list_IDs_batch)\n        \n        if self.mode == 'fit':\n            y = self.__generate_y(list_IDs_batch)\n            \n            if self.augment:\n                X, y = self.__augment_batch(X, y)\n            \n            return X, y\n        \n        elif self.mode == 'predict':\n            return X\n\n        else:\n            raise AttributeError('The mode parameter should be set to \"fit\" or \"predict\".')\n        \n    def on_epoch_end(self):\n        'Updates indexes after each epoch'\n        self.indexes = np.arange(len(self.list_IDs))\n        if self.shuffle == True:\n            np.random.seed(self.random_state)\n            np.random.shuffle(self.indexes)\n    \n    def __generate_X(self, list_IDs_batch):\n        'Generates data containing batch_size samples'\n        # Initialization\n        if self.reshape is None:\n            X = np.empty((self.batch_size, *self.dim, self.n_channels))\n        else:\n            X = np.empty((self.batch_size, *self.reshape, self.n_channels))\n        \n        # Generate data\n        for i, ID in enumerate(list_IDs_batch):\n           # print(\" ids +\", i, ID)\n            #if(self.modi is None):\n            im_name = self.df['ImageId'].loc[ID]\n            img_path = f\"{self.base_path}/{im_name}\"\n            img = self.__load_rgb(img_path)\n            \n            if self.reshape is not None:\n                img = np_resize(img, self.reshape)\n            \n            # Adjust gamma\n            if self.gamma is not None:\n                img = adjust_gamma(img, gamma=self.gamma)\n            \n            # Store samples\n            X[i,] = img\n\n        return X\n    \n    def __generate_y(self, list_IDs_batch):\n        if self.reshape is None:\n            y = np.empty((self.batch_size, *self.dim, self.n_classes), dtype=int)\n        else:\n            y = np.empty((self.batch_size, *self.reshape, self.n_classes), dtype=int)\n        \n        for i, ID in enumerate(list_IDs_batch):\n            im_name = self.df['ImageId'].iloc[ID]\n            image_df = self.target_df[self.target_df['ImageId'] == im_name]\n            \n            rles = image_df['EncodedPixels'].values\n            \n            if self.reshape is not None:\n                masks = build_masks(rles, input_shape=self.dim, reshape=self.reshape)\n            else:\n                masks = build_masks(rles, input_shape=self.dim)\n            \n            y[i, ] = masks\n\n        return y\n    \n    def __load_grayscale(self, img_path):\n        img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)\n        img = img.astype(np.float32) / 255.\n        img = np.expand_dims(img, axis=-1)\n\n        return img\n    \n    def __load_rgb(self, img_path):\n        img = cv2.imread(img_path)\n       # print(img_path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        img = img.astype(np.float32) / 255.\n        #plt.imshow(img)\n        #plt.show()\n\n        return img\n    \n    def __random_transform(self, img, masks):\n        composition = albu.Compose([\n            albu.HorizontalFlip(),\n        ])\n        \n        composed = composition(image=img, mask=masks)\n        aug_img = composed['image']\n        aug_masks = composed['mask']\n        \n        return aug_img, aug_masks\n    \n    def __augment_batch(self, img_batch, masks_batch):\n        for i in range(img_batch.shape[0]):\n            img_batch[i, ], masks_batch[i, ] = self.__random_transform(\n                img_batch[i, ], masks_batch[i, ])\n        \n        return img_batch, masks_batch","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def H(lst, name, use_gn=False):\n    if use_gn:\n        norm = GroupNormalization(groups=1, name=name+'_gn')\n    else:\n        norm = BatchNormalization(name=name+'_bn')\n    \n    x = concatenate(lst)\n    num_filters = int(x.shape.as_list()[-1]/2)\n    \n    x = Conv2D(num_filters, (2, 2), padding='same', name=name)(x)\n    x = norm(x)\n    x = LeakyReLU(alpha=0.1, name=name+'_activation')(x)\n    \n    return x\n\ndef U(x, use_gn=False):\n    if use_gn:\n        norm = GroupNormalization(groups=1)\n    else:\n        norm = BatchNormalization()\n    \n    num_filters = int(x.shape.as_list()[-1]/2)\n    \n    x = Conv2DTranspose(num_filters, (3, 3), strides=(2, 2), padding='same')(x)\n    x = norm(x)\n    x = LeakyReLU(alpha=0.1)(x)\n    \n    return x","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Model Architecture from xhlulus amazing Kernel: https://www.kaggle.com/xhlulu/severstal-u-net-with-efficientnetb4"},{"metadata":{"trusted":true},"cell_type":"code","source":"import efficientnet.keras as efn \ndef EfficientUNet(input_shape):\n    backbone = efn.EfficientNetB4(\n        weights=None,\n        include_top=False,\n        input_shape=input_shape\n    )\n    \n    input = backbone.input\n    x00 = backbone.input  # (256, 512, 3)\n    x10 = backbone.get_layer('stem_activation').output  # (128, 256, 4)\n    x20 = backbone.get_layer('block2d_add').output  # (64, 128, 32)\n    x30 = backbone.get_layer('block3d_add').output  # (32, 64, 56)\n    x40 = backbone.get_layer('block5f_add').output  # (16, 32, 160)\n    x50 = backbone.get_layer('block7b_add').output  # (8, 16, 448)\n    \n    x01 = H([x00, U(x10)], 'X01')\n    x11 = H([x10, U(x20)], 'X11')\n    x21 = H([x20, U(x30)], 'X21')\n    x31 = H([x30, U(x40)], 'X31')\n    x41 = H([x40, U(x50)], 'X41')\n    \n    x02 = H([x00, x01, U(x11)], 'X02')\n    x12 = H([x11, U(x21)], 'X12')\n    x22 = H([x21, U(x31)], 'X22')\n    x32 = H([x31, U(x41)], 'X32')\n    \n    x03 = H([x00, x01, x02, U(x12)], 'X03')\n    x13 = H([x12, U(x22)], 'X13')\n    x23 = H([x22, U(x32)], 'X23')\n    \n    x04 = H([x00, x01, x02, x03, U(x13)], 'X04')\n    x14 = H([x13, U(x23)], 'X14')\n    \n    x05 = H([x00, x01, x02, x03, x04, U(x14)], 'X05')\n    \n    x_out = Concatenate(name='bridge')([x01, x02, x03, x04, x05])\n    x_out = Conv2D(4, (3,3), padding=\"same\", name='final_output', activation=\"sigmoid\")(x_out)\n    \n    return Model(inputs=input, outputs=x_out)\n\nmodel = EfficientUNet((320, 480 ,3))\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#model.load_weights(\"../input/cloudmodels/EfficientNetB4.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"minsizes = [20000 ,20000, 22500, 10000]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sigmoid = lambda x: 1 / (1 + np.exp(-x))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = []\n\nsubsize = 500\n\nfor i in range(0, test_imgs.shape[0], subsize):\n    batch_idx = list(\n        range(i, min(test_imgs.shape[0], i + subsize))\n    )\n\n    test_generator = DataGenerator(\n        batch_idx,\n        df=test_imgs,\n        shuffle=False,\n        mode='predict',\n        dim=(350, 525),\n        reshape=(320, 480),\n        gamma=0.8,\n        n_channels=3,\n        base_path='../input/understanding_cloud_organization/test_images',\n        target_df=sub_df,\n        batch_size=1,\n        n_classes=4\n    )\n\n    batch_pred_masks = model.predict_generator(\n        test_generator, \n        workers=1,\n        verbose=1\n    )\n\n    for j, b in enumerate(batch_idx):\n        filename = test_imgs['ImageId'].iloc[b]\n        image_df = sub_df[sub_df['ImageId'] == filename].copy()\n\n        pred_masks = batch_pred_masks[j, ]\n        \n        pred_masks = cv2.resize(pred_masks, dsize=(525, 350), interpolation=cv2.INTER_LINEAR)\n\n        arrt = np.array([])\n        for t in range(4):\n            a, num_predict = post_process(sigmoid(pred_masks[:, :, t]), 0.6, minsizes[t])\n            \n            \n            if(arrt.shape == (0,)):\n                arrt = a.reshape(350, 525, 1)\n            else:\n                arrt = np.append(arrt, a.reshape(350, 525, 1), axis = 2)\n           \n        pred_rles = build_rles(arrt, reshape=(350, 525))\n\n        image_df['EncodedPixels'] = pred_rles\n        test_df.append(image_df)\n\nsub_df = pd.concat(test_df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df = sub_df[['Image_Label', 'EncodedPixels']]\nsub_df.to_csv('submission.csv', index=False)\ndisplay(sub_df.head(10))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":1}