{"cells":[{"metadata":{"_uuid":"586fb67f-ecfc-4171-a588-5192c57b0f61","_cell_guid":"8f9210c1-21b7-46b1-a874-c744f0e21cf5","trusted":true},"cell_type":"code","source":"! /opt/conda/bin/python3.7 -m pip install --upgrade pip\n! pip install -U tensorflow==2.2.0\n! pip install -U keras==2.4.2\n! pip install -U segmentation-models==1.0.0\n! pip install keras-rectified-adam\n! pip install albumentations\nimport segmentation_models as sm\nfrom segmentation_models import get_preprocessing\nfrom keras_radam.training import RAdamOptimizer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DualTransform:\n\n    identity_param = None\n\n    def prepare(self, params):\n        if isinstance(params, tuple):\n            params = list(params)\n        elif params is None:\n            params = []\n        elif not isinstance(params, list):\n            params = [params]\n\n        if not self.identity_param in params:\n            params.append(self.identity_param)\n        return params\n\n    def forward(self, image, param):\n        raise NotImplementedError\n\n    def backward(self, image, param):\n        raise NotImplementedError\n\n\nclass SingleTransform(DualTransform):\n\n    def backward(self, image, param):\n        return image\n\n\nclass HFlip(DualTransform):\n\n    identity_param = 0\n\n    def prepare(self, params):\n        if params == False:\n            return [0]\n        if params == True:\n            return [1, 0]\n\n    def forward(self, image, param):\n        return tf.image.flip_left_right(image) if param else image\n\n    def backward(self, image, param):\n        return self.forward(image, param)\n\n\nclass VFlip(DualTransform):\n\n    identity_param = 0\n\n    def prepare(self, params):\n        if params == False:\n            return [0]\n        if params == True:\n            return [1, 0]\n\n    def forward(self, image, param):\n        return tf.image.flip_up_down(image) if param else image\n\n    def backward(self, image, param):\n        return self.forward(image, param)\n\n\nclass Rotate(DualTransform):\n\n    identity_param = 0\n\n    def forward(self, image, angle):\n        k = angle // 90 if angle >= 0 else (angle + 360) // 90\n        return tf.image.rot90(image, k)\n\n    def backward(self, image, angle):\n        return self.forward(image, -angle)\n\n\nclass HShift(DualTransform):\n\n    identity_param = 0\n\n    def forward(self, image, param):\n        return tf.roll(image, param, axis=0)\n\n    def backward(self, image, param):\n        return tf.roll(image, -param, axis=0)\n\n\nclass VShift(DualTransform):\n\n    identity_param = 0\n\n    def forward(self, image, param):\n        return tf.roll(image, param, axis=1)\n\n    def backward(self, image, param):\n        return tf.roll(image, -param, axis=1)\n\n\nclass Contrast(SingleTransform):\n\n    identity_param = 1\n\n    def forward(self, image, param):\n        return tf.image.adjust_contrast(image, param)\n\n\nclass Add(SingleTransform):\n\n    identity_param = 0\n\n    def forward(self, image, param):\n        return image + param\n\n\nclass Multiply(SingleTransform):\n\n    identity_param = 1\n\n    def forward(self, image, param):\n        return image * param\n\n\ndef gmean(x):\n    g_pow = 1 / x.get_shape().as_list()[0]\n    x = tf.reduce_prod(x, axis=0, keepdims=True)\n    x = tf.pow(x, g_pow)\n    return x\n\n\ndef mean(x):\n    return tf.reduce_mean(x, axis=0, keepdims=True)\n\n\ndef tta_max(x):\n    return tf.reduce_max(x, axis=0, keepdims=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import itertools\n\nclass Augmentation(object):\n\n    transforms = {\n        'h_flip': HFlip(),\n        'v_flip': VFlip(),\n        'rotation':Rotate(),\n        'h_shift': HShift(),\n        'v_shift': VShift(),\n        'contrast':Contrast(),\n        'add':Add(),\n        'mul':Multiply(),\n    }\n\n    def __init__(self, **params):\n        super().__init__()\n\n        transforms = [Augmentation.transforms[k] for k in params.keys()]\n        transform_params = [params[k] for k in params.keys()]\n\n        # add identity parameters for all transforms and convert to list\n        transform_params = [t.prepare(params) for t, params in zip(transforms, transform_params)]\n\n        # get all combinations of transforms params\n        transform_params = list(itertools.product(*transform_params))\n\n        self.forward_aug = [t.forward for t in transforms]\n        self.forward_params = transform_params\n\n        self.backward_aug = [t.backward for t in transforms[::-1]] # reverse transforms\n        self.backward_params = [p[::-1] for p in transform_params] # reverse params\n\n        self.n_transforms = len(transform_params)\n\n    @property\n    def forward(self):\n        return self.forward_aug, self.forward_params\n\n    @property\n    def backward(self):\n        return self.backward_aug, self.backward_params","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import Layer\n\n\nclass Repeat(Layer):\n    \"\"\"\n    Layer for cloning input information\n    input_shape = (1, H, W, C)\n    output_shape = (N, H, W, C)\n    \"\"\"\n    def __init__(self, n, **kwargs):\n        super().__init__(**kwargs)\n        self.n = n\n\n    def call(self, x):\n        return tf.stack([x[0]] * self.n, axis=0)\n\n    def compute_output_shape(self, input_shape):\n        return (self.n, *input_shape[1:])\n\n\nclass TTA(Layer):\n\n    def __init__(self, functions, params):\n        super().__init__()\n        self.functions = functions\n        self.params = params\n\n    def apply_transforms(self, images):\n        transformed_images = []\n        for i, args in enumerate(self.params):\n            image = images[i]\n            for f, arg in zip(self.functions, args):\n                image = f(image, arg)\n            transformed_images.append(image)\n        return tf.stack(transformed_images, 0)\n\n    def call(self, images):\n        return self.apply_transforms(images)\n\n\nclass Merge(Layer):\n\n    def __init__(self, type):\n        super().__init__()\n        self.type = type\n\n    def merge(self, x):\n        if self.type == 'mean':\n            return mean(x)\n        if self.type == 'gmean':\n            return gmean(x)\n        if self.type == 'tta_max':\n            return tta_max(x)\n        else:\n            raise ValueError(f'Wrong merge type {type}')\n\n    def call(self, x):\n        return self.merge(x)\n\n    def compute_output_shape(self, input_shape):\n        return (1, *input_shape[1:])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input\n\n\n\ndoc = \"\"\"\n    IMPORTANT constraints:\n        1) model has to have 1 input and 1 output\n        2) inference batch_size = 1\n        3) image height == width if rotate augmentation is used\n    Args:\n        model: instance of Keras model\n        h_flip: (bool) horizontal flip\n        v_flip: (bool) vertical flip\n        h_shifts: (list of int) list of horizontal shifts (e.g. [10, -10])\n        v_shifts: (list of int) list of vertical shifts (e.g. [10, -10])\n        rotation: (list of int) list of angles (deg) for rotation in range [0, 360),\n            should be divisible by 90 deg (e.g. [90, 180, 270])\n        contrast: (list of float) values for contrast adjustment\n        add: (list of int or float) values to add on image (e.g. [-10, 10])\n        mul: (list of float) values to multiply image on (e.g. [0.9, 1.1])\n        merge: one of 'mean', 'gmean' and 'max' - mode of merging augmented\n            predictions together.\n    Returns:\n        Keras Model instance\n\"\"\"\n\ndef segmentation(\n    model,\n    h_flip=False,\n    v_flip=False,  \n    h_shift=None,\n    v_shift=None,\n    rotation=None,\n    contrast=None,\n    add=None,\n    mul=None,\n    merge='mean',\n    input_shape=None,\n):\n    \"\"\"\n    Segmentation model test time augmentation wrapper.\n    \"\"\"\n    tta = Augmentation(\n        h_flip=h_flip,\n        v_flip=v_flip,\n        h_shift=h_shift,\n        v_shift=v_shift,\n        rotation=rotation,\n        contrast=contrast,\n        add=add,\n        mul=mul,\n    )\n\n    if input_shape is None:\n        try:\n            input_shape = model.input_shape[1:]\n        except AttributeError:\n            raise AttributeError(\n                'Can not determine input shape automatically, please provide `input_shape` '\n                'argument to wrapper (e.g input_shape=(None, None, 3)).'\n            )\n    batch_shape = (1, *input_shape) # add batch dimension\n\n    inp = Input(batch_shape=batch_shape)\n    x = Repeat(tta.n_transforms)(inp)\n    x = TTA(*tta.forward)(x)\n    x = model(x)\n    x = TTA(*tta.backward)(x)\n    x = Merge(merge)(x)\n    tta_model = Model(inp, x)\n\n    return tta_model\n\n\ndef classification(\n    model,\n    h_flip=False,\n    v_flip=False,\n    h_shift=None,\n    v_shift=None,\n    rotation=None,\n    contrast=None,\n    add=None,\n    mul=None,\n    merge='mean',\n    input_shape=None,\n):\n    \"\"\"\n    Classification model test time augmentation wrapper.\n    \"\"\"\n\n    tta = Augmentation(\n        h_flip=h_flip,\n        v_flip=v_flip,\n        h_shift=h_shift,\n        v_shift=v_shift,\n        rotation=rotation,\n        contrast=contrast,\n        add=add,\n        mul=mul,\n    )\n    \n    if input_shape is None:\n        try:\n            input_shape = model.input_shape[1:]\n        except AttributeError:\n            raise AttributeError(\n                'Can not determine input shape automatically, please provide `input_shape` '\n                'argument to wrapper (e.g input_shape=(None, None, 3)).'\n            )\n    batch_shape = (1, *input_shape) # add batch dimension\n\n    inp = Input(batch_shape=batch_shape)\n    x = Repeat(tta.n_transforms)(inp)\n    x = TTA(*tta.forward)(x)\n    x = model(x)\n    x = Merge(merge)(x)\n    tta_model = Model(inp, x)\n\n    return tta_model\n\n\nclassification.__doc__ += doc\nsegmentation.__doc__ += doc\n\n# legacy support\ntta_classification = classification\ntta_segmentation = segmentation","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport pathlib\nimport cv2 as cv\nimport copy\nimport shutil\nimport time\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n# --------------------\nimport tensorflow as tf\nfrom tensorflow.keras import backend as K\nfrom tensorflow.keras.callbacks import Callback\nfrom sklearn.model_selection import train_test_split\nimport albumentations as albu\nfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom tensorflow.keras.optimizers import SGD\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.models import load_model\nimport math","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\n\nimport tensorflow as tf\n\nimport cProfile\nprint(tf.__version__)\ntf.executing_eagerly()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"PROJECT_PATH = '../input/understanding_cloud_organization'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# First, we load the DF\ntrain = pd.read_csv(PROJECT_PATH + \"/\" + \"train.csv\")\n\n# We get images shape\nimg = cv.imread(PROJECT_PATH + '/train_images/' + '04df149.jpg', -1)\nHEIGHT = img.shape[0]\nWIDTH = img.shape[1]\nDIMENSIONS = (HEIGHT, WIDTH)\n\n\ntrain['image'] = train['Image_Label'].apply(lambda x: x.split('_')[0])\ntrain['label'] = train['Image_Label'].apply(lambda x: x.split('_')[1])\n\n# Create one column for each mask\ntrain_df = pd.pivot_table(train, index=['image'], values=['EncodedPixels'], columns=['label'], aggfunc=np.min).reset_index()\ntrain_df.columns = ['image', 'Fish_mask', 'Flower_mask', 'Gravel_mask', 'Sugar_mask']\ncorrected_df = train_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_train_val(path):\n    \"\"\"\n    Extract the directory under study\n    Parameters:\n        path : whole path of the directory\n    Return:\n        string: the directory we are creating (train/val/test)\n    \"\"\"\n    sub_string = path.split('/')[3]\n    return sub_string.split('_')[0].capitalize()\n\n\ndef check_if_exist(list_files, path):\n    \"\"\"\n    Check if N (here N = 50) images exist in the train/test/val directory. If they exist, do not move them again. If\n    they do not, they move.\n    Parameters:\n        list_files: the list of files to check\n        path: where the files are\n    Return:\n        boolean: if all the files exist or not\n    \"\"\"\n    for i in range(len(list_files)):\n        if os.path.isdir('/kaggle/working/' + path):\n            if not os.path.isfile('/kaggle/working/' + path + '/' + list_files[i]):\n                print(\"Files do not match. Creating {} directory...\".format(get_train_val('/kaggle/working/' + path)))\n                return False\n    print('Files do exist in {} directory.'.format(get_train_val('/kaggle/working/' + path)))\n    return True\n\n\ndef get_resize_image(img_name, shape, test_train):\n    \"\"\"\n    Resizes and changes from BGR to RGB an image opened by OpenCV\n    Parameters:\n        img_name: the name of the image\n        shape: the shape of the future image\n    Returns:\n        numpy-array: the img converted\n    \"\"\"\n    if test_train == 'train':\n        img = cv.imread(PROJECT_PATH + '/train_images/' + img_name)\n    elif test_train =='test':\n        img = cv.imread(PROJECT_PATH + '/test_images/' + img_name)\n    img = cv.cvtColor(img, cv.COLOR_BGR2RGB)\n    resized_img = cv.resize(img, shape)\n    return resized_img\n\ndef 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\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 cv.resize(img, (width, height))\n\n\ndef move_data(image_df, path, HEIGHT=384, WIDTH=480, test_train='train'):\n    \"\"\"\n    Creates an image in a given directory\n    Parameters:\n        image_list: the list of images\n        path: where the images are\n        HEIGHT: the dimensions of the image\n        WIDTH: the dimensions of the image\n    \"\"\"\n    for i in range(image_df.shape[0]):\n        item = image_df.iloc[i]\n        img_name = item['image']\n        image = get_resize_image(img_name,  (WIDTH, HEIGHT), test_train)\n        cv.imwrite(path + img_name, image)\n\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 cv.resize(img, (width, height))        \n\n\ndef rle2mask(rle, input_shape):\n    width, height = input_shape[:2]\n    mask = np.zeros( width*height ).astype(np.uint8)\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\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 dice_coefficient(y_true, y_pred):\n    \"\"\"The metrics.\n    For further information refer to: https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient\n    Parameters:\n        y_true: true label\n        y_pred: predicted label\n    Returns\n        double: the result\n    \"\"\"\n    y_true = np.asarray(y_true).astype(np.bool)\n    y_pred = np.asarray(y_pred).astype(np.bool)\n    intersection = np.logical_and(y_true, y_pred)\n    return (2. * intersection.sum()) / (y_true.sum() + y_pred.sum())\n\n\ndef dice_coef(y_true, y_pred, smooth=1):\n    \"\"\"The metrics.\n    For further information refer to: https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient\n    Parameters:\n        y_true: true label\n        y_pred: predicted label\n        smooth: smooth of the metric\n    Returns\n        double: the result\n    \"\"\"\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\n# Model evaluation\ndef plot_metrics(history, metric_list=['loss', 'dice_coef'], figsize=(22, 14)):\n    fig, axes = plt.subplots(len(metric_list), 1, sharex='col', figsize=(22, len(metric_list)*4))\n    axes = axes.flatten()\n    \n    for index, metric in enumerate(metric_list):\n        axes[index].plot(history[metric], label='Train %s' % metric)\n        axes[index].plot(history['val_%s' % metric], label='Validation %s' % metric)\n        axes[index].legend(loc='best')\n        axes[index].set_title(metric)\n\n    plt.xlabel('Epochs')\n    sns.despine()\n    plt.show()\n    \n# Model post process\ndef post_process(probability, threshold=0.5, min_size=10000):\n    mask = cv.threshold(probability, threshold, 1, cv.THRESH_BINARY)[1]\n    num_component, component = cv.connectedComponents(mask.astype(np.uint8))\n    predictions = np.zeros(probability.shape, np.float32)\n    for c in range(1, num_component):\n        p = (component == c)\n        if p.sum() > min_size:\n            predictions[p] = 1\n    return predictions\n    \n    \n    # Prediction evaluation\ndef get_metrics(model, target_df, df, df_images_dest_path, tresholds, min_mask_sizes, N_CLASSES=4, seed=0, preprocessing=None, set_name='Complete set'):\n    class_names = ['Fish', 'Flower', 'Gravel', 'Sugar']\n    metrics = []\n\n    for class_name in class_names:\n        metrics.append([class_name, 0, 0])\n\n    metrics_df = pd.DataFrame(metrics, columns=['Class', 'Dice', 'Dice Post'])\n    \n    for i in range(0, df.shape[0], 200):\n        batch_idx = list(range(i, min(df.shape[0], i + 200)))\n        batch_set = df[batch_idx[0]: batch_idx[-1]+1]\n        ratio = len(batch_set) / len(df)\n\n        generator = DataGenerator(\n                      directory=df_images_dest_path,\n                      dataframe=batch_set,\n                      target_df=target_df,\n                      batch_size=len(batch_set), \n                      target_size=model.input_shape[1:3],\n                      n_channels=model.input_shape[3],\n                      n_classes=N_CLASSES,\n                      preprocessing=preprocessing,\n                      mode='fit',\n                      shuffle=False)\n\n        x, y = generator.__getitem__(0)\n        preds = model.predict(x)\n        \n        for class_index in range(N_CLASSES):\n            class_score = []\n            class_score_post = []\n            mask_class = y[..., class_index]\n            pred_class = preds[..., class_index]\n            for index in range(len(batch_idx)):\n                sample_mask = mask_class[index, ]\n                sample_pred = pred_class[index, ]\n                sample_pred_post = post_process(sample_pred, threshold=tresholds[class_index], min_size=min_mask_sizes[class_index])\n                if (sample_mask.sum() == 0) & (sample_pred.sum() == 0):\n                    dice_score = 1.\n                else:\n                    dice_score = dice_coefficient(sample_pred, sample_mask)\n                if (sample_mask.sum() == 0) & (sample_pred_post.sum() == 0):\n                    dice_score_post = 1.\n                else:\n                    dice_score_post = dice_coefficient(sample_pred_post, sample_mask)\n                class_score.append(dice_score)\n                class_score_post.append(dice_score_post)\n            metrics_df.loc[metrics_df['Class'] == class_names[class_index], 'Dice'] += np.mean(class_score) * ratio\n            metrics_df.loc[metrics_df['Class'] == class_names[class_index], 'Dice Post'] += np.mean(class_score_post) * ratio\n\n    metrics_df = metrics_df.append({'Class':set_name, 'Dice':np.mean(metrics_df['Dice'].values), 'Dice Post':np.mean(metrics_df['Dice Post'].values)}, ignore_index=True).set_index('Class')\n    \n    return metrics_df\n\ndef inspect_predictions(df, image_ids, images_dest_path, pred_col=None, label_col='EncodedPixels', title_col='Image_Label', img_shape=(525, 350), figsize=(22, 6)):\n    if pred_col:\n        for sample in image_ids:\n            sample_df = df[df['image'] == sample]\n            fig, axes = plt.subplots(2, 5, figsize=figsize)\n            img = cv.imread(images_dest_path + sample_df['image'].values[0])\n            img = cv.resize(img, img_shape)\n            axes[0][0].imshow(img)\n            axes[1][0].imshow(img)\n            axes[0][0].set_title('Label', fontsize=16)\n            axes[1][0].set_title('Predicted', fontsize=16)\n            axes[0][0].axis('off')\n            axes[1][0].axis('off')\n            for i in range(4):\n                mask = sample_df[label_col].values[i]\n                try:\n                    math.isnan(mask)\n                    mask = np.zeros((img_shape[1], img_shape[0]))\n                except:\n                    mask = rle_decode(mask)\n                axes[0][i+1].imshow(mask)\n                axes[1][i+1].imshow(rle2mask(sample_df[pred_col].values[i], img.shape))\n                axes[0][i+1].set_title(sample_df[title_col].values[i], fontsize=18)\n                axes[1][i+1].set_title(sample_df[title_col].values[i], fontsize=18)\n                axes[0][i+1].axis('off')\n                axes[1][i+1].axis('off')\n    else:\n        for sample in image_ids:\n            sample_df = df[df['image'] == sample]\n            fig, axes = plt.subplots(1, 5, figsize=figsize)\n            img = cv.imread(images_dest_path + sample_df['image'].values[0])\n            img = cv.resize(img, img_shape)\n            axes[0].imshow(img)\n            axes[0].set_title('Original', fontsize=16)\n            axes[0].axis('off')\n            for i in range(4):\n                axes[i+1].imshow(rle2mask(sample_df[label_col].values[i], img.shape))\n                axes[i+1].set_title(sample_df[title_col].values[i], fontsize=18)\n                axes[i+1].axis('off')\n\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 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","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DataGenerator(tf.keras.utils.Sequence):\n    def __init__(self, dataframe, directory, batch_size, n_channels, target_size,  n_classes, \n                 mode='fit', target_df=None, shuffle=True, preprocessing=None, augmentation=None, seed=0):\n        \n        self.batch_size = batch_size\n        self.dataframe = dataframe\n        self.mode = mode\n        self.directory = directory\n        self.target_df = target_df\n        self.target_size = target_size\n        self.n_channels = n_channels\n        self.n_classes = n_classes\n        self.shuffle = shuffle\n        self.augmentation = augmentation\n        self.preprocessing = preprocessing\n        self.seed = seed\n        self.mask_shape = (1400, 2100)\n        self.list_IDs = self.dataframe.index\n        \n        if self.seed is not None:\n            np.random.seed(self.seed)\n        \n        self.on_epoch_end()\n\n    def __len__(self):\n        return len(self.list_IDs) // self.batch_size\n\n    def __getitem__(self, index):\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n        list_IDs_batch = [self.list_IDs[k] for k in indexes]\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.augmentation:\n                X, Y = self.__augment_batch(X, Y)\n            \n            return X, Y\n        \n        elif self.mode == 'predict':\n            return X\n        \n    def on_epoch_end(self):\n        self.indexes = np.arange(len(self.list_IDs))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n    \n    def __generate_X(self, list_IDs_batch):\n        X = np.empty((self.batch_size, *self.target_size, self.n_channels))\n        \n        for i, ID in enumerate(list_IDs_batch):\n            img_name = self.dataframe['image'].loc[ID]\n            img_path = self.directory + img_name\n            img = cv.imread(img_path)\n            img = cv.cvtColor(img, cv.COLOR_BGR2RGB)\n\n            if self.preprocessing:\n                img = self.preprocessing(img)\n                \n            X[i,] = img\n\n        return X\n    \n    def __generate_Y(self, list_IDs_batch):\n        Y = np.empty((self.batch_size, *self.target_size, self.n_classes), dtype=int)\n        \n        for i, ID in enumerate(list_IDs_batch):\n            img_name = self.dataframe['image'].loc[ID]\n            image_df = self.target_df[self.target_df['image'] == img_name]\n            rles = image_df['EncodedPixels'].values\n            masks = build_masks(rles, input_shape=self.mask_shape, reshape=self.target_size)\n            Y[i, ] = masks\n\n        return Y\n    \n    def __augment_batch(self, X_batch, Y_batch):\n        for i in range(X_batch.shape[0]):\n            X_batch[i, ], Y_batch[i, ] = self.__random_transform(X_batch[i, ], Y_batch[i, ])\n        \n        return X_batch, Y_batch\n    \n    def __random_transform(self, X, Y):\n        composed = self.augmentation(image=X, mask=Y)\n        X_aug = composed['image']\n        Y_aug = composed['mask']\n        \n        return X_aug, Y_aug","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"now = time.time()\n\n# We create a copy from our already loaded and preprocessed DT\nDF = copy.deepcopy(corrected_df)\n\n# Why deep copy instead of assigment operator ?\n# We will shuffle the list -->  https://www.geeksforgeeks.org/copy-python-deep-copy-shallow-copy/\n\n# We split into train and validation sets, adding an additional column to distinguish them\nX_train, X_val = train_test_split(DF, test_size=0.2, random_state=1997)\n\nX_train.insert(0, 'Set', ['Train' for _ in range(len(X_train))], True)\nX_train.reset_index()\nrandom_select_train = np.random.choice(X_train['image'].values, 50)\n\nX_val.insert(0, 'Set', ['Val' for _ in range(len(X_val))], True)\nX_val.reset_index()\nrandom_select_val = np.random.choice(X_val['image'].values, 50)\n\nsize_train = len(X_train)\nsize_val = len(X_val)\n\nprint('# train examples {}'.format(size_train))\nprint('# val examples {}'.format(size_val))\nprint(time.time() - now)\n\n# We create a distinct folders for both train and validation\n# TODO: put this in a different file\n# TODO: do the same without creating the folders","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images_path = '/kaggle/working/train_images_dict/'\nvalidation_images_path = '/kaggle/working/val_images_dict/'\n\nif not os.path.exists(validation_images_path):\n    os.makedirs(validation_images_path)\n    \nif not check_if_exist(random_select_val, 'val_images_dict'):\n    if os.path.exists(validation_images_path):\n        shutil.rmtree(validation_images_path)\n\n    os.makedirs(validation_images_path)\n    try:\n        move_data(X_val, validation_images_path)\n        print('moved and created')\n        print(str((time.time() - now)/60.0) + \" minutes\")    \n    except IndexError:\n        shutil.rmtree(validation_images_path)\n\n\n# Since directories should be created only once\nif not os.path.exists(train_images_path):\n    os.makedirs(train_images_path)\n\nif not check_if_exist(random_select_train, 'train_images_dict'):\n    if os.path.exists(train_images_path):\n        shutil.rmtree(train_images_path)\n\n    os.makedirs(train_images_path)\n    try:\n        move_data(X_train, train_images_path)\n        print('moved and created')\n        print(str((time.time() - now)/60.0) + \" minutes\")    \n    except IndexError:\n        shutil.rmtree(train_images_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BACKBONE = 'resnet152'\nBATCH_SIZE = 14\nEPOCHS = 15\nLEARNING_RATE = 1e-4\nHEIGHT = 384\nWIDTH = 480\nCHANNELS = 3\nN_CLASSES = 4\nES_PATIENCE = 5\nRLROP_PATIENCE = 3\nDECAY_DROP = 0.5\nmodel_path = 'uNet_%s_%sx%s.h5' % (BACKBONE, HEIGHT, WIDTH)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We add augmentation and preprocessing\npreprocessing = sm.get_preprocessing(BACKBONE)\n\naugmentation = albu.Compose([albu.HorizontalFlip(),\n                             albu.VerticalFlip(),\n                             albu.ShiftScaleRotate(rotate_limit=30, shift_limit=0.1),\n                             ])\n\ntrain_generator = DataGenerator(\n                  directory=train_images_path,\n                  dataframe=X_train,\n                  target_df=train,\n                  batch_size=BATCH_SIZE,\n                  target_size=(HEIGHT, WIDTH),\n                  n_channels=CHANNELS,\n                  n_classes=N_CLASSES,\n                  augmentation=augmentation,\n                  preprocessing=preprocessing)\n\nvalid_generator = DataGenerator(\n                  directory=validation_images_path,\n                  dataframe=X_val,\n                  target_df=train,\n                  batch_size=BATCH_SIZE, \n                  target_size=(HEIGHT, WIDTH),\n                  n_channels=CHANNELS,\n                  n_classes=N_CLASSES,\n                  preprocessing=preprocessing)\n\nmodel = sm.Unet(backbone_name=BACKBONE,\n                encoder_weights='imagenet',\n                classes=4,\n                activation='sigmoid',\n                input_shape=(HEIGHT, WIDTH, 3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class OneCycleScheduler(tf.keras.callbacks.Callback):\n    def __init__(self, iterations, max_rate, start_rate=None,\n                 last_iterations=None, last_rate=None):\n        self.iterations = iterations\n        self.max_rate = max_rate\n        self.start_rate = start_rate or max_rate / 10\n        self.last_iterations = last_iterations or iterations // 10 + 1\n        self.half_iteration = (iterations - self.last_iterations) // 2\n        self.last_rate = last_rate or self.start_rate / 1000\n        self.iteration = 0\n    def _interpolate(self, iter1, iter2, rate1, rate2):\n        return ((rate2 - rate1) * (self.iteration - iter1)\n                / (iter2 - iter1) + rate1)\n    def on_batch_begin(self, batch, logs):\n        if self.iteration < self.half_iteration:\n            rate = self._interpolate(0, self.half_iteration, self.start_rate, self.max_rate)\n        elif self.iteration < 2 * self.half_iteration:\n            rate = self._interpolate(self.half_iteration, 2 * self.half_iteration,\n                                     self.max_rate, self.start_rate)\n        else:\n            rate = self._interpolate(2 * self.half_iteration, self.iterations,\n                                     self.start_rate, self.last_rate)\n            rate = max(rate, self.last_rate)\n        self.iteration += 1\n        K.set_value(self.model.optimizer.lr, rate)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"onecycle = OneCycleScheduler(len(X_train) // BATCH_SIZE * EPOCHS, max_rate=0.05)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"checkpoint = ModelCheckpoint(model_path, monitor='val_loss', mode='min', save_best_only=True, save_weights_only=True)\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, sm.metrics.iou_score]\ncallback_list = [checkpoint, es, onecycle]\n\n\noptimizer = tf.keras.optimizers.SGD(learning_rate=LEARNING_RATE, momentum=0.9,nesterov=True)\nmodel.compile(optimizer, loss=sm.losses.bce_dice_loss, metrics=metric_list)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"STEP_SIZE_TRAIN = len(X_train) // BATCH_SIZE\nSTEP_SIZE_VALID = len(X_val) // BATCH_SIZE\n\nhistory = model.fit(\n    train_generator,  \n    steps_per_epoch=STEP_SIZE_TRAIN,\n    validation_data=valid_generator,\n    validation_steps=STEP_SIZE_VALID,\n    callbacks=callback_list,\n    epochs=EPOCHS,\n    verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nmax(2,5)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(str((time.time() - now)/60.0) + \" minutes\")    \nplot_metrics(history.history, metric_list=['loss', 'dice_coef', 'iou_score'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_names = ['Fish  ', 'Flower', 'Gravel', 'Sugar ']\nbest_tresholds = [.5, .5, .5, .35]\nbest_masks = [25000, 20000, 22500, 15000]\n\nfor index, name in enumerate(class_names):\n    print('%s treshold=%.2f mask size=%d' % (name, best_tresholds[index], best_masks[index]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_metrics = get_metrics(model, train, X_train, train_images_path, best_tresholds, best_masks, preprocessing=preprocessing, set_name='Train')\ndisplay(train_metrics)\n\nprint(str((time.time() - now)/60.0) + \" minutes\")    \n\nvalidation_metrics = get_metrics(model, train, X_val, validation_images_path, best_tresholds, best_masks, preprocessing=preprocessing, set_name='Validation')\ndisplay(validation_metrics)\nprint(str((time.time() - now)/60.0) + \" minutes\")    \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = segmentation(model, h_flip=True, v_flip=True, h_shift=(-10, 10), v_shift=(-10, 10), merge='mean')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = pd.read_csv('../input/understanding_cloud_organization/sample_submission.csv')\nsubmission['image'] = submission['Image_Label'].apply(lambda x: x.split('_')[0])\ntest = pd.DataFrame(submission['image'].unique(), columns=['image'])\n\nrandom_select_test = np.random.choice(test['image'].values, 30)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images_path = '/kaggle/working/test_images_dict/'\nif not os.path.exists(test_images_path):\n    os.makedirs(test_images_path)\n    \nif not check_if_exist(random_select_test, 'test_images_dict'):\n    if os.path.exists(test_images_path):\n        shutil.rmtree(test_images_path)\n\n    os.makedirs(test_images_path)\n    try:\n        move_data(test, test_images_path, test_train='test')\n        print('created')\n        print(str((time.time() - now)/60.0) + \" minutes\")\n    except IndexError:\n        shutil.rmtree(test_images_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = []\n\nfor i in range(0, test.shape[0], 300):\n    batch_idx = list(range(i, min(test.shape[0], i + 300)))\n    batch_set = test[batch_idx[0]: batch_idx[-1]+1]\n    \n    test_generator = DataGenerator(\n                      directory=test_images_path,\n                      dataframe=batch_set,\n                      target_df=submission,\n                      batch_size=1, \n                      target_size=(HEIGHT, WIDTH),\n                      n_channels=CHANNELS,\n                      n_classes=N_CLASSES,\n                      preprocessing=preprocessing,\n                      mode='predict',\n                      shuffle=False)\n    \n    model.run_eagerly = True\n    preds = model.predict_generator(test_generator)\n\n    for index, b in enumerate(batch_idx):\n        filename = test['image'].iloc[b]\n        image_df = submission[submission['image'] == filename].copy()\n        pred_masks = preds[index, ].round().astype(int)\n        pred_rles = build_rles(pred_masks, reshape=(350, 525))\n        image_df['EncodedPixels'] = pred_rles\n\n        ### Post procecssing\n        pred_masks_post = preds[index, ].astype('float32') \n        for class_index in range(N_CLASSES):\n            pred_mask = pred_masks_post[...,class_index]\n            pred_mask = post_process(pred_mask, threshold=best_tresholds[class_index], min_size=best_masks[class_index])\n            pred_masks_post[...,class_index] = 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        test_df.append(image_df)\n\nsub_df = pd.concat(test_df)\nprint(str((time.time() - now)/60.0) + \" minutes\")    \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Choose 3 samples at random\nimages_to_inspect = np.random.choice(X_val['image'].unique(), 3, replace=False)\ninspect_set = train[train['image'].isin(images_to_inspect)].copy()\ninspect_set_temp = []\n\ninspect_generator = DataGenerator(\n                    directory=validation_images_path,\n                    dataframe=inspect_set,\n                    target_df=train,\n                    batch_size=1, \n                    target_size=(HEIGHT, WIDTH),\n                    n_channels=CHANNELS,\n                    n_classes=N_CLASSES,\n                    preprocessing=preprocessing,\n                    mode='fit',\n                    shuffle=False)\n\npreds = model.predict_generator(inspect_generator)\nprint(str((time.time() - now)/60.0) + \" minutes\")    \n\nfor index, b in enumerate(range(len(preds))):\n    filename = inspect_set['image'].iloc[b]\n    image_df = inspect_set[inspect_set['image'] == filename].copy()\n    pred_masks = preds[index, ].round().astype(int)\n    pred_rles = build_rles(pred_masks, reshape=(350, 525))\n    image_df['EncodedPixels_pred'] = pred_rles\n    \n    ### Post procecssing\n    pred_masks_post = preds[index, ].astype('float32') \n    for class_index in range(N_CLASSES):\n        pred_mask = pred_masks_post[...,class_index]\n        pred_mask = post_process(pred_mask, threshold=best_tresholds[class_index], min_size=best_masks[class_index])\n        pred_masks_post[...,class_index] = pred_mask\n\n    pred_rles_post = build_rles(pred_masks_post, reshape=(350, 525))\n    image_df['EncodedPixels_pred_post'] = pred_rles_post\n    ###\n    inspect_set_temp.append(image_df)\n\n\ninspect_set = pd.concat(inspect_set_temp)\ninspect_predictions(inspect_set, images_to_inspect, validation_images_path, pred_col='EncodedPixels_pred')\nprint(str((time.time() - now)/60.0) + \" minutes\")    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inspect_predictions(inspect_set, images_to_inspect, validation_images_path, pred_col='EncodedPixels_pred_post')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Choose 5 samples at random\nimages_to_inspect_test =  np.random.choice(sub_df['image'].unique(), 4, replace=False)\ninspect_predictions(sub_df, images_to_inspect_test, test_images_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inspect_predictions(sub_df, images_to_inspect_test, test_images_path, label_col='EncodedPixels_post')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"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())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df = sub_df[['Image_Label' ,'EncodedPixels']]\nsubmission_df.to_csv('submission.csv', index=False)\ndisplay(submission_df.head())\nprint(str((time.time() - now)/60.0) + \" minutes\")    ","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":4}