{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Quick, Draw! Doodle Recognition Challenge\n\n* local PC environment (GPU 사용)\n* keras framework - 직관적이고 간결하게 모듈을 사용할 수 있어서 선택했습니다.\n* MobileNet model - 이미지 데이터를 사용하므로 CNN 기반 모델 중 ResNet, DenseNet, MobileNet 3가지 모델 사용했습니다. 그 중 가장 정확도가 높게 나온 MobileNet model 사용했습니다. (Tensorboard 사용해서 모니터링)  \n-ResNet : layer가 깊어져 생기는 문제를 skip connection으로 극복합니다.  \n-DenseNet : 기존 skip connection을 확장하여 여러 level의 feature 활용합니다.   \n-MobileNet : depthwise separable convolution 사용해서 parameter 줄여서 연산을 줄입니다.\n* Dataset - 기존에 shuffle해서 저장해놓은 csv파일을 사용합니다. (train:validation = 99:1)\n* Accuracy - accracy, top_k_categorical_accuracy; 정확도와 상위 3개 항목의 정확도를 사용했습니다."},{"metadata":{},"cell_type":"markdown","source":"# Data Load"},{"metadata":{"trusted":false},"cell_type":"code","source":"%matplotlib inline\nimport os\nimport cv2\nimport json\nimport pandas as pd\nimport numpy as np\nfrom glob import glob\nfrom keras.utils.np_utils import to_categorical","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"SHUFFLE_DIR = 'E:\\\\project\\\\shuffle_data'\nTEST_DIR = 'E:\\\\project\\\\data\\\\'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**parameter**"},{"metadata":{"trusted":false},"cell_type":"code","source":"base_size = 256\nshuffle_data_num = 100\nnum_classes = 340\nimg_size = 64\nepochs = 20\nsteps = 600\nbatch_size = 800","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**train dataset class name**"},{"metadata":{"trusted":false},"cell_type":"code","source":"TRAIN_LIST = glob('E:\\\\project\\\\data\\\\train_simplified\\\\*.csv')\nclass_list = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"for item in TRAIN_LIST:\n    class_name = os.path.basename(item).split('.')[0]\n    class_name = class_name.replace(' ', '_')\n    class_list.append(class_name)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":false,"trusted":false},"cell_type":"code","source":"class_list[:5]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**validation dataset**"},{"metadata":{"trusted":false},"cell_type":"code","source":"valid_df = pd.read_csv(os.path.join(SHUFFLE_DIR, 'train_k99.csv.gz'), nrows=34000)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"valid_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"def drawing(raw_strokes, img_size, lw=6, time_color=True):\n    img = np.zeros((256, 256), np.uint8)\n    for t, stroke in enumerate(raw_strokes):\n        color = 255 - min(t, 10) * 13\n        for i in range(len(stroke[0]) - 1):\n            _ = cv2.line(img, (stroke[0][i], stroke[1][i]),\n                         (stroke[0][i + 1], stroke[1][i + 1]), color, lw)\n    if img_size != 256:\n        return cv2.resize(img, (img_size, img_size))/255\n    else:\n        return img/255","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"def data_generator(df, img_size, lw=6, time_color=True):\n    df['drawing'] = df['drawing'].apply(json.loads)\n    x = np.zeros((len(df), img_size, img_size, 1))\n    for i, raw_strokes in enumerate(df.drawing.values):\n        x[i, :, :, 0] = drawing(raw_strokes, img_size=img_size, lw=lw, time_color=time_color)\n    return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"x_valid = data_generator(valid_df, img_size)\ny_valid = to_categorical(valid_df.y, num_classes=num_classes)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":false,"trusted":false},"cell_type":"code","source":"print(x_valid.shape, y_valid.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### train dataset"},{"metadata":{"trusted":false},"cell_type":"code","source":"def train_generator(img_size, batch_size, iters, lw=6, time_color=True):\n    while True:\n        for iter in np.random.permutation(iters):\n            filename = os.path.join(SHUFFLE_DIR, 'train_k{}.csv.gz'.format(iter))\n            for df in pd.read_csv(filename, chunksize=batch_size):\n                df['drawing'] = df['drawing'].apply(json.loads)\n                x = np.zeros((len(df), img_size, img_size, 1))\n                for i, raw_strokes in enumerate(df.drawing.values):\n                    x[i, :, :, 0] = drawing(raw_strokes, img_size=img_size, lw=lw, time_color=time_color)\n                y = to_categorical(df.y, num_classes=num_classes)\n                yield x, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"train_data = train_generator(img_size, batch_size, range(shuffle_data_num-1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"x, y = next(train_data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"print(x.shape, y.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Modeling"},{"metadata":{"trusted":false},"cell_type":"code","source":"import keras\nfrom time import time\nfrom keras import Model\nfrom keras.models import load_model\nfrom keras.layers import GlobalAveragePooling2D, Dense, Dropout, Flatten\nfrom keras.applications import MobileNet\nfrom keras import optimizers\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint, TensorBoard\nfrom keras.metrics import categorical_accuracy, top_k_categorical_accuracy, categorical_crossentropy","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**accuracy**"},{"metadata":{"trusted":false},"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":{},"cell_type":"markdown","source":"**create model**"},{"metadata":{"trusted":false},"cell_type":"code","source":"model = MobileNet(input_shape=(img_size, img_size, 1), alpha=1, weights=None, classes=340)","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":false},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"c = keras.optimizers.adam(lr=0.002)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"model.compile(loss='categorical_crossentropy', optimizer=c, metrics=['accuracy', top_3_accuracy])","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"callbacks = [\n    ReduceLROnPlateau(monitor='top_3_accuracy', factor=0.8, patience=3, min_delta=0.001,\n                          mode='max', min_lr=1e-5, verbose=1),\n    EarlyStopping(patience=3, monitor='top_3_accuracy'),\n    ModelCheckpoint('model_mobilenet.h5', monitor='top_3_accuracy', mode='max', save_best_only=True,\n                    save_weights_only=True),\n    TensorBoard(log_dir=\"logs/{}\".format(time()))\n]","execution_count":null,"outputs":[]},{"metadata":{"scrolled":true,"trusted":false},"cell_type":"code","source":"hist = model.fit_generator(\n    train_data, steps_per_epoch=steps, epochs=epochs, verbose=1,\n    validation_data=(x_valid, y_valid), callbacks=callbacks)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**validation**"},{"metadata":{"trusted":false},"cell_type":"code","source":"valid_preds = model.predict(x_valid, batch_size=batch_size, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"answer = []\nfor i in range(len(valid_preds)):\n    top3 = valid_preds[i].argsort()[::-1][:3]\n    word = ''\n    for j in top3:\n        word += class_list[j]\n        word += \" \"\n    answer.append(word)\nvalid_preds_df = pd.DataFrame(answer)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"valid_preds_df.head(20)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"valid_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Test"},{"metadata":{"trusted":false},"cell_type":"code","source":"test = pd.read_csv('E:\\\\project\\\\data\\\\test_simplified.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"test.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"x_test = data_generator(test, img_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"test_preds = model.predict(x_test, batch_size=batch_size, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"def create_submission(test, test_preds):\n    pred_rows = []\n    answer = []\n    for i in range(len(test_preds)):\n        top3 = test_preds[i].argsort()[::-1][:3]\n        word = ''\n        for j in top3:\n            word += class_list[j]\n            word += \" \"\n        answer.append(word)\n    df = pd.DataFrame(answer)\n    test['word'] = df\n    sub = test[['key_id', 'word']]\n    sub.to_csv('submission_{}.csv'.format(time()), index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"create_submission(test, test_preds)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.5"}},"nbformat":4,"nbformat_minor":1}