{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","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 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  = 24\nEPOCHS      = 10\nTHRESHOLD   = 1.0","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"","_uuid":"","trusted":true},"cell_type":"code","source":"train_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","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 iou_coef(y_true, y_pred, smooth=1):\n    intersection = K.sum(K.abs(y_true * y_pred), axis=[1,2,3])\n    union = K.sum(y_true,[1,2,3])+K.sum(y_pred,[1,2,3])-intersection\n    return K.mean((intersection + smooth) / (union + smooth), axis=0)\n\ndef threshold_binarize(x, threshold=THRESHOLD):\n    ge = tf.greater_equal(x, tf.constant(threshold))\n    return tf.where(ge, x=tf.ones_like(x), y=tf.zeros_like(x))\n\ndef iou_thresholded(y_true, y_pred, threshold=THRESHOLD, smooth=1.):\n    y_pred = threshold_binarize(y_pred, threshold)\n    return iou_coef(y_true, y_pred, smooth)\n\ndef jaccard_coef(y_true, y_pred):\n    intersection = K.sum(y_true * y_pred)\n    union = K.sum(y_true + y_pred)\n    jac = (intersection + 1.) / (union - intersection + 1.)\n    return K.mean(jac)\n\ndef jaccard_distance(y_true, y_pred,smooth=300):\n    intersection = K.sum(K.abs(y_true * y_pred), axis=-1)\n    sum_ = K.sum(K.abs(y_true) + K.abs(y_pred), axis=-1)\n    jac = (intersection + smooth) / (sum_ - intersection + smooth)\n    return (1 - jac) * smooth\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(optimizer='adam', loss=jaccard_distance, metrics=[iou_coef])\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = get_unet_model()\n# model.summary()\n# tf.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.001 * math.pow(0.9, 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('iou_coef'))\n        self.val_accuracy.append(logs.get('val_iou_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=\"iou_coef\")\n        ax1.plot(self.x, self.val_accuracy,'bo', label=\"val_iou_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 right')\n        plt.show()\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":"steps_per_epoch = 12\nhistory = model.fit_generator(train_gen,\n                             steps_per_epoch=steps_per_epoch,\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['jaccard_coef']\nloss = history.history['loss']\nval_accuracy = history.history['val_jaccard_coef']\nval_loss = history.history['val_loss']\nprint(f'Training Accuracy: {np.max(accuracy)}')\nprint(f'Training Loss: {np.min(loss)}\\n')\nprint(f'Validation Accuracy: {np.max(val_accuracy)}')\nprint(f'Validation Loss: {np.min(val_loss)}\\n')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights(weight_path)\nmodel.save('model_jaccard_distance.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.models import Sequential\nfrom keras.models import load_model\nfrom keras.layers import UpSampling2D, AvgPool2D\nfrom skimage.io import imread\nfrom skimage.transform import resize\nfrom matplotlib.cm import get_cmap\nfrom skimage.segmentation import mark_boundaries\nfrom skimage.morphology import binary_opening, disk, label\nimport os","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def multi_rle_encode(img, **kwargs):\n    '''\n    Encode connected regions as separated masks\n    '''\n    labels = label(img)\n    if img.ndim > 2:\n        return [rle_encode(np.sum(labels==k, axis=2), **kwargs) for k in np.unique(labels[labels>0])]\n    else:\n        return [rle_encode(labels==k, **kwargs) for k in np.unique(labels[labels>0])]\n    \ndef rle_encode(img, min_max_threshold=1e-3, max_mean_threshold=None):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    if np.max(img) < min_max_threshold:\n        return '' ## no need to encode if it's all zeros\n    if max_mean_threshold and np.mean(img) > max_mean_threshold:\n        return '' ## ignore overfilled mask\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)\ndef masks_as_color(in_mask_list):\n    # Take the individual ship masks and create a color mask array for each ships\n    all_masks = np.zeros((768, 768), dtype = np.float)\n    scale = lambda x: (len(in_mask_list)+x+1) / (len(in_mask_list)*2) ## scale the heatmap image to shift \n    for i,mask in enumerate(in_mask_list):\n        if isinstance(mask, str):\n            all_masks[:,:] += scale(i) * rle_decode(mask)\n    return all_masks\ndef rle_decode(mask_rle, shape=(768, 768)):\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    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).T  # Needed to align to RLE direction","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_PATH   = '../input/airbus-ship-detection/'\nTEST_PATH   = DATA_PATH+'test_v2/'\n\nfullres_model = Sequential()\nfullres_model.add(AvgPool2D((3,3), input_shape = (None, None, 3)))\nfullres_model.add(model)\nfullres_model.add(UpSampling2D((3,3)))\n\ndef raw_prediction(img, path=TEST_PATH):\n    c_img = imread(os.path.join(path, c_img_name))\n    c_img = np.expand_dims(c_img, 0)/255.0\n    cur_seg = fullres_model.predict(c_img)[0]\n    return cur_seg, c_img[0]\n\ndef smooth(cur_seg):\n    return binary_opening(cur_seg>0.99, np.expand_dims(disk(2), -1))\n\ndef predict(img, path=TEST_PATH):\n    cur_seg, c_img = raw_prediction(img, path=path)\n    return smooth(cur_seg), c_img\n\ntest_paths = np.array(os.listdir(TEST_PATH))\nprint(len(test_paths), 'test images found')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def pred_encode(img, **kwargs):\n    cur_seg, _ = predict(img)\n    cur_rles = multi_rle_encode(cur_seg, **kwargs)\n    return [[img, rle] for rle in cur_rles if rle is not None]\n\nout_pred_rows = []\nfor c_img_name in test_paths[0:200]: ## only a subset as it takes too long to run\n    out_pred_rows += pred_encode(c_img_name, min_max_threshold=1.0)\n    \nsub = pd.DataFrame(out_pred_rows)\nsub.columns = ['ImageId', 'EncodedPixels']\nprint(sub.shape[0])\nsub = sub[sub.EncodedPixels.notnull()]\nprint(sub.shape[0])\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## let's see what we got\nTOP_PREDICTIONS = 20\nfig, m_axs = plt.subplots(TOP_PREDICTIONS, 3, figsize = (14, TOP_PREDICTIONS*4))\n[c_ax.axis('off') for c_ax in m_axs.flatten()]\n\nfor (ax1, ax2, ax3), c_img_name in zip(m_axs, sub.ImageId.unique()[:TOP_PREDICTIONS]):\n    pred, c_img = raw_prediction(c_img_name)\n    ax1.imshow(c_img)\n    ax1.set_title('Image: ' + c_img_name)\n    ax2.imshow(pred[...,0], cmap=get_cmap('jet'))\n    ax2.set_title('Prediction')\n    ax3.imshow(masks_as_color(sub.query('ImageId==\\\"{}\\\"'.format(c_img_name))['EncodedPixels']))\n    ax3.set_title('Masks')","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}