{"cells":[{"metadata":{},"cell_type":"markdown","source":"Quick Draw는 많은 사용자들이 그린 그림을 맞추는 게임이다.\nclass는 340개이지만 사람의 습관에 따라 같은 class도 달라진다는 것을 생각했을때 수많은 경우의 수를 생각하여 결과를 내어야 한다.\n\n본 과제에서는 좌표형태의 데이터를 다시 이미지로 변환시킨다.\n이미지 분류에 좋은 성능을 가지고 있는 CNN을 이용하여 데이터 학습을 진행하였다."},{"metadata":{},"cell_type":"markdown","source":"**Trainning model**\n\n\nmodel의 input을 주기 위해 csv의 데이터에서 x,y점의 좌표를 읽어 전처리 작업을 행한다. "},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport re\nfrom glob import glob\nfrom tqdm import tqdm\nimport numpy as np\nimport pandas as pd\nimport ast\nimport matplotlib.pyplot as plt\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fnames = glob('../input/train_simplified/*.csv') #<class 'list'>\ncnames = ['countrycode', 'drawing', 'key_id', 'recognized', 'timestamp', 'word']\ndrawlist = []\nfor f in fnames[0:6]: # num of word : 5\n    first = pd.read_csv(f, nrows=10) # make sure we get a recognized drawing\n    first = first[first.recognized==True].head(2) # top head 2 get \n    drawlist.append(first)\ndraw_df = pd.DataFrame(np.concatenate(drawlist), columns=cnames) # <class 'pandas.core.frame.DataFrame'>","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"draw_df.drawing.values[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"evens = range(0,11,2)\nodds = range(1,12, 2)\n# We have drawing images, 2 per label, consecutively\ndf1 = draw_df[draw_df.index.isin(evens)]\ndf2 = draw_df[draw_df.index.isin(odds)]\n\nexample1s = [ast.literal_eval(pts) for pts in df1.drawing.values]\nexample2s = [ast.literal_eval(pts) for pts in df2.drawing.values]\nlabels = df2.word.tolist()\n\nfor i, example in enumerate(example1s):\n    plt.figure(figsize=(6,3))\n    \n    for x,y in example:\n        plt.subplot(1,2,1)\n        plt.plot(x, y, marker='.')\n        plt.axis('off')\n\n    for x,y, in example2s[i]:\n        plt.subplot(1,2,2)\n        plt.plot(x, y, marker='.')\n        plt.axis('off')\n        label = labels[i]\n        plt.title(label, fontsize=10)\n\n    plt.show()  ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Keras\ntensorflow 위에 구현된 keras를 사용하였다.\ntensorflow 기반을 필두로 하여 keras를 사용하는데 큰 부담이 들지 않았다.\n"},{"metadata":{},"cell_type":"markdown","source":"좌표를 이용해서 이미지를 변환하는 과정은 시간의 문제점이 있었다.\n해서 데이터 셋의 배열의 크기를 바꾸고 연속된 좌표의 패턴을 학습하였다."},{"metadata":{"trusted":true},"cell_type":"code","source":"import 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 json\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.models import Sequential\nfrom keras.models import Model\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 keras.layers import Input, Conv1D, Dense, Dropout, BatchNormalization, Flatten, MaxPool1D\nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"path = '../input/train_simplified/'\nclassfiles = os.listdir(path)\n\nnumstonames = {i: v[:-4].replace(\" \", \"_\") for i, v in enumerate(classfiles)} # sleeping bag -> sleeping_bag\nfiles = [os.path.join(path, file) for i, file in enumerate(classfiles)]\nword_mapping = {file.split('/')[-1][:-4]:i for i, file in enumerate(files)}\n\nnum_classes = len(files)    #340\nimheight, imwidth = 32, 32 # size of an image\nims_per_class = 2000  #max? # in the code above and above, there existed more than 100 thousand images per class(/label)\nsequence_length = 80\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**making train data**\n\n총 340개의 class 개수가 있다.\n한 class 마다 sleeping bag.csv 에서 15000 읽어오는 작업을 수해한다. (단, colum 'drawing', 'recognized'만 추출 온다)\n\n이중 'recognized' 가 'True' 인 애들 탑 10000 개를 뽑는다.\n\nX\n\nsequence of x- 와 y-coordinates 의 패턴을 X 배열에 넣는다.\nX 배열의 차원을 줄여 [10000, 160] 배열을 만든다.\n\ny\n\nindex 값 중 class를 구별 할 수 있는 것만 넣어 [10000, 1] 배열을 만든다.\n\nX와 y 배열을 결합한다. [10000, 161]\n\ntrain_grand\n\nx와 y를 결합한 것을 'train_grand'에 넣어주고 shape을 변환한다.\n[340, 10000, 161] -> [3400000, 161]"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_grand= []\n\nclass_paths = glob('../input/train_simplified/*.csv')\n\ndf = []\n\nfor i,c in enumerate(tqdm(class_paths[0: num_classes])):\n    train = pd.read_csv(c, usecols=['drawing', 'recognized'], nrows=15000) # [2500 rows x 2 columns]\n    train = train[train.recognized == True].head(10000) # use data only recognized == True -> [2000 rows x 2 columns]\n    \n    X = []\n    for values in train.drawing.values:\n        image = json.loads(values)\n        strokes = []\n        for x_axis, y_axis in image:\n            strokes.extend(list(zip(x_axis, y_axis)))\n        strokes = np.array(strokes)\n        pad = np.zeros((sequence_length, 2))\n        if sequence_length>strokes.shape[0]:\n            pad[:strokes.shape[0],:] = strokes\n        else:\n            pad = strokes[:sequence_length, :]\n        X.append(pad)\n    X = np.array(X)\n    y = np.full((train.shape[0], 1), i)\n    X = np.reshape(X, (10000, -1))\n    X = np.concatenate((y, X), axis=1)\n    train_grand.append(X)\n   \n    \ntrain_grand = np.array([train_grand.pop() for i in np.arange(num_classes)]) \nprint(train_grand.shape)\ntrain_grand = train_grand.reshape((-1, sequence_length*2+1))\nprint(train_grand.shape)\n\ndel X\ndel train","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Define model using keras \n\n* 입력 : 채널 한개의 (32,32)\n* 다리 : 필터개수 32개의 (3,3)\n* 출력 : 채널 32의 (32,32)\n\n지역적 특징 추출을 위해 1D filters 이용"},{"metadata":{"trusted":true},"cell_type":"code","source":"def createNetwork(seq_len):\n    \n    # Function to add a convolution layer with batch normalization\n    def addConv(network, features, kernel):\n        network = BatchNormalization()(network)\n        return Conv1D(features, kernel, padding='same', activation='relu')(network)\n    \n    # Function to add a dense layer with batch normalization and dropout\n    def addDense(network, size):\n        network = BatchNormalization()(network)\n        network = Dropout(0.2)(network)\n        return Dense(size, activation='relu')(network)\n    \n    \n    # Input layer\n    input = Input(shape=(seq_len, 2))\n    network = input\n    \n    # Add 1D Convolution\n    for features in [16, 24, 32]:\n        network = addConv(network, features, 5)\n    network = MaxPool1D(pool_size=5)(network)\n    \n    # Add 1D Convolution\n    for features in [64, 96, 128]:\n        network = addConv(network, features, 5)\n    network = MaxPool1D(pool_size=5)(network)\n\n    # Add 1D Convolution\n    for features in [256, 384, 512]:\n        network = addConv(network, features, 5)\n    #network = MaxPool1D(pool_size=5)(network)\n\n    # Flatten\n    network = Flatten()(network)\n    \n    # Dense layer for combination\n    for size in [128, 128]:\n        network = addDense(network, size)\n    \n    # Output layer\n    output = Dense(len(files), activation='softmax')(network)\n\n\n    # Create and compile model\n    model = Model(inputs = input, outputs = output)\n\n\n\n    return model\n\nmodel = createNetwork(sequence_length)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**모델 사용**\n\nmodel.compile()\n\n\n다중 클래스 -> ‘categorical_crossentropy’\n경사 하강법 알고리즘 ‘adam’을 사용\n평가 척도를 의미하며 분류 문제는 ‘accuracy'(일반적)\n\n\nmodel.fit()\n\n모델 학습\n\n훈련 데이터셋 , batch 사이즈, epoch 수, 검증 데이터셋, 학습 중 출력되는 문구등을 내포"},{"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\n\nreduceLROnPlat = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3, \n                                   verbose=1, mode='auto', min_delta=0.005, cooldown=5, min_lr=0)\n\nearlystop = EarlyStopping(monitor='val_loss', mode='auto', patience=2,verbose=0) \n\n\nmodel.compile(loss='categorical_crossentropy',\n              optimizer='adam',\n              metrics=['accuracy', top_3_accuracy])\n\nmodel.summary()\n\nmodel.fit(x=X_train, y=y_train,\n          batch_size = 1000,\n          epochs = 25,\n          validation_data = (X_val, y_val),\n          verbose = 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ttvlist = []\nreader = pd.read_csv('../input/test_simplified.csv', index_col=['key_id'],\n    chunksize=2048)\n\nfor chunk in tqdm(reader, total=55):\n    X =[]\n    for values in chunk.drawing.values:\n        image = json.loads(values)\n        strokes = []\n        for x_axis, y_axis in image:\n            strokes.extend(list(zip(x_axis, y_axis)))\n        strokes = np.array(strokes)\n        pad = np.zeros((sequence_length, 2))\n        if sequence_length>strokes.shape[0]:\n            pad[:strokes.shape[0],:] = strokes\n        else:\n            pad = strokes[:sequence_length, :]\n        X.append(pad)\n        \n    X = np.array(X)\n    X = np.reshape(X, (-1,sequence_length, 2))\n    testpreds = model.predict(X, verbose=0)\n    ttvs = np.argsort(-testpreds)[:, 0:3]\n    ttvlist.append(ttvs)\n\n    \nttvarray = np.concatenate(ttvlist)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":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('submission_cnn.csv')\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"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.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}