{"cells":[{"metadata":{},"cell_type":"markdown","source":"# This kernel was forked from my  previous steel competition kernel named  [*Severstal: unet++ with efficientnetb4 keras*](https://www.kaggle.com/mobassir/severstal-unet-with-efficientnetb4-keras)\n\ni will try to re implement that kernel again for this competition and the reason for re implementation can be understood by reading next couple of cells"},{"metadata":{},"cell_type":"markdown","source":"[**Review: DeepLabv3+ — Atrous Separable Convolution (Semantic Segmentation)**](https://medium.com/@sh.tsang/review-deeplabv3-atrous-separable-convolution-semantic-segmentation-a625f6e83b90)"},{"metadata":{},"cell_type":"markdown","source":"**Let’s review about DeepLabv3+, which is invented by Google. DeepLab series has come along for versions from DeepLabv1 (2015 ICLR), DeepLabv2 (2018 TPAMI), and DeepLabv3 (arXiv).**\n\n![](https://miro.medium.com/max/1557/1*Llh9dQ1ZMBqPMOJSf7WaBQ.png)"},{"metadata":{},"cell_type":"markdown","source":"1.     (a): With Atrous Spatial Pyramid Pooling (ASPP), able to encode multi-scale contextual information.\n\n2.     (b): With Encoder-Decoder Architecture, the location/spatial information is recovered. Encoder-Decoder Architecture has been proved to be useful in literature such as FPN, DSSD, TDM, SharpMask, RED-Net, and U-Net for different kinds of purposes.\n\n3.     (c): DeepLabv3+ makes use of (a) and (b).\n\n4.     Further, with the use of Modified Aligned Xception, and Atrous Separable Convolution, a faster and stronger network is developed.\n\n5.     Finally, DeepLabv3+ outperforms PSPNet (1st place in 2016 ILSVRC Scene Parsing Challenge) and its previous DeepLabv3.\n\nIt is published in 2018 ECCV with more than 600 citations. (Sik-Ho Tsang @ Medium)\n\nSource : https://medium.com/@sh.tsang/review-deeplabv3-atrous-separable-convolution-semantic-segmentation-a625f6e83b90"},{"metadata":{},"cell_type":"markdown","source":"# About this kernel\n\n*I will be experimenting  with google's deeplabv3+ with mobilenetv2 encoder.*\n\n## Changelog\n\nV1: running only for 2 epochs just to see if i get any error or not!\n## References\n\n* Data generator: https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly\n* RLE encoding and decoding: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode\n* Architecture: https://www.kaggle.com/jesperdramsch/intro-chest-xray-dicom-viz-u-nets-full-data\n* Mask encoding: https://www.kaggle.com/c/siim-acr-pneumothorax-segmentation/data\n* Source for `bce_dice_loss`: https://lars76.github.io/neural-networks/object-detection/losses-for-segmentation/\n* xhlulu's kernel : https://www.kaggle.com/xhlulu/severstal-simple-keras-u-net-boilerplate\n"},{"metadata":{},"cell_type":"markdown","source":"** <p style=\"color:red;\"> I hope this kernel helpful and some UPVOTES would be very much appreciated</p>  **"},{"metadata":{},"cell_type":"markdown","source":"Note : i am new in computer vision field,if you find any error or implementation bug please let me know and  recommendations of any idea in the comment box to improve this kernel are  highly appreciated,thanks in advance :)"},{"metadata":{},"cell_type":"markdown","source":"**Imports**"},{"metadata":{"trusted":true},"cell_type":"code","source":"'''!pip uninstall tensorflow-gpu\n!pip uninstall Keras'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#!pip install tensorflow-gpu==0.12.1\n!pip install tensorflow-gpu==1.14.0\n!pip install Keras==2.2.4","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"import os\nimport json\n\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\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\n\n\n!pip install albumentations > /dev/null\n#!pip install -U efficientnet==0.0.4\nimport numpy as np\nimport pandas as pd\nimport gc\nimport keras\nfrom skimage.transform import resize\nimport matplotlib.pyplot as plt\nplt.style.use('seaborn-white')\nimport seaborn as sns\nsns.set_style(\"white\")\n\nfrom sklearn.model_selection import train_test_split,StratifiedKFold\n\nfrom skimage.transform import resize\nimport tensorflow as tf\nimport keras.backend as K\nfrom keras.losses import binary_crossentropy\n\nfrom keras.preprocessing.image import load_img\nfrom keras import Model\nfrom keras.callbacks import  ModelCheckpoint\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 tqdm import tqdm_notebook\nfrom keras import initializers\nfrom keras import regularizers\nfrom keras import constraints\nfrom keras.utils import conv_utils\nfrom keras.utils.data_utils import get_file\nfrom keras.engine.topology import get_source_inputs\nfrom keras.engine import InputSpec\nfrom keras import backend as K\nfrom keras.layers import LeakyReLU\nfrom keras.layers import ZeroPadding2D\nfrom keras.losses import binary_crossentropy\nimport keras.callbacks as callbacks\nfrom keras.callbacks import Callback\nfrom keras.applications.xception import Xception\nfrom keras.layers import multiply\n\n\nfrom keras.models import load_model\nfrom keras.preprocessing import image\n\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\n\nimport glob\nimport shutil\nimport os\nimport random\nfrom PIL import Image\n\n\nfrom sklearn.utils import shuffle\nfrom os.path import isfile, join\nimport keras\n\n# Standard dependencies\nimport cv2\nimport time\nimport scipy as sp\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom PIL import Image\nfrom functools import partial\nimport matplotlib.pyplot as plt\n\n# Machine Learning\nimport tensorflow as tf\nimport keras\nfrom keras import initializers\nfrom keras import regularizers\nfrom keras import constraints\nfrom keras import backend as K\nfrom keras.activations import elu\nfrom keras.optimizers import Adam\nfrom keras.models import Sequential\nfrom keras.engine import Layer, InputSpec\nfrom keras.utils.generic_utils import get_custom_objects\nfrom keras.callbacks import Callback, EarlyStopping, ReduceLROnPlateau\nfrom keras.layers import Dense, Conv2D, Flatten, GlobalAveragePooling2D, Dropout\nfrom sklearn.metrics import cohen_kappa_score\nimport pydicom\n\nimport json\n\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport pydicom\nfrom keras import layers\nfrom keras.callbacks import Callback, ModelCheckpoint\nfrom keras.models import Sequential\nfrom keras.optimizers import Adam\nfrom tqdm import tqdm\n\n  \nfrom keras import backend as K\nimport tensorflow as tf\n\n!pip install pydensecrf\nseed = 10\nrandom.seed(seed)\nos.environ['PYTHONHASHSEED'] = str(seed)\nnp.random.seed(seed)\ntf.set_random_seed(seed)\n    \n%matplotlib inline\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nprint(os.listdir('../input/kerasdeeplabv3plus/keras-deeplab-v3-plus-master'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(os.listdir('../input/kerasdeeplabv31/Keras-segmentation-deeplab-v3.1-master'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!cp -r ../input/kerasdeeplabv31/Keras-segmentation-deeplab-v3.1-master/* ./","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!cp -r ../input/kerasdeeplabv3plus/keras-deeplab-v3-plus-master/* ./","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"'''import numpy as np\nfrom PIL import Image\nfrom matplotlib import pyplot as plt\n\nfrom model import Deeplabv3'''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"h = 400\nw = 400","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":"# Utility Functions\n\nSource: https://www.kaggle.com/paulorzp/rle-functions-run-lenght-encode-decode"},{"metadata":{},"cell_type":"markdown","source":"## Mask encoding and decoding"},{"metadata":{"trusted":true},"cell_type":"code","source":"def 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 formatted\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    current_output = mask.reshape(height, width).T\n    #new_output = np.expand_dims(current_output, axis=-1)\n    return current_output","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndef build_masks(rles, input_shape, reshape=None):\n    depth = len(rles)\n    d=depth\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":"## Loss function"},{"metadata":{},"cell_type":"markdown","source":"Source for `bce_dice_loss`: https://lars76.github.io/neural-networks/object-detection/losses-for-segmentation/"},{"metadata":{"trusted":true},"cell_type":"code","source":"def 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)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data Generator"},{"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=16, dim=(h, w, 3),\n                 n_classes=4, random_state=2019, shuffle=True, reshape=None):\n        self.dim = dim\n        self.batch_size = batch_size\n        self.df = df\n        self.mode = mode\n        self.reshape = reshape\n        self.base_path = base_path\n        self.target_df = target_df\n        self.list_IDs = list_IDs\n        self.n_channels = 3\n        self.n_classes = n_classes\n        self.shuffle = shuffle\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            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[:-1], self.n_channels))\n        else:\n            X = np.empty((self.batch_size, *self.reshape, self.n_channels))\n    \n        #X = np.empty((self.batch_size, *self.dim))\n        \n        # Generate data\n        for i, ID in enumerate(list_IDs_batch):\n            im_name = self.df['ImageId'].iloc[ID]\n            img_path = f\"{self.base_path}/{im_name}\"\n            #img = self.__load_grayscale(img_path)\n            #img = cv2.imread(img_path)\n            im = glob.glob(img_path)\n            for j in range(len(im)):\n                img = cv2.imread(im[j])\n                img = cv2.resize(img,(w,h))\n    \n       \n            #img = image.load_img(img_path, target_size=(img_size, img_size))\n            # Preprocessing the image\n            #img = image.img_to_array(img)\n            #img = np.expand_dims(img, axis=0)\n            \n            #img = cv2.resize(img, dim, interpolation = cv2.INTER_LINEAR)\n            # Store samples\n            X[i,] = img\n            #print(X)\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[:-1], 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            if self.reshape is not None:\n                masks = build_masks(rles, input_shape=self.dim[:-1], reshape=self.reshape)\n            else:\n                masks = build_masks(rles, input_shape=self.dim[:-1])\n            \n            y[i,] = masks\n\n        return y\n    \n    ''' def __load_grayscale(self, img_path):\n        #img = image.load_img(img_path, target_size=(512, 512))\n        img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)\n        #img = cv2.resize(img, (img_size, img_size), interpolation = cv2.INTER_CUBIC)\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        #img = cv2.resize(img, (img_size, img_size), interpolation = cv2.INTER_CUBIC)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        img = img.astype(np.float32) / 255.\n        #img = resize(img, (img_size, img_size))\n\n        return img   '''","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 16\n\ntrain_idx, val_idx = train_test_split(\n    mask_count_df.index, random_state=2019, test_size=0.2\n)\n\ntrain_generator = DataGenerator(\n    train_idx, \n    df=mask_count_df,\n    target_df=train_df,\n    batch_size=BATCH_SIZE, \n    n_classes=4\n)\n\nval_generator = DataGenerator(\n    val_idx, \n    df=mask_count_df,\n    target_df=train_df,\n    batch_size=BATCH_SIZE, \n    n_classes=4\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model Architecture (Deeplabv3+)\n\n"},{"metadata":{},"cell_type":"markdown","source":"**Depthwise Separable Convolution Using Atrous Convolution**\n\n![](https://miro.medium.com/max/1515/1*8n__Ky2heYAweOOv9MoKAQ.png)"},{"metadata":{},"cell_type":"markdown","source":"*     (a) and (b), Depthwise Separable Convolution: It factorize a standard convolution into a depthwise convolution followed by a point-wise convolution (i.e., 1×1 convolution), drastically reduces computation complexity.\n*     This is introduced in MobileNetV1. (If interested. please read  review on MobileNetV1 about Depthwise Separable Convolution from here : [LINK](https://towardsdatascience.com/review-mobilenetv1-depthwise-separable-convolution-light-weight-model-a382df364b69) )\n*     (c) Atrous Depthwise Convolution: Atrous convolution is supported in the depthwise convolution. And it is found that it significantly reduces the computation complexity of proposed model while maintaining similar (or better) performance.\n*     Combining with point-wise convolution, it is Atrous Separable Convolution."},{"metadata":{},"cell_type":"markdown","source":"## DeepLabv3+ Extends DeepLabv3"},{"metadata":{},"cell_type":"markdown","source":"![](https://miro.medium.com/max/1556/1*2mYfKnsX1IqCCSItxpXSGA.png)"},{"metadata":{},"cell_type":"markdown","source":" \"\"\"Instantiates the Deeplabv3+ architecture\n    Optionally loads weights pre-trained\n    on PASCAL VOC or Cityscapes. This model is available for TensorFlow only.\n    # Arguments\n        weights: one of 'pascal_voc' (pre-trained on pascal voc),\n            'cityscapes' (pre-trained on cityscape) or None (random initialization)\n        input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)\n            to use as image input for the model.\n        input_shape: shape of input image. format HxWxC\n            PASCAL VOC model was trained on (512,512,3) images. None is allowed as shape/width\n        classes: number of desired classes. PASCAL VOC has 21 classes, Cityscapes has 19 classes.\n            If number of classes not aligned with the weights used, last layer is initialized randomly\n        backbone: backbone to use. one of {'xception','mobilenetv2'}\n        activation: optional activation to add to the top of the network.\n            One of 'softmax', 'sigmoid' or None\n        OS: determines input_shape/feature_extractor_output ratio. One of {8,16}.\n            Used only for xception backbone.\n        alpha: controls the width of the MobileNetV2 network. This is known as the\n            width multiplier in the MobileNetV2 paper.\n                - If `alpha` < 1.0, proportionally decreases the number\n                    of filters in each layer.\n                - If `alpha` > 1.0, proportionally increases the number\n                    of filters in each layer.\n                - If `alpha` = 1, default number of filters from the paper\n                    are used at each layer.\n            Used only for mobilenetv2 backbone. Pretrained is only available for alpha=1.\n    # Returns\n        A Keras model instance.\n    # Raises\n        RuntimeError: If attempting to run this model with a\n            backend that does not support separable convolutions.\n        ValueError: in case of invalid argument for `weights` or `backbone`\"\"\"\"\n    "},{"metadata":{"trusted":true},"cell_type":"code","source":"#model Source : https://github.com/Golbstein/Keras-segmentation-deeplab-v3.1/blob/master/deeplabv3p.py","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"# -*- coding: utf-8 -*-\n\n\"\"\" Deeplabv3+ model for Keras.\nThis model is based on TF repo:\nhttps://github.com/tensorflow/models/tree/master/research/deeplab\nOn Pascal VOC, original model gets to 84.56% mIOU\n\nNow this model is only available for the TensorFlow backend,\ndue to its reliance on `SeparableConvolution` layers, but Theano will add\nthis layer soon.\n\nMobileNetv2 backbone is based on this repo:\nhttps://github.com/JonathanCMitchell/mobilenet_v2_keras\n\n# Reference\n- [Encoder-Decoder with Atrous Separable Convolution\n    for Semantic Image Segmentation](https://arxiv.org/pdf/1802.02611.pdf)\n- [Xception: Deep Learning with Depthwise Separable Convolutions]\n    (https://arxiv.org/abs/1610.02357)\n- [Inverted Residuals and Linear Bottlenecks: Mobile Networks for\n    Classification, Detection and Segmentation](https://arxiv.org/abs/1801.04381)\n\"\"\"\n\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport numpy as np\n\nfrom keras.models import Model\nfrom keras import layers\nfrom keras.layers import Input\nfrom keras.layers import Activation\nfrom keras.layers import Concatenate\nfrom keras.layers import Add\nfrom keras.layers import Dropout\nfrom keras.layers import BatchNormalization\nfrom keras.layers import Conv2D\nfrom keras.layers import DepthwiseConv2D\nfrom keras.layers import ZeroPadding2D\nfrom keras.layers import AveragePooling2D\nfrom keras.engine import Layer\nfrom keras.engine import InputSpec\nfrom keras.engine.topology import get_source_inputs\nfrom keras import backend as K\nfrom keras.applications import imagenet_utils\nfrom keras.utils import conv_utils\nfrom keras.utils.data_utils import get_file\n\nWEIGHTS_PATH_X = \"https://github.com/bonlime/keras-deeplab-v3-plus/releases/download/1.1/deeplabv3_xception_tf_dim_ordering_tf_kernels.h5\"\nWEIGHTS_PATH_MOBILE = \"https://github.com/bonlime/keras-deeplab-v3-plus/releases/download/1.1/deeplabv3_mobilenetv2_tf_dim_ordering_tf_kernels.h5\"\n\n\nclass BilinearUpsampling(Layer):\n    \"\"\"Just a simple bilinear upsampling layer. Works only with TF.\n       Args:\n           upsampling: tuple of 2 numbers > 0. The upsampling ratio for h and w\n           output_size: used instead of upsampling arg if passed!\n    \"\"\"\n\n    def __init__(self, upsampling=(2, 2), output_size=None, data_format=None, **kwargs):\n\n        super(BilinearUpsampling, self).__init__(**kwargs)\n\n        #self.data_format = K.normalize_data_format(data_format)\n        self.data_format = None\n        self.input_spec = InputSpec(ndim=4)\n        if output_size:\n            self.output_size = conv_utils.normalize_tuple(\n                output_size, 2, 'output_size')\n            self.upsampling = None\n        else:\n            self.output_size = None\n            self.upsampling = conv_utils.normalize_tuple(\n                upsampling, 2, 'upsampling')\n\n    def compute_output_shape(self, input_shape):\n        if self.upsampling:\n            height = self.upsampling[0] * \\\n                input_shape[1] if input_shape[1] is not None else None\n            width = self.upsampling[1] * \\\n                input_shape[2] if input_shape[2] is not None else None\n        else:\n            height = self.output_size[0]\n            width = self.output_size[1]\n        return (input_shape[0],\n                height,\n                width,\n                input_shape[3])\n\n    def call(self, inputs):\n        if self.upsampling:\n            return K.tf.image.resize_bilinear(inputs, (inputs.shape[1] * self.upsampling[0],\n                                                       inputs.shape[2] * self.upsampling[1]),\n                                              align_corners=True)\n        else:\n            return K.tf.image.resize_bilinear(inputs, (self.output_size[0],\n                                                       self.output_size[1]),\n                                              align_corners=True)\n\n    def get_config(self):\n        config = {'upsampling': self.upsampling,\n                  'output_size': self.output_size,\n                  'data_format': self.data_format}\n        base_config = super(BilinearUpsampling, self).get_config()\n        return dict(list(base_config.items()) + list(config.items()))\n\n\ndef SepConv_BN(x, filters, prefix, stride=1, kernel_size=3, rate=1, depth_activation=False, epsilon=1e-3):\n    \"\"\" SepConv with BN between depthwise & pointwise. Optionally add activation after BN\n        Implements right \"same\" padding for even kernel sizes\n        Args:\n            x: input tensor\n            filters: num of filters in pointwise convolution\n            prefix: prefix before name\n            stride: stride at depthwise conv\n            kernel_size: kernel size for depthwise convolution\n            rate: atrous rate for depthwise convolution\n            depth_activation: flag to use activation between depthwise & poinwise convs\n            epsilon: epsilon to use in BN layer\n    \"\"\"\n\n    if stride == 1:\n        depth_padding = 'same'\n    else:\n        kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)\n        pad_total = kernel_size_effective - 1\n        pad_beg = pad_total // 2\n        pad_end = pad_total - pad_beg\n        x = ZeroPadding2D((pad_beg, pad_end))(x)\n        depth_padding = 'valid'\n\n    if not depth_activation:\n        x = Activation('relu')(x)\n    x = DepthwiseConv2D((kernel_size, kernel_size), strides=(stride, stride), dilation_rate=(rate, rate),\n                        padding=depth_padding, use_bias=False, name=prefix + '_depthwise')(x)\n    x = BatchNormalization(name=prefix + '_depthwise_BN', epsilon=epsilon)(x)\n    if depth_activation:\n        x = Activation('relu')(x)\n    x = Conv2D(filters, (1, 1), padding='same',\n               use_bias=False, name=prefix + '_pointwise')(x)\n    x = BatchNormalization(name=prefix + '_pointwise_BN', epsilon=epsilon)(x)\n    if depth_activation:\n        x = Activation('relu')(x)\n\n    return x\n\n\ndef _conv2d_same(x, filters, prefix, stride=1, kernel_size=3, rate=1):\n    \"\"\"Implements right 'same' padding for even kernel sizes\n        Without this there is a 1 pixel drift when stride = 2\n        Args:\n            x: input tensor\n            filters: num of filters in pointwise convolution\n            prefix: prefix before name\n            stride: stride at depthwise conv\n            kernel_size: kernel size for depthwise convolution\n            rate: atrous rate for depthwise convolution\n    \"\"\"\n    if stride == 1:\n        return Conv2D(filters,\n                      (kernel_size, kernel_size),\n                      strides=(stride, stride),\n                      padding='same', use_bias=False,\n                      dilation_rate=(rate, rate),\n                      name=prefix)(x)\n    else:\n        kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)\n        pad_total = kernel_size_effective - 1\n        pad_beg = pad_total // 2\n        pad_end = pad_total - pad_beg\n        x = ZeroPadding2D((pad_beg, pad_end))(x)\n        return Conv2D(filters,\n                      (kernel_size, kernel_size),\n                      strides=(stride, stride),\n                      padding='valid', use_bias=False,\n                      dilation_rate=(rate, rate),\n                      name=prefix)(x)\n\n\ndef _xception_block(inputs, depth_list, prefix, skip_connection_type, stride,\n                    rate=1, depth_activation=False, return_skip=False):\n    \"\"\" Basic building block of modified Xception network\n        Args:\n            inputs: input tensor\n            depth_list: number of filters in each SepConv layer. len(depth_list) == 3\n            prefix: prefix before name\n            skip_connection_type: one of {'conv','sum','none'}\n            stride: stride at last depthwise conv\n            rate: atrous rate for depthwise convolution\n            depth_activation: flag to use activation between depthwise & pointwise convs\n            return_skip: flag to return additional tensor after 2 SepConvs for decoder\n            \"\"\"\n    residual = inputs\n    for i in range(3):\n        residual = SepConv_BN(residual,\n                              depth_list[i],\n                              prefix + '_separable_conv{}'.format(i + 1),\n                              stride=stride if i == 2 else 1,\n                              rate=rate,\n                              depth_activation=depth_activation)\n        if i == 1:\n            skip = residual\n    if skip_connection_type == 'conv':\n        shortcut = _conv2d_same(inputs, depth_list[-1], prefix + '_shortcut',\n                                kernel_size=1,\n                                stride=stride)\n        shortcut = BatchNormalization(name=prefix + '_shortcut_BN')(shortcut)\n        outputs = layers.add([residual, shortcut])\n    elif skip_connection_type == 'sum':\n        outputs = layers.add([residual, inputs])\n    elif skip_connection_type == 'none':\n        outputs = residual\n    if return_skip:\n        return outputs, skip\n    else:\n        return outputs\n\n\ndef relu6(x):\n    return K.relu(x, max_value=6)\n\n\ndef _make_divisible(v, divisor, min_value=None):\n    if min_value is None:\n        min_value = divisor\n    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)\n    # Make sure that round down does not go down by more than 10%.\n    if new_v < 0.9 * v:\n        new_v += divisor\n    return new_v\n\n\ndef _inverted_res_block(inputs, expansion, stride, alpha, filters, block_id, skip_connection, rate=1):\n    in_channels = inputs._keras_shape[-1]\n    pointwise_conv_filters = int(filters * alpha)\n    pointwise_filters = _make_divisible(pointwise_conv_filters, 8)\n    x = inputs\n    prefix = 'expanded_conv_{}_'.format(block_id)\n    if block_id:\n        # Expand\n\n        x = Conv2D(expansion * in_channels, kernel_size=1, padding='same',\n                   use_bias=False, activation=None,\n                   name=prefix + 'expand')(x)\n        x = BatchNormalization(epsilon=1e-3, momentum=0.999,\n                               name=prefix + 'expand_BN')(x)\n        x = Activation(relu6, name=prefix + 'expand_relu')(x)\n    else:\n        prefix = 'expanded_conv_'\n    # Depthwise\n    x = DepthwiseConv2D(kernel_size=3, strides=stride, activation=None,\n                        use_bias=False, padding='same', dilation_rate=(rate, rate),\n                        name=prefix + 'depthwise')(x)\n    x = BatchNormalization(epsilon=1e-3, momentum=0.999,\n                           name=prefix + 'depthwise_BN')(x)\n\n    x = Activation(relu6, name=prefix + 'depthwise_relu')(x)\n\n    # Project\n    x = Conv2D(pointwise_filters,\n               kernel_size=1, padding='same', use_bias=False, activation=None,\n               name=prefix + 'project')(x)\n    x = BatchNormalization(epsilon=1e-3, momentum=0.999,\n                           name=prefix + 'project_BN')(x)\n\n    if skip_connection:\n        return Add(name=prefix + 'add')([inputs, x])\n\n    # if in_channels == pointwise_filters and stride == 1:\n    #    return Add(name='res_connect_' + str(block_id))([inputs, x])\n\n    return x\n\n\ndef Deeplabv3plus(weights='pascal_voc', input_tensor=None, input_shape=(512, 512, 3), classes=21, backbone='mobilenetv2', OS=16, alpha=1.):\n    \"\"\" Instantiates the Deeplabv3+ architecture\n\n    Optionally loads weights pre-trained\n    on PASCAL VOC. This model is available for TensorFlow only,\n    and can only be used with inputs following the TensorFlow\n    data format `(width, height, channels)`.\n    # Arguments\n        weights: one of 'pascal_voc' (pre-trained on pascal voc)\n            or None (random initialization)\n        input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)\n            to use as image input for the model.\n        input_shape: shape of input image. format HxWxC\n            PASCAL VOC model was trained on (512,512,3) images\n        classes: number of desired classes. If classes != 21,\n            last layer is initialized randomly\n        backbone: backbone to use. one of {'xception','mobilenetv2'}\n        OS: determines input_shape/feature_extractor_output ratio. One of {8,16}.\n            Used only for xception backbone.\n        alpha: controls the width of the MobileNetV2 network. This is known as the\n            width multiplier in the MobileNetV2 paper.\n                - If `alpha` < 1.0, proportionally decreases the number\n                    of filters in each layer.\n                - If `alpha` > 1.0, proportionally increases the number\n                    of filters in each layer.\n                - If `alpha` = 1, default number of filters from the paper\n                    are used at each layer.\n            Used only for mobilenetv2 backbone\n\n    # Returns\n        A Keras model instance.\n\n    # Raises\n        RuntimeError: If attempting to run this model with a\n            backend that does not support separable convolutions.\n        ValueError: in case of invalid argument for `weights` or `backbone`\n\n    \"\"\"\n\n    if not (weights in {'pascal_voc', None}):\n        raise ValueError('The `weights` argument should be either '\n                         '`None` (random initialization) or `pascal_voc` '\n                         '(pre-trained on PASCAL VOC)')\n\n    if K.backend() != 'tensorflow':\n        raise RuntimeError('The Deeplabv3+ model is only available with '\n                           'the TensorFlow backend.')\n\n    if not (backbone in {'xception', 'mobilenetv2'}):\n        raise ValueError('The `backbone` argument should be either '\n                         '`xception`  or `mobilenetv2` ')\n\n    if input_tensor is None:\n        img_input = Input(shape=input_shape)\n    else:\n        if not K.is_keras_tensor(input_tensor):\n            img_input = Input(tensor=input_tensor, shape=input_shape)\n        else:\n            img_input = input_tensor\n\n    if backbone == 'xception':\n        if OS == 8:\n            entry_block3_stride = 1\n            middle_block_rate = 2  # ! Not mentioned in paper, but required\n            exit_block_rates = (2, 4)\n            atrous_rates = (12, 24, 36)\n        else:\n            entry_block3_stride = 2\n            middle_block_rate = 1\n            exit_block_rates = (1, 2)\n            atrous_rates = (6, 12, 18)\n\n        x = Conv2D(32, (3, 3), strides=(2, 2),\n                   name='entry_flow_conv1_1', use_bias=False, padding='same')(img_input)\n        x = BatchNormalization(name='entry_flow_conv1_1_BN')(x)\n        x = Activation('relu')(x)\n\n        x = _conv2d_same(x, 64, 'entry_flow_conv1_2', kernel_size=3, stride=1)\n        x = BatchNormalization(name='entry_flow_conv1_2_BN')(x)\n        x = Activation('relu')(x)\n\n        x = _xception_block(x, [128, 128, 128], 'entry_flow_block1',\n                            skip_connection_type='conv', stride=2,\n                            depth_activation=False)\n        x, skip1 = _xception_block(x, [256, 256, 256], 'entry_flow_block2',\n                                   skip_connection_type='conv', stride=2,\n                                   depth_activation=False, return_skip=True)\n\n        x = _xception_block(x, [728, 728, 728], 'entry_flow_block3',\n                            skip_connection_type='conv', stride=entry_block3_stride,\n                            depth_activation=False)\n        for i in range(16):\n            x = _xception_block(x, [728, 728, 728], 'middle_flow_unit_{}'.format(i + 1),\n                                skip_connection_type='sum', stride=1, rate=middle_block_rate,\n                                depth_activation=False)\n\n        x = _xception_block(x, [728, 1024, 1024], 'exit_flow_block1',\n                            skip_connection_type='conv', stride=1, rate=exit_block_rates[0],\n                            depth_activation=False)\n        x = _xception_block(x, [1536, 1536, 2048], 'exit_flow_block2',\n                            skip_connection_type='none', stride=1, rate=exit_block_rates[1],\n                            depth_activation=True)\n\n    else:\n        OS = 8\n        first_block_filters = _make_divisible(32 * alpha, 8)\n        x = Conv2D(first_block_filters,\n                   kernel_size=3,\n                   strides=(2, 2), padding='same',\n                   use_bias=False, name='Conv')(img_input)\n        x = BatchNormalization(\n            epsilon=1e-3, momentum=0.999, name='Conv_BN')(x)\n        x = Activation(relu6, name='Conv_Relu6')(x)\n\n        x = _inverted_res_block(x, filters=16, alpha=alpha, stride=1,\n                                expansion=1, block_id=0, skip_connection=False)\n\n        x = _inverted_res_block(x, filters=24, alpha=alpha, stride=2,\n                                expansion=6, block_id=1, skip_connection=False)\n        x = _inverted_res_block(x, filters=24, alpha=alpha, stride=1,\n                                expansion=6, block_id=2, skip_connection=True)\n\n        x = _inverted_res_block(x, filters=32, alpha=alpha, stride=2,\n                                expansion=6, block_id=3, skip_connection=False)\n        x = _inverted_res_block(x, filters=32, alpha=alpha, stride=1,\n                                expansion=6, block_id=4, skip_connection=True)\n        x = _inverted_res_block(x, filters=32, alpha=alpha, stride=1,\n                                expansion=6, block_id=5, skip_connection=True)\n\n        # stride in block 6 changed from 2 -> 1, so we need to use rate = 2\n        x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1,  # 1!\n                                expansion=6, block_id=6, skip_connection=False)\n        x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1, rate=2,\n                                expansion=6, block_id=7, skip_connection=True)\n        x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1, rate=2,\n                                expansion=6, block_id=8, skip_connection=True)\n        x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1, rate=2,\n                                expansion=6, block_id=9, skip_connection=True)\n\n        x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1, rate=2,\n                                expansion=6, block_id=10, skip_connection=False)\n        x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1, rate=2,\n                                expansion=6, block_id=11, skip_connection=True)\n        x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1, rate=2,\n                                expansion=6, block_id=12, skip_connection=True)\n\n        x = _inverted_res_block(x, filters=160, alpha=alpha, stride=1, rate=2,  # 1!\n                                expansion=6, block_id=13, skip_connection=False)\n        x = _inverted_res_block(x, filters=160, alpha=alpha, stride=1, rate=4,\n                                expansion=6, block_id=14, skip_connection=True)\n        x = _inverted_res_block(x, filters=160, alpha=alpha, stride=1, rate=4,\n                                expansion=6, block_id=15, skip_connection=True)\n\n        x = _inverted_res_block(x, filters=320, alpha=alpha, stride=1, rate=4,\n                                expansion=6, block_id=16, skip_connection=False)\n\n    # end of feature extractor\n\n    # branching for Atrous Spatial Pyramid Pooling\n\n    # Image Feature branch\n    #out_shape = int(np.ceil(input_shape[0] / OS))\n    b4 = AveragePooling2D(pool_size=(int(np.ceil(input_shape[0] / OS)), int(np.ceil(input_shape[1] / OS))))(x)\n    b4 = Conv2D(256, (1, 1), padding='same',\n                use_bias=False, name='image_pooling')(b4)\n    b4 = BatchNormalization(name='image_pooling_BN', epsilon=1e-5)(b4)\n    b4 = Activation('relu')(b4)\n    b4 = BilinearUpsampling((int(np.ceil(input_shape[0] / OS)), int(np.ceil(input_shape[1] / OS))))(b4)\n\n    # simple 1x1\n    b0 = Conv2D(256, (1, 1), padding='same', use_bias=False, name='aspp0')(x)\n    b0 = BatchNormalization(name='aspp0_BN', epsilon=1e-5)(b0)\n    b0 = Activation('relu', name='aspp0_activation')(b0)\n\n    # there are only 2 branches in mobilenetV2. not sure why\n    if backbone == 'xception':\n        # rate = 6 (12)\n        b1 = SepConv_BN(x, 256, 'aspp1',\n                        rate=atrous_rates[0], depth_activation=True, epsilon=1e-5)\n        # rate = 12 (24)\n        b2 = SepConv_BN(x, 256, 'aspp2',\n                        rate=atrous_rates[1], depth_activation=True, epsilon=1e-5)\n        # rate = 18 (36)\n        b3 = SepConv_BN(x, 256, 'aspp3',\n                        rate=atrous_rates[2], depth_activation=True, epsilon=1e-5)\n\n        # concatenate ASPP branches & project\n        x = Concatenate()([b4, b0, b1, b2, b3])\n    else:\n        x = Concatenate()([b4, b0])\n\n    x = Conv2D(256, (1, 1), padding='same',\n               use_bias=False, name='concat_projection')(x)\n    x = BatchNormalization(name='concat_projection_BN', epsilon=1e-5)(x)\n    x = Activation('relu')(x)\n    x = Dropout(0.1)(x)\n\n    # DeepLab v.3+ decoder\n\n    if backbone == 'xception':\n        # Feature projection\n        # x4 (x2) block\n        x = BilinearUpsampling(output_size=(int(np.ceil(input_shape[0] / 4)),\n                                            int(np.ceil(input_shape[1] / 4))))(x)\n        dec_skip1 = Conv2D(48, (1, 1), padding='same',\n                           use_bias=False, name='feature_projection0')(skip1)\n        dec_skip1 = BatchNormalization(\n            name='feature_projection0_BN', epsilon=1e-5)(dec_skip1)\n        dec_skip1 = Activation('relu')(dec_skip1)\n        x = Concatenate()([x, dec_skip1])\n        x = SepConv_BN(x, 256, 'decoder_conv0',\n                       depth_activation=True, epsilon=1e-5)\n        x = SepConv_BN(x, 256, 'decoder_conv1',\n                       depth_activation=True, epsilon=1e-5)\n\n    # you can use it with arbitary number of classes\n    if classes == 21:\n        last_layer_name = 'logits_semantic'\n    else:\n        last_layer_name = 'custom_logits_semantic'\n\n    x = Conv2D(classes, (1, 1), padding='same', name=last_layer_name)(x)\n    x = BilinearUpsampling(output_size=(input_shape[0], input_shape[1]))(x)\n\n    # Ensure that the model takes into account\n    # any potential predecessors of `input_tensor`.\n    if input_tensor is not None:\n        inputs = get_source_inputs(input_tensor)\n    else:\n        inputs = img_input\n\n    model = Model(inputs, x, name='deeplabv3+')\n\n    # load weights\n\n    if weights == 'pascal_voc':\n        if backbone == 'xception':\n            weights_path = get_file('deeplabv3_xception_tf_dim_ordering_tf_kernels.h5',\n                                    WEIGHTS_PATH_X,\n                                    cache_subdir='models')\n        else:\n            weights_path = get_file('deeplabv3_mobilenetv2_tf_dim_ordering_tf_kernels.h5',\n                                    WEIGHTS_PATH_MOBILE,\n                                    cache_subdir='models')\n        model.load_weights(weights_path, by_name=True)\n    return model\n\n\ndef preprocess_input(x):\n    \"\"\"Preprocesses a numpy array encoding a batch of images.\n    # Arguments\n        x: a 4D numpy array consists of RGB values within [0, 255].\n    # Returns\n        Input array scaled to [-1.,1.]\n    \"\"\"\n    return imagenet_utils.preprocess_input(x, mode='tf')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"backbone = 'mobilenetv2'\nload_pretrained_weights = True\nmodel = Deeplabv3plus(weights='pascal_voc', input_tensor=None, \n              input_shape=(h, w,3), classes=4, backbone=backbone,OS=16, alpha=1.)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"if you use xception instead of mobilenetv2....\n**Modified Aligned Xception**\n![](https://miro.medium.com/max/1490/1*Aa8oEhKhD8qspG6wMqTxnA.png)"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer = Adam(lr=5e-4, epsilon=1e-8, decay=1e-6), sample_weight_mode = \"temporal\",\n              loss = dice_loss)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"checkpoint = ModelCheckpoint(\n    'model.h5', \n    monitor='val_dice_coef', \n    verbose=0, \n    save_best_only=True, \n    save_weights_only=False,\n    mode='auto'\n)\n\nhistory = model.fit_generator(\n    train_generator,\n    validation_data=val_generator,\n    callbacks=[checkpoint],\n    use_multiprocessing=False,\n    workers=1,\n    epochs=1\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Evaluation & Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"with open('history.json', 'w') as f:\n    json.dump(history.history, f)\n\nhistory_df = pd.DataFrame(history.history)\nhistory_df[['loss', 'val_loss']].plot()\n#history_df[['dice_coef', 'val_dice_coef']].plot()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**For more about deeplabv3 you can check my another kernel : https://www.kaggle.com/mobassir/deeplabv3-resnet101-for-severstal-sdd**"},{"metadata":{"trusted":true},"cell_type":"code","source":"#model.load_weights('model.h5')\ntest_df = []\n\nfor i in range(0, test_imgs.shape[0], 500):\n    batch_idx = list(\n        range(i, min(test_imgs.shape[0], i + 500))\n    )\n    \n    test_generator = DataGenerator(\n        batch_idx,\n        df=test_imgs,\n        shuffle=False,\n        mode='predict',\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        use_multiprocessing=False\n    )\n    for j, b in tqdm(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, ].round().astype(int)\n        #print(pred_masks)\n        pred_rles = build_rles(pred_masks, reshape=(w, h))\n        \n        image_df['EncodedPixels'] = pred_rles\n        test_df.append(image_df)\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.concat(test_df)\ntest_df.drop(columns='ImageId', inplace=True)\ntest_df.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Future Plans\n- augmentation\n- TTA"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}