{"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":{"_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":{"trusted":true,"_uuid":"c54201381d4fc250fcca8e034d1f779749ff0c49"},"cell_type":"code","source":"BATCH_SIZE = 128\nMAX_TRAIN_EPOCHS = 20\nSTEPS_PER_EPOCH = 900\nNCSVS = 100\nCSV_DIR = '../input/doodle-detection-dataprep'\nBASE_SIZE = 256\nsize = 64","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"59a95b432cbd484ff0ee0d4ec684f2c5e8e96b38"},"cell_type":"markdown","source":"converting 340 given categories into one hot encoding\n"},{"metadata":{"trusted":true,"_uuid":"ddb553da22c7f6389765ecf32dca72b0ee60907c"},"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":{"_uuid":"f2772b080dfab527f479c1448fa38082465f98b4","trusted":true},"cell_type":"code","source":"len(word_encoder.classes_)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"455f24327fb140d89b9705fff0f31fa11a551d4e"},"cell_type":"markdown","source":"#### draw_cv2 : \nfunction for converting sketches into images\n"},{"metadata":{"_uuid":"efff3de53380926f3d751524f54a36869a7f3ee2"},"cell_type":"markdown","source":"#### image_generator_xd:\ntraining data image generator\ntakes 100 compressed csvs formed from 340 category csvs in doodle detection dataprep"},{"metadata":{"trusted":true,"_uuid":"7ac40238b7e5b143ae79cccc9586323ce07f75e1"},"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":{"trusted":true,"_uuid":"f09f3f2a3893f8724629fd6cf39d82f2f6438770"},"cell_type":"markdown","source":"#### df_to_image_array_xd:\nreads dataframe and returns array of images from drawing column"},{"metadata":{"trusted":true,"_uuid":"b57bbb92be18d5bb1f7d330a46f8b0b223ff936f"},"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":"6dbabe9fc125870207096917fe5299d9c1da4deb"},"cell_type":"code","source":"train_datagen = image_generator_xd(batchsize=BATCH_SIZE, ks=range(NCSVS - 1), size=size)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e64cd5b0ea0be7e3b4d534d0629df0b9b0a83a25"},"cell_type":"code","source":"train_x, train_y = next(train_datagen)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3e743b8788767fcb31a40b91fb0d4a721f244561"},"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())\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7a7838108169c5c4a4624a41d47a51ae3b271da0"},"cell_type":"markdown","source":"Forming validation dataset¶\n"},{"metadata":{"trusted":true,"_uuid":"541e6f595bfff4ec11d62eb0d125da5243226602"},"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)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"de67923235a1392498305cb9f55bc454c16798f2"},"cell_type":"markdown","source":"#### Forming training dataset"},{"metadata":{"trusted":true,"_uuid":"88c610f018ab015af4b9de1bb11bcf6e94d1dcd1"},"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":"652bf637cd4e32c0ef9bc1821a0096960fe92e3c"},"cell_type":"markdown","source":"### Train data visualization\n"},{"metadata":{"trusted":true,"_uuid":"c6618d70290c263f6e848a3e9e5d40cb0bce71ff"},"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":"e6cc48e209a147bc0fd13648e70cf45b4625fc64"},"cell_type":"markdown","source":"## Model building: CNN"},{"metadata":{"trusted":true,"_uuid":"07e10cc405a7022cb990319b8fe7dcd6d60aeafa"},"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":"59a3c65085ecf3796f9cb9d84e8224b090569c0a"},"cell_type":"code","source":"model = doodle(input_shape = train_x.shape[1:])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"02a17a6c5c9acaffcedbb7ac543c19cfecfa61df"},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"29f9cb880c5780f573516238fe6fb606f0c0ae5b"},"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":"43d9b09702e9cd4691cbd16f1e2e2efa8cd568fc"},"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":"b2b80023b093a307452858b1fe4cd01d3a279271"},"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":"ac0bdb75ea2f9ee9117600dc2bbe28799a86b093"},"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                                           )]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2726a51357e3e99d27ac4f5f70b6131a88b86483"},"cell_type":"code","source":"model.load_weights(weight_path)\nmodel.save('model.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c65b3086f557ebc8a22e40e18ac01acae26b5434"},"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":"c91862db05e130954c77c4885ca19c151cda15a2"},"cell_type":"code","source":"print ('train accuray: {}'.format(max(train_accuracy)))\nprint ('test accuray: {}'.format(max(test_accuracy)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ac5bb63c361ebccbf9d3b80a90d2494c80c24a97"},"cell_type":"code","source":"#### Model performance","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"260d14fcdcd97a27275370023f7f013f05bafb51"},"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":"4c9d4ee39160677185b366ee01949feea45484dc"},"cell_type":"markdown","source":"## Validation"},{"metadata":{"trusted":true,"_uuid":"bf85b3279228998bc20fe2a7e39d89dad514a864"},"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":"94d1f41308c1fefbf106591df7919c19e69ddb86"},"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":"0f3a5fcaa428d000567798bd31ed5eba211a2572"},"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":"ef1aed7a2dcd39c80541f3539aa16e90006e8103"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e0cdaae2818c982291af12f4e0f7b8eee3d09d28"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ada03f60f175af6f5a510badfef6ec371267aa31"},"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}