{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport math\nfrom matplotlib import pyplot as plt\nfrom os.path import join\nfrom keras.losses import binary_crossentropy\nimport keras.backend as K\nfrom keras.models import Model\nfrom keras.layers import Input, concatenate, Conv2D, MaxPooling2D, BatchNormalization, Conv2DTranspose, Dropout\nfrom keras.optimizers import Adam\nfrom sklearn.model_selection import train_test_split\nfrom skimage.io import imread\nimport tensorflow as tf\nfrom IPython.display import clear_output","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"DATA_PATH   = '../input/airbus-ship-detection/'\nTRAIN_PATH  = DATA_PATH+'train_v2/'\nTEST_PATH   = DATA_PATH+'test_v2/' \nIMG_SIZE    = (768, 768)\nINPUT_SHAPE = (768, 768)\nTARGET_SIZE = (256, 256)\nBATCH_SIZE  = 128\nEPOCHS      = 10","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"","_uuid":"","trusted":true},"cell_type":"code","source":"# formed on the basis of https://www.kaggle.com/drobchak1988/understand-dataset\ntrain_df = pd.read_csv('../input/airbusshipbalance/train_df.csv')\nvalid_df = pd.read_csv('../input/airbusshipbalance/valid_df.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_mask_with_image(ImageId, masks_df):\n    image = imread(join(TRAIN_PATH, ImageId))\n    image = image[::3,::3]\n    mask  = masks_as_image(masks_df['EncodedPixels'].values)\n    mask  = np.expand_dims(mask, -1)\n    mask  = mask[::3,::3]\n    return [image],[mask]\n\ndef masks_as_image(in_mask_list):\n    # Take the individual ship masks and create a single mask array for all ships\n    all_masks = np.zeros((768, 768), dtype = np.uint8)\n    for mask in in_mask_list:\n        if isinstance(mask, str):\n            all_masks |= rle_decode(mask)\n    return all_masks\n\ndef rle_decode(mask_rle, shape=INPUT_SHAPE):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height,width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n\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).T\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_image_gen(in_df, batch_size=BATCH_SIZE):\n    all_batches = list(in_df.groupby('ImageId'))\n    masks = []\n    images = []\n    while True:\n        np.random.shuffle(all_batches)\n        for image, masks_df in all_batches:\n            image, mask = get_mask_with_image(image, masks_df)            \n            images += image\n            masks += mask\n            if len(images)>=batch_size:\n                yield np.stack(images, 0)/255.0, np.stack(masks, 0)\n                masks, images=[], []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def dice_coef(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 = 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    return 1 - dice_coef(y_true, y_pred)\n\ndef bce_dice_loss(y_true, y_pred):\n    return binary_crossentropy(y_true, y_pred) + dice_loss(y_true, y_pred)\n     \ndef get_unet_model(input_shape=(256, 256, 3), num_classes=1):\n\n    def fire(x, filters, kernel_size, dropout):\n        y1 = Conv2D(filters, kernel_size, activation='relu', padding='same')(x)\n        if dropout is not None:\n            y1= Dropout(dropout)(y1)\n        y2 = Conv2D(filters, kernel_size, activation='relu', padding='same')(y1)\n        y3 = BatchNormalization(momentum=0.99)(y2)     \n        return y3\n\n    def fire_module(filters, kernel_size, dropout=0.2):\n        return lambda x: fire(x, filters, kernel_size, dropout)\n\n    def fire_up(x, filters, kernel_size, concat_layer):\n        y1 = Conv2DTranspose(filters, (2, 2), strides=(2, 2), padding='same')(x)\n        y2 = concatenate([y1, concat_layer])\n        y3 = fire_module(filters, kernel_size, dropout=None)(y2)\n        return y3\n\n    def up_fire_module(filters, kernel_size, concat_layer):\n        return lambda x: fire_up(x, filters, kernel_size, concat_layer)\n\n    input_img = Input(shape=input_shape) #256\n\n    down1 = fire_module(8, (3, 3))(input_img)\n    pool1 = MaxPooling2D((2, 2))(down1)  #128\n\n    down2 = fire_module(16, (3, 3))(pool1)\n    pool2 = MaxPooling2D((2, 2))(down2) #64\n    \n    down3 = fire_module(32, (3, 3))(pool2)\n    pool3 = MaxPooling2D((2, 2))(down3) #32\n    \n    down4 = fire_module(64, (3, 3))(pool3)\n    pool4 = MaxPooling2D((2, 2))(down4) #16\n    \n    down5 = fire_module(128, (3, 3))(pool4)\n    pool5 = MaxPooling2D((2, 2))(down5) # 8\n    \n    down6 = fire_module(256, (3, 3))(pool5) #center\n    \n    up6 = up_fire_module(128, (3, 3), down5)(down6) #16\n    up7 = up_fire_module(64, (3, 3), down4)(up6) #32\n    up8 = up_fire_module(32, (3, 3), down3)(up7) #64\n    up9 = up_fire_module(16, (3, 3), down2)(up8) #128\n    up10 = up_fire_module(8, (3, 3), down1)(up9) #256\n    \n    outputs = Conv2D(num_classes, (1, 1), activation='sigmoid')(up10) \n\n    model = Model(inputs=[input_img], outputs=[outputs])\n    model.compile(loss=bce_dice_loss, metrics=[dice_coef], optimizer='adam')\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"model = get_unet_model()\ntf.keras.utils.plot_model(model, show_shapes=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau, TerminateOnNaN, TensorBoard\nweight_path=\"{}_weights.best.hdf5\".format('model')\n\ncheckpoint = ModelCheckpoint(weight_path, monitor='val_loss', verbose=1, save_best_only=True, mode='min', save_weights_only=True)\n\ndef lr_decay(epoch):\n  return 0.1 * math.pow(0.766, epoch)\n\ncallback_learning_rate = LearningRateScheduler(lr_decay, verbose=1)\n\nclass EarlyStop(tf.keras.callbacks.Callback):\n  def on_epoch_end(self, epoch, logs={}):\n    if(logs.get('val_loss')<0.05):\n      print(\"\\nReached 005%% value losse so cancelling training!\")\n      self.model.stop_training = True\n        \nearly_stop = EarlyStop()  \n\nclass PlotLosses(tf.keras.callbacks.Callback):\n    def on_train_begin(self, logs={}):\n        self.i = 0\n        self.x = []\n        self.losses = []\n        self.val_losses = []\n        self.accuracy = []\n        self.val_accuracy = []\n        self.fig = plt.figure()\n\n        self.logs = []\n\n    def on_epoch_end(self, epoch, logs={}):\n        \n        self.logs.append(logs)\n        self.x.append(self.i)\n        self.losses.append(logs.get('loss'))\n        self.val_losses.append(logs.get('val_loss'))\n        self.accuracy.append(logs.get('dice_coef'))\n        self.val_accuracy.append(logs.get('val_dice_coef'))\n        self.i += 1\n\n        clear_output(wait=True)\n        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))\n        ax1.plot(self.x, self.accuracy, 'r', label=\"dice_coef\")\n        ax1.plot(self.x, self.val_accuracy, 'bo', label=\"val_dice_coef\")\n        ax1.set_title('Model accuracy')\n        ax1.set_ylabel('Accuracy')\n        ax1.set_xlabel('Epoch')\n        ax1.set_ylim([0, 1])\n        ax1.legend(['Train', 'Test'], loc='upper left')\n         \n        ax2.plot(self.x, self.losses, 'r', label=\"loss\")\n        ax2.plot(self.x, self.val_losses,'bo', label=\"val_loss\")\n        ax2.set_title('Model loss')\n        ax2.set_ylabel('Loss')\n        ax2.set_xlabel('Epoch')\n        ax2.set_ylim([0, 1])\n        ax2.legend(['Train', 'Test'], loc='upper left')\n        plt.show()\n\n        print(logs)\nplot_losses = PlotLosses()\n\n# tensorboard_log = TensorBoard(log_dir=\"./logs\")  callback_learning_rate,\n\ncallbacks_list = [checkpoint, plot_losses]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_gen = make_image_gen(train_df)\nvalid_x, valid_y = next(make_image_gen(valid_df))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(\n     train_gen,\n     steps_per_epoch=len(train_df)//BATCH_SIZE,\n     epochs=EPOCHS,\n     validation_data=(valid_x, valid_y),\n     callbacks=callbacks_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"accuracy = history.history['dice_coef']\nloss = history.history['loss']\nval_accuracy = history.history['val_dice_coef']\nval_loss = history.history['val_loss']\n\nprint(f'Training Accuracy: {np.max(accuracy)}')\nprint(f'Training Loss: {np.min(loss)}')\nprint(f'Validation Accuracy: {np.max(val_accuracy)}')\nprint(f'Validation Loss: {np.min(val_loss)}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights(weight_path)\nmodel.save('model_dice_coef_with_binary_cross_loss.h5')","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":1}