{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom skimage.data import imread\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nfrom sklearn.model_selection import train_test_split\nfrom skimage.segmentation import mark_boundaries\nimport skimage.util.montage as montage\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nmontage_rgb = lambda x: np.stack([montage(x[:, :, :, i]) for i in range(x.shape[3])], -1)\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\nimport gc; gc.enable()\nimport os\nprint(os.listdir(\"../input\"))\ntrain_image_dir = os.path.join('../input', 'train_v2')\ntest_image_dir = os.path.join('../input', 'test_v2')\nVALID_IMG_COUNT = 400\nIMG_SCALING = (1, 1)\nBATCH_SIZE = 50\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"train = os.listdir('../input/train_v2')\nprint(len(train))\n\ntest = os.listdir('../input/test_v2')\nprint(len(test))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2e41464b15c81863b4b4832291a9b9c6233bfa35"},"cell_type":"code","source":"# coding utils\nfrom skimage.morphology import label\ndef multi_rle_encode(img):\n    labels = label(img[:, :, 0])\n    return [rle_encode(labels==k) for k in np.unique(labels[labels>0])]\n\n# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\ndef rle_encode(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 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\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.int16)\n    #if isinstance(in_mask_list, list):\n    for mask in in_mask_list:\n        if isinstance(mask, str):\n            all_masks += rle_decode(mask)\n    return np.expand_dims(all_masks, -1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c6dbe55d09328048f5f7b98aedd8eaa8f68a3751"},"cell_type":"code","source":"submission = pd.read_csv('../input/sample_submission_v2.csv')\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6122ccb9e58bfac6fa5e11c86121e78d9e5151b1"},"cell_type":"code","source":"# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\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    '''\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,"_uuid":"206104f888afa9c62a0bbcb45229f58111094f18"},"cell_type":"code","source":"masks = pd.read_csv('../input/train_ship_segmentations_v2.csv')\nmasks.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"63e18e8573dbb3fe1d3ff1d72b6dc756e067d43a","scrolled":true},"cell_type":"code","source":"ImageId = '0005d01c8.jpg'\n\nimg = imread('../input/train_v2/' + ImageId)\nimg_masks = masks.loc[masks['ImageId'] == ImageId, 'EncodedPixels'].tolist()\n\n# Take the individual ship masks and create a single mask array for all ships\nall_masks = np.zeros((768, 768))\nfor mask in img_masks:\n    all_masks += rle_decode(mask)\n\nfig, axarr = plt.subplots(1, 3, figsize=(15, 40))\naxarr[0].axis('off')\naxarr[1].axis('off')\naxarr[2].axis('off')\naxarr[0].imshow(img)\naxarr[1].imshow(all_masks)\naxarr[2].imshow(img)\naxarr[2].imshow(all_masks, alpha=0.4)\nplt.tight_layout(h_pad=0.1, w_pad=0.1)\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"eb0a8bfa1038e6d8e6de4643c75e2b8e58e96a46"},"cell_type":"code","source":"# Courtesy of Kevin Mader - https://www.kaggle.com/kmader/baseline-u-net-model-part-1\nmasks['ships'] = masks['EncodedPixels'].map(lambda c_row: 1 if isinstance(c_row, str) else 0)\nunique_img_ids = masks.groupby('ImageId').agg({'ships': 'sum'}).reset_index()\nunique_img_ids['has_ship'] = unique_img_ids['ships'].map(lambda x: 1.0 if x>0 else 0.0)\nunique_img_ids['has_ship_vec'] = unique_img_ids['has_ship'].map(lambda x: [x])\n# some files are too small/corrupt\nunique_img_ids['file_size_kb'] = unique_img_ids['ImageId'].map(lambda c_img_id: \n                                                               os.stat(os.path.join(train_image_dir, \n                                                                                    c_img_id)).st_size/1024)\nunique_img_ids = unique_img_ids[unique_img_ids['file_size_kb']>50] # keep only 50kb files\nunique_img_ids['file_size_kb'].hist()\nmasks.drop(['ships'], axis=1, inplace=True)\nunique_img_ids.sample(5)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"93e331a954173bacb0d80f90260b7762453d5612"},"cell_type":"code","source":"# validation and test sets\n\nx_train, x_val = train_test_split(unique_img_ids, \n                 test_size = 0.3, \n                 stratify = unique_img_ids['ships'])\nx_train_df = pd.merge(masks, x_train)\nx_val_df = pd.merge(masks, x_val)\nprint(x_train_df.shape[0], 'training masks')\nprint(x_val_df.shape[0], 'validation masks')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e6df0e4bec02b527b90898dff7809d275967f381"},"cell_type":"code","source":"# balance the data - too many empty images\n\nx_train_df['grouped_ship_count'] = x_train_df['ships'].map(lambda x: (x+1)//2).clip(0, 7)\ndef sample_ships(in_df, base_rep_val=1500):\n    if in_df['ships'].values[0]==0:\n        return in_df.sample(base_rep_val//3) # even more strongly undersample no ships\n    else:\n        return in_df.sample(base_rep_val, replace=(in_df.shape[0]<base_rep_val))\n    \nbalanced_train_df = x_train_df.groupby('grouped_ship_count').apply(sample_ships)\nbalanced_train_df['ships'].hist(bins=np.arange(10))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"24c66826adf2058482c2d2997e7324d052e899bd"},"cell_type":"code","source":"# keras image batch generator\ndef make_image_gen(in_df, batch_size = BATCH_SIZE):\n    all_batches = list(in_df.groupby('ImageId'))\n    out_rgb = []\n    out_mask = []\n    while True:\n        np.random.shuffle(all_batches)\n        for c_img_id, c_masks in all_batches:\n            rgb_path = os.path.join(train_image_dir, c_img_id)\n            c_img = imread(rgb_path)\n            c_mask = masks_as_image(c_masks['EncodedPixels'].values)\n            if IMG_SCALING is not None:\n                c_img = c_img[::IMG_SCALING[0], ::IMG_SCALING[1]]\n                c_mask = c_mask[::IMG_SCALING[0], ::IMG_SCALING[1]]\n            out_rgb += [c_img]\n            out_mask += [c_mask]\n            if len(out_rgb)>=batch_size:\n                yield np.stack(out_rgb, 0)/255.0, np.stack(out_mask, 0)\n                out_rgb, out_mask=[], []\n                \ntrain_gen = make_image_gen(balanced_train_df)\nvalid_x, valid_y = next(make_image_gen(x_val_df, VALID_IMG_COUNT))\nprint(valid_x.shape, valid_y.shape)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a96be17dec6cca0f6e841b45dc961f35c690c361"},"cell_type":"code","source":"#generate more data - basically rotates already known images lul\nAUGMENT_BRIGHTNESS = False\ndg_args = dict(featurewise_center = False, \n                  samplewise_center = False,\n                  rotation_range = 15, \n                  width_shift_range = 0.1, \n                  height_shift_range = 0.1, \n                  shear_range = 0.01,\n                  zoom_range = [0.9, 1.25],  \n                  horizontal_flip = True, \n                  vertical_flip = True,\n                  fill_mode = 'reflect',\n               \n                   data_format = 'channels_last')\n\nimage_gen = ImageDataGenerator(**dg_args)\nlabel_gen = ImageDataGenerator(**dg_args)\n\ndef create_aug_gen(in_gen, seed = None):\n    np.random.seed(seed if seed is not None else np.random.choice(range(9999)))\n    for in_x, in_y in in_gen:\n        seed = np.random.choice(range(9999))\n        # keep the seeds syncronized otherwise the augmentation to the images is different from the masks\n        g_x = image_gen.flow(255*in_x, \n                             batch_size = in_x.shape[0], \n                             seed = seed, \n                             shuffle=True)\n        g_y = label_gen.flow(in_y, \n                             batch_size = in_x.shape[0], \n                             seed = seed, \n                             shuffle=True)\n\n        yield next(g_x)/255.0, next(g_y)\n        \ncur_gen = create_aug_gen(train_gen)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":false,"_uuid":"247602cc645efb3b94b620dac9489413ebd01b82"},"cell_type":"code","source":"# U-net keras version\ndef unet(pretrained_weights = None,input_size = (768,768,3)):\n    inputs = tf.keras.layers.Input(input_size)\n    conv1 = tf.keras.layers.Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs)\n    conv1 = tf.keras.layers.Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv1)\n    pool1 = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(conv1)\n    conv2 = tf.keras.layers.Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool1)\n    conv2 = tf.keras.layers.Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv2)\n    pool2 = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(conv2)\n    conv3 = tf.keras.layers.Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool2)\n    conv3 = tf.keras.layers.Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv3)\n    pool3 = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(conv3)\n    conv4 = tf.keras.layers.Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool3)\n    conv4 = tf.keras.layers.Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv4)\n    drop4 = tf.keras.layers.Dropout(0.5)(conv4)\n    pool4 = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(drop4)\n\n    conv5 = tf.keras.layers.Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(pool4)\n    conv5 = tf.keras.layers.Conv2D(1024, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv5)\n    drop5 = tf.keras.layers.Dropout(0.5)(conv5)\n\n    up6 = tf.keras.layers.Conv2D(512, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(tf.keras.layers.UpSampling2D(size = (2,2))(drop5))\n    merge6 = tf.keras.layers.concatenate([drop4,up6])\n    conv6 = tf.keras.layers.Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge6)\n    conv6 = tf.keras.layers.Conv2D(512, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv6)\n\n    up7 = tf.keras.layers.Conv2D(256, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(tf.keras.layers.UpSampling2D(size = (2,2))(conv6))\n    merge7 = tf.keras.layers.concatenate([conv3,up7])\n    conv7 = tf.keras.layers.Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge7)\n    conv7 = tf.keras.layers.Conv2D(256, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv7)\n\n    up8 = tf.keras.layers.Conv2D(128, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(tf.keras.layers.UpSampling2D(size = (2,2))(conv7))\n    merge8 = tf.keras.layers.concatenate([conv2,up8])\n    conv8 = tf.keras.layers.Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge8)\n    conv8 = tf.keras.layers.Conv2D(128, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv8)\n\n    up9 = tf.keras.layers.Conv2D(64, 2, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(tf.keras.layers.UpSampling2D(size = (2,2))(conv8))\n    merge9 = tf.keras.layers.concatenate([conv1,up9])\n    conv9 = tf.keras.layers.Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(merge9)\n    conv9 = tf.keras.layers.Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)\n    conv9 = tf.keras.layers.Conv2D(2, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)\n    conv10 = tf.keras.layers.Conv2D(1, 1, activation = 'sigmoid')(conv9)\n\n    model = tf.keras.Model(inputs = inputs, outputs = conv10)\n\n    model.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])\n    \n    #model.summary()\n\n    if(pretrained_weights):\n    \tmodel.load_weights(pretrained_weights)\n    model.summary()\n    return model\n\nmodel = unet()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"758ff758da5b7dd9af4baac32d07871ca2c4dda9"},"cell_type":"code","source":"# keras fit\n# early termination call back\nearly = EarlyStopping(monitor=\"val_dice_coef\", \n                      mode=\"max\", \n                      patience=15)\n\ncallbacks = [early]\n\nepochs = 10\nsteps = 200\nstep_count = min(steps, balanced_train_df.shape[0]//BATCH_SIZE)\n#checkpoint saving\nweight_path=\"{}_weights.best.hdf5\".format('model')\n# augemnter image generator boiz\naug_gen = create_aug_gen(make_image_gen(balanced_train_df))\nmodel.fit_generator(aug_gen, \n                             steps_per_epoch=step_count, \n                             epochs=epochs, \n                             validation_data=(valid_x, valid_y),\n                             callbacks=callbacks,\n                            workers=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b8aae5626da4c645ea26daf96b60369201c5f5d3"},"cell_type":"code","source":"test_paths = os.listdir(test_image_dir)\nprint(len(test_paths), 'test images found')\n\nfig, m_axs = plt.subplots(20, 2, figsize = (10, 40))\n[c_ax.axis('off') for c_ax in m_axs.flatten()]\nfor (ax1, ax2), c_img_name in zip(m_axs, test_paths):\n    c_path = os.path.join(test_image_dir, c_img_name)\n    c_img = imread(c_path)\n    first_img = np.expand_dims(c_img, 0)/255.0\n    first_seg = model.predict(first_img)\n    ax1.imshow(first_img[0])\n    ax1.set_title('Image')\n    ax2.imshow(first_seg[0, :, :, 0], vmin = 0, vmax = 1)\n    ax2.set_title('Prediction')\nfig.savefig('test_predictions.png')","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}