{"cells":[{"metadata":{"_cell_guid":"67e8fd4b-e795-4385-935f-d3db055e71ac","_uuid":"b8d1c1593b4892a11e30c5362c7557657492c205"},"cell_type":"markdown","source":"# Overview\nThe notebook aims to organize the data and hack Keras so that we can train a model in a fairly simple way. The aim here is to get a model working that can reliably segment the images into objects and then we can make a model that handles grouping the objects into categories based on the labels. As you will see the Keras requires a fair bit of hackery to get it to load images from a dataframe and then get it to read the label images correctly (uint16 isn't supported well). Once that is done, training a U-Net model is really easy.\n\n## Focus\nThe focus here is to get the vehicles as accurately as possible without looking at the other classes. We can also try to differentiate between the various class"},{"metadata":{"collapsed":true,"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":true},"cell_type":"code","source":"%matplotlib inline\nimport os\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom glob import glob\nimport matplotlib.pyplot as plt\nfrom skimage.io import imread\nfrom skimage.segmentation import mark_boundaries\nDATA_DIR = os.path.join('..', 'input')","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_cell_guid":"6d4b4799-f19b-45e6-af6d-e0457fd951af","_uuid":"4c44fdfe35ffacea05514b6aaf0b042ecf3cbe6a","trusted":true},"cell_type":"code","source":"class_str = \"\"\"car, 33\nmotorbicycle, 34\nbicycle, 35\nperson, 36\nrider, 37\ntruck, 38\nbus, 39\ntricycle, 40\nothers, 0\nrover, 1\nsky, 17\ncar_groups, 161\nmotorbicycle_group, 162\nbicycle_group, 163\nperson_group, 164\nrider_group, 165\ntruck_group, 166\nbus_group, 167\ntricycle_group, 168\nroad, 49\nsiderwalk, 50\ntraffic_cone, 65\nroad_pile, 66\nfence, 67\ntraffic_light, 81\npole, 82\ntraffic_sign, 83\nwall, 84\ndustbin, 85\nbillboard, 86\nbuilding, 97\nbridge, 98\ntunnel, 99\noverpass, 100\nvegatation, 113\nunlabeled, 255\"\"\"\nclass_dict = {v.split(', ')[0]: int(v.split(', ')[-1]) for v in class_str.split('\\n')}\n# we will just try to find moving things\ncar_classes = [ 'bus',  'car', 'bus_group', 'car_groups', 'truck', 'truck_group']\ncar_idx = [v for k,v in class_dict.items() if k in car_classes]\ndef read_label_image(in_path):\n    idx_image = imread(in_path)//1000\n    return np.isin(idx_image.ravel(), car_idx).reshape(idx_image.shape).astype(np.float32)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"group_df = pd.read_csv('../input/label-analysis/label_breakdown.csv', index_col = 0)\n# fix the paths\ngroup_df['color'] = group_df['color'].map(lambda x: x.replace('/input/', '/input/cvpr-2018-autonomous-driving/'))\ngroup_df['label'] = group_df['label'].map(lambda x: x.replace('/input/', '/input/cvpr-2018-autonomous-driving/'))\ngroup_df.sample(3)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"bdc56573-f430-4134-9cca-5c96621894cf","_uuid":"6d8b81b1a68845346aad9d359bb48c8c0687e4dd"},"cell_type":"markdown","source":"1. # Let's train with very vehicle images\nHere we select a group of images with lots of vehicle in them to make the dataset less imbalanced."},{"metadata":{"_cell_guid":"cb0565b2-ff44-4e25-b401-8794472552d7","_uuid":"6892e98b6dcec247664d1b7a521ec25beeb84619","trusted":true},"cell_type":"code","source":"def total_car_vol(in_row):\n    out_val = 0.0\n    for k in car_classes:\n        out_val += in_row[k]\n    return out_val\ngroup_df['total_vehicle'] = group_df.apply(total_car_vol,1)\ngroup_df['total_vehicle'].plot.hist(bins = 50, normed = True)\ntrain_df = group_df.sort_values('total_vehicle', ascending = False).head(1000)\ntrain_df['total_vehicle'].plot.hist(bins = 50, normed = True)\nprint(train_df.shape[0], 'rows')","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"567d4f91-cb7d-4b04-8798-2d1e1a3fcc14","_uuid":"7019801430e6b9ebe234e07544d2d4ce47d31015"},"cell_type":"markdown","source":"# Explore the training set\nHere we can show the training data image by image to see what exactly we are supposed to detect with the model"},{"metadata":{"_cell_guid":"2a63d977-02c8-43a9-8f8c-02b3499309c4","_uuid":"d5c261be25e697941928a396e4d6f5a4b1ca4395","trusted":true},"cell_type":"code","source":"sample_rows = 6\nfig, m_axs = plt.subplots(sample_rows, 3, figsize = (20, 6*sample_rows))\n[c_ax.axis('off') for c_ax in m_axs.flatten()]\nfor (ax1, ax2, ax3), (_, c_row) in zip(m_axs, train_df.sample(sample_rows).iterrows()):\n    c_img = imread(c_row['color'])\n    l_img = read_label_image(c_row['label'])\n    ax1.imshow(c_img)\n    ax1.set_title('Color')\n    \n    ax2.imshow(l_img, cmap = 'nipy_spectral')\n    ax2.set_title('Labels')\n    xd, yd = np.where(l_img)\n    bound_img = mark_boundaries(image = c_img, label_img = l_img, color = (1,0,0), background_label = 255, mode = 'thick')\n    ax3.imshow(bound_img[xd.min():xd.max(), yd.min():yd.max(),:])\n    ax3.set_title('Cropped Overlay')","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"41ccd780-75e2-4858-8dd7-26ab54c0290e","_uuid":"c13081e6618b920cdc36285fde271983d2c3a218","trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_split_df, valid_split_df = train_test_split(train_df, random_state = 2018, test_size = 0.25)\nprint('Training Images', train_split_df.shape[0])\nprint('Holdout Images', valid_split_df.shape[0])","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"ddb1c113-1c53-4bc3-948e-e9d1edadc082","_uuid":"2c17e0ab0d9347cdf6af56b97aae9047be40d766","trusted":true},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\nfrom keras.applications.resnet50 import preprocess_input\nIMG_SIZE = (1024, 1024) # many of the ojbects are small so 512x512 lets us see them\nimg_gen_args = dict(samplewise_center=False, \n                              samplewise_std_normalization=False, \n                              horizontal_flip = True, \n                              vertical_flip = False, \n                              height_shift_range = 0.05, \n                              width_shift_range = 0.02, \n                              rotation_range = 3, \n                              shear_range = 0.01,\n                              fill_mode = 'nearest',\n                              zoom_range = 0.05)\nrgb_gen = ImageDataGenerator(preprocessing_function = preprocess_input, **img_gen_args)\nlab_gen = ImageDataGenerator(**img_gen_args)","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_cell_guid":"4b67ae84-2f58-425f-9296-dcc7d2d62c9e","_uuid":"0ce7b0154f7d68add10776c10e9053b83b3e255e","trusted":true},"cell_type":"code","source":"def flow_from_dataframe(img_data_gen, in_df, path_col, y_col, seed = None, **dflow_args):\n    base_dir = os.path.dirname(in_df[path_col].values[0])\n    print('## Ignore next message from keras, values are replaced anyways: seed: {}'.format(seed))\n    df_gen = img_data_gen.flow_from_directory(base_dir, \n                                     class_mode = 'sparse',\n                                              seed = seed,\n                                    **dflow_args)\n    df_gen.filenames = in_df[path_col].values\n    df_gen.classes = np.stack(in_df[y_col].values)\n    df_gen.samples = in_df.shape[0]\n    df_gen.n = in_df.shape[0]\n    df_gen._set_index_array()\n    df_gen.directory = '' # since we have the full path\n    print('Reinserting dataframe: {} images'.format(in_df.shape[0]))\n    return df_gen","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"28767464-3a4c-4110-a5a2-f0ecbbcf8f51","_uuid":"f8d2dfeb980142e54ba517815984bb5570ef91a2"},"cell_type":"markdown","source":"## Replace PIL with scikit-image \nThis lets us handle the 16bit numbers well in the instanceIds image. This is incredibly, incredibly hacky, please do not use this code outside of this kernel."},{"metadata":{"collapsed":true,"_cell_guid":"5951c0bc-1df1-4a8a-8e87-c076d88f7e12","_uuid":"5b435e6727af094fb76eb157a67950178fc54485","trusted":true},"cell_type":"code","source":"import keras.preprocessing.image as KPImage\nfrom PIL import Image\nclass pil_image_awesome():\n    @staticmethod\n    def open(in_path):\n        if 'instanceIds' in in_path:\n            # we only want to keep the positive labels not the background\n            return Image.fromarray(read_label_image(in_path))\n        else:\n            return Image.open(in_path)\n    fromarray = Image.fromarray\nKPImage.pil_image = pil_image_awesome","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"0e9ec0f2-fe4b-4a6f-a9a3-118b4b4f8112","_uuid":"75d08811cbb12786d7cdb8f82ac3b8aa95867e41"},"cell_type":"markdown","source":"# Create the generators\nWe want to generate parallel streams of images and labels"},{"metadata":{"collapsed":true,"_cell_guid":"6c287bc5-9ec0-4291-8747-4d0d80b51dd5","_uuid":"bb9b79c1b61f3f7948e6fb6c50ae859df9f10c3b","trusted":true},"cell_type":"code","source":"from skimage.filters.rank import maximum\nfrom scipy.ndimage import zoom\ndef lab_read_func(in_path):\n    bin_img = (imread(in_path)>1000).astype(np.uint8)\n    x_dim, y_dim = bin_img.shape\n    max_label_img = maximum(bin_img, np.ones((x_dim//IMG_SIZE[0], y_dim//IMG_SIZE[1])))\n    return np.expand_dims(zoom(max_label_img, (IMG_SIZE[0]/x_dim, IMG_SIZE[1]/y_dim), order = 3), -1)\n\n\ndef train_and_lab_gen_func(in_df, batch_size = 8, seed = None):\n    if seed is None:\n        seed = np.random.choice(range(1000))\n    train_rgb_gen = flow_from_dataframe(rgb_gen, in_df, \n                             path_col = 'color',\n                            y_col = 'id', \n                            target_size = IMG_SIZE,\n                             color_mode = 'rgb',\n                            batch_size = batch_size,\n                                   seed = seed)\n    train_lab_gen = flow_from_dataframe(lab_gen, in_df, \n                             path_col = 'label',\n                            y_col = 'id', \n                            target_size = IMG_SIZE,\n                             color_mode = 'grayscale',\n                            batch_size = batch_size,\n                                   seed = seed)\n    for (x, _), (y, _) in zip(train_rgb_gen, train_lab_gen):\n        yield x, y\n    \ntrain_and_lab_gen = train_and_lab_gen_func(train_split_df, batch_size = 8)\nvalid_and_lab_gen = train_and_lab_gen_func(valid_split_df, batch_size = 8)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"7d2e62b7-de3e-4fd6-9fe7-bde1e28f7c19","_uuid":"abbef517deaa6fed4d2988e6306dc0e388a19851","trusted":true},"cell_type":"code","source":"(rgb_batch, lab_batch) = next(valid_and_lab_gen)\n\nsample_rows = 4\nfig, m_axs = plt.subplots(sample_rows, 3, figsize = (20, 6*sample_rows))\n[c_ax.axis('off') for c_ax in m_axs.flatten()]\nfor (ax1, ax2, ax3), rgb_img, lab_img in zip(m_axs, rgb_batch, lab_batch):\n    # undoing the vgg correction is tedious\n    r_rgb_img = np.clip(rgb_img+110, 0, 255).astype(np.uint8)\n    ax1.imshow(r_rgb_img)\n    ax1.set_title('Color')\n    ax2.imshow(lab_img[:,:,0], cmap = 'nipy_spectral')\n    ax2.set_title('Labels')\n    if lab_img.max()>0.1:\n        xd, yd = np.where(lab_img[:,:,0]>0)\n        bound_img = mark_boundaries(image = r_rgb_img, label_img = lab_img[:,:,0], \n                                    color = (1,0,0), background_label = 255, mode = 'thick')\n        ax3.imshow(bound_img[xd.min():xd.max(), yd.min():yd.max(),:])\n        ax3.set_title('Cropped Overlay')","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_cell_guid":"6a2dae1d-611c-41c2-9a01-be3a9b35ef90","_uuid":"4594d6041fd33698055e8145bb9010833a6c2280","trusted":true},"cell_type":"code","source":"out_depth = 128\nscale_factor = 2","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e86c5aaba21f73da6a0c9c34fcef8bac6964dc8b"},"cell_type":"markdown","source":"# Add a spatial information\nWe use the meshgrid functionality to add a linearly spaced $xx$ and $yy$ dimension to the image so the CNN knows where it is\n"},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"dde295ffbd5602d4651651c588c83ce68a28cf33"},"cell_type":"code","source":"import tensorflow as tf\ndef add_simple_grid_tf(in_layer,  # type: tf.Tensor\n                       x_cent=0.0,  # type: tf.Tensor\n                       y_cent=0.0,  # type: tf.Tensor\n                       x_wid=1.0,  # type: tf.Tensor\n                       y_wid=1.0,  # type: tf.Tensor\n                       z_cent=None,  # type: Optional[tf.Tensor]\n                       concat=False\n                       ):\n    # type: (...) -> tf.Tensor\n    \"\"\"\n    Adds spatial grids to images for making segmentation easier\n    :param in_layer: the base image to use for x,y dimensions\n    :param x_cent: the x mid coordinate\n    :param y_cent: the y mid coordinate\n    :param x_wid: the width in x (pixel spacing)\n    :param y_wid: the width in y (pixel spacing)\n    :param z_cent: the center location in z\n    :return:\n    \"\"\"\n    with tf.variable_scope('add_grid'):\n        batch_size = tf.shape(in_layer)[0]\n        xg_wid = tf.shape(in_layer)[1]\n        yg_wid = tf.shape(in_layer)[2]\n        x_min = x_cent - x_wid\n        x_max = x_cent + x_wid\n        y_min = y_cent - y_wid\n        y_max = y_cent + y_wid\n\n        if z_cent is None:\n            xx, yy = tf.meshgrid(tf.linspace(x_min, x_max, xg_wid),\n                                 tf.linspace(y_min, y_max, yg_wid),\n                                 indexing='ij')\n        else:\n            xx, yy, zz = tf.meshgrid(tf.linspace(x_min, x_max, xg_wid),\n                                     tf.linspace(y_min, y_max, yg_wid),\n                                     tf.linspace(z_cent, z_cent, 1),\n                                     indexing='ij')\n\n        xx = tf.reshape(xx, (xg_wid, yg_wid, 1))\n        yy = tf.reshape(yy, (xg_wid, yg_wid, 1))\n        if z_cent is None:\n            xy_vec = tf.expand_dims(tf.concat([xx, yy], -1), 0)\n        else:\n            zz = tf.reshape(zz, (xg_wid, yg_wid, 1))\n            xy_vec = tf.expand_dims(tf.concat([xx, yy, zz], -1), 0)\n        txy_vec = tf.tile(xy_vec, [batch_size, 1, 1, 1])\n        if concat:\n            return tf.concat([in_layer, txy_vec], -1)\n        else:\n            return txy_vec","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"cd584b6c-c185-4519-96b6-047fa587386b","_uuid":"33b097924b25db4b5863e0abce591c03ccddae0a","trusted":true},"cell_type":"code","source":"from keras.models import Model, load_model\nfrom keras.layers import Input, BatchNormalization, Dropout, Flatten, Reshape, Dense, Lambda\nfrom keras.layers.convolutional import Conv2D, Conv2DTranspose\nfrom keras.layers.pooling import MaxPooling2D\nfrom keras.layers.merge import concatenate\n\n# Build U-Net model\ninputs = Input((None, None)+(3,))\ns = BatchNormalization()(inputs) # we can learn the normalization step\ns = Dropout(0.5)(s)\n\nc1 = Conv2D(scale_factor*8, (3, 3), activation='relu', padding='same') (s)\nc1 = Conv2D(scale_factor*8, (3, 3), activation='relu', padding='same') (c1)\np1 = MaxPooling2D((2, 2)) (c1)\n\nc2 = Conv2D(scale_factor*16, (3, 3), activation='relu', padding='same') (p1)\nc2 = Conv2D(scale_factor*16, (3, 3), activation='relu', padding='same') (c2)\np2 = MaxPooling2D((2, 2)) (c2)\n\nc3 = Conv2D(scale_factor*32, (3, 3), activation='relu', padding='same') (p2)\nc3 = Conv2D(scale_factor*32, (3, 3), activation='relu', padding='same') (c3)\np3 = MaxPooling2D((2, 2)) (c3)\n\nc4 = Conv2D(scale_factor*64, (3, 3), activation='relu', padding='same') (p3)\nc4 = Conv2D(scale_factor*64, (3, 3), activation='relu', padding='same') (c4)\np4 = MaxPooling2D(pool_size=(2, 2)) (c4)\n\n\nc5 = Conv2D(scale_factor*128, (3, 3), activation='relu', padding='same') (p4)\nc5 = Conv2D(scale_factor*128, (3, 3), activation='relu', padding='same') (c5)\n\n# spatial layers and some post processing before combining with real layers\nnew_c5 = Lambda(add_simple_grid_tf, name = 'JustSpatialDimensions')(c5)\nnew_c5 = BatchNormalization()(new_c5)\nnew_c5 = Conv2D(out_depth//2, (1, 1), activation='relu', padding='same')(new_c5)\nnew_c5 = concatenate([new_c5, c5], name = 'AddingSpatialComponents')\nnew_c5 = Conv2D(out_depth, (3, 3), activation='relu', padding='same')(new_c5)\nnew_c5 = Conv2D(out_depth, (1, 1), activation='relu', padding='same')(new_c5)\n\nu6 = Conv2DTranspose(scale_factor*64, (2, 2), strides=(2, 2), padding='same') (new_c5)\nu6 = concatenate([u6, c4])\nc6 = Conv2D(scale_factor*64, (3, 3), activation='relu', padding='same') (u6)\nc6 = Conv2D(scale_factor*64, (3, 3), activation='relu', padding='same') (c6)\n\nu7 = Conv2DTranspose(scale_factor*32, (2, 2), strides=(2, 2), padding='same') (c6)\nu7 = concatenate([u7, c3])\nc7 = Conv2D(scale_factor*32, (3, 3), activation='relu', padding='same') (u7)\nc7 = Conv2D(scale_factor*32, (3, 3), activation='relu', padding='same') (c7)\n\nu8 = Conv2DTranspose(scale_factor*16, (2, 2), strides=(2, 2), padding='same') (c7)\nu8 = concatenate([u8, c2])\nc8 = Conv2D(scale_factor*16, (3, 3), activation='relu', padding='same') (u8)\nc8 = Conv2D(scale_factor*16, (3, 3), activation='relu', padding='same') (c8)\n\nu9 = Conv2DTranspose(scale_factor*8, (2, 2), strides=(2, 2), padding='same') (c8)\nu9 = concatenate([u9, c1], axis=3)\nc9 = Conv2D(scale_factor*8, (3, 3), activation='relu', padding='same') (u9)\nc9 = Conv2D(scale_factor*8, (3, 3), activation='relu', padding='same') (c9)\n\noutputs = Conv2D(1, (1, 1), activation='sigmoid') (c9)\n\nmodel = Model(inputs=[inputs], outputs=[outputs])\nprint(model.predict(rgb_batch[:1]).shape, 'make sure model works')\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_cell_guid":"1016dae1-b7a7-439e-9d5d-6ee661a4ff6e","_uuid":"99c84b4c88ce8a6319bd5ed8830f1d9d864f5035","trusted":true},"cell_type":"code","source":"import tensorflow as tf\nfrom keras import backend as K\nfrom keras.losses import binary_crossentropy\n# Define IoU metric\ndef mean_iou(y_true, y_pred):\n    prec = []\n    for t in np.arange(0.5, 1.0, 0.05):\n        y_pred_ = tf.to_int32(y_pred > t)\n        score, up_opt = tf.metrics.mean_iou(y_true, y_pred_, 2)\n        K.get_session().run(tf.local_variables_initializer())\n        with tf.control_dependencies([up_opt]):\n            score = tf.identity(score)\n        prec.append(score)\n    return K.mean(K.stack(prec))\n\nsmooth = 1.\ndef dice_coef(y_true, y_pred):\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_coef_loss(y_true, y_pred):\n    return -dice_coef(y_true, y_pred)\n\ndef dice_bce_loss(y_true, y_pred):\n    return 0.5*binary_crossentropy(y_true, y_pred)-dice_coef(y_true, y_pred)\n\nmodel.compile(optimizer = 'adam', \n                   loss = dice_bce_loss, \n                   metrics = [dice_coef, 'binary_accuracy', 'mse'])","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"fdf99eeb-1bbb-4e19-a106-238a38261edf","_uuid":"4695ec7bd66e624aee98971a92c97268a5c68b0f","trusted":true},"cell_type":"code","source":"from keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nweight_path=\"{}_weights.best.hdf5\".format('unet')\n\ncheckpoint = ModelCheckpoint(weight_path, monitor='val_loss', verbose=1, \n                             save_best_only=True, mode='min', save_weights_only = True)\n\nreduceLROnPlat = ReduceLROnPlateau(monitor='loss', factor=0.8, patience=10, verbose=1, mode='auto', epsilon=0.0001, cooldown=5, min_lr=0.0001)\nearly = EarlyStopping(monitor=\"val_loss\", \n                      mode=\"min\", \n                      patience=5) # probably needs to be more patient, but kaggle time is limited\ncallbacks_list = [checkpoint, early, reduceLROnPlat]","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"775fc5c8-b93a-48fa-8711-368f7880985c","_uuid":"631939949c70b3674b7b093b558fc0719cce0190","trusted":true,"collapsed":true},"cell_type":"code","source":"# reset the generators so they all have different seeds when multiprocessing lets loose\nfrom IPython.display import clear_output\nbatch_size = 8\ntrain_and_lab_gen = train_and_lab_gen_func(train_split_df, batch_size = batch_size)\nvalid_and_lab_gen = train_and_lab_gen_func(valid_split_df, batch_size = batch_size)\nmodel.fit_generator(train_and_lab_gen, \n                    steps_per_epoch = 2048//batch_size,\n                    validation_data = valid_and_lab_gen,\n                    validation_steps = 256//batch_size,\n                    epochs = 2, \n                    workers = 2,\n                    max_queue_size=3,\n                    use_multiprocessing = True,\n                    callbacks = callbacks_list)\nclear_output()","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_cell_guid":"cc41838c-b14b-4207-b714-ce61a4db457d","_uuid":"6a15fd3abf00fae73e3b96c7fac8aee35a073aa8","trusted":true},"cell_type":"code","source":"model.load_weights(weight_path)\nmodel.save('vehicle_unet.h5')","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"cf9b5b54-8e2e-4ae1-ba4b-3bd9016f6ef9","_uuid":"5c9411a0df905551571a69420386a193efa7d806","trusted":true,"collapsed":true},"cell_type":"code","source":"# Show the performance on a small batch since we delete the other messages\neval_out =  model.evaluate_generator(valid_and_lab_gen, steps=8)\nclear_output()","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79aac45b-f265-42b1-aca6-93ecce666cbd","_uuid":"4838ed44da9479a6353ca3d4f81a148bb27caf6a","trusted":true,"collapsed":true},"cell_type":"code","source":"print('Loss: %2.2f, DICE: %2.2f, Accuracy %2.2f%%, Mean Squared Error: %2.2f' % (eval_out[0], eval_out[1], eval_out[2]*100, eval_out[3]))","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"7c4caaf8-3c31-4e0e-8298-8d9cc3f44c12","_uuid":"b8e001a984e00b9aa70d9a418cb43e8913e4c8ea"},"cell_type":"markdown","source":"# Showing the results\nHere we can preview the output of the model on a few examples"},{"metadata":{"_cell_guid":"40f63c1e-4067-4702-878e-2f8c0474c401","_uuid":"57800bbeb10c674020f31bc788518b89551626d9","trusted":true,"collapsed":true},"cell_type":"code","source":"(rgb_batch, lab_batch) = next(valid_and_lab_gen)\nsample_rows = 8\nfig, m_axs = plt.subplots(sample_rows, 5, figsize = (20, 6*sample_rows), dpi = 120)\n[c_ax.axis('off') for c_ax in m_axs.flatten()]\nfor (ax1, ax2, ax2_pred, ax3, ax3_pred), rgb_img, lab_img in zip(m_axs, rgb_batch, lab_batch):\n    # undoing the vgg correction is tedious\n    r_rgb_img = np.clip(rgb_img+110, 0, 255).astype(np.uint8)\n    lab_pred = model.predict(np.expand_dims(rgb_img, 0))[0]\n    \n    ax1.imshow(r_rgb_img)\n    ax1.set_title('Color')\n    ax2.imshow(lab_img[:,:,0], cmap = 'bone_r')\n    ax2.set_title('Labels')\n    ax2_pred.imshow(lab_pred[:,:,0], cmap = 'bone_r')\n    ax2_pred.set_title('Pred Labels')\n    if lab_img.max()>0.1:\n        xd, yd = np.where(lab_img[:,:,0]>0)\n        bound_img = mark_boundaries(image = r_rgb_img, label_img = lab_img[:,:,0], \n                                    color = (1,0,0), background_label = 255, mode = 'thick')\n        ax3.imshow(bound_img[xd.min():xd.max(), yd.min():yd.max(),:])\n        ax3.set_title('Cropped Overlay')\n        bound_pred = mark_boundaries(image = r_rgb_img, label_img = (lab_pred[:,:,0]>0.5).astype(int), \n                                    color = (1,0,0), background_label = 0, mode = 'thick')\n        ax3_pred.imshow(bound_pred[xd.min():xd.max(), yd.min():yd.max(),:])\n        ax3_pred.set_title('Cropped Prediction')\nfig.savefig('trained_model.png')","execution_count":null,"outputs":[]},{"metadata":{"collapsed":true,"_cell_guid":"b305f765-d263-4792-85f8-0192a8df2a35","_uuid":"e49199a14b41cff1cc8ee7fc8908219be633ac9e","trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"language_info":{"name":"python","version":"3.6.4","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}