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