CNN_classification.ipynb 38.2 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "D:/Games/Images/train\n",
      "antelope  파일 길이 :  0\n",
      "cats  파일 길이 :  0\n",
      "chimpanzee  파일 길이 :  0\n",
      "cow  파일 길이 :  0\n",
      "dogs  파일 길이 :  0\n",
      "hippopotamus  파일 길이 :  0\n",
      "horse  파일 길이 :  0\n",
      "otter  파일 길이 :  0\n",
      "raccoon  파일 길이 :  0\n",
      "rat  파일 길이 :  0\n",
      "rhinoceros  파일 길이 :  0\n",
      "squirrel  파일 길이 :  0\n",
      "weasel  파일 길이 :  0\n",
      "wolf  파일 길이 :  0\n",
      "ok 0\n"
     ]
    }
   ],
   "source": [
    "from PIL import Image\n",
    "import os, glob, numpy as np\n",
    "from sklearn.model_selection import train_test_split\n",
    "caltech_dir = \"D:/Games/Images/train\"\n",
    "categories = [\"antelope\", \"cats\", \"chimpanzee\", \"cow\", \"dogs\", \"hippopotamus\",\"horse\",\"otter\",\"raccoon\",\"rat\",\"rhinoceros\",\"squirrel\",\"weasel\",\"wolf\"]\n",
    "nb_classes = len(categories)\n",
    "print(caltech_dir)\n",
    "image_w = 64\n",
    "image_h = 64\n",
    "\n",
    "pixels = image_h * image_w * 3\n",
    "\n",
    "X = []\n",
    "y = []\n",
    "\n",
    "for idx, cat in enumerate(categories):\n",
    "    \n",
    "    #one-hot 돌리기.\n",
    "    label = [0 for i in range(nb_classes)]\n",
    "    label[idx] = 1\n",
    "\n",
    "    image_dir = caltech_dir + \"/\" + cat\n",
    "    files = glob.glob(image_dir+\"/*.jpg\")\n",
    "    print(cat, \" 파일 길이 : \", len(files))\n",
    "    for i, f in enumerate(files):\n",
    "        img = Image.open(f)\n",
    "        img = img.convert(\"RGB\")\n",
    "        img = img.resize((image_w, image_h))\n",
    "        data = np.asarray(img)\n",
    "\n",
    "        X.append(data)\n",
    "        y.append(label)\n",
    "\n",
    "        if i % 700 == 0:\n",
    "            print(cat, \" : \", f)\n",
    "\n",
    "X = np.array(X)\n",
    "y = np.array(y)\n",
    "#1 0 0 0 이면 airplanes\n",
    "#0 1 0 0 이면 buddha 이런식\n",
    "\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y)\n",
    "xy = (X_train, X_test, y_train, y_test)\n",
    "np.save(\"./numpy_data/multi_image_data3.npy\", xy)\n",
    "\n",
    "print(\"ok\", len(y))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0,)\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "import os, glob, numpy as np\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Conv2D, MaxPooling2D, Dense, Flatten, Dropout\n",
    "from keras.callbacks import EarlyStopping, ModelCheckpoint\n",
    "import matplotlib.pyplot as plt\n",
    "from keras import optimizers\n",
    "import keras.backend.tensorflow_backend as K\n",
    "\n",
    "import tensorflow as tf\n",
    "config = tf.ConfigProto()\n",
    "config.gpu_options.allow_growth = True\n",
    "session = tf.Session(config=config)\n",
    "\n",
    "np_load_old = np.load\n",
    "np.load = lambda *a,**k: np_load_old(*a, allow_pickle=True, **k)\n",
    "X_train, X_test, y_train, y_test = np.load('./numpy_data/multi_image_data3.npy')\n",
    "np.load = np_load_old\n",
    "print(X_train.shape)\n",
    "print(X_train.shape[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "categories = [\"antelope\", \"cats\", \"chimpanzee\", \"cow\", \"dogs\", \"hippopotamus\",\"horse\",\"otter\",\"raccoon\",\"rat\",\"rhinoceros\",\"squirrel\",\"weasel\",\"wolf\"]\n",
    "nb_classes = len(categories)\n",
    "\n",
    "#일반화\n",
    "X_train = X_train.astype(float) / 255\n",
    "X_test = X_test.astype(float) / 255"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with K.tf_ops.device('/device:GPU:0'):\n",
    "    model = Sequential()\n",
    "    model.add(Conv2D(32, (3,3), padding=\"same\", input_shape=X_train.shape[1:], activation='relu'))\n",
    "    model.add(MaxPooling2D(pool_size=(2,2)))\n",
    "    model.add(Dropout(0.25))\n",
    "    \n",
    "    model.add(Conv2D(64, (3,3), padding=\"same\", activation='relu'))\n",
    "    model.add(MaxPooling2D(pool_size=(2,2)))\n",
    "    model.add(Dropout(0.25))\n",
    "    \n",
    "    model.add(Flatten())\n",
    "    model.add(Dense(256, activation='relu'))\n",
    "    model.add(Dropout(0.5))\n",
    "    model.add(Dense(nb_classes, activation='softmax'))\n",
    "    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n",
    "    model_dir = './model'\n",
    "    \n",
    "    if not os.path.exists(model_dir):\n",
    "        os.mkdir(model_dir)\n",
    "    \n",
    "    model_path = model_dir + '/multi_img_classification.model'\n",
    "    checkpoint = ModelCheckpoint(filepath=model_path , monitor='val_loss', verbose=1, save_best_only=True)\n",
    "    early_stopping = EarlyStopping(monitor='val_loss', patience=6)\n",
    "    model.summary()\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 4623 samples, validate on 1541 samples\n",
      "Epoch 1/100\n",
      "4623/4623 [==============================] - 10s 2ms/step - loss: 13.5012 - acc: 0.1622 - val_loss: 13.5869 - val_acc: 0.1570\n",
      "\n",
      "Epoch 00001: val_loss improved from inf to 13.58690, saving model to ./model/multi_img_classification.model\n",
      "Epoch 2/100\n",
      "4623/4623 [==============================] - 2s 468us/step - loss: 13.4753 - acc: 0.1640 - val_loss: 13.5869 - val_acc: 0.1570\n",
      "\n",
      "Epoch 00002: val_loss did not improve from 13.58690\n",
      "Epoch 3/100\n",
      "4623/4623 [==============================] - 2s 470us/step - loss: 13.4753 - acc: 0.1640 - val_loss: 13.5869 - val_acc: 0.1570\n",
      "\n",
      "Epoch 00003: val_loss did not improve from 13.58690\n",
      "Epoch 4/100\n",
      "4623/4623 [==============================] - 2s 481us/step - loss: 13.4753 - acc: 0.1640 - val_loss: 13.5869 - val_acc: 0.1570\n",
      "\n",
      "Epoch 00004: val_loss did not improve from 13.58690\n",
      "Epoch 5/100\n",
      "4623/4623 [==============================] - 2s 471us/step - loss: 13.4753 - acc: 0.1640 - val_loss: 13.5869 - val_acc: 0.1570\n",
      "\n",
      "Epoch 00005: val_loss did not improve from 13.58690\n",
      "Epoch 6/100\n",
      "4623/4623 [==============================] - 2s 473us/step - loss: 13.4753 - acc: 0.1640 - val_loss: 13.5869 - val_acc: 0.1570\n",
      "\n",
      "Epoch 00006: val_loss did not improve from 13.58690\n",
      "Epoch 7/100\n",
      "4623/4623 [==============================] - 2s 471us/step - loss: 13.4753 - acc: 0.1640 - val_loss: 13.5869 - val_acc: 0.1570\n",
      "\n",
      "Epoch 00007: val_loss did not improve from 13.58690\n",
      "Model: \"sequential_10\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d_22 (Conv2D)           (None, 64, 64, 32)        896       \n",
      "_________________________________________________________________\n",
      "max_pooling2d_22 (MaxPooling (None, 32, 32, 32)        0         \n",
      "_________________________________________________________________\n",
      "dropout_30 (Dropout)         (None, 32, 32, 32)        0         \n",
      "_________________________________________________________________\n",
      "conv2d_23 (Conv2D)           (None, 32, 32, 64)        18496     \n",
      "_________________________________________________________________\n",
      "max_pooling2d_23 (MaxPooling (None, 16, 16, 64)        0         \n",
      "_________________________________________________________________\n",
      "dropout_31 (Dropout)         (None, 16, 16, 64)        0         \n",
      "_________________________________________________________________\n",
      "flatten_9 (Flatten)          (None, 16384)             0         \n",
      "_________________________________________________________________\n",
      "dense_17 (Dense)             (None, 256)               4194560   \n",
      "_________________________________________________________________\n",
      "dropout_32 (Dropout)         (None, 256)               0         \n",
      "_________________________________________________________________\n",
      "dense_18 (Dense)             (None, 14)                3598      \n",
      "=================================================================\n",
      "Total params: 4,217,550\n",
      "Trainable params: 4,217,550\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "\n",
    "#데이터셋이 적어서 validation을 그냥 test 데이터로 했습니다. \n",
    "#데이터셋이 충분하시면 이렇게 하시지 마시고 validation_split=0.2 이렇게 하셔서 테스트 셋으로 나누시길 권장합니다.\n",
    "history = model.fit(X_train, y_train, batch_size=34, epochs=100, validation_data=(X_test, y_test), callbacks=[checkpoint, early_stopping])\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1541/1541 [==============================] - 0s 173us/step\n",
      "정확도 : 0.1570\n"
     ]
    }
   ],
   "source": [
    "print(\"정확도 : %.4f\" % (model.evaluate(X_test, y_test)[1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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F7BwYdhWDx9i1ixrIn/zjb1Hx4w5OGiclHR0z501bbAwfo4C8gThjto551jhv0cfhXvugddfB5FTmDLF3v9B3/dxcTYe0a6d9efOm2ebDzmXl1dftSX/mZn2n/eHH9qbMJS+/hquu84SxJlnwn//a/u/h9rRJpkw8zEIFxIlSsDtt9siTwBVYdcum7iUo4QEePttOP54++/shx8KJVYXw2bOtHGAjAxblLNnj31wX3mlDY5t3Xp0j79tm42N1a9vU/dGj7aNscKRHGKAJwgXUr1725idiK2oe+op+Pe/c7lD1aq2RiI93WrNbNuWy8numJWZaXOre/SwcatSpawVGh9vReumT7c3X6VK1ip96CFYtiz/KzszM22B2hlnWFIYMMC6lW64wf77OUZ5gnAhldWteuWV3zF1Kpx11sFxiT/+yOFODRrYlNdVq+zkffsKNWYX5bZts8Rw771wxRXWn/nhhzZoPHeuveF++826KW+6yc6/9VZo3Bhq1LCteHNrXXzyib1xBw6EU06xaawTJkCVKoX6Y0alnHYSisWL7ygXPbLi3LtX9e67VePiVGvUUP3gg1zu9MILtiPdkCGqmZmFEqdqIbym+dzlLy+x9rsPia++sp0K4+JUx43L//ti40bViRNVe/dWLV/e3lfFi6u2bav64IOqkyfruksvVe3SxY5Vrao6ebJqRkboYg+hcP7uyWVHOR+kdmEVH289A127WiuiY0ebFPKvf1lX1CEGD7bprw89ZN0IN98ckZhD6t13be3H/v02xz3HUXv3J++8Y1PkSpSwdQRHMg20alVrEQwcaC3SRYtsoHnWLGtdENiYBuyNOX68rW52h/AuJlcomje3noHhw2HsWCs5s3RpkBMfeAD69IFbboG//tV2zIol6en2IXTjjbYNa5cuNs89M9Pm0M+cGekIo5+q/Qdx4YX2j8LixUe3RiA+3tYc/OtfttHOyJEgYpvVxMVZJUpPDkF5gnCFpkwZGDcO3nvPuoPPPtvywSF7YRcrBkOH2tdp06zGTdmyVhDq/POtlXHPPdZHPHs2rF6d8zLuUBdTC2bPHusHv/NOaN3aFkd162Y/6F/+An//u7UcROyD74kn7IfevTt8McWy9HQbh7r9dujXD+bPt3UyoXTRRVCqFJnFikXtArVo4V1MrtB16gTLl9sC6jvusJmu//d/cNppgRMW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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "y_vloss = history.history['val_loss']\n",
    "y_loss = history.history['loss']\n",
    "\n",
    "x_len = np.arange(len(y_loss))\n",
    "\n",
    "plt.plot(x_len, y_vloss, marker='.', c='red', label='val_set_loss')\n",
    "plt.plot(x_len, y_loss, marker='.', c='blue', label='train_set_oss')\n",
    "plt.legend()\n",
    "plt.xlabel('epochs')\n",
    "plt.ylabel('loss')\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i: [0.000 0.000 0.000 1.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000\n",
      " 0.000 0.000]\n",
      "pre_ans:  3\n",
      "해당 antelope1.jpg이미지는 cow로 추정됩니다.\n",
      "i: [0.000 0.000 0.000 1.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000\n",
      " 0.000 0.000]\n",
      "pre_ans:  3\n",
      "해당 cat.jpg이미지는 cow로 추정됩니다.\n",
      "i: [0.000 0.000 1.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000\n",
      " 0.000 0.000]\n",
      "pre_ans:  2\n",
      "해당 raccoon.jpg이미지는 chimpanzee로 추정됩니다.\n",
      "i: [0.000 0.000 0.000 1.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000\n",
      " 0.000 0.000]\n",
      "pre_ans:  3\n",
      "해당 raccoon2.jpg이미지는 cow로 추정됩니다.\n",
      "i: [0.000 0.000 0.000 1.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000\n",
      " 0.000 0.000]\n",
      "pre_ans:  3\n",
      "해당 rat.jpg이미지는 cow로 추정됩니다.\n",
      "i: [0.000 1.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000\n",
      " 0.000 0.000]\n",
      "pre_ans:  1\n",
      "해당 squirrel.jpg이미지는 cats으로 추정됩니다.\n"
     ]
    }
   ],
   "source": [
    "from PIL import Image\n",
    "import os, glob, numpy as np\n",
    "from keras.models import load_model\n",
    "\n",
    "caltech_dir = \"D:/Games/Images/val2\"\n",
    "image_w = 64\n",
    "image_h = 64\n",
    "\n",
    "pixels = image_h * image_w * 3\n",
    "\n",
    "X = []\n",
    "filenames = []\n",
    "files = glob.glob(caltech_dir+\"/*.*\")\n",
    "for i, f in enumerate(files):\n",
    "    img = Image.open(f)\n",
    "    img = img.convert(\"RGB\")\n",
    "    img = img.resize((image_w, image_h))\n",
    "    data = np.asarray(img)\n",
    "    filenames.append(f)\n",
    "    X.append(data)\n",
    "\n",
    "X = np.array(X)\n",
    "model = load_model('./model/multi_img_classification.model')\n",
    "\n",
    "prediction = model.predict(X)\n",
    "np.set_printoptions(formatter={'float': lambda x: \"{0:0.3f}\".format(x)})\n",
    "cnt = 0\n",
    "\n",
    "#이 비교는 그냥 파일들이 있으면 해당 파일과 비교. 카테고리와 함께 비교해서 진행하는 것은 _4 파일.\n",
    "for i in prediction:\n",
    "    pre_ans = i.argmax()  # 예측 레이블\n",
    "    print(\"i:\",i)\n",
    "    print(\"pre_ans: \",pre_ans)\n",
    "    pre_ans_str = ''\n",
    "    if pre_ans == 0: pre_ans_str = \"antelope\"\n",
    "    elif pre_ans == 1: pre_ans_str = \"cats\"\n",
    "    elif pre_ans == 2: pre_ans_str = \"chimpanzee\"\n",
    "    elif pre_ans == 3: pre_ans_str = \"cow\"\n",
    "    elif pre_ans == 4: pre_ans_str = \"dogs\"\n",
    "    elif pre_ans == 5: pre_ans_str = \"hippopotamus\"\n",
    "    elif pre_ans == 6: pre_ans_str = \"horse\"\n",
    "    elif pre_ans == 7: pre_ans_str = \"otter\"\n",
    "    elif pre_ans == 8: pre_ans_str = \"raccooon\"\n",
    "    elif pre_ans == 9: pre_ans_str = \"rat\"\n",
    "    elif pre_ans == 10: pre_ans_str = \"rhinoceros\"\n",
    "    elif pre_ans == 11: pre_ans_str = \"squirrel\"\n",
    "    elif pre_ans == 12: pre_ans_str = \"weasel\"\n",
    "    else: pre_ans_str = \"wolf\"\n",
    "    if i[0] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[1] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"으로 추정됩니다.\")\n",
    "    if i[2] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[3] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[4] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[5] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[6] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[7] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[8] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[9] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[10] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[11] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    if i[12] >= 0.8: print(\"해당 \"+filenames[cnt].split(\"\\\\\")[1]+\"이미지는 \"+pre_ans_str+\"로 추정됩니다.\")\n",
    "    cnt += 1\n",
    "    # print(i.argmax()) #얘가 레이블 [1. 0. 0.] 이런식으로 되어 있는 것을 숫자로 바꿔주는 것.\n",
    "    # 즉 얘랑, 나중에 카테고리 데이터 불러와서 카테고리랑 비교를 해서 같으면 맞는거고, 아니면 틀린거로 취급하면 된다.\n",
    "    # 이걸 한 것은 _4.py에.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "project",
   "language": "python",
   "name": "project"
  },
  "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.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}