{"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":"<center><img src=\"https://raw.githubusercontent.com/dimitreOliveira/MachineLearning/master/Kaggle/Understanding%20Clouds%20from%20Satellite%20Images/banner.png\" width=\"800\"></center>\n\n<h1><center>Understanding Clouds from Satellite Images</center></h1>\n<h2><center>Can you classify cloud structures from satellites?</center></h2>\n\n#### In this competition we need to analyze and process cloud images taken from satellites in order to identify cloud formations and help improve the earth's climate understanding.\n\n### Dependencies","metadata":{}},{"cell_type":"code","source":"!pip install keras-segmentation\n!pip install tensorflow==1.14\n!pip install keras==2.2.4\n!pip install -U segmentation-models==1.0.*","metadata":{"execution":{"iopub.status.busy":"2021-09-20T13:28:07.462978Z","iopub.execute_input":"2021-09-20T13:28:07.463258Z","iopub.status.idle":"2021-09-20T13:28:33.373377Z","shell.execute_reply.started":"2021-09-20T13:28:07.46321Z","shell.execute_reply":"2021-09-20T13:28:33.37256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport keras\nimport random\nimport warnings\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport albumentations as albu\nimport matplotlib.pyplot as plt\nfrom tensorflow import set_random_seed\nfrom sklearn.model_selection import train_test_split\nfrom keras import optimizers\nfrom keras import backend as K\nfrom keras.models import Model\nfrom keras.losses import binary_crossentropy\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau\nfrom keras.layers import Input, Conv2D, Conv2DTranspose, MaxPooling2D, Concatenate\n\ndef seed_everything(seed=0):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    set_random_seed(seed)\n\nseed = 0\nseed_everything(seed)\n%matplotlib inline\nwarnings.filterwarnings(\"ignore\")\n\n!pip install segmentation-models\nimport segmentation_models as sm\nkeras.backend.set_image_data_format('channels_last')\nmodel = sm.Unet()\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-09-20T13:28:33.375292Z","iopub.execute_input":"2021-09-20T13:28:33.37559Z","iopub.status.idle":"2021-09-20T13:28:47.39952Z","shell.execute_reply.started":"2021-09-20T13:28:33.375544Z","shell.execute_reply":"2021-09-20T13:28:47.398797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Load data","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv('../input/understanding_cloud_organization/train.csv')\nsubmission = pd.read_csv('../input/understanding_cloud_organization/sample_submission.csv')\nprint('Number of train samples:', train.shape[0])\nprint('Number of test samples:', submission.shape[0])\n\n# Preprocecss data\ntrain['image'] = train['Image_Label'].apply(lambda x: x.split('_')[0])\ntrain['label'] = train['Image_Label'].apply(lambda x: x.split('_')[1])\nsubmission['image'] = submission['Image_Label'].apply(lambda x: x.split('_')[0])\ntest = pd.DataFrame(submission['image'].unique(), columns=['image'])\n\ndisplay(train.head())\ndisplay(train.describe())","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:28:47.40099Z","iopub.execute_input":"2021-09-20T13:28:47.401277Z","iopub.status.idle":"2021-09-20T13:28:51.051998Z","shell.execute_reply.started":"2021-09-20T13:28:47.401233Z","shell.execute_reply":"2021-09-20T13:28:51.051288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EDA\n\n### We have four possible label classes(Fish, Flower, Gravel, Sugar), now let's look at some samples from the training set\n\n\n#### Without mask","metadata":{}},{"cell_type":"code","source":"sns.set_style(\"white\")\nplt.figure(figsize=[60, 20])\nfor index, row in train[:8].iterrows():\n    img = cv2.imread(\"../input/understanding_cloud_organization/train_images/%s\" % row['image'])[...,[2, 1, 0]]\n    plt.subplot(2, 4, index+1)\n    plt.imshow(img)\n    plt.title(\"Image %s - Label %s\" % (index, row['label']), fontsize=22)\n    plt.axis('off')    \n    \nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:28:51.053467Z","iopub.execute_input":"2021-09-20T13:28:51.05377Z","iopub.status.idle":"2021-09-20T13:28:53.693635Z","shell.execute_reply.started":"2021-09-20T13:28:51.053719Z","shell.execute_reply":"2021-09-20T13:28:53.69269Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### With mask","metadata":{}},{"cell_type":"code","source":"def rle_decode(mask_rle, shape=(1400, 2100)):\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, order='F')  # Needed to align to RLE direction\n\nplt.figure(figsize=[60, 20])\nfor index, row in train[:8].iterrows():\n    img = cv2.imread(\"../input/understanding_cloud_organization/train_images/%s\" % row['image'])[...,[2, 1, 0]]\n    mask_rle = row['EncodedPixels']\n    try: # label might not be there!\n        mask = rle_decode(mask_rle)\n    except:\n        mask = np.zeros((1400, 2100))\n    plt.subplot(2, 4, index+1)\n    plt.imshow(img)\n    plt.imshow(mask, alpha=0.5, cmap='gray')\n    plt.title(\"Image %s - Label %s\" % (index, row['label']), fontsize=22)\n    plt.axis('off')    \n    \nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:28:53.697582Z","iopub.execute_input":"2021-09-20T13:28:53.697867Z","iopub.status.idle":"2021-09-20T13:28:57.656671Z","shell.execute_reply.started":"2021-09-20T13:28:53.69783Z","shell.execute_reply":"2021-09-20T13:28:57.648002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Looking at these samples some images seem to have a light reflection, maybe we can remove them during preprocess, or even add this reflection to other images for some image augmentation.\n\nAlso, some have a black area, from the competition description the reason is this: \"Due to the small footprint of the imager (MODIS) on board these satellites, an image might be stitched together from two orbits. The remaining area, which has not been covered by two succeeding orbits, is marked black.\"","metadata":{}},{"cell_type":"markdown","source":"## Number of samples for each label (cloud formation)\n\n As we can see the dataset if perfectly balanced, at least looking at the label count, we have 5546 samples for each of the 4 cloud formation types.","metadata":{}},{"cell_type":"code","source":"for lbl in train['label'].unique():\n    print('%s %s' % (lbl, len(train[train['label'] == lbl])))\n\nsns.set(style=\"whitegrid\")\nf, ax = plt.subplots(figsize=(14, 6))\nax = sns.countplot(y=\"label\", data=train, palette=\"GnBu_d\")\nsns.despine()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:28:57.659164Z","iopub.execute_input":"2021-09-20T13:28:57.659644Z","iopub.status.idle":"2021-09-20T13:28:58.181559Z","shell.execute_reply.started":"2021-09-20T13:28:57.659569Z","shell.execute_reply":"2021-09-20T13:28:58.173605Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Let's take a look at a sample from each class","metadata":{}},{"cell_type":"code","source":"train['Has Mask'] = ~train['EncodedPixels'].isna()\nmaskedSamples = train[train['Has Mask'] == True]\nfirstLabel = maskedSamples.groupby('label').first().reset_index()\n\nsns.set_style(\"white\")\nplt.figure(figsize=[15, 10])\nfor index, row in firstLabel.iterrows():\n    img = cv2.imread(\"../input/understanding_cloud_organization/train_images/%s\" % row['image'])[...,[2, 1, 0]]\n    plt.subplot(2, 2, index+1)\n    mask_rle = row['EncodedPixels']\n    try: # label might not be there!\n        mask = rle_decode(mask_rle)\n    except:\n        mask = np.zeros((1400, 2100))\n    plt.imshow(img)\n    plt.imshow(mask, alpha=0.5, cmap='gray')\n    plt.title(\"Image %s - Label %s\" % (row['image'], row['label']), fontsize=22)\n    plt.axis('off')\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:28:58.184648Z","iopub.execute_input":"2021-09-20T13:28:58.197457Z","iopub.status.idle":"2021-09-20T13:28:59.843299Z","shell.execute_reply.started":"2021-09-20T13:28:58.184937Z","shell.execute_reply":"2021-09-20T13:28:59.842367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Segmented area distribution\n\n### Some of the samples don't have a segmentation mask, this means that the image doesn't have any of the label's cloud formation\n\nAlmost half of the samples don't have a mask, images that don't have any of the four cloud formations should not have a prediction on the output file.","metadata":{}},{"cell_type":"code","source":"sns.set(style=\"whitegrid\")\nf, ax = plt.subplots(figsize=(14, 6))\nax = sns.countplot(y=\"Has Mask\", data=train)\nsns.despine()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:28:59.844797Z","iopub.execute_input":"2021-09-20T13:28:59.84532Z","iopub.status.idle":"2021-09-20T13:29:00.060112Z","shell.execute_reply.started":"2021-09-20T13:28:59.845038Z","shell.execute_reply":"2021-09-20T13:29:00.059014Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Number of mask per sample\n\n#### Each image can have more than one label, and labels from different classes.\n\nSo on the dataset each image will have four rows and will only have \"EncodedPixels\" feature if it has that label, look at the image \"0011165.jpg\" it has \"Fish\" and  \"Flower\" cloud formations, so it has values for those labels, and the other are null","metadata":{}},{"cell_type":"code","source":"display(train[train['image'] == '0011165.jpg'])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:29:00.061588Z","iopub.execute_input":"2021-09-20T13:29:00.06187Z","iopub.status.idle":"2021-09-20T13:29:00.088001Z","shell.execute_reply.started":"2021-09-20T13:29:00.061824Z","shell.execute_reply":"2021-09-20T13:29:00.087136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Most of the images have at least 2 labels, and only a few have all the 4 cloud formations.","metadata":{}},{"cell_type":"code","source":"maskedSamples_gp = maskedSamples.groupby('image').size().reset_index(name='Number of masks')\n\nfor n_masks in np.sort(maskedSamples_gp['Number of masks'].unique()):\n    print('Samples with %s masks: %s' % (n_masks, len(maskedSamples_gp[maskedSamples_gp['Number of masks'] == n_masks])))\n    \nf, ax = plt.subplots(figsize=(18, 6))\nax = sns.countplot(y=\"Number of masks\", data=maskedSamples_gp, palette=\"GnBu_d\")\nsns.despine()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:29:00.092766Z","iopub.execute_input":"2021-09-20T13:29:00.095224Z","iopub.status.idle":"2021-09-20T13:29:00.362285Z","shell.execute_reply.started":"2021-09-20T13:29:00.095162Z","shell.execute_reply":"2021-09-20T13:29:00.361493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Split train and validation sets","metadata":{}},{"cell_type":"code","source":"mask_count_df = train.groupby('image').agg(np.sum).reset_index()\nmask_count_df.sort_values('Has Mask', ascending=False, inplace=True)\ntrain_idx, val_idx = train_test_split(mask_count_df.index, test_size=0.2, random_state=seed)","metadata":{"execution":{"iopub.status.busy":"2021-09-20T13:29:00.366713Z","iopub.execute_input":"2021-09-20T13:29:00.369171Z","iopub.status.idle":"2021-09-20T13:29:00.401394Z","shell.execute_reply.started":"2021-09-20T13:29:00.369109Z","shell.execute_reply":"2021-09-20T13:29:00.400544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def np_resize(img, input_shape):\n    height, width = input_shape\n    return cv2.resize(img, (width, height))\n    \ndef mask2rle(img):\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    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\n\ndef dice_coef(y_true, y_pred, smooth=1):\n    y_true_f = K.flatten(y_true)\n    y_pred_f = K.flatten(y_pred)\n    intersection = K.sum(y_true_f * y_pred_f)\n    return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)\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(y_true, y_pred) + dice_loss(y_true, y_pred)\n\ndef post_process(probability, threshold=0.5, min_size=10000):\n    mask = cv2.threshold(probability, threshold, 1, cv2.THRESH_BINARY)[1]\n    num_component, component = cv2.connectedComponents(mask.astype(np.uint8))\n    predictions = np.zeros(probability.shape, 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","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:29:00.406098Z","iopub.execute_input":"2021-09-20T13:29:00.408613Z","iopub.status.idle":"2021-09-20T13:29:00.441274Z","shell.execute_reply.started":"2021-09-20T13:29:00.408553Z","shell.execute_reply":"2021-09-20T13:29:00.44057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model parameters","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 32\nEPOCHS = 15\nLEARNING_RATE = 3e-4\nHEIGHT = 320\nWIDTH = 480\nCHANNELS = 3\nN_CLASSES = train['label'].nunique()\nES_PATIENCE = 5\nRLROP_PATIENCE = 3\nDECAY_DROP = 0.5\nBACKBONE = 'resnet34'","metadata":{"execution":{"iopub.status.busy":"2021-09-20T13:29:00.442939Z","iopub.execute_input":"2021-09-20T13:29:00.443189Z","iopub.status.idle":"2021-09-20T13:29:00.457695Z","shell.execute_reply.started":"2021-09-20T13:29:00.443146Z","shell.execute_reply":"2021-09-20T13:29:00.457003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data generator\n\n#### I got the data generators and predictions from @xhlulu kernel: [Satellite Clouds: Yet another U-Net boilerplate](https://www.kaggle.com/xhlulu/satellite-clouds-yet-another-u-net-boilerplate/notebook) check out, I just changed a few things to make the code more familiar to me.","metadata":{}},{"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=BATCH_SIZE, dim=(1400, 2100), n_channels=CHANNELS, reshape=None, \n                 n_classes=N_CLASSES, random_state=seed, shuffle=True, augment=False):\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.n_channels = n_channels\n        self.n_classes = n_classes\n        self.shuffle = shuffle\n        self.augment = augment\n        self.random_state = random_state\n        \n        self.on_epoch_end()\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            im_name = self.df['image'].iloc[ID]\n            img_path = f\"{self.base_path}/{im_name}\"\n            img = cv2.imread(img_path)\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n            img = img.astype(np.float32) / 255.\n            \n            if self.reshape is not None:\n                img = np_resize(img, self.reshape)\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['image'].iloc[ID]\n            image_df = self.target_df[self.target_df['image'] == 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 __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(img_batch[i, ], masks_batch[i, ])\n        \n        return img_batch, masks_batch\n    \n    def __random_transform(self, img, masks):\n        composition = albu.Compose([albu.HorizontalFlip(p=0.5),\n                               albu.VerticalFlip(p=0.5),\n                               albu.GridDistortion(p=0.2),\n                               albu.ElasticTransform(p=0.2)\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    \ntrain_generator = DataGenerator(\n                  train_idx, \n                  df=mask_count_df,\n                  target_df=train,\n                  batch_size=BATCH_SIZE,\n                  reshape=(HEIGHT, WIDTH),\n                  n_channels=CHANNELS,\n                  n_classes=N_CLASSES,\n                  augment=True,\n                  random_state=seed)\n\nvalid_generator = DataGenerator(\n                  val_idx, \n                  df=mask_count_df,\n                  target_df=train,\n                  batch_size=BATCH_SIZE, \n                  reshape=(HEIGHT, WIDTH),\n                  n_channels=CHANNELS,\n                  n_classes=N_CLASSES,\n                  random_state=seed)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T13:29:00.459265Z","iopub.execute_input":"2021-09-20T13:29:00.459677Z","iopub.status.idle":"2021-09-20T13:29:00.493404Z","shell.execute_reply.started":"2021-09-20T13:29:00.459617Z","shell.execute_reply":"2021-09-20T13:29:00.492657Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model\n\n#### You can find the explaination about the loss function on [this great post](https://lars76.github.io/neural-networks/object-detection/losses-for-segmentation/).","metadata":{}},{"cell_type":"code","source":"preprocess_input = sm.get_preprocessing(BACKBONE)\nmodel = sm.Unet('resnet34', classes=N_CLASSES,\n           activation='sigmoid',\n           input_shape=(HEIGHT, WIDTH, CHANNELS), encoder_weights=None)\n\n\n\n\nes = EarlyStopping(monitor='val_loss', mode='min', patience=ES_PATIENCE, restore_best_weights=True, verbose=1)\nrlrop = ReduceLROnPlateau(monitor='val_loss', mode='min', patience=RLROP_PATIENCE, factor=DECAY_DROP, min_lr=1e-6, verbose=1)\n\nmetric_list = [dice_coef]\ncallback_list = [es, rlrop]\noptimizer = optimizers.Adam(lr=LEARNING_RATE)\nmodel.compile(optimizer=optimizer, loss=bce_dice_loss, metrics=metric_list)\nmodel.summary()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-09-20T13:37:22.131382Z","iopub.execute_input":"2021-09-20T13:37:22.131725Z","iopub.status.idle":"2021-09-20T13:37:26.517255Z","shell.execute_reply.started":"2021-09-20T13:37:22.131674Z","shell.execute_reply":"2021-09-20T13:37:26.51485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit_generator(generator=train_generator,\n                              validation_data=valid_generator,\n                              epochs=EPOCHS,\n                              callbacks=callback_list,\n                              verbose=2).history","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-09-20T13:37:39.917091Z","iopub.execute_input":"2021-09-20T13:37:39.917424Z","iopub.status.idle":"2021-09-20T17:14:51.108476Z","shell.execute_reply.started":"2021-09-20T13:37:39.917358Z","shell.execute_reply":"2021-09-20T17:14:51.107516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model loss graph","metadata":{}},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, sharex='col', figsize=(20, 12))\n\nax1.plot(history['loss'], label='Train loss')\nax1.plot(history['val_loss'], label='Validation loss')\nax1.legend(loc='best')\nax1.set_title('Loss')\n\nax2.plot(history['dice_coef'], label='Train Dice coefficient')\nax2.plot(history['val_dice_coef'], label='Validation Dice coefficient')\nax2.legend(loc='best')\nax2.set_title('Dice coefficient')\n\nplt.xlabel('Epochs')\nsns.despine()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T17:16:04.885663Z","iopub.execute_input":"2021-09-20T17:16:04.885981Z","iopub.status.idle":"2021-09-20T17:16:05.387191Z","shell.execute_reply.started":"2021-09-20T17:16:04.885931Z","shell.execute_reply":"2021-09-20T17:16:05.386131Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Apply model to test set","metadata":{}},{"cell_type":"code","source":"test_df = []\n\nfor i in range(0, test.shape[0], 500):\n    batch_idx = list(range(i, min(test.shape[0], i + 500)))\n    \n    test_generator = DataGenerator(\n                     batch_idx,\n                     df=test,\n                     target_df=submission,\n                     batch_size=1,\n                     reshape=(HEIGHT, WIDTH),\n                     dim=(350, 525),\n                     n_channels=CHANNELS,\n                     n_classes=N_CLASSES,\n                     random_state=seed,\n                     base_path='../input/understanding_cloud_organization/test_images',\n                     mode='predict',\n                     shuffle=False)\n    \n    batch_pred_masks = model.predict_generator(test_generator)\n    \n    for j, b in enumerate(batch_idx):\n        filename = test['image'].iloc[b]\n        image_df = submission[submission['image'] == filename].copy()\n        pred_masks = batch_pred_masks[j, ].round().astype(int)\n        \n        ### Post procecssing\n        pred_masks_post = batch_pred_masks[j, ].astype('float32') \n        for k in range(pred_masks_post.shape[-1]):\n            pred_mask = pred_masks_post[...,k]\n\n            pred_mask, num_predict = post_process(pred_mask)\n            pred_masks_post[...,k] = pred_mask\n\n        pred_rles_post = build_rles(pred_masks_post, reshape=(350, 525))\n        image_df['EncodedPixels_post'] = pred_rles_post\n        ###\n        \n        pred_rles = build_rles(pred_masks, reshape=(350, 525))        \n        image_df['EncodedPixels'] = pred_rles\n        test_df.append(image_df)\n        \nsub_df = pd.concat(test_df)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T17:16:17.530344Z","iopub.execute_input":"2021-09-20T17:16:17.530658Z","iopub.status.idle":"2021-09-20T17:23:49.966059Z","shell.execute_reply.started":"2021-09-20T17:16:17.530607Z","shell.execute_reply":"2021-09-20T17:23:49.965085Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inspecting some of the predictions","metadata":{}},{"cell_type":"code","source":"sns.set_style(\"white\")\nplt.figure(figsize=[60, 20])\nfor index, row in sub_df[:8].iterrows():\n    img = cv2.imread(\"../input/understanding_cloud_organization/test_images/%s\" % row['image'])[...,[2, 1, 0]]\n    img = cv2.resize(img, (525, 350))\n    mask_rle = row['EncodedPixels']\n    try: # label might not be there!\n        mask = rle_decode(mask_rle)\n    except:\n        mask = np.zeros((1400, 2100))\n    plt.subplot(2, 4, index+1)\n    plt.imshow(img)\n    plt.imshow(rle2mask(mask_rle, img.shape), alpha=0.5, cmap='gray')\n    plt.title(\"Image %s\" % (row['Image_Label']), fontsize=18)\n    plt.axis('off')    \n    \nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T17:23:49.968022Z","iopub.execute_input":"2021-09-20T17:23:49.968303Z","iopub.status.idle":"2021-09-20T17:23:52.381489Z","shell.execute_reply.started":"2021-09-20T17:23:49.968259Z","shell.execute_reply":"2021-09-20T17:23:52.380726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Without background","metadata":{}},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 5, figsize=(30, 30))\naxs[0].imshow(cv2.resize(plt.imread('../input/understanding_cloud_organization/test_images/%s' % sub_df['image'][0]),(525, 350)))\naxs[0].set_title('Original', fontsize=16)\naxs[0].axis('off')\nfor i in range(4):\n    axs[i+1].imshow(rle2mask(sub_df['EncodedPixels'][i], img.shape))\n    axs[i+1].set_title(sub_df['Image_Label'][i], fontsize=18)\n    axs[i+1].axis('off')\n    \nfig, axs = plt.subplots(1, 5, figsize=(30, 30))\naxs[0].imshow(cv2.resize(plt.imread('../input/understanding_cloud_organization/test_images/%s' % sub_df['image'][4]),(525, 350)))\naxs[0].set_title('Original', fontsize=16)\naxs[0].axis('off')\nfor i in range(4):\n    axs[i+1].imshow(rle2mask(sub_df['EncodedPixels'][4 + i], img.shape))\n    axs[i+1].set_title(sub_df['Image_Label'][4 + i], fontsize=18)\n    axs[i+1].axis('off')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T17:23:52.382775Z","iopub.execute_input":"2021-09-20T17:23:52.383189Z","iopub.status.idle":"2021-09-20T17:23:53.910653Z","shell.execute_reply.started":"2021-09-20T17:23:52.383141Z","shell.execute_reply":"2021-09-20T17:23:53.909826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Without background and with post processing","metadata":{}},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 5, figsize=(30, 30))\naxs[0].imshow(cv2.resize(plt.imread('../input/understanding_cloud_organization/test_images/%s' % sub_df['image'][0]),(525, 350)))\naxs[0].set_title('Original', fontsize=16)\naxs[0].axis('off')\nfor i in range(4):\n    axs[i+1].imshow(rle2mask(sub_df['EncodedPixels_post'][i], img.shape))\n    axs[i+1].set_title(sub_df['Image_Label'][i], fontsize=18)\n    axs[i+1].axis('off')\n    \nfig, axs = plt.subplots(1, 5, figsize=(30, 30))\naxs[0].imshow(cv2.resize(plt.imread('../input/understanding_cloud_organization/test_images/%s' % sub_df['image'][4]),(525, 350)))\naxs[0].set_title('Original', fontsize=16)\naxs[0].axis('off')\nfor i in range(4):\n    axs[i+1].imshow(rle2mask(sub_df['EncodedPixels_post'][4 + i], img.shape))\n    axs[i+1].set_title(sub_df['Image_Label'][4 + i], fontsize=18)\n    axs[i+1].axis('off')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T17:23:53.911952Z","iopub.execute_input":"2021-09-20T17:23:53.912481Z","iopub.status.idle":"2021-09-20T17:23:55.392025Z","shell.execute_reply.started":"2021-09-20T17:23:53.912195Z","shell.execute_reply":"2021-09-20T17:23:55.391296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Regular submission","metadata":{}},{"cell_type":"code","source":"submission_df = sub_df[['Image_Label' ,'EncodedPixels']]\nsubmission_df.to_csv('submission.csv', index=False)\ndisplay(submission_df.head())","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T17:26:13.735615Z","iopub.execute_input":"2021-09-20T17:26:13.735926Z","iopub.status.idle":"2021-09-20T17:26:15.006796Z","shell.execute_reply.started":"2021-09-20T17:26:13.735878Z","shell.execute_reply":"2021-09-20T17:26:15.006049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Submission with post processing","metadata":{}},{"cell_type":"code","source":"submission_df_post = sub_df[['Image_Label' ,'EncodedPixels_post']]\nsubmission_df_post.columns = ['Image_Label' ,'EncodedPixels']\nsubmission_df_post.to_csv('submission_post.csv', index=False)\ndisplay(submission_df_post.head())","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-09-20T17:26:21.36097Z","iopub.execute_input":"2021-09-20T17:26:21.36127Z","iopub.status.idle":"2021-09-20T17:26:22.293526Z","shell.execute_reply.started":"2021-09-20T17:26:21.361221Z","shell.execute_reply":"2021-09-20T17:26:22.292382Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.models import load_model\n\nmodel.save('my_model.h5')","metadata":{"execution":{"iopub.status.busy":"2021-09-20T17:37:52.78132Z","iopub.execute_input":"2021-09-20T17:37:52.781672Z","iopub.status.idle":"2021-09-20T17:37:53.737684Z","shell.execute_reply.started":"2021-09-20T17:37:52.781615Z","shell.execute_reply":"2021-09-20T17:37:53.736588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}