{
"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",
"\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
}