{"cells":[{"metadata":{"_uuid":"aa8401d73c7a19e1a43fdd6a992ea9dcb60039a2","id":"8W4CjXpk5ahe","colab_type":"text"},"cell_type":"markdown","source":"# Assignment: Object Detection\nỞ bài tập này, chúng ta sẽ tiến hành detect (xác định) tàu, thuyền từ ảnh hàng không, sử dụng mạng Unet. Bộ dataset được lấy từ cuộc thi https://www.kaggle.com/c/airbus-ship-detection/overview "},{"metadata":{"id":"MDWxsMLA6Nci","colab_type":"text"},"cell_type":"markdown","source":"## Kết nối dataset\nKết nối đến bộ dataset: *Airbus ship detection* trên Kaggle đã được đưa vào Google Colab"},{"metadata":{"id":"HyQc1K5NAAKw","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":122},"outputId":"4dcd6286-956a-4f2c-8ed3-523eae9d9e7f","trusted":false},"cell_type":"code","source":"from google.colab import drive\ndrive.mount('/content/drive')","execution_count":null,"outputs":[]},{"metadata":{"id":"M7SVvzHNADCg","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":34},"outputId":"eebefb37-3e6f-42cf-ce66-e677bf8817c6","trusted":false},"cell_type":"code","source":"cd /content/drive/My Drive/ship/","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a6cd9d5ad61ffe3b8858769f20a5f9493f024a56","id":"q0OiAkMd5ahf","colab_type":"text"},"cell_type":"markdown","source":"## Cài đặt các thông số cho mô hình\nChúng ta có thể điều chỉnh các thông số để thử và cải thiện mô hình của mình"},{"metadata":{"trusted":true,"_uuid":"301a5d939c566d1487a049bb2554d09b592b18b1","scrolled":true,"id":"cnXCqDld5ahg","colab_type":"code","colab":{}},"cell_type":"code","source":"BATCH_SIZE = 48\nEDGE_CROP = 16\nGAUSSIAN_NOISE = 0.1\nUPSAMPLE_MODE = 'SIMPLE'\n# downsampling inside the network\nNET_SCALING = (1, 1)\n# downsampling in preprocessing\nIMG_SCALING = (3, 3)\n# number of validation images to use\nVALID_IMG_COUNT = 900\n# maximum number of steps_per_epoch in training\nMAX_TRAIN_STEPS = 9\nMAX_TRAIN_EPOCHS = 15\nAUGMENT_BRIGHTNESS = False","execution_count":0,"outputs":[]},{"metadata":{"id":"s7ALJpP-634k","colab_type":"text"},"cell_type":"markdown","source":"# Encode/decode image\nTiến trình:\n$$  RLE_0 \\stackrel{Decode}{\\longrightarrow} \\textrm{Image}_0 \\stackrel{Encode}{\\longrightarrow} RLE_1 \\stackrel{Decode}{\\longrightarrow} \\textrm{Image}_1 $$\nChúng ta muốn rằng: \n$ \\textrm{Image}_0 \\stackrel{?}{=} \\textrm{Image}_1 $"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"id":"ksXEk4mw5ahj","colab_type":"code","colab":{}},"cell_type":"code","source":"import os\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom skimage.io import imread\nimport matplotlib.pyplot as plt\nfrom matplotlib.cm import get_cmap\nfrom skimage.segmentation import mark_boundaries\nfrom skimage.util import montage as montage\nfrom skimage.morphology import binary_opening, disk, label\nimport gc; gc.enable() # memory is tight\n\nmontage_rgb = lambda x: np.stack([montage(x[:, :, :, i]) for i in range(x.shape[3])], -1)\nship_dir = '/content/drive/My Drive/ship/'\ntrain_image_dir = os.path.join(ship_dir, 'train_v2')\ntest_image_dir = os.path.join(ship_dir, 'test_v2')\n\ndef 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\n# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\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)\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.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 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","execution_count":0,"outputs":[]},{"metadata":{"id":"ZCwPYhCMCyEU","colab_type":"code","colab":{"base_uri":"https://localhost:8080/","height":238},"outputId":"15416682-9f1d-44b3-d360-aa7caddc446e","trusted":false},"cell_type":"code","source":"masks = pd.read_csv(os.path.join('/content/drive/My Drive/ship/', 'train_ship_segmentations_v2.csv'))\nnot_empty = pd.notna(masks.EncodedPixels)\nprint(not_empty.sum(), 'masks in', masks[not_empty].ImageId.nunique(), 'images')\nprint((~not_empty).sum(), 'empty images in', masks.ImageId.nunique(), 'total images')\nmasks.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fdedd5965f47f84aa8f3aab1cad978512781a1cc","colab_type":"text","id":"RmLaY1WC7Rqw"},"cell_type":"markdown","source":"# Đảm bảo bộ encode/decode hoạt động\n\nHãy đảm bảo\n$ \\textrm{Image}_0 \\stackrel{?}{=} \\textrm{Image}_1 $\nChúng ta có thể kiểm tra RLEs nhưng sẽ lâu hơn. \n\n"},{"metadata":{"trusted":true,"_uuid":"0081fd6f387abd7c05eb35f29575a2ee6ddc2236","colab_type":"code","outputId":"19eba88e-f21f-49c0-f09a-cab51418f446","id":"ffDL0oGj7RaJ","colab":{"base_uri":"https://localhost:8080/","height":292}},"cell_type":"code","source":"fig, (ax1, ax2, ax3, ax4) = plt.subplots(1, 4, figsize = (16, 5))\nrle_0 = masks.query('ImageId==\"00021ddc3.jpg\"')['EncodedPixels']\nimg_0 = masks_as_image(rle_0)\nax1.imshow(img_0)\nax1.set_title('Mask as image')\nrle_1 = multi_rle_encode(img_0)\nimg_1 = masks_as_image(rle_1)\nax2.imshow(img_1)\nax2.set_title('Re-encoded')\nimg_c = masks_as_color(rle_0)\nax3.imshow(img_c)\nax3.set_title('Masks in colors')\nimg_c = masks_as_color(rle_1)\nax4.imshow(img_c)\nax4.set_title('Re-encoded in colors')\nprint('Check Decoding->Encoding',\n      'RLE_0:', len(rle_0), '->',\n      'RLE_1:', len(rle_1))\nprint(np.sum(img_0 - img_1), 'error')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"40cb72e241c0c3d8bc245b4e3c663b4a835b0011","id":"xfhKrmNR5ahz","colab_type":"text"},"cell_type":"markdown","source":"# Chia tập train và val\n"},{"metadata":{"trusted":true,"_uuid":"c4f008bf6898518fd371de013418f936edaa09f8","colab_type":"code","outputId":"7c7f12d3-a724-4f0e-9bdf-df876881e0bc","id":"2b3OqvdBHIfP","colab":{}},"cell_type":"code","source":"masks['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(7)","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"c21d5bff04bf9180463969ac120379345745ed03","id":"gd7ll3W25ah6","colab_type":"text"},"cell_type":"markdown","source":"### Kiểm tra số lượng hình ảnh tàu\nThống kê số lượng ảnh của mỗi nhóm ảnh phân theo số lượng tàu, chuẩn hoá ảnh không có tàu về 0"},{"metadata":{"trusted":true,"_uuid":"2612fa47c7e9fdcaa7aa720c4e15fc86fd65d69a","id":"DnE_GWC25ah7","colab_type":"code","colab":{},"outputId":"4c03b61c-23f1-44a7-e604-807aa66ab975"},"cell_type":"code","source":"unique_img_ids['ships'].hist(bins=unique_img_ids['ships'].max())","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"ef8115a80749ac47f295e9a70217a5553970c2b3","id":"jYX_uecO5aiD","colab_type":"text"},"cell_type":"markdown","source":"# Xoá bớt các ảnh trống\nBỏ bớt các ảnh trống để giảm bớt sự mất cân bằng trong data"},{"metadata":{"trusted":true,"_uuid":"0cf0bb261eda957cb0a12a330260e1390c57c8c9","id":"AsAKykeS5aiE","colab_type":"code","colab":{},"outputId":"3bcafc42-9bda-49cd-9b9a-3090840321b1"},"cell_type":"code","source":"SAMPLES_PER_GROUP = 2000\nbalanced_train_df = unique_img_ids.groupby('ships').apply(lambda x: x.sample(SAMPLES_PER_GROUP) if len(x) > SAMPLES_PER_GROUP else x)\nbalanced_train_df['ships'].hist(bins=balanced_train_df['ships'].max()+1)\nprint(balanced_train_df.shape[0], 'masks')","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a26cd030942c2cd763c6fcd08b370f886c93ecdf","id":"okZknN_w5aiJ","colab_type":"code","colab":{},"outputId":"919fe3c6-07ee-4545-93ed-441c88f3e5a5"},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_ids, valid_ids = train_test_split(balanced_train_df, \n                 test_size = 0.2, \n                 stratify = balanced_train_df['ships'])\ntrain_df = pd.merge(masks, train_ids)\nvalid_df = pd.merge(masks, valid_ids)\nprint(train_df.shape[0], 'training masks')\nprint(valid_df.shape[0], 'validation masks')","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"a3fb9fe33d81374c7bd836f5bc86a1df89190805","id":"tIQPKomL5aiO","colab_type":"text"},"cell_type":"markdown","source":"# Giải mã RLEs thành hình ảnh\nPhát hiện và tạo ra các lô hình ảnh gộp theo số lượng BATC_SIZE"},{"metadata":{"trusted":true,"_uuid":"6181ac51577e5636995e38a9e29311cf47f513ca","id":"dV6w3D035aiQ","colab_type":"code","colab":{}},"cell_type":"code","source":"def 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 = np.expand_dims(masks_as_image(c_masks['EncodedPixels'].values), -1)\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=[], []","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1983738da75b031f2bec8ba36db01c095e7c5d59","id":"ALX0FS_J5aiU","colab_type":"code","colab":{},"outputId":"2f23caab-beb0-4619-ec51-fe60bc5ddfd8"},"cell_type":"code","source":"train_gen = make_image_gen(train_df)\ntrain_x, train_y = next(train_gen)\nprint('x', train_x.shape, train_x.min(), train_x.max())\nprint('y', train_y.shape, train_y.min(), train_y.max())","execution_count":0,"outputs":[]},{"metadata":{"id":"TH4GgnCh9JaM","colab_type":"text"},"cell_type":"markdown","source":"# Visualization"},{"metadata":{"trusted":true,"_uuid":"b4396cd28ddd2e4c8076fcb165e9b61e3baeeeb7","id":"Ret1rDen5aiZ","colab_type":"code","colab":{},"outputId":"2d6bf2ac-4d9d-4dd0-9191-b54eafc7e9f1"},"cell_type":"code","source":"fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize = (30, 10))\nbatch_rgb = montage_rgb(train_x)\nbatch_seg = montage(train_y[:, :, :, 0])\nax1.imshow(batch_rgb)\nax1.set_title('Images')\nax2.imshow(batch_seg)\nax2.set_title('Segmentations')\nax3.imshow(mark_boundaries(batch_rgb, \n                           batch_seg.astype(int)))\nax3.set_title('Outlined Ships')\nfig.savefig('overview.png')","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"8f47639c987a10ebcb53e51f55aa8a11c98fa860","id":"3cwM09eU5aie","colab_type":"text"},"cell_type":"markdown","source":"# Tạo bộ Validation Set"},{"metadata":{"trusted":true,"_uuid":"30cb02a2a7103a9d66e90f701991199de1e5b73e","id":"h5XI6ciC5aif","colab_type":"code","colab":{},"outputId":"c5b797c4-22bd-46b2-a86d-e36294090355"},"cell_type":"code","source":"%%time\nvalid_x, valid_y = next(make_image_gen(valid_df, VALID_IMG_COUNT))\nprint(valid_x.shape, valid_y.shape)","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"a8f65e7942816fb75b687a549dc1d5cc48d00e21","id":"KvCaq_9y5aii","colab_type":"text"},"cell_type":"markdown","source":"# Chuẩn hoá dữ liệu"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"id":"Fj7by_wV5aik","colab_type":"code","colab":{}},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\ndg_args = dict(featurewise_center = False, \n                  samplewise_center = False,\n                  rotation_range = 45, \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                   data_format = 'channels_last')\n# brightness can be problematic since it seems to change the labels differently from the images \nif AUGMENT_BRIGHTNESS:\n    dg_args[' brightness_range'] = [0.5, 1.5]\nimage_gen = ImageDataGenerator(**dg_args)\n\nif AUGMENT_BRIGHTNESS:\n    dg_args.pop('brightness_range')\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)","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6122ccb9e58bfac6fa5e11c86121e78d9e5151b1","scrolled":true,"id":"jWulfwu-5aim","colab_type":"code","colab":{},"outputId":"e99fe887-2181-4758-c061-951795e896c9"},"cell_type":"code","source":"cur_gen = create_aug_gen(train_gen)\nt_x, t_y = next(cur_gen)\nprint('x', t_x.shape, t_x.dtype, t_x.min(), t_x.max())\nprint('y', t_y.shape, t_y.dtype, t_y.min(), t_y.max())\n# only keep first 9 samples to examine in detail\nt_x = t_x[:9]\nt_y = t_y[:9]\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize = (20, 10))\nax1.imshow(montage_rgb(t_x), cmap='gray')\nax1.set_title('images')\nax2.imshow(montage(t_y[:, :, :, 0]), cmap='gray_r')\nax2.set_title('ships')","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"33300c4f03b6600da7b418f775d11d7ebf76a35a","id":"TefGCavd5aip","colab_type":"code","colab":{},"outputId":"6c54ca3f-5fcb-4e61-8f28-0c5d7e6f858e"},"cell_type":"code","source":"gc.collect()","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"ba08494eb9736ec3556b7c879143cdcdea89febf","id":"Ch93PVsr5aiu","colab_type":"text"},"cell_type":"markdown","source":"# Xây dựng model Unet\nỞ đây chúng ta xây dựng các bộ upsampleing 2 chế độ: DECONV hoặc SIMPLE"},{"metadata":{"trusted":true,"_uuid":"2687377309d3cbbab1197f4eccd2b50ab996f5a6","id":"58uqSGFt5aiv","colab_type":"code","colab":{},"outputId":"df3ea80c-f2bd-4aae-d8a1-aa252a343901"},"cell_type":"code","source":"from keras import models, layers\n# Build U-Net model\ndef upsample_conv(filters, kernel_size, strides, padding):\n    return layers.Conv2DTranspose(filters, kernel_size, strides=strides, padding=padding)\ndef upsample_simple(filters, kernel_size, strides, padding):\n    return layers.UpSampling2D(strides)\n\nif UPSAMPLE_MODE=='DECONV':\n    upsample=upsample_conv\nelse:\n    upsample=upsample_simple\n    \ninput_img = layers.Input(t_x.shape[1:], name = 'RGB_Input')\npp_in_layer = input_img\n\nif NET_SCALING is not None:\n    pp_in_layer = layers.AvgPool2D(NET_SCALING)(pp_in_layer)\n    \npp_in_layer = layers.GaussianNoise(GAUSSIAN_NOISE)(pp_in_layer)\npp_in_layer = layers.BatchNormalization()(pp_in_layer)\n\nc1 = layers.Conv2D(8, (3, 3), activation='relu', padding='same') (pp_in_layer)\nc1 = layers.Conv2D(8, (3, 3), activation='relu', padding='same') (c1)\np1 = layers.MaxPooling2D((2, 2)) (c1)\n\nc2 = layers.Conv2D(16, (3, 3), activation='relu', padding='same') (p1)\nc2 = layers.Conv2D(16, (3, 3), activation='relu', padding='same') (c2)\np2 = layers.MaxPooling2D((2, 2)) (c2)\n\nc3 = layers.Conv2D(32, (3, 3), activation='relu', padding='same') (p2)\nc3 = layers.Conv2D(32, (3, 3), activation='relu', padding='same') (c3)\np3 = layers.MaxPooling2D((2, 2)) (c3)\n\nc4 = layers.Conv2D(64, (3, 3), activation='relu', padding='same') (p3)\nc4 = layers.Conv2D(64, (3, 3), activation='relu', padding='same') (c4)\np4 = layers.MaxPooling2D(pool_size=(2, 2)) (c4)\n\n\nc5 = layers.Conv2D(128, (3, 3), activation='relu', padding='same') (p4)\nc5 = layers.Conv2D(128, (3, 3), activation='relu', padding='same') (c5)\nc5 = layers.Dropout(0.5)(c5)\n\nu6 = upsample(64, (2, 2), strides=(2, 2), padding='same') (c5)\nu6 = layers.concatenate([u6, c4])\nc6 = layers.Conv2D(64, (3, 3), activation='relu', padding='same') (u6)\nc6 = layers.Conv2D(64, (3, 3), activation='relu', padding='same') (c6)\n\nu7 = upsample(32, (2, 2), strides=(2, 2), padding='same') (c6)\nu7 = layers.concatenate([u7, c3])\nc7 = layers.Conv2D(32, (3, 3), activation='relu', padding='same') (u7)\nc7 = layers.Conv2D(32, (3, 3), activation='relu', padding='same') (c7)\n\nu8 = upsample(16, (2, 2), strides=(2, 2), padding='same') (c7)\nu8 = layers.concatenate([u8, c2])\nc8 = layers.Conv2D(16, (3, 3), activation='relu', padding='same') (u8)\nc8 = layers.Conv2D(16, (3, 3), activation='relu', padding='same') (c8)\n\nu9 = upsample(8, (2, 2), strides=(2, 2), padding='same') (c8)\nu9 = layers.concatenate([u9, c1], axis=3)\nc9 = layers.Conv2D(8, (3, 3), activation='relu', padding='same') (u9)\nc9 = layers.Conv2D(8, (3, 3), activation='relu', padding='same') (c9)\n\nd = layers.Conv2D(1, (1, 1), activation='sigmoid') (c9)\n#d = layers.Cropping2D((EDGE_CROP, EDGE_CROP))(d)\n#d = layers.ZeroPadding2D((EDGE_CROP, EDGE_CROP))(d)\nif NET_SCALING is not None:\n    d = layers.UpSampling2D(NET_SCALING)(d)\n\nseg_model = models.Model(inputs=[input_img], outputs=[d])\nseg_model.summary()","execution_count":0,"outputs":[]},{"metadata":{"id":"Lvs9RFcL90WF","colab_type":"text"},"cell_type":"markdown","source":"# Xây dựng hàm loss\nHàm loss sử dụng ở đây là Dice coefficient\n\n\n![alt text](https://forums.fast.ai/uploads/default/original/2X/1/1cd52c46e9efaed7670655859a6f919e87a5f7a0.png)\n"},{"metadata":{"trusted":true,"_uuid":"1678069aa8013510264ba898291c6ae2dce88a76","id":"aB3d9GFP5aiz","colab_type":"code","colab":{}},"cell_type":"code","source":"import keras.backend as K\nfrom keras.optimizers import Adam\nfrom keras.losses import binary_crossentropy\n\ndef dice_coef(y_true, y_pred, smooth=1.):\n    intersection = K.sum(y_true * y_pred)\n    union = K.sum(y_true) + K.sum(y_pred)\n    return (2.0 * intersection + smooth) / (union + smooth)\n\n#def dice_coef(y_true, y_pred, smooth=1):\n#    intersection = K.sum(y_true * y_pred, axis=[1,2,3])\n#    union = K.sum(y_true, axis=[1,2,3]) + K.sum(y_pred, axis=[1,2,3])\n#    return K.mean( (2. * intersection + smooth) / (union + smooth), axis=0)\n\ndef dice_coef_loss(y_true, y_pred):\n    return 1 - dice_coef(y_true, y_pred, smooth=1.)\n#def dice_p_bce(in_gt, in_pred):\n#    return 1e-3*binary_crossentropy(in_gt, in_pred) - dice_coef(in_gt, in_pred)\ndef true_positive_rate(y_true, y_pred):\n    return K.sum(K.flatten(y_true)*K.flatten(K.round(y_pred)))/K.sum(y_true)\n\ndef iou_coef(y_true, y_pred, smooth=1.):\n    intersection = K.sum(y_true * y_pred)\n    union = K.sum(y_true) + K.sum(y_pred) - intersection\n    return (intersection + smooth) / (union + smooth)\n    \n## intersection over union\n#def IoU(y_true, y_pred, eps=1e-6):\n#    if np.max(y_true) == 0.0:\n#        return IoU(1-y_true, 1-y_pred) ## empty image; calc IoU of zeros\n#    intersection = K.sum(y_true * y_pred, axis=[1,2,3])\n#    union = K.sum(y_true, axis=[1,2,3]) + K.sum(y_pred, axis=[1,2,3]) - intersection\n#    return -K.mean( (intersection + eps) / (union + eps), axis=0)","execution_count":0,"outputs":[]},{"metadata":{"id":"mCVjHNIP_Tkq","colab_type":"text"},"cell_type":"markdown","source":"# Callbacks\n**Callbacks:** khi model chúng ta lớn có khi training thì gặp sự cố ta muốn lưu lại model để chạy lại thì callback giúp t làm điều này.\n\n\n\n\n*  *** ModelCheckpoint:*** lưu lại model sau mỗi epoch\n*   *** EarlyStopping: *** stop training khi training ko cải thiện model\n*  *** ReduceLROnPlateau:*** giảm learning mỗi khi metrics ko được cải thiện\n\n\n\n"},{"metadata":{"trusted":true,"_uuid":"7282d18de3aff1cee12ff89b7d511a391702814f","id":"8168Fv4C5ai2","colab_type":"code","colab":{}},"cell_type":"code","source":"from keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nweight_path=\"{}_weights.best.hdf5\".format('seg_model')\n\ncheckpoint = ModelCheckpoint(weight_path, monitor='val_loss', verbose=1, save_best_only=True, mode='min', save_weights_only=True)\n\nreduceLROnPlat = ReduceLROnPlateau(monitor='val_loss', factor=0.33,\n                                   patience=1, verbose=1, mode='min',\n                                   min_delta=0.0001, cooldown=0, min_lr=1e-8)\n\nearly = EarlyStopping(monitor=\"val_loss\", mode=\"min\", verbose=2,\n                      patience=20) # probably needs to be more patient, but kaggle time is limited\n\ncallbacks_list = [checkpoint, early, reduceLROnPlat]","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5b67d808c0b8c7e28bff41e6d3858ff6f09dd626","scrolled":false,"id":"Q5NGIMab5ai4","colab_type":"code","colab":{},"outputId":"a8278128-8d1e-49bc-c0cd-6640014027c0"},"cell_type":"code","source":"def fit():\n    seg_model.compile(optimizer=Adam(1e-3, decay=1e-6), loss= dice_coef_loss , metrics= [dice_coef, iou_coef])\n    \n    step_count = min(MAX_TRAIN_STEPS, train_df.shape[0]//BATCH_SIZE)\n    aug_gen = create_aug_gen(make_image_gen(train_df))\n    loss_history = [seg_model.fit_generator(aug_gen,\n                                 steps_per_epoch=step_count,\n                                 epochs=MAX_TRAIN_EPOCHS,\n                                 validation_data=(valid_x, valid_y),\n                                 callbacks=callbacks_list,\n                                workers=1 # the generator is not very thread safe\n                                           )]\n    return loss_history\n\nloss_history = fit()\n#while True:\n#    loss_history = fit()\n#    if np.min([mh.history['val_loss'] for mh in loss_history]) < 0.2:\n#        break","execution_count":0,"outputs":[]},{"metadata":{"id":"5jwCnw_TAbOt","colab_type":"text"},"cell_type":"markdown","source":"# Hiện quá trình"},{"metadata":{"trusted":true,"_uuid":"a168c8b1af446b800f6129104906003ededd61c4","id":"3xRcHMW25ai7","colab_type":"code","colab":{},"outputId":"56641fa3-ee55-4ff2-f611-25e6e176802e"},"cell_type":"code","source":"def show_loss(loss_history):\n    epochs = np.concatenate([mh.epoch for mh in loss_history])\n    fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(22, 10))\n    \n    _ = ax1.plot(epochs, np.concatenate([mh.history['loss'] for mh in loss_history]), 'b-',\n                 epochs, np.concatenate([mh.history['val_loss'] for mh in loss_history]), 'r-')\n    ax1.legend(['Training', 'Validation'])\n    ax1.set_title('Loss')\n    \n    _ = ax2.plot(epochs, np.concatenate([mh.history['dice_coef'] for mh in loss_history]), 'b-',\n                 epochs, np.concatenate([mh.history['val_dice_coef'] for mh in loss_history]), 'r-')\n    ax2.legend(['Training', 'Validation'])\n    ax2.set_title('Dice (%)')\n\n    _ = ax3.plot(epochs, np.concatenate([mh.history['iou_coef'] for mh in loss_history]), 'b-',\n                 epochs, np.concatenate([mh.history['val_iou_coef'] for mh in loss_history]), 'r-')\n    ax3.legend(['Training', 'Validation'])\n    ax3.set_title('IoU (%)')\n    \nshow_loss(loss_history)","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ce1167e9f09200f537e61f93f486168a13be1711","id":"3Q-IPNfa5ai9","colab_type":"code","colab":{}},"cell_type":"code","source":"seg_model.load_weights(weight_path)\nseg_model.save('seg_model.h5')","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"275b411dc97a350aacaba46c8562efcf2658b1a7","id":"lG2tSQ8K5ai_","colab_type":"code","colab":{},"outputId":"292ba591-1653-4ac2-a788-e24866f2dfce"},"cell_type":"code","source":"pred_y = seg_model.predict(valid_x)\nprint(pred_y.shape, pred_y.min(axis=0).max(), pred_y.max(axis=0).min(), pred_y.mean())","execution_count":0,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6a4fd2ca0cf47ba069a314356bf74c7b531c56ac","id":"jVk4Hv9c5ajC","colab_type":"code","colab":{},"outputId":"30bd846e-8338-4011-a147-d1d93b0b1963"},"cell_type":"code","source":"fig, ax = plt.subplots(1, 1, figsize = (6, 6))\nax.hist(pred_y.ravel(), np.linspace(0, 1, 20))\nax.set_xlim(0, 1)\nax.set_yscale('log', nonposy='clip')","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"0018ab172d18936f8cc2c5df33d2f840dc16bf4f","id":"HvorGAqL5ajF","colab_type":"text"},"cell_type":"markdown","source":"# Lưu lại kết quả"},{"metadata":{"trusted":true,"_uuid":"17408f0ee8dc16149b8eff0447a1427ab3ed82ba","id":"ThRpw9165ajF","colab_type":"code","colab":{}},"cell_type":"code","source":"if IMG_SCALING is not None:\n    fullres_model = models.Sequential()\n    fullres_model.add(layers.AvgPool2D(IMG_SCALING, input_shape = (None, None, 3)))\n    fullres_model.add(seg_model)\n    fullres_model.add(layers.UpSampling2D(IMG_SCALING))\nelse:\n    fullres_model = seg_model\nfullres_model.save('fullres_model.h5')","execution_count":0,"outputs":[]},{"metadata":{"_uuid":"17edb177402ae51651692511827a7e9d60646533","id":"8FGSklTg5ajI","colab_type":"text"},"cell_type":"markdown","source":"# Hiện kết quả dự đoán"},{"metadata":{"trusted":true,"_uuid":"e2c9ede3ab20bd7bfdd89c4fd18f09552cb4f5cb","id":"wgtBjPO85ajJ","colab_type":"code","colab":{},"outputId":"cec074f8-a6dc-4d2d-dd74-b44e371ca8ce"},"cell_type":"code","source":"def raw_prediction(img, path=test_image_dir):\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_image_dir):\n    cur_seg, c_img = raw_prediction(img, path=path)\n    return smooth(cur_seg), c_img\n\n## Get a sample of each group of ship count\nsamples = valid_df.groupby('ships').apply(lambda x: x.sample(1))\nfig, m_axs = plt.subplots(samples.shape[0], 4, figsize = (15, samples.shape[0]*4))\n[c_ax.axis('off') for c_ax in m_axs.flatten()]\n\nfor (ax1, ax2, ax3, ax4), c_img_name in zip(m_axs, samples.ImageId.values):\n    first_seg, first_img = raw_prediction(c_img_name, train_image_dir)\n    ax1.imshow(first_img)\n    ax1.set_title('Image: ' + c_img_name)\n    ax2.imshow(first_seg[:, :, 0], cmap=get_cmap('jet'))\n    ax2.set_title('Model Prediction')\n    reencoded = masks_as_color(multi_rle_encode(smooth(first_seg)[:, :, 0]))\n    ax3.imshow(reencoded)\n    ax3.set_title('Prediction Masks')\n    ground_truth = masks_as_color(masks.query('ImageId==\"{}\"'.format(c_img_name))['EncodedPixels'])\n    ax4.imshow(ground_truth)\n    ax4.set_title('Ground Truth')\n    \nfig.savefig('validation.png')","execution_count":null,"outputs":[]}],"metadata":{"colab":{"name":"Hunghx_ship_detection.ipynb","version":"0.3.2","provenance":[],"collapsed_sections":[],"toc_visible":true},"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"},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":1}