{"cells":[{"metadata":{},"cell_type":"markdown","source":"https://www.kaggle.com/jpmiller/image-based-cnn 참고함."},{"metadata":{"trusted":true,"_uuid":"779113b4b0ef5fbe50ddda59813b019b3b769b58"},"cell_type":"code","source":"#%% import\nimport os\nfrom glob import glob\nimport re\nimport ast\nimport numpy as np \nimport pandas as pd\nfrom PIL import Image, ImageDraw \nfrom tqdm import tqdm\nfrom dask import bag\nimport time\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Dropout, Flatten\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D\nfrom tensorflow.keras.metrics import top_k_categorical_accuracy\nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\nfrom keras.models import load_model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### hyperparameter"},{"metadata":{"trusted":true,"_uuid":"44e5965471a53f3ca6d87a1df8c0e1b2538cd34c"},"cell_type":"code","source":"#%% set label dictionary and params\nclassfiles = os.listdir('../input/train_simplified/')\nnumstonames = {i: v[:-4].replace(\" \", \"_\") for i, v in enumerate(classfiles)} #adds underscores\n\nnum_classes = 340    #class 개수: 340\nimheight, imwidth = 64, 64  \nims_per_class = 100","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### data preprocessing"},{"metadata":{"trusted":true,"_uuid":"1ce1101eea3b2a0787c1dbe6b675e2a481802f67","_kg_hide-output":false,"scrolled":true},"cell_type":"code","source":"# 점들을 연결하여 그려줌  \ndef draw_it(strokes):\n    image = Image.new(\"P\", (256,256), color=255) #\"P\": (8-bit pixels, mapped to any other mode using a color palette)\n    image_draw = ImageDraw.Draw(image)\n    for stroke in ast.literal_eval(strokes):\n        for i in range(len(stroke[0])-1):\n            image_draw.line([stroke[0][i], \n                             stroke[1][i],\n                             stroke[0][i+1], \n                             stroke[1][i+1]],\n                            fill=0, width=5)\n    image = image.resize((imheight, imwidth))\n    return np.array(image)/255.\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**data loading**"},{"metadata":{"trusted":true},"cell_type":"code","source":"def data_load(ims_ind_st):\n    #%% get train arrays\n    train_grand = []\n    class_paths = glob('../input/train_simplified/*.csv')\n    for i,c in enumerate(class_paths[0: num_classes]):#enumerate(tqdm(class_paths[0: num_classes])):\n        train = pd.read_csv(c, usecols=['drawing', 'recognized'])\n        train = train[train.recognized == True][ims_ind_st:ims_ind_st+ims_per_class]\n        imagebag = bag.from_sequence(train.drawing.values).map(draw_it) \n        trainarray = np.array(imagebag.compute())  # PARALLELIZE\n        trainarray = np.reshape(trainarray, (ims_per_class, -1))    \n        labelarray = np.full((train.shape[0], 1), i)\n        trainarray = np.concatenate((labelarray, trainarray), axis=1)\n        train_grand.append(trainarray)\n        del trainarray\n        del train\n        time.sleep(0.1)\n    train_grand = np.array([train_grand.pop() for i in np.arange(num_classes)]) #less memory than np.concatenate\n    train_grand = train_grand.reshape((-1, (imheight*imwidth+1)))\n    return train_grand","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6788c33f4a9dd552d473e3667387491c40dbfe4b","_kg_hide-input":false,"scrolled":true},"cell_type":"code","source":"def train_val_split(train_grand):\n    # memory-friendly alternative to train_test_split?\n    valfrac = 0.05\n    cutpt = int(valfrac * train_grand.shape[0])\n    # shuffle 후 train data/ validation data 나눠줌 \n    np.random.shuffle(train_grand)\n    y_train, X_train = train_grand[cutpt: , 0], train_grand[cutpt: , 1:]\n    y_val, X_val = train_grand[0:cutpt, 0], train_grand[0:cutpt, 1:] #validation set is recognized==True\n    del train_grand\n\n    y_train = keras.utils.to_categorical(y_train, num_classes)\n    X_train = X_train.reshape(X_train.shape[0], imheight, imwidth, 1)\n    y_val = keras.utils.to_categorical(y_val, num_classes)\n    X_val = X_val.reshape(X_val.shape[0], imheight, imwidth, 1)\n\n    print(y_train.shape, \"\\n\",\n          X_train.shape, \"\\n\",\n          y_val.shape, \"\\n\",\n          X_val.shape)\n    \n    return X_train, y_train, X_val, y_val","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8b9f5b85771add0d7672f7611a62e4668a28453c"},"cell_type":"markdown","source":"## Convolutional Neural Network (CNN)"},{"metadata":{"trusted":true,"_uuid":"002b62eec9f0b5c139c4c08f82476433ccc11026"},"cell_type":"code","source":"model = Sequential()\nmodel.add(Conv2D(64, kernel_size=(3, 3), padding='same', activation='relu', input_shape=(imheight, imwidth, 1)))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Conv2D(128, kernel_size=(3, 3), padding='same', activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Conv2D(256, kernel_size=(3, 3), padding='same', activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Conv2D(128, kernel_size=(3, 3), padding='same', activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.2))\nmodel.add(Flatten())\nmodel.add(Dense(num_classes, activation='softmax'))\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train,y_train,X_val,y_val = train_val_split(data_load(0))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def top_3_accuracy(x,y): \n    t3 = top_k_categorical_accuracy(x,y, 3)\n    return t3","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"reduceLROnPlat = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, \n                                   verbose=1, mode='auto', min_delta=0.005, cooldown=5, min_lr=0.0001)\nearlystop = EarlyStopping(monitor='val_top_3_accuracy', mode='max', patience=5) \ncallbacks = [reduceLROnPlat, earlystop]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6464e84f6f0c7303110db9e26c74a5c90a0a9ab9","_kg_hide-output":true,"scrolled":false},"cell_type":"code","source":"model.compile(loss='categorical_crossentropy',\n              optimizer='adam',\n              metrics=['accuracy', top_3_accuracy])\n\nmodel.fit(x=X_train, y=y_train,\n          batch_size = 512,\n          epochs = 10,\n          validation_data = (X_val, y_val),\n          callbacks = callbacks,\n          verbose = 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(1, 10):\n    time.sleep(3)\n    X_train,y_train,X_val,y_val = train_val_split(data_load(i*ims_per_class))\n    \n    model.fit(x=X_train, y=y_train,\n          batch_size = 512,\n          epochs = 10,\n          validation_data = (X_val, y_val),\n          callbacks = callbacks,\n          verbose = 1)\n    \n    del X_train,y_train,X_val,y_val","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4125359749cd237de207eca0ab62074431df8323"},"cell_type":"markdown","source":"## Predicting on the Test data\nThe CNN does OK on the validation data, even with a basic model and limited training data. Let's generate predictions on the test set and submit."},{"metadata":{"trusted":true,"_uuid":"2828f46cdf053261a1435e6eca1a4aea55195273","_kg_hide-input":false,"_kg_hide-output":true},"cell_type":"code","source":"#%% get test set\nttvlist = []\nreader = pd.read_csv('../input/test_simplified.csv', index_col=['key_id'],\n    chunksize=2048)\nfor chunk in tqdm(reader, total=55):\n    imagebag = bag.from_sequence(chunk.drawing.values).map(draw_it) # 점 연결 \n    testarray = np.array(imagebag.compute())\n    testarray = np.reshape(testarray, (testarray.shape[0], imheight, imwidth, 1))\n    testpreds = model.predict(testarray, verbose=0) #학습된 모델에 적용 \n    ttvs = np.argsort(-testpreds)[:, 0:3]  # top 3\n    ttvlist.append(ttvs)\n    \nttvarray = np.concatenate(ttvlist)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5c650c6f9a0ec6f99042e6132ffc4a25b2b2f0b3","_kg_hide-input":false,"_kg_hide-output":true},"cell_type":"code","source":"preds_df = pd.DataFrame({'first': ttvarray[:,0], 'second': ttvarray[:,1], 'third': ttvarray[:,2]})\npreds_df = preds_df.replace(numstonames)\npreds_df['words'] = preds_df['first'] + \" \" + preds_df['second'] + \" \" + preds_df['third']\n\nsub = pd.read_csv('../input/sample_submission.csv', index_col=['key_id'])\nsub['word'] = preds_df.words.values\nsub.to_csv('cnn_3.csv')\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"494ef170cb02e2425e82a897a0ca6c794c676b5a"},"cell_type":"markdown","source":" A full version with 6000 images per class at 28x28 gets just under 0.60 on the public LB.  "}],"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}