{"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)\n\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\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5dfed0c533c3ad7a51404e53c632cb5ff5544fdc"},"cell_type":"markdown","source":"#### Importing libraries"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport ast\nimport pandas as pd\nfrom keras.utils.np_utils import to_categorical\nfrom keras import layers\nfrom keras.layers import Input, Add, Dense, Activation, BatchNormalization, Conv2D, AveragePooling2D, MaxPooling2D, Flatten, LSTM, Dropout, Flatten\nfrom keras.models import Model, load_model\nfrom keras.metrics import top_k_categorical_accuracy\nfrom keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nfrom sklearn.preprocessing import LabelEncoder\nfrom skimage.io import imread, imshow\nfrom tensorflow.keras.applications.mobilenet import preprocess_input\nimport keras\nimport cv2","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a4039298fbfd00f6b77455229b8268688a377881"},"cell_type":"markdown","source":"#### defining parameters for model training:\nbatch size, number of epochs, steps per epoch"},{"metadata":{"trusted":true,"_uuid":"770d8b7e6322a3f9ceea1e2ef437cc5322773724"},"cell_type":"code","source":"BATCH_SIZE = 128\nMAX_TRAIN_EPOCHS = 100\nSTEPS_PER_EPOCH = 900\nNCSVS = 100\nCSV_DIR = '../input/doodle-detection-dataprep'\nBASE_SIZE = 256\nsize = 64","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2d365461378ae87f3faeab2f7fb30e4c101d559f"},"cell_type":"code","source":"# def get_image_array(drawing_vec, pixels=PIXELS):\n#     \"\"\"\n#     converting vector stroke to img\n#     \"\"\"\n#     strokes = literal_eval(drawing_vec) \n#     fig, ax = plt.subplots()\n#     for x,y in strokes:\n#         ax.plot(x, y, linewidth=12.)\n#     ax.axis('off')\n#     fig.canvas.draw()\n#     X = np.array(fig.canvas.renderer._renderer)\n#     plt.close('all')\n#     X = (cv2.resize(X, (pixels, pixels)) / 255.)[::-1]\n#     X = X[:, :, 3]\n# #     X = np.stack((X,)*3, -1)\n#     return X\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8253eb62b96b7c8e5f13fc6a6df91d169fbb2515"},"cell_type":"markdown","source":"#### converting 340 given categories into one hot encoding"},{"metadata":{"trusted":true,"_uuid":"1240f0c4b882901706191455f66ebff9355b7103"},"cell_type":"code","source":"word_encoder = LabelEncoder()\ncategories = [word.split('.')[0] for word in os.listdir(os.path.join(\"../input/quickdraw-doodle-recognition/train_simplified/\"))]\nword_encoder.fit(categories)\nprint('words', len(word_encoder.classes_), '=>', ', '.join([x for x in word_encoder.classes_]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9b7ce45c84c5488a2289bded8cd6bf85f4ee16c5"},"cell_type":"code","source":"len(word_encoder.classes_)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4d3236ca6dd07d9ff6cd2375fcff9bc1b8a2c4a0"},"cell_type":"markdown","source":"#### draw_cv2 : \nfunction for converting sketches into images\n\n#### image_generator_xd:\ntraining data image generator\ntakes 100 compressed csvs formed from 340 category csvs in doodle detection dataprep"},{"metadata":{"trusted":true,"_uuid":"0aa9069f48bfac7f4155fd4ca5202f1d402219cd"},"cell_type":"code","source":"def draw_cv2(raw_strokes, size=256, lw=6, time_color=True):\n    img = np.zeros((BASE_SIZE, BASE_SIZE), np.uint8)\n    for t, stroke in enumerate(raw_strokes):\n        for i in range(len(stroke[0]) - 1):\n            color = 255 - min(t, 10) * 13 if time_color else 255\n            _ = cv2.line(img, (stroke[0][i], stroke[1][i]),\n                         (stroke[0][i + 1], stroke[1][i + 1]), color, lw)\n    if size != BASE_SIZE:\n        return cv2.resize(img, (size, size))\n    else:\n        return img\n\ndef image_generator_xd(size, batchsize, ks, lw=6, time_color=True):\n    while True:\n        for k in np.random.permutation(ks):\n            filename = os.path.join(CSV_DIR, 'train_k{}.csv.gz'.format(k))\n            for df in pd.read_csv(filename, chunksize=batchsize):\n                df['drawing'] = df['drawing'].apply(ast.literal_eval)\n                x = np.zeros((len(df), size, size, 1))\n                for i, raw_strokes in enumerate(df.drawing.values):\n                    x[i, :, :, 0] = draw_cv2(raw_strokes, size=size, lw=lw,\n                                             time_color=time_color)\n                x = preprocess_input(x).astype(np.float32)\n                y = to_categorical(word_encoder.transform(df[\"word\"].values),num_classes=340).astype(np.int32)\n                yield x, y\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"64ac98101adfaee52ca95cced5deda2f77bbf40f"},"cell_type":"markdown","source":"#### df_to_image_array_xd:\nreads dataframe and returns array of images from drawing column"},{"metadata":{"trusted":true,"_uuid":"549449d29ff2f86bc06a4cd5d83f3ac2bb75fba1"},"cell_type":"code","source":"def df_to_image_array_xd(df, size, lw=6, time_color=True):\n    df['drawing'] = df['drawing'].apply(ast.literal_eval)\n    x = np.zeros((len(df), size, size, 1))\n    for i, raw_strokes in enumerate(df.drawing.values):\n        x[i, :, :, 0] = draw_cv2(raw_strokes, size=size, lw=lw, time_color=time_color)\n    x = preprocess_input(x).astype(np.float32)\n    return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4df9295511e747024b1b6cf936510ed0c1448e30"},"cell_type":"code","source":"# def image_generator_xd(batchsize, ks):\n#     while True:\n#         for k in np.random.permutation(ks):\n#             filename = os.path.join(CSV_DIR, 'train_k{}.csv.gz'.format(k))\n#             for df in pd.read_csv(filename, chunksize=batchsize):\n# #                 out_imgs = list(map(draw_cv2, df['drawing'].apply(ast.literal_eval)))\n# #                 X = np.expand_dims(np.array(out_imgs),-1).astype(np.float32)\n#                 df['drawing'] = df['drawing'].apply(ast.literal_eval)\n#                 x = np.zeros((len(df), PIXELS, PIXELS, 1))\n#                 for i, raw_strokes in enumerate(df.drawing.values):\n#                     x[i, :, :, 0] = draw_cv2(raw_strokes)\n#                 x = preprocess_input(x).astype(np.float32)\n#                 y = to_categorical(word_encoder.transform(df[\"word\"].values),num_classes=340).astype(np.int32)\n#                 yield x, y\n\n# def df_to_image_array_xd(df):\n#     out_imgs = list(map(get_image_array, df[\"drawing\"]))\n#     X = np.expand_dims(np.array(out_imgs),-1).astype(np.float32)\n#     return X","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d3d2605347c778fa8091dbc96b5330f3b5a3af13"},"cell_type":"markdown","source":"#### Forming training dataset"},{"metadata":{"trusted":true,"_uuid":"c3cbae43fdcb058bb95106ebe7d294c3b10f7744"},"cell_type":"code","source":"train_datagen = image_generator_xd(batchsize=BATCH_SIZE, ks=range(NCSVS - 1), size=size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"00207b632129f5d0ee19333c4fec4ffdfe944266"},"cell_type":"code","source":"train_x, train_y = next(train_datagen)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3338fdab1ddc2885e478eb6f0d4d8b3a8f4d928f","scrolled":true},"cell_type":"code","source":"print ('train x shape:{}'.format(train_x.shape))\nprint ('train y shape:{}'.format(train_y.shape))\nprint('train_x', train_x.dtype, train_x.min(), train_x.max())\nprint('train_y', train_y.dtype, train_y.min(), train_y.max())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0ded50039cc342fd9700a1018f3e51246ba80694"},"cell_type":"markdown","source":"#### Forming validation dataset"},{"metadata":{"trusted":true,"_uuid":"aeae5c36c81222faabb4e43e21ffd1fd07f88f68"},"cell_type":"code","source":"valid_set = pd.read_csv(os.path.join(CSV_DIR, 'train_k{}.csv.gz'.format(NCSVS - 1)), nrows=10000)\nvalid_x = df_to_image_array_xd(valid_set, size)\nvalid_y = to_categorical(word_encoder.transform(valid_set[\"word\"].values),num_classes=340).astype(np.int32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"cff2cf89706c1f432bcf5a2d39910b3f47fa08fb"},"cell_type":"code","source":"print ('valid x shape:{}'.format(valid_x.shape))\nprint ('valid y shape:{}'.format(valid_y.shape))\nprint('valid_x', valid_x.dtype, valid_x.min(), valid_x.max())\nprint('valid_y', valid_y.dtype, valid_y.min(), valid_y.max())","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"139795740553e2f544ac7541b383f6bec85bb02e"},"cell_type":"markdown","source":"### Train data visualization\n"},{"metadata":{"trusted":true,"_uuid":"46484bb86f1e2b3082c894a4a0ebbbc6ca7f2909"},"cell_type":"code","source":"fig, m_axs = plt.subplots(4,4, figsize = (8, 8))\nrand_idxs = np.random.choice(range(train_x.shape[0]), size = 16, replace=False)\nfor c_id, c_ax in zip(rand_idxs, m_axs.flatten()):\n    test_arr = train_x[c_id, :, :, 0]  \n    c_ax.imshow(test_arr, cmap=plt.cm.gray)\n    c_ax.axis('off')\n    c_ax.set_title(word_encoder.classes_[np.argmax(train_y[c_id])])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"79a25a1af5320be79d50f8a8353f25776f0e292f"},"cell_type":"markdown","source":"## Model building: CNN"},{"metadata":{"trusted":true,"_uuid":"6eaf4e52f2c6038e5ba992d286bb5600ad1c2cdb"},"cell_type":"code","source":"def doodle(input_shape):\n    input_img = Input(input_shape)\n    conv0= Conv2D(256, (3, 3), activation='relu', padding='valid')(input_img) \n    pool0 = MaxPooling2D(pool_size=(2, 2))(conv0)\n    conv1= Conv2D(128, (3, 3), activation='relu', padding='valid')(pool0)\n    pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)\n    conv2= Conv2D(64, (3, 3), activation='relu', padding='valid')(pool1) \n    pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)\n    conv3 = Conv2D(32, (3, 3), activation='relu', padding='valid')(pool2) \n    pool3 = MaxPooling2D(pool_size=(2, 2))(conv3) \n#     conv4 = Conv2D(16, (3, 3), activation='relu', padding='valid')(pool3) \n#     pool4 = MaxPooling2D(pool_size=(2, 2))(conv4)\n    flat = Flatten()(pool3)\n    dense1 = Dense(680, activation='relu')(flat)\n    dense2 = Dense(len(word_encoder.classes_), activation = 'softmax')(dense1)\n    \n    model =  Model(inputs = input_img, outputs = dense2, name = 'Doodle_model')    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b4827b59246067d821bd7b173f8efbf9f141a554"},"cell_type":"code","source":"model = doodle(input_shape = train_x.shape[1:])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"80d6654dea18d80b3c8a31bf7a57bfa2d18a4547"},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b3929b44f7d824a4f6187b04cd3acf3ba67dec44"},"cell_type":"code","source":"def top_3_accuracy(y_true, y_pred):\n    return top_k_categorical_accuracy(y_true, y_pred, k=3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2d86104fd24fa2439daec82c226abe1020701031"},"cell_type":"code","source":"model.compile(optimizer = 'adam', loss='categorical_crossentropy', metrics = ['categorical_accuracy', top_3_accuracy])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9f63cbdfe588281238c5e22eabc24b58c01e1bea"},"cell_type":"code","source":"weight_path=\"model_weights.best.hdf5\"\n\ncheckpoint = ModelCheckpoint(weight_path, monitor='val_top_3_accuracy', verbose=1, save_best_only=True, mode='max', save_weights_only=True, period=1)\n\nearly = EarlyStopping(monitor=\"val_top_3_accuracy\", mode=\"max\", verbose=2,\n                      patience=8) # patience is number of epochs with no improvement after which training will be stopped\n\ncallbacks_list = [checkpoint, early]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"14fc0782a78415459f0813ff1966e96ba1773bc7","_kg_hide-output":false},"cell_type":"code","source":"loss_history = [model.fit_generator(train_datagen,\n                                 epochs=MAX_TRAIN_EPOCHS,\n                                 steps_per_epoch=STEPS_PER_EPOCH,\n                                 validation_data=(valid_x, valid_y),\n                                 callbacks=callbacks_list,\n                                workers=1 # the generator is not very thread safe\n                                           )]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9b4d3f0d6cc8ecd3387cba0c0ddc34a968642b4e"},"cell_type":"code","source":"model.load_weights(weight_path)\nmodel.save('model.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2cbfd73d02ca5d62a88d8cdd9273ecdd2613dd85"},"cell_type":"code","source":"epochs = np.concatenate([mh.epoch for mh in loss_history])\nloss = np.concatenate([mh.history['loss'] for mh in loss_history])\nval_loss  = np.concatenate([mh.history['val_loss'] for mh in loss_history])\ntrain_accuracy = np.concatenate([mh.history['top_3_accuracy'] for mh in loss_history])\ntest_accuracy = np.concatenate([mh.history['val_top_3_accuracy'] for mh in loss_history])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b3e8b9d5320f2badbbeb2d0a5078ff335e2ba743"},"cell_type":"code","source":"print ('train accuray: {}'.format(max(train_accuracy)))\nprint ('test accuray: {}'.format(max(test_accuracy)))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1b96b9fef7fb574c118999a93626a17f1a972d0b"},"cell_type":"markdown","source":"#### Model performance"},{"metadata":{"trusted":true,"_uuid":"66c1bef1c63956002912e3d5d5905d63333892bc"},"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(1,2, figsize = (30,10))\n\nax1.plot(epochs,train_accuracy, epochs,test_accuracy)\nax1.legend(['Training', 'Validation'])\nax1.set_xlabel('epoch')\nax1.set_ylabel('accuracy')\nax1.set_title('accuracy train vs validation')\n\nax2.plot(epochs,loss, epochs,val_loss)\nax2.legend(['Training', 'Validation'])\nax2.set_xlabel('epoch')\nax2.set_ylabel('loss')\nax2.set_title('loss train vs validation')\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e01c91db0064eb8177313d56652c32164a2ad0ba"},"cell_type":"markdown","source":"## Validation"},{"metadata":{"trusted":true,"_uuid":"e70804e36af76765baaaa8a92d29d7cf0844ce42"},"cell_type":"code","source":"valid_set = pd.read_csv(os.path.join(CSV_DIR, 'train_k{}.csv.gz'.format(NCSVS - 1)), nrows=16)\nvalid_x = df_to_image_array_xd(valid_set, size)\nvalid_y = to_categorical(word_encoder.transform(valid_set[\"word\"].values),num_classes=340).astype(np.int32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5c17057f3ed5cc0c2a6862f662deb1bcf20413fb"},"cell_type":"code","source":"valid_img_label = model.predict(valid_x, verbose=True)\ntop_3_pred_valid = [word_encoder.classes_[np.argsort(-1*c_pred)[:3]] for c_pred in valid_img_label]\ntop_3_pred_valid = [' '.join([col.replace(' ', '_') for col in row]) for row in top_3_pred_valid]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7aa15980d4d15980ba95d1387a316be29f74fc9a"},"cell_type":"code","source":"fig, m_axs = plt.subplots(4,4, figsize = (20, 20))\nrand_idxs = np.random.choice(range(valid_x.shape[0]), size = 16, replace=False)\nfor c_id, c_ax in zip(rand_idxs, m_axs.flatten()):\n    test_arr = valid_x[c_id, :, :, 0]\n    c_ax.imshow(test_arr,cmap=plt.cm.gray)\n    c_ax.axis('off')\n    c_ax.set_title((top_3_pred_valid[c_id],valid_set[\"word\"].iloc[c_id]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7c095fb0afce8a1fedca48685c14c246c951d56c"},"cell_type":"markdown","source":"## Make a submission"},{"metadata":{"trusted":true,"_uuid":"46d4c1491f7e29b2074f6e7a466e4caa918f6152"},"cell_type":"code","source":"test_data = pd.read_csv(\"../input/quickdraw-doodle-recognition/test_simplified.csv\")\ntest_data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a845b79980eece03881a9e5e397a5a7a9f3fb47e"},"cell_type":"code","source":"test_data.count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f9c00d1ba9204829e0d3ec499de5827ee1747390"},"cell_type":"code","source":"test_x = df_to_image_array_xd(test_data, size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b151ed78210afbda9cc930f6c13b347ad586f183"},"cell_type":"code","source":"test_x.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"87f0336a8662b810d0f5f557183438a3a9f3bd04"},"cell_type":"code","source":"test_img_label = model.predict(test_x, batch_size=128, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"439fc4b3a11e2f4848dad992b3c4455646f47516"},"cell_type":"code","source":"top_3_pred = [word_encoder.classes_[np.argsort(-1*c_pred)[:3]] for c_pred in test_img_label]\ntop_3_pred = [' '.join([col.replace(' ', '_') for col in row]) for row in top_3_pred]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1088be824e9db7002e11b2732c88abe66bad286e"},"cell_type":"code","source":"test_data['word_pred'] = top_3_pred","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fa41b8e7b72e2e0e9807ba0e0aae2eb38fd8dc79"},"cell_type":"code","source":"test_data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"da81f99b54f9e3b973546890c9faa92496768ebb"},"cell_type":"code","source":"submit = test_data[['key_id','word_pred']].rename(columns={'word_pred': 'word'})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"007513a4efb467d1fcb61946c9620a42ac4a08e3"},"cell_type":"code","source":"submit.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"658af44fb0052f82ae8e1f376b618f8c216df2ae"},"cell_type":"code","source":"submit.isnull().values.any()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e4af512bbff44ed05f5dabb2259643a21861bf4d"},"cell_type":"code","source":"submit.to_csv('submission_file.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d90f6bb7bdf2b99c936eb3eb17071bdb1f3cbaea"},"cell_type":"code","source":"","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}