{"cells":[{"metadata":{"_uuid":"a4cc84fbce7ecaa1bedb3f451989cdf390fa4955"},"cell_type":"markdown","source":"# Load Packages"},{"metadata":{"trusted":true,"_uuid":"65292ed389678fcfa0db3fd434d7df8fcc05841d"},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport cv2\nfrom glob import glob\nimport os\nfrom sklearn.preprocessing import LabelEncoder\nfrom keras.utils.np_utils import to_categorical\nimport random\nimport ast\nimport csv","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9f95fd166b621bbd64c2baeed74e73ab72e0de50"},"cell_type":"markdown","source":"# Set Parameters"},{"metadata":{"trusted":true,"_uuid":"e2388932040c1c7d269c044662a944429d4031e2"},"cell_type":"code","source":"IMG_SIZE = 64\nIMG_BASE_SIZE = 256\nBATCH_SIZE = 512\nTRAIN_CSV_PATH_LIST = glob('../input/train_simplified/*.csv')\nSKIP_RECORD = 0\nRECORD_RANGE = 10000","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"da2bc79d249e8b6d5cce825187bd3961520dfd0b"},"cell_type":"code","source":"TRAIN_CSV_PATH_LIST[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"49e3831ae4aa0d531ab61826aa804fd78a2338cc"},"cell_type":"code","source":"len(TRAIN_CSV_PATH_LIST)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cee3b909b78d694dd3f1caa30ea9af2cc5aa05e1"},"cell_type":"markdown","source":"# Create One Hot Encoder"},{"metadata":{"trusted":true,"_uuid":"090ca956190e5d7b47fb5f3f12df83f8d4485164"},"cell_type":"code","source":"class_list = []\nfor item in TRAIN_CSV_PATH_LIST:\n    classname = os.path.basename(item).split('.')[0]\n    class_list.append(classname)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"756c7933654bf8e06c674d84f600fd17be9832b2"},"cell_type":"code","source":"class_list = sorted(class_list)\nclass_list[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fa640f4d2effdcb44e6ebd06b7d87ba99fd49110"},"cell_type":"code","source":"len(class_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a497eb461b27dc7f7597748bc4a6cbab1fe6d94a"},"cell_type":"code","source":"word_encoder = LabelEncoder()\nword_encoder.fit(class_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9e785b4833af7f9388aa69c866fb27061020a4b2"},"cell_type":"code","source":"word_encoder.transform(class_list[:5])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fba004f658ae10bd52acb2cf986ff7dd9cb269bf"},"cell_type":"code","source":"def my_one_hot_encoder(word):\n    return to_categorical(word_encoder.transform([word]),num_classes=340).reshape(340)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"09926d58f6a09eaf41f56277324718b4a6335390"},"cell_type":"code","source":"test_y = my_one_hot_encoder('The Eiffel Tower')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"92353fe7709165318df8a87b9380fdaaebdebb54"},"cell_type":"code","source":"test_y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4b2ae8f594d86b4d0b461af9690b944374226b5d"},"cell_type":"code","source":"test_y.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1b4c54f95a52545be7cec5555af2d7899050a902"},"cell_type":"markdown","source":"# Create Train Data  Generator"},{"metadata":{"trusted":true,"_uuid":"2843922e5402b0f903551a10157553f751506929"},"cell_type":"code","source":"def train_generator(path_list, img_size, batch_size, lw=6):\n    while True:\n        csv_path_list = random.choices(path_list, k=batch_size)\n        x = np.zeros((batch_size, img_size, img_size, 3))\n        y = np.zeros((batch_size, 340))\n        for j in range(batch_size):\n            csv_path = csv_path_list[j]\n            f = open(csv_path, 'r')\n            reader = csv.reader(f)\n            for _ in range(SKIP_RECORD+1):\n                __ = next(reader)\n            i = 0\n            s = np.random.randint(RECORD_RANGE)\n            for row in reader:\n                if i == s:\n                    drawing = row[1]\n                    break\n                else:\n                    i += 1\n            f.close()\n            lst = ast.literal_eval(drawing)\n            img = np.zeros((IMG_BASE_SIZE, IMG_BASE_SIZE), np.uint8)\n            for t, stroke in enumerate(lst):\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]), (stroke[0][i + 1], stroke[1][i + 1]), color, lw)\n            if img_size != IMG_BASE_SIZE:\n                x[j, :, :, 0] = cv2.resize(img, (img_size, img_size))/255\n                x[j, :, :, 1] = cv2.resize(img, (img_size, img_size))/255\n                x[j, :, :, 2] = cv2.resize(img, (img_size, img_size))/255\n            else:\n                x[j, :, :, 0] = img/255\n                x[j, :, :, 1] = img/255\n                x[j, :, :, 2] = img/255\n            classname = os.path.basename(csv_path).split('.')[0]\n            y_tmp = my_one_hot_encoder(classname)\n            y[j] = y_tmp\n        yield x, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dc7c6cb5bc1f9b3bd449f2f8bb564427bf432dfe"},"cell_type":"code","source":"datagen = train_generator(path_list=TRAIN_CSV_PATH_LIST, img_size=IMG_SIZE, batch_size=BATCH_SIZE, lw=6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d7c4865694cbf48f5cd4857ab66955a6a0e1c9b2"},"cell_type":"code","source":"x, y = next(datagen)","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"x.shape, y.shape, x.min(), x.max(), y.min(), y.max(), y.sum(), y[0].sum()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1212885d538f824a7d034248fa6f321381755261"},"cell_type":"markdown","source":"# Create Validation Set\ncontained classes of VAL_CLASS (choiced random)"},{"metadata":{"trusted":true,"_uuid":"744cfc8420fba1ef02503d890b2d7b3b463c9969"},"cell_type":"code","source":"VAL_IMAGES_PER_CLASS = 20\nVAL_CLASS = 170\nVAL_SKIP_RECORD = SKIP_RECORD + RECORD_RANGE","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"097de6062b5b613419ad8fd8f9037440ef3c15fb"},"cell_type":"code","source":"def create_val_set(path_list, val_class, val_images_per_class, img_size, lw=6):\n    csv_path_list = random.sample(path_list, k=val_class)\n    x = np.zeros((val_class*val_images_per_class, img_size, img_size, 3))\n    y = np.zeros((val_class*val_images_per_class, 340))\n    for k in range(val_class):\n        csv_path = csv_path_list[k]\n        f = open(csv_path, 'r')\n        reader = csv.reader(f)\n        for _ in range(VAL_SKIP_RECORD+1):\n            __ = next(reader)\n        s = 0\n        for row in reader:\n            if s == val_images_per_class:\n                break\n            else:\n                drawing = row[1]\n                lst = ast.literal_eval(drawing)\n                img = np.zeros((IMG_BASE_SIZE, IMG_BASE_SIZE), np.uint8)\n                for t, stroke in enumerate(lst):\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]), (stroke[0][i + 1], stroke[1][i + 1]), color, lw)\n                if img_size != IMG_BASE_SIZE:\n                    x[k*val_images_per_class+s, :, :, 0] = cv2.resize(img, (img_size, img_size))/255\n                    x[k*val_images_per_class+s, :, :, 1] = cv2.resize(img, (img_size, img_size))/255\n                    x[k*val_images_per_class+s, :, :, 2] = cv2.resize(img, (img_size, img_size))/255\n                else:\n                    x[k*val_images_per_class+s, :, :, 0] = img/255\n                    x[k*val_images_per_class+s, :, :, 1] = img/255\n                    x[k*val_images_per_class+s, :, :, 2] = img/255\n                classname = os.path.basename(csv_path).split('.')[0]\n                y_tmp = my_one_hot_encoder(classname)\n                y[k*val_images_per_class+s,:] = y_tmp\n                s += 1\n        f.close()\n    return x, y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c3045c91d888f25fa27e1296a841f0d89276c70d"},"cell_type":"code","source":"valid_x, valid_y = create_val_set(path_list=TRAIN_CSV_PATH_LIST, val_class=VAL_CLASS,\n                                  val_images_per_class=VAL_IMAGES_PER_CLASS, img_size=IMG_SIZE, lw=6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f8fe3244c92523da68cf2432eea440dc29a5557b"},"cell_type":"code","source":"valid_x.shape, valid_y.shape, valid_x.min(), valid_x.max(), valid_y.min(), valid_y.max(), valid_y.sum(), valid_y[0].sum()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b3349ebee5afbf18b5e988ed372e6f9fad269300"},"cell_type":"markdown","source":"# Create metric function"},{"metadata":{"trusted":true,"_uuid":"079b80c5af255fd4f8c81ea6cdd91939ed8ce097"},"cell_type":"code","source":"def calc_map3_per_image(true_label, pred_3label):\n    if true_label == pred_3label[0]:\n        score = 1\n    elif true_label == pred_3label[1]:\n        score = 1/2\n    elif true_label == pred_3label[2]:\n        score = 1/3\n    else:\n        score = 0\n    return score","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"da2e7131743791eeb9329e300fe8c2625f4d8e75"},"cell_type":"code","source":"def calc_map3_allimage(y_trues, y_preds):\n    num = y_trues.shape[0]\n    scores = list()\n    for i in range(num):\n        true_label = y_trues[i].argsort()[::-1][0]\n        pred_3label = y_preds[i].argsort()[::-1][:3]\n        score = calc_map3_per_image(true_label, pred_3label)\n        scores.append(score)\n    return np.mean(scores)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"efb79d102ff43725909cc760b8cf75cb0238971a"},"cell_type":"code","source":"import tensorflow as tf\ndef my_metric(y_trues, y_preds):\n    return tf.py_func(calc_map3_allimage, [y_trues, y_preds], tf.float64)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4ca64880122413d782f3f8801e8e6429a03120ee"},"cell_type":"markdown","source":"# Create Model"},{"metadata":{"trusted":true,"_uuid":"3c95d702b3e59641fc6d99cf9cfbab21c5176d8a"},"cell_type":"code","source":"from keras import Model\nfrom keras.layers import GlobalAveragePooling2D\nfrom keras.layers import Dense\nfrom keras.layers import Dropout\nfrom keras.applications import ResNet50\nfrom keras import optimizers\n\ndef get_model(input_shape):\n    base_model = ResNet50(input_shape=input_shape, include_top=False, weights=None)\n    for l in base_model.layers:\n        l.trainable = True\n    x = base_model.output\n    x = GlobalAveragePooling2D()(x)\n    x = Dense(1024, activation='relu')(x)\n    x = Dropout(0.5)(x)\n    x = Dense(340, activation='softmax')(x)\n    model = Model(base_model.input, x)\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"31495461924ca982c753560aa5e37dea24bb8a25"},"cell_type":"code","source":"model = get_model(input_shape=(IMG_SIZE,IMG_SIZE,3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"942545835a7764ff3ae9b37f73daf1432b02ebaa"},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"24e35250d9e5f74e47ae24a7a2bf2f3b9ba18be0"},"cell_type":"code","source":"c = optimizers.adam(lr = 0.001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"10f546b307fe6091903b48487d6219d853eeb7bc"},"cell_type":"code","source":"model.compile(loss='categorical_crossentropy', optimizer=c, metrics=[my_metric])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"012b453ce3dca17150bf526558eb3816719d342a"},"cell_type":"markdown","source":"# Training"},{"metadata":{"trusted":true,"_uuid":"7bbae4edc38776ace1d9972f69ce9a4899f98c69"},"cell_type":"code","source":"history = model.fit_generator(datagen, epochs=40, steps_per_epoch=30, verbose=1, validation_data=(valid_x, valid_y))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6d9398b5aa02c32e3485ef20aef3303ba2768b6c"},"cell_type":"markdown","source":"# Predict and Create Submission file"},{"metadata":{"trusted":true,"_uuid":"6c113c2ee37278f2c37f7db41915ab6388a89cdb"},"cell_type":"code","source":"test_df = pd.read_csv('../input/test_simplified.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"fec8e22b3836e8ac5c580e3a228aad783d794ae7"},"cell_type":"code","source":"test_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"88b6f5f184c4a902cdeea53c157215f8c3ff917a"},"cell_type":"code","source":"test_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"24429e5f300b66fa8e97eaf65f200f49527c0278"},"cell_type":"code","source":"def create_test_data(img_size, lw=6):\n    x = np.zeros((test_df.shape[0], img_size, img_size, 3))\n    for j in range(test_df.shape[0]):\n        drawing = test_df.loc[j,'drawing']\n        lst = ast.literal_eval(drawing)\n        img = np.zeros((IMG_BASE_SIZE, IMG_BASE_SIZE), np.uint8)\n        for t, stroke in enumerate(lst):\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]), (stroke[0][i + 1], stroke[1][i + 1]), color, lw)\n        if img_size != IMG_BASE_SIZE:\n            x[j, :, :, 0] = cv2.resize(img, (img_size, img_size))/255\n            x[j, :, :, 1] = cv2.resize(img, (img_size, img_size))/255\n            x[j, :, :, 2] = cv2.resize(img, (img_size, img_size))/255\n        else:\n            x[j, :, :, 0] = img/255\n            x[j, :, :, 1] = img/255\n            x[j, :, :, 2] = img/255\n    return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"577d2f468295707f95521c97536bb4ddf209c130"},"cell_type":"code","source":"test_x = create_test_data(img_size=IMG_SIZE, lw=6)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0b5b1d540196ff36cf33e4c5816b8be2912ac2b2"},"cell_type":"code","source":"test_x.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"96336473ccc55cb1a8cad311d4452eaf58553934"},"cell_type":"code","source":"test_pred = model.predict(test_x, batch_size=128, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"08239a67c36f2e34656ef209ac4a46a27c27ea73"},"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f4eedfa505c17d85cf51652d1b66f88568dc9989"},"cell_type":"code","source":"pred_rows = []\nfor i in range(test_df.shape[0]):\n    test_top3 = test_pred[i].argsort()[::-1][:3]\n    test_top3_words = word_encoder.inverse_transform(test_top3).tolist()\n    test_top3_words = [k.replace(' ', '_') for k in test_top3_words]\n    pred_words = test_top3_words[0] + ' ' + test_top3_words[1] + ' ' + test_top3_words[2]\n    pred_rows += [{'key_id': test_df.loc[i, 'key_id'], 'word': pred_words}] ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e7941ecbab1de8aeb8361aada267b563bc313ed3"},"cell_type":"code","source":"sub = pd.DataFrame(pred_rows)[['key_id', 'word']]\nsub.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b560dd8d243b23501cd3aa9f9bd3433a09218e8b"},"cell_type":"code","source":"sub.head()","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}