{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Keras 10mins\n", "\n", "**Tensorflow2 부터 Keras가 Core API 로 제공됩니다. 백엔드 엔진으로 Tensorflow를 쓰시는 분들은 Tensorflow2를 통해 Keras를 사용하시길 추천드립니다.**\n", "\n", "[Keras](https://keras.io/)는 Deep Learning 을 위한 배우고 사용하기 위한 API 를 지향하면서 다양한 백엔드 엔진에 대한 통일된 API 를 제공합니다. 몇 줄 안되는 코드로 Deep Learning 구조들을 쉽게 만들고 시험해 볼수 있습니다.\n", "\n", "![Deep Learning Framework Power Scores 2018](https://s3.amazonaws.com/keras.io/img/dl_frameworks_power_scores.png)\n", "\n", "참조\n", "* [Keras Cheat Sheet](https://www.datacamp.com/community/blog/keras-cheat-sheet)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "pandas ver=0.24.1\n", "numpy ver=1.16.2\n" ] } ], "source": [ "from IPython.core.display import display, HTML\n", "display(HTML(\"\"))\n", "\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "import numpy as np\n", "np.set_printoptions(precision=5)\n", "\n", "import pandas as pd\n", "pd.set_option('display.max_rows', None) \n", "pd.set_option('display.max_columns', None) \n", "pd.set_option('display.max_colwidth', -1)\n", "pd.options.display.float_format = '{:,.5f}'.format\n", "\n", "print(\"pandas ver={}\".format(pd.__version__))\n", "print(\"numpy ver={}\".format(np.__version__))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Keras 에서는 2가지 방식의 딥러닝 모델 구성 방식을 제공합니다.\n", "\n", "* [Sequential Model](https://keras.io/getting-started/sequential-model-guide/)\n", " * 스택처럼 쌓아서 만드는 단일 구조의 딥러닝 모델을 간편하게 설계할 수 있습니다.\n", "* [Function API](https://keras.io/getting-started/functional-api-guide/)\n", " * 다양한 모델을 엮어 만드는 복잡한 구조의 딥러닝 모델을 설계할 수 있습니다.\n", " * multi-output models, directed acyclic graphs, 또는 shared layers를 가지는 모델들의 설계가 가능합니다.\n", " \n", "MNIST 데이터셋을 2가지 방식으로 DNN을 구축해보면서 각 구현 방식의 차이점에 대해서 알아봅니다." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Using TensorFlow backend.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "r=60000, w=28, h=28\n", "(60000, 784)\n", "(10000, 784)\n", "(60000, 10)\n", "[[0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]\n", " [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", " [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]]\n" ] } ], "source": [ "from keras.datasets import mnist\n", "\n", "# MNIST 샘플 데이터\n", "(np_train_xs, np_train_ys), (np_test_xs, np_test_ys) = mnist.load_data()\n", "\n", "r, w, h = np_train_xs.shape\n", "print(\"r={}, w={}, h={}\".format(r, w, h))\n", "\n", "# 전처리 - 28x28 2D 이미지를 DNN 모델링을 위해 784 1D 로 변환합니다. \n", "dim_x = w * h\n", "np_train_xs = np_train_xs.reshape(-1, dim_x).astype('float32')\n", "np_test_xs = np_test_xs.reshape(-1, dim_x).astype('float32')\n", "print(np_train_xs.shape)\n", "print(np_test_xs.shape)\n", "\n", "# 전처리 - 0~1 사이로 데이터 Min Max Scaling\n", "from sklearn import preprocessing\n", "\n", "scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))\n", "np_train_xs = scaler.fit_transform(np_train_xs)\n", "np_test_xs = scaler.transform(np_test_xs)\n", "\n", "# 전처리 - 레이블을 One Hot 인코팅 \n", "from keras.utils import np_utils\n", "\n", "n_class = 10\n", "np_train_ys = np_utils.to_categorical(np_train_ys, n_class)\n", "np_test_ys = np_utils.to_categorical(np_test_ys, n_class)\n", "print(np_train_ys.shape)\n", "print(np_train_ys[:3])" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "_________________________________________________________________\n", "Layer (type) Output Shape Param # \n", "=================================================================\n", "input_2 (InputLayer) (None, 784) 0 \n", "_________________________________________________________________\n", "dense_5 (Dense) (None, 384) 301440 \n", "_________________________________________________________________\n", "dense_6 (Dense) (None, 128) 49280 \n", "_________________________________________________________________\n", "dense_7 (Dense) (None, 64) 8256 \n", "_________________________________________________________________\n", "dense_8 (Dense) (None, 10) 650 \n", "=================================================================\n", "Total params: 359,626\n", "Trainable params: 359,626\n", "Non-trainable params: 0\n", "_________________________________________________________________\n" ] } ], "source": [ "from keras import layers, models, optimizers\n", "\n", "# Sequential Model를 사용\n", "def dnn_seq(n_i, n_hs, n_o):\n", " m = models.Sequential()\n", " m.add(layers.Dense(n_i, activation='relu', input_shape=(n_i,)))\n", " for l, n_h in enumerate(n_hs):\n", " m.add(layers.Dense(n_h, activation='relu'))\n", " m.add(layers.Dense(n_o, activation = 'softmax'))\n", " sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)\n", " m.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n", " return m\n", "\n", "class DnnSeq(models.Sequential):\n", " def __init__(self, n_i, n_hs, n_o):\n", " super().__init__()\n", " self.add(layers.Dense(n_i, activation='relu', input_shape=(n_i,)))\n", " for l, n_h in enumerate(n_hs):\n", " self.add(layers.Dense(n_h, activation='relu'))\n", " self.add(layers.Dense(n_o, activation = 'softmax'))\n", " sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)\n", " self.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n", "\n", "# Function API를 사용\n", "def dnn_func(n_i, n_hs, n_o):\n", " i = layers.Input(shape = (n_i,))\n", " for l, n_h in enumerate(n_hs):\n", " if l == 0:\n", " h = layers.Dense(n_h, activation = 'relu')(i) \n", " else:\n", " h = layers.Dense(n_h, activation = 'relu')(h) \n", " o = layers.Dense(n_o, activation = 'softmax')(h)\n", " m = models.Model(inputs=[i], outputs=[o])\n", " sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)\n", " m.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n", " return m\n", "\n", "class DnnFunc(models.Model):\n", " def __init__(self, n_i, n_hs, n_o):\n", " i = layers.Input(shape = (n_i,))\n", " for l, n_h in enumerate(n_hs):\n", " if l == 0:\n", " h = layers.Dense(n_h, activation = 'relu')(i) \n", " else:\n", " h = layers.Dense(n_h, activation = 'relu')(h) \n", " o = layers.Dense(n_o, activation = 'softmax')(h)\n", " \n", " super().__init__(inputs=[i], outputs=[o])\n", " sgd = optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)\n", " self.compile(optimizer=sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n", " \n", "#model = dnn_seq(n_i = dim_x, n_hs = [384, 128, 64], n_o = n_class)\n", "#model = DnnSeq(n_i = dim_x, n_hs = [384, 128, 64], n_o = n_class)\n", "#model = dnn_func(n_i = dim_x, n_hs = [384, 128, 64], n_o = n_class)\n", "model = DnnFunc(n_i = dim_x, n_hs = [384, 128, 64], n_o = n_class)\n", "\n", "model.summary()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:From /usr/local/lib/python3.5/dist-packages/tensorflow/python/ops/math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use tf.cast instead.\n", "Train on 48000 samples, validate on 12000 samples\n", "Epoch 1/10\n", "48000/48000 [==============================] - 2s 32us/step - loss: 0.4390 - acc: 0.8731 - val_loss: 0.1959 - val_acc: 0.9461\n", "Epoch 2/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.1683 - acc: 0.9508 - val_loss: 0.1449 - val_acc: 0.9585\n", "Epoch 3/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.1157 - acc: 0.9659 - val_loss: 0.1164 - val_acc: 0.9668\n", "Epoch 4/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.0860 - acc: 0.9745 - val_loss: 0.1134 - val_acc: 0.9660\n", "Epoch 5/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.0669 - acc: 0.9796 - val_loss: 0.0897 - val_acc: 0.9734\n", "Epoch 6/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.0509 - acc: 0.9854 - val_loss: 0.0908 - val_acc: 0.9717\n", "Epoch 7/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.0400 - acc: 0.9881 - val_loss: 0.0889 - val_acc: 0.9733\n", "Epoch 8/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.0320 - acc: 0.9910 - val_loss: 0.0808 - val_acc: 0.9758\n", "Epoch 9/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.0247 - acc: 0.9933 - val_loss: 0.0783 - val_acc: 0.9770\n", "Epoch 10/10\n", "48000/48000 [==============================] - 1s 28us/step - loss: 0.0189 - acc: 0.9949 - val_loss: 0.0767 - val_acc: 0.9792\n", "10000/10000 [==============================] - 0s 9us/step\n", "[0.07681204915992566, 0.9782000082731247]\n" ] } ], "source": [ "# 학습과 평가\n", "history = model.fit(np_train_xs, np_train_ys, epochs=10, batch_size=100, validation_split=0.2)\n", "eval = model.evaluate(np_test_xs, np_test_ys, batch_size=100)\n", "print(eval)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Model Persistance\n", "\n", "Keras에서 학습한 모델을 저장하고 불러오는 방법을 알아봅니다.\n", "\n", "참조: https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model\n", "\n", "### 전체 모델 저장하기/불러오기 (architecture + weights + optimizer state)\n", "\n", "모델을 하나의 HD5 파일 형식으로 하나의 파일에 저장하고 불러올 수 있습니다. 저장되는 정보는 아래와 같습니다.\n", "\n", "* the architecture of the model, allowing to re-create the model\n", "* the weights of the model\n", "* the training configuration (loss, optimizer)\n", "* the state of the optimizer, allowing to resume training exactly where you left off.\n", "\n", "```python\n", "from keras.models import load_model\n", "\n", "model.save('my_model.h5') # creates a HDF5 file 'my_model.h5'\n", "del model # deletes the existing model\n", "\n", "# returns a compiled model\n", "# identical to the previous one\n", "model = load_model('my_model.h5')\n", "```\n", "\n", "전체 모델을 저장하고/불러오기 위해서는 Keras의 기본 모델을 이용하여 모델을 생성해야 합니다. 코드의 가독성을 위해 Keras 모델을 상속하여 모델 클래스를 만들어 사용하는 경우는 모델의 가중치 값만을 저장하고 불러올 수 있습니다. 복잡한 모델의 경우는 모델의 구조를 저장하는 것이 유리하기때문에 기본 Keras 클래스를 통해 모델을 생성하는 것을 추천합니다.\n", "\n", "### 모델 구조만 저장하기/불러오기\n", "\n", "JSON 또는 YAML 형태로 모델을 저장하고 불러올 수 있습니다.\n", "\n", "```python\n", "from keras.models import model_from_json\n", "from keras.models import model_from_yaml\n", "\n", "# JSON\n", "json_string = model.to_json()\n", "model = model_from_json(json_string)\n", "\n", "# YAML\n", "yaml_string = model.to_yaml()\n", "model = model_from_yaml(yaml_string)\n", "```\n", "\n", "### 모델 가중치만 저장하기/불러오기\n", "\n", "모델을 학습시킨 결과 가중치만 HDF5 형식으로 저장하고 불러올 수 있습니다. 저장된 가중치를 사용하기 위해서는 저장한 모델의 구조가 동일해야 합니다\n", "\n", "```python\n", "model.save_weights('my_model_weights.h5')\n", "model.load_weights('my_model_weights.h5')\n", "```\n", "\n", "Fine-tuning 또는 Transfer-learning 과 같이 불러온 가중치를 다른 모델에서 사용해야 할 경우에는 layer 의 이름을 통해 해당 layer 의 가중치만 불러오기도 가능합니다.\n", "\n", "```python\n", "\"\"\"\n", "Assuming the original model looks like this:\n", " model = Sequential()\n", " model.add(Dense(2, input_dim=3, name='dense_1'))\n", " model.add(Dense(3, name='dense_2'))\n", " ...\n", " model.save_weights(fname)\n", "\"\"\"\n", "\n", "# new model\n", "model = Sequential()\n", "model.add(Dense(2, input_dim=3, name='dense_1')) # will be loaded\n", "model.add(Dense(10, name='new_dense')) # will not be loaded\n", "\n", "# load weights from first model; will only affect the first layer, dense_1.\n", "model.load_weights(fname, by_name=True)\n", "```\n", "\n", "### 모델에 custom layers (or other custom objects) 포함된 경우\n", "\n", "자신만의 모델을 위해 custom layer/object/function 를 작성한 경우, 모델을 불러올 때는 해당 정보를 모델에 넘겨 줘야 합니다.\n", "\n", "```python\n", "from keras.models import load_model\n", "# Assuming your model includes instance of an \"AttentionLayer\" class\n", "model = load_model('my_model.h5', custom_objects={'AttentionLayer': AttentionLayer})\n", "\n", "from keras.utils import CustomObjectScope\n", "# Alternatively, you can use a custom object scope:\n", "with CustomObjectScope({'AttentionLayer': AttentionLayer}):\n", " model = load_model('my_model.h5')\n", "\n", "from keras.models import model_from_json\n", "# Custom objects handling works the same way for load_model, model_from_json, model_from_yaml:\n", "model = model_from_json(json_string, custom_objects={'AttentionLayer': AttentionLayer})\n", "```\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.9 64-bit ('3.8.9')", "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.8.9" }, "nikola": { "category": "", "date": "2019-03-09", "description": "", "link": "", "slug": "ml-keras-10mins", "tags": "", "title": "Machine Learning - Keras 10분만에 훑어보기", "type": "text" }, "notebookId": 2469278771832403, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "vscode": { "interpreter": { "hash": "81b98c941daad6509d4c89342869ca88f891260205139ff875cb30be518b42c4" } } }, "nbformat": 4, "nbformat_minor": 4 }