Tools/Keras (12)

Early Stopping 이란 무엇인가? 


딥러닝을 비롯한 머신러닝 모델의 한 가지 중요한 딜레마는 다음과 같다. 


너무 많은 Epoch 은 overfitting 을 일으킨다. 하지만 너무 적은 Epoch 은 underfitting 을 일으킨다. 


이런 상황에서 Epoch 을 어떻게 설정해야하는가? 

Epoch 을 정하는데 많이 사용되는 Early stopping 은 무조건 Epoch 을 많이 돌린 후, 특정 시점에서 멈추는 것이다. 


그 특정시점을 어떻게 정하느냐가 Early stopping 의 핵심이라고 할 수 있다. 일반적으로 hold-out validation set 에서의 성능이 더이상 증가하지 않을 때 학습을 중지시키게 된다. 본 포스팅에서는 Keras 를 이용하여 Early stopping 을 구현하는 법과 성능이 더 이상 증가하지 않는다는 것은 어떤 기준으로 정하는 것인지를 중점으로 정리해보고자 한다.  


Early Stopping in Keras


Keras 의 Early stopping 을 구현하는 Early stopping 함수를 통해 구현할 수 있다. 


from keras.callbacks import EarlyStopping


Earlystopping 클래스의 구성 요소

  • Performance measure: 어떤 성능을 monitoring 할 것인가?
  • Trigger: 언제 training 을 멈출 것인가?

Earlystopping 객체는 초기화될 때 두개의 요소를 정의하게 된다. 


아래와 같이 지정하면 validation set 의 loss 를 monitoring 한다는 뜻이다. 


es = EarlyStopping(monitor='val_loss')


만약 performance measure가 최소화 시켜야하는 것이면 mode를 min 으로, 최대화 시켜야하는 것이면 mode를 max로 지정한다. loss 의 경우, 최소화 시키는 방향으로 training 이 진행되므로 min 을 지정한다. 


es = EarlyStopping(monitor='val_loss', mode='min')


mode 의 default 는 auto 인데, 이는 keras 에서 알아서 min, max 를 선택하게 된다. 여기까지가 가장 기본적인 Early stopping 의 사용법이다. performance measure를 정의하고, 이것을 최대화 할지, 최소화 할지를 지정하는 것이다. 그러면 keras 에서 알아서 적절한 epoch 에서 training 을 멈춘다. verbose=1 로 지정하면, 언제 keras 에서 training 을 멈추었는지를 화면에 출력할 수 있다. 


성능이 증가하지 않는다고, 그 순간 바로 멈추는 것은 효과적이지않을 수 있다. patience 는 성능이 증가하지 않는 epoch 을 몇 번이나 허용할 것인가를 정의한다. partience 는 다소 주관적인 기준이다. 사용한 데이터와 모델의 설계에 따라 최적의 값이 바뀔 수 있다. 


es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=50)


만약 performance measure 를 practical 하게 설정한 경우 성능의 증가의 기준을 직접 정의할 수 있다. 예를 들어 아래 코드는 validation accuracy 가 1% 증가하지 않는 경우, 성능의 증가가 없다고 정의한다. 


특정값에 도달했을 때, 더 이상 training 이 필요하지 않은 경우가 있다. 이 경우 baseline 파라미터를 통해 정의할 수 있다. 


es = EarlyStopping(monitor='val_loss', mode='min', baseline=0.4)


최종적으로 mode.fit 함수의 callback 으로 early stopping 객체를 넣어주면 early stopping 을 적용할 수 있다. 


hist = model.fit(train_x, train_y, nb_epoch=10,  

                 batch_size=10, verbose=2, validation_split=0.2,   

                 callbacks=[early_stopping])  


Model Choice


Early stopping 객체에 의해 트레이닝이 중지되었을 때, 그 상태는 이전 모델에 비해 일반적으로 validation error 가 높은 상태일 것이다. 따라서, Earlystopping 을 하는 것은 특정 시점에 모델의 트레이닝을 멈춤으로써, 모델의 validation error 가 더 이상 낮아지지 않도록 조절할 수는 있겠지만, 중지된 상태가 최고의 모델은 아닐 것이다. 따라서 가장 validation performance 가 좋은 모델을 저장하는 것이 필요한데, keras 에서는 이를 위해 ModelCheckpoint 라고 하는 객체를 존재한다. 이 객체는 validation error 를 모니터링하면서, 이전 epoch 에 비해 validation performance 가 좋은 경우, 무조건 이 때의 parameter 들을 저장한다. 이를 통해 트레이닝이 중지되었을 때, 가장 validation performance 가 높았던 모델을 반환할 수 있다. 


from keras.callbacks import ModelCheckpoint


mc = ModelCheckpoint('best_model.h5', monitor='val_loss', mode='min', save_best_only=True)


위 ModelCheckpoint instance를 callbacks 파라미터에 넣어줌으로써, 가장 validation performance 가 좋았던 모델을 저장할 수 있게된다.


hist = model.fit(train_x, train_y, nb_epoch=10,  

                 batch_size=10, verbose=2, validation_split=0.2,   

                 callbacks=[early_stopping, mc])  

참고

https://machinelearningmastery.com/how-to-stop-training-deep-neural-networks-at-the-right-time-using-early-stopping/

https://machinelearningmastery.com/early-stopping-to-avoid-overtraining-neural-network-models/


Keras 멀티 GPU 이용하기


keras 2.0.9 버전부터 멀티 GPU를 손쉽게 활용할 수 있게 업데이트되었습니다. 이번 포스팅은 기존 모델을 멀티 GPU를 사용하여 트레이닝하는 예제입니다.


1. keras 2.0.9 이상에서 지원하므로 2.0.9 이상으로 업데이트

pip install --upgrade keras

2. keras 모델 생성


일반적인 keras CNN을 예로 들어 설명하겠습니다. 대략 이런 cnn model이 있다고 합시다. (패키지 임포트문 생략)

def cnn_model(): # create model model = Sequential() model.add(Convolution2D(16, 3, 3, border_mode='same', activation='relu', input_shape=(256,256,1))) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(32, 3, 3, border_mode='same', activation='relu')) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(32, 3, 3, border_mode='same', activation='relu')) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(64, 3, 3, border_mode='same', activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(64, 3, 3, border_mode='same', activation='relu')) model.add(BatchNormalization()) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(64, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(64, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(3, activation='softmax')) return model


2.0.9 버전 이후부터 제공하는 multi_gpu_model을 임포트

from keras.utils.training_utils import multi_gpu_model

모델을 만들고 multi_gpu_model을 통해서 multi gpu를 활용한다는 선언을 합니다. gpus 파라미터에 사용하고 싶은 gpu 수를 설정합니다. 모델을 compile하고 fit하면 트레이닝이 됩니다.

model = cnn_model()
model = multi_gpu_model(model, gpus=4)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(train_x, train_y, validation_data=(test_x, test_y), nb_epoch=20, batch_size=32, verbose=1)

트레이닝이 잘됩니다.

Train on 215 samples, validate on 107 samples
Epoch 1/20
215/215 [==============================] - 1s - loss: 2.0448 - acc: 0.4465 - val_loss: 1.0884 - val_acc: 0.2710
Epoch 2/20
215/215 [==============================] - 0s - loss: 1.5974 - acc: 0.4791 - val_loss: 1.1431 - val_acc: 0.1963
Epoch 3/20
215/215 [==============================] - 0s - loss: 1.2704 - acc: 0.5302 - val_loss: 1.2524 - val_acc: 0.4486
Epoch 4/20
215/215 [==============================] - 0s - loss: 1.1777 - acc: 0.4512 - val_loss: 1.3994 - val_acc: 0.5327
Epoch 5/20
215/215 [==============================] - 0s - loss: 1.0600 - acc: 0.5953 - val_loss: 1.4960 - val_acc: 0.5888
Epoch 6/20
215/215 [==============================] - 0s - loss: 1.0486 - acc: 0.6512 - val_loss: 1.5189 - val_acc: 0.5888
Epoch 7/20
215/215 [==============================] - 0s - loss: 0.9968 - acc: 0.6186 - val_loss: 1.5151 - val_acc: 0.5888
Epoch 8/20
215/215 [==============================] - 0s - loss: 1.0375 - acc: 0.6000 - val_loss: 1.4286 - val_acc: 0.5888
Epoch 9/20
215/215 [==============================] - 0s - loss: 0.9987 - acc: 0.6093 - val_loss: 1.3102 - val_acc: 0.5701
Epoch 10/20


서버에서 nvidia-smi를 쳐보면 이렇게 모든 gpu가 모두 활용되는 것을 볼 수 있습니다.




참고


https://www.pyimagesearch.com/2017/10/30/how-to-multi-gpu-training-with-keras-python-and-deep-learning/

Keras- Tensorflow Backend에서 특정 디바이스 사용법


Keras에 tensorflow backend를 사용할 때, 기본적으로 gpu를 사용하여 돌아갑니다. gpu가 있는데 cpu를 사용할 필요는 없겠지만, gpu의 성능을 측정하거나 하는 목적을 위해 강제로 cpu를 사용하도록 하는 방법에 대해 알아보겠습니다.


keras + tensorflow에서 사용가능한 하드웨어 자원보기


아래와 같이 tensorflow의 device_lib이라는 함수를 통해 현재 사용가능한 하드웨어 디바이스들의 리스트를 볼 수 있습니다. 여기서 name을 통해 해당 하드웨어에 접근할 수 있습니다. 제가 사용하는 환경의 경우 1080ti 4개를 사용하는데, 이 디바이스들의 리스트가 나오는 것을 볼 수 있습니다.

from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())
[name: "/cpu:0"
device_type: "CPU"
memory_limit: 268435456
locality {
}
incarnation: ....
, name: "/gpu:0"
device_type: "GPU"
memory_limit: 295043072
locality {
  bus_id: 1
}
incarnation: .....
physical_device_desc: "device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:02:00.0"
, name: "/gpu:1"
device_type: "GPU"
memory_limit: 366346240
locality {
  bus_id: 1
}
...

특정 device 사용하여 모델 구축, 트레이닝하기


아래와 같이 keras.backend.tensorflow_backend를 K 라는 이름으로 불러오고 with 문을 통해 해당 환경에서 모델을 구축후, fitting을 하면 해당 디바이스 환경에서 모델을 트레이닝 할 수 있습니다. 주의할 점은 model = Sequential()을 통해 모델을 생성할 때부터 with문을 통해 해당 device를 사용한다는 것을 알려줘야 한다는 것입니다. 단순히 model.fit 만 with 아래에서 돌리면 with 문이 먹히지 않더군요..

import keras.backend.tensorflow_backend as K
with K.tf.device('/gpu:0'):
    model = Sequential()
    model.add(Dense(512, input_dim=28*28, activation='relu'))
    model.add(Dense(256, activation='relu'))
    model.add(Dense(128, activation='relu'))
    model.add(Dense(32, activation='relu'))
    model.add(Dense(10, activation='softmax'))

    model.compile(loss='categorical_crossentropy',
                  optimizer='rmsprop',
                  metrics=['accuracy'])
    h = model.fit(X_train, y_train_cat, batch_size=128*4, epochs=10, verbose=1, validation_split=0.3)
Train on 42000 samples, validate on 18000 samples
Epoch 1/10
42000/42000 [==============================] - 0s - loss: 0.5832 - acc: 0.8240 - val_loss: 0.4741 - val_acc: 0.8254
Epoch 2/10
42000/42000 [==============================] - 0s - loss: 0.2057 - acc: 0.9379 - val_loss: 0.1414 - val_acc: 0.9566
Epoch 3/10
42000/42000 [==============================] - 0s - loss: 0.1359 - acc: 0.9585 - val_loss: 0.1454 - val_acc: 0.9548
Epoch 4/10
42000/42000 [==============================] - 0s - loss: 0.0919 - acc: 0.9717 - val_loss: 0.0964 - val_acc: 0.9716
Epoch 5/10

gpu를 사용하면 아래와 같이 한 epoch 당 1초도 안되어서 트레이닝이되는 것을 볼 수 있습니다. 이번엔 cpu로 한 번 모델을 구축해보겠습니다. 아래와 같이 device 이름을 /cpu:0으로 변경한 후 모델을 구축, fitting을 하면, 한 epoch 당 2초가 걸리는 것을 확인할 수 있습니다.

import keras.backend.tensorflow_backend as K
with K.tf.device('/cpu:0'):
    model = Sequential()
    model.add(Dense(512, input_dim=28*28, activation='relu'))
    model.add(Dense(256, activation='relu'))
    model.add(Dense(128, activation='relu'))
    model.add(Dense(32, activation='relu'))
    model.add(Dense(10, activation='softmax'))

    model.compile(loss='categorical_crossentropy',
                  optimizer='rmsprop',
                  metrics=['accuracy'])
    h = model.fit(X_train, y_train_cat, batch_size=128*4, epochs=10, verbose=1, validation_split=0.3)
Train on 42000 samples, validate on 18000 samples
Epoch 1/10
42000/42000 [==============================] - 2s - loss: 0.6009 - acc: 0.8115 - val_loss: 0.3323 - val_acc: 0.8966
Epoch 2/10
42000/42000 [==============================] - 2s - loss: 0.2008 - acc: 0.9404 - val_loss: 0.3604 - val_acc: 0.8832
Epoch 3/10
42000/42000 [==============================] - 2s - loss: 0.1293 - acc: 0.9605 - val_loss: 0.1384 - val_acc: 0.9578
Epoch 4/10
42000/42000 [==============================] - 2s - loss: 0.0914 - acc: 0.9716 - val_loss: 0.1376 - val_acc: 0.9590
Epoch 5/10
42000/42000 [==============================] - 2s - loss: 0.0676 - acc: 0.9796 - val_loss: 0.1145 - val_acc: 0.9674
Epoch 6/10
42000/42000 [==============================] - 2s - loss: 0.0494 - acc: 0.9842 - val_loss: 0.0903 - val_acc: 0.9742


Keras - CNN ImageDataGenerator 활용하기


keras에서는 이미지데이터 학습을 쉽게하도록 하기위해 다양한 패키지를 제공한다. 그 중 하나가 ImageDataGenerator 클래스이다. ImageDataGenerator 클래스를 통해 객체를 생성할 때 파라미터를 전달해주는 것을 통해 데이터의 전처리를 쉽게할 수 있고, 또 이 객체의 flow_from_directory 메소드를 활용하면 폴더 형태로된 데이터 구조를 바로 가져와서 사용할 수 있다. 이 과정은 매우 직관적이고 코드도 ImageDataGenerator를 사용하지 않는 방법에 비해 상당히 짧아진다. 환경은 keras tensorflow backend를 이용하였다.



1. 라이브러리 임포트

# Part 1 - Building the CNN # Importing the Keras libraries and packages from keras.models import Sequential from keras.layers import Conv2D from keras.layers import MaxPooling2D from keras.layers import Flatten from keras.layers import Dense

2. 모델 작성


ImageDataGenerator 클래스를 이용하는 것과 독립적으로 CNN 네트워크를 만들어준다. Input Image의 크기는 64x64이며, Conv-Pool-Conv-Pool-Fully Connected Layer로 이어지는 아주 간단한 구조의 CNN 모델이다. 데이터는 binary 데이터이기 때문에 activation function은 sigmoid함수 이며 손실 함수로 binary_crossentropy, 최적화 함수로는 adam을 사용한다.

# Initialising the CNN
classifier = Sequential()

# Step 1 - Convolution
classifier.add(Conv2D(32, (3, 3), input_shape = (64, 64, 3), activation = 'relu'))

# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))

# Adding a second convolutional layer
classifier.add(Conv2D(32, (3, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))

# Step 3 - Flattening
classifier.add(Flatten())

# Step 4 - Full connection
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))

# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])

3. ImageDataGenerator를 통한 트레이닝, 테스트 데이터 만들기


ImageDataGenerator를 만들 때 아래와 같이 rescale, shear_range, zoom_range, horizontal_flip을 설정해줌으로써 해당 데이터의 전처리를 어떻게 할지를 정해준다. 이 때 파라미터가 무엇을 뜻하는지를 정리하면 아래와 같다. (https://keras.io/preprocessing/image/)

  • shear_range: Float. Shear Intensity (Shear angle in counter-clockwise direction as radians)
  • zoom_range: Float or [lower, upper]. Range for random zoom. If a float,
  • horizontal_flip: Boolean. Randomly flip inputs horizontally.
  • rescale: rescaling factor. Defaults to None. If None or 0, no rescaling is applied, otherwise we multiply the data by the value provided (before applying any other transformation).
# Part 2 - Fitting the CNN to the images
from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale = 1./255,
                                   shear_range = 0.2,
                                   zoom_range = 0.2,
                                   horizontal_flip = True)

test_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory('dataset/training_set',
                                                 target_size = (64, 64),
                                                 batch_size = 32,
                                                 class_mode = 'binary')

test_set = test_datagen.flow_from_directory('dataset/test_set',
                                            target_size = (64, 64),
                                            batch_size = 32,
                                            class_mode = 'binary')

classifier.fit_generator(training_set,
                         steps_per_epoch = 300,
                         epochs = 25,
                         validation_data = test_set,
                         validation_steps = 2000)

또한 flow_from_directory 메소드를 사용하면 폴더구조를 그대로 가져와서 ImageDataGenerator 객체의 실제 데이터를 채워준다. 이 데이터를 불러올 때 앞서 정의한 파라미터로 전처리를 한다. 마지막으로 fit_generator 함수를 실행함으로써 fitting이 이루어진다. 이 예제의 경우 ImageDataGenerator 객체를 사용하였기 때문에 fit_generator 함수를 통해 fitting한다. steps_per_epoch은 한 번 epoch 돌 때, 데이터를 몇 번 볼 것인가를 정해준다. [트레이닝데이터수/배치사이즈]를 사용하면 되는듯하다. validation_steps는 한 번 epoch 돌 고난 후, validation set을 통해 validation accuracy를 측정할 때 validation set을 몇 번 볼 것인지를 정해준다. 이 때도 마찬가지로 [validation data수/배치사이즈]를 사용하면 된다. 즉 ImageDataGenerator를 쓴 경우, fit_generator를 사용하면 된다고 기억하면 된다. 폴더 구조는 아래와 같이 하면 된다. flow_from_directory에 넣어준 경로(dataset/training_set) 밑에 이런식으로 class(cats, dogs) 별로 폴더를 만들고 폴더 밑에 이미지들을 넣어준다. 그러면 알아서 labeling을 하게 된다.





4. 테스트셋 예측하기


output = classifier.predict_generator(test_set, steps=5)
print(test_set.class_indices)
print(output)
{'cats': 0, 'dogs': 1}
[[ 0.58327454]
 [ 0.08756679]
 [ 0.44407782]
 [ 0.66460747]
 [ 0.38810217]
 [ 0.52190965]
 [ 0.67696238]
 [ 0.67470866]
 [ 0.77020335]
 [ 0.68121213]
 [ 0.66256768]
 [ 0.82018822]
...



Keras를 통한 LSTM 구현


/* 2017.8.29 by. 3months */


- LSTM에 대한 개념 학습

http://blog.naver.com/kmkim1222/221069000196

https://www.youtube.com/watch?v=6niqTuYFZLQ&list=PL3FW7Lu3i5JvHM8ljYj-zLfQRF3EO8sYv


- 코드 및 데이터 출처  -https://github.com/Dataweekends/zero_to_deep_learning_udemy


LSTM 개념


LSTM은 기존 vanilla RNN을 개선한 모델로써 데이터의 long-term dependency를 학습하는데 효과적인 모델입니다. 또한 내부적으로 구성요소간에 additive, elementwise interaction을 통해 backpropagation 할 때, gradient explosion, vanishing 문제를 기존 RNN에 비해 매우 줄인 것이 중요한 개선점입니다.


코드 실습을 통해 LSTM을 학습하기 위해서는 어떠한 데이터 구조가 필요한지, 즉, INPUT은 어떤 모양이어야 하고, OUTPUT이 어떻게 생성되며, 네트워크 구조를 코드 상으로 어떻게 정의하는지 알아보겠습니다.


사용할 데이터


cansim-0800020-eng-6674700030567901031.csv


데이터 임포트


데이터를 임포트합니다. 데이터는 날짜별로 특정한 값이 있는 데이터입니다. Unadjusted이 Raw 값이고, Seaonally adjusted는 Season의 효과를 보정한 값입니다. 보통 주식과 같은 시계열 데이터는 Season에 의한 효과가 있는데, Seasonally adjusted는 이 Season에 의한 효과를 보정하여 전체적인 추세만 보고자할 때 사용하는 변수입니다. 우리가 학습할 변수는 Season에 의한 효과를 보정하지 않은 Unadjusted입니다.

import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt

df = pd.read_csv('data/cansim-0800020-eng-6674700030567901031.csv',
                 skiprows=6, skipfooter=9,
                 engine='python')
df.head()

Adjustments Unadjusted Seasonally adjusted
0 Jan-1991 12588862 15026890
1 Feb-1991 12154321 15304585
2 Mar-1991 14337072 15413591
3 Apr-1991 15108570 15293409
4 May-1991 17225734 15676083



전처리

from pandas.tseries.offsets import MonthEnd df['Adjustments'] = pd.to_datetime(df['Adjustments']) + MonthEnd(1) df = df.set_index('Adjustments') print(df.head()) df.plot()

우선 문자열로된 Adjustments 변수를 datetime 객체로 만들어주고, MonthEnd(1)을 더하면 해당 월의 맨 끝 날짜가 지정되게 됩니다. 그리고 이 날짜를 index로 만들어줍니다. 이후에 plot을 하면 날짜를 index로 해서 Unadjusted와 Seasonally adjusted 변수의 그래프를 그릴 수 있습니다.



Unadjusted Seasonally adjusted
Adjustments

1991-01-31 12588862 15026890
1991-02-28 12154321 15304585
1991-03-31 14337072 15413591
1991-04-30 15108570 15293409
1991-05-31 17225734 15676083


인덱스가 0,1,2,3 ... 에서 날짜로 변했음을 알 수 있습니다. (가장 왼쪽열. 또한 index의 이름이 Adjustements가 되었음을 알 수 있음.)



우리가 학습할 변수는 파란색 선 Unadjusted 입니다.



트레이닝셋 테스트셋 SPLIT


2011/1/1 을 기준으로 트레이닝셋과 테스트셋으로 구분합니다. 그리고 학습과 테스트에 사용할 Unadjusted 변수만 남겨놓습니다.

split_date = pd.Timestamp('01-01-2011')
# 2011/1/1 까지의 데이터를 트레이닝셋.
# 그 이후 데이터를 테스트셋으로 한다.

train = df.loc[:split_date, ['Unadjusted']]
test = df.loc[split_date:, ['Unadjusted']]
# Feature는 Unadjusted 한 개

ax = train.plot()
test.plot(ax=ax)
plt.legend(['train', 'test'])



변수 Scaling


MinMax Scaling을 통해 변수를 Scaling합니다. MinMax Scaling : http://3months.tistory.com/167

그러면 아래와 같이 Scaling 된 것을 볼 수 있고, scaling의 결과는 2차원의 numpy ndarray 타입으로 변환이 되게 됩니다.

from sklearn.preprocessing import MinMaxScaler

sc = MinMaxScaler()

train_sc = sc.fit_transform(train)
test_sc = sc.transform(test)

train_sc
(240, 1)
[[ 0.01402033]
 [ 0.        ]
 [ 0.0704258 ]
 [ 0.09531795]
 [ 0.16362761]
 [ 0.13514108]
 [ 0.12395846]
 [ 0.12617398] 
......


Pandas Dataframe으로 변환


이를 다시 pandas dataframe 데이터 타입으로 변환해봅시다. Dataframe에서 작업을 해야지 Window를 만들기 유용하기 때문입니다. Window는 RNN을 트레이닝 하기위한 단위로 Window size는 Timestep과 같다고 생각하시면 됩니다.

train_sc_df = pd.DataFrame(train_sc, columns=['Scaled'], index=train.index)
test_sc_df = pd.DataFrame(test_sc, columns=['Scaled'], index=test.index)
train_sc_df.head()



Scaled
Adjustments
1991-01-31 0.014020
1991-02-28 0.000000
1991-03-31 0.070426
1991-04-30 0.095318
1991-05-31 0.163628



pandas shift를 통해 Window 만들기


shift는 이전 정보 다음 row에서 다시 쓰기 위한 pandas의 함수입니다. 이를 통해 아래와 같이 과거의 값들을 shift_s 와 같은 형태로 저장할 수 있습니다. 과거값은 총 12개를 저장하며, timestep은 12개가 됩니다. 우리의 목적은 과거값 shift1~12를 통해 현재값 Scaled를 예측하는 것입니다.

for s in range(1, 13):
    train_sc_df['shift_{}'.format(s)] = train_sc_df['Scaled'].shift(s)
    test_sc_df['shift_{}'.format(s)] = test_sc_df['Scaled'].shift(s)

train_sc_df.head(13)



Scaled shift_1 shift_2 shift_3 shift_4 shift_5 shift_6 shift_7 shift_8 shift_9 shift_10 shift_11 shift_12
Adjustments












1991-01-31 0.014020 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1991-02-28 0.000000 0.014020 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1991-03-31 0.070426 0.000000 0.014020 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1991-04-30 0.095318 0.070426 0.000000 0.014020 NaN NaN NaN NaN NaN NaN NaN NaN NaN
1991-05-31 0.163628 0.095318 0.070426 0.000000 0.014020 NaN NaN NaN NaN NaN NaN NaN NaN
1991-06-30 0.135141 0.163628 0.095318 0.070426 0.000000 0.014020 NaN NaN NaN NaN NaN NaN NaN
1991-07-31 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000 0.014020 NaN NaN NaN NaN NaN NaN
1991-08-31 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000 0.014020 NaN NaN NaN NaN NaN
1991-09-30 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000 0.014020 NaN NaN NaN NaN
1991-10-31 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000 0.014020 NaN NaN NaN
1991-11-30 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000 0.014020 NaN NaN
1991-12-31 0.200913 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000 0.01402 NaN
1992-01-31 0.030027 0.200913 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.00000 0.01402



트레이닝셋과 테스트셋 만들기


dropna를 통해 NaN이 있는 데이터를 제거하고, shift_1 ~ shift_12는 X로 Scaled는 Y로 지정을 합니다.

X_train = train_sc_df.dropna().drop('Scaled', axis=1)
y_train = train_sc_df.dropna()[['Scaled']]

X_test = test_sc_df.dropna().drop('Scaled', axis=1)
y_test = test_sc_df.dropna()[['Scaled']]


최종 트레이닝셋과 테스트셋의 모양은 아래와 같습니다.


X_train.head()



shift_1 shift_2 shift_3 shift_4 shift_5 shift_6 shift_7 shift_8 shift_9 shift_10 shift_11 shift_12
Adjustments











1992-01-31 0.200913 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000 0.014020
1992-02-29 0.030027 0.200913 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426 0.000000
1992-03-31 0.019993 0.030027 0.200913 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318 0.070426
1992-04-30 0.065964 0.019993 0.030027 0.200913 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628 0.095318
1992-05-31 0.109831 0.065964 0.019993 0.030027 0.200913 0.131738 0.111395 0.092309 0.126174 0.123958 0.135141 0.163628


y_train.head()



Scaled
Adjustments
1992-01-31 0.030027
1992-02-29 0.019993
1992-03-31 0.065964
1992-04-30 0.109831
1992-05-31 0.149130



다시 ndarray로 변환하기


데이터구조를 다시 ndarray로 변환시켜줍니다. 실제 deep learning 모델의 트레이닝과 테스트로 사용되는 데이터는 일반적으로 numpy의 ndarray입니다. 아래와 같이 .values를 통해 ndarray 값을 얻을 수 있습니다. 트레이닝 데이터는 timestep=12, size = 228 입니다.

X_train = X_train.values
X_test= X_test.values

y_train = y_train.values
y_test = y_test.values
print(X_train.shape)
print(X_train)
print(y_train_shape)
print(y_train)
(228, 12)
[[ 0.20091289  0.13173822  0.11139526 ...,  0.0704258   0.          0.01402033]
 [ 0.03002688  0.20091289  0.13173822 ...,  0.09531795  0.0704258   0.        ]
 [ 0.01999285  0.03002688  0.20091289 ...,  0.16362761  0.09531795
   0.0704258 ]
 ..., 
 [ 0.79916654  0.81439355  0.86398323 ...,  0.92972161  0.71629034
   0.77368724]
 [ 0.80210057  0.79916654  0.81439355 ...,  0.59734863  0.92972161
   0.71629034]
 [ 0.81482896  0.80210057  0.79916654 ...,  0.53166512  0.59734863
   0.92972161]]
(228, 1)
[[ 0.03002688]
 [ 0.01999285]
 [ 0.06596369]
 [ 0.10983126]
 [ 0.14912986]
....


최종 트레이닝셋과 테스트셋의 X 만들기


이부분이 중요한데, keras에서는 RNN 계열의 모델을 트레이닝할 대 요구되는 데이터의 형식이 있습니다. 바로 3차원 데이터여야하며 각각의 차원은 (size, timestep, feature) 을 순서대로 나타내주어야하는 것입니다. 따라서 이 형태로 데이터를 reshape 해주어야합니다. 일반적인 MLP 모델에서는 size와 feature만 있기 때문에 2차원이지만, RNN에서는 "시간" 이라는 개념이 있기 때문에 차원이 한 차원 늘어나게 된 것입니다. 합리적인 데이터 구조라고 볼 수 있습니다.


아래 코드를 통해 Training set과 Test set의 X를 RNN 학습에 맞는 형태로 reshape 해줍니다.

X_train_t = X_train.reshape(X_train.shape[0], 12, 1) X_test_t = X_test.reshape(X_test.shape[0], 12, 1)

print("최종 DATA")
print(X_train_t.shape)
print(X_train_t)
print(y_train)
최종 DATA
(228, 12, 1)
[[[ 0.20091289]
  [ 0.13173822]
  [ 0.11139526]
  ..., 
  [ 0.0704258 ]
  [ 0.        ]
  [ 0.01402033]]

 [[ 0.03002688]
  [ 0.20091289]
  [ 0.13173822]
  ..., 
  [ 0.09531795]
  [ 0.0704258 ]
  [ 0.        ]]


LSTM 모델 만들기


아래와 같이 keras를 통해 LSTM 모델을 만들 수 있습니다. input_shape=(timestep, feature)으로 만들어줍니다. size는 모델 설계시에는 중요하지 않으므로, feature, timestep만 모델에 알려주면 됩니다. 또 예측하고자하는 target의 갯수가 1이므로 마지막에 Dense(1)을 하나 추가해줍니다. 또한 실제 연속적인 값을 예측하는 것이기 때문에 loss function은 mean squared error가 됩니다. 또한 일반적으로 optimizer는 adam을 자주 사용합니다.

from keras.layers import LSTM from keras.models import Sequential from keras.layers import Dense import keras.backend as K from keras.callbacks import EarlyStopping K.clear_session() model = Sequential() # Sequeatial Model model.add(LSTM(20, input_shape=(12, 1))) # (timestep, feature) model.add(Dense(1)) # output = 1 model.compile(loss='mean_squared_error', optimizer='adam') model.summary()


모델 Fitting


모델을 Fitting한다는 것은 Training data set으로 optimization 과정을 통해 모델의 weight를 찾는 것입니다. early stopping 객체를 이용해 epoch마다 early stopping을 체크합니다. 아래와 같은 결과를 내면서 트레이닝이 잘 되는 것을 확인할 수 있습니다.

early_stop = EarlyStopping(monitor='loss', patience=1, verbose=1)

model.fit(X_train_t, y_train, epochs=100,
          batch_size=30, verbose=1, callbacks=[early_stop])
Epoch 1/100
228/228 [==============================] - 0s - loss: 0.3396     
Epoch 2/100
228/228 [==============================] - 0s - loss: 0.2958     
Epoch 3/100
228/228 [==============================] - 0s - loss: 0.2551     
Epoch 4/100
228/228 [==============================] - 0s - loss: 0.2175   
...


학습된 모델을 통해 테스트셋 Test 하기


테스트셋은 2011/1/1 이후의 데이터를 나타냅니다. 트레이닝에는 1991년~ 2010년 까지 데이터가 이용되었기 때문에, 이 실습은 1991년~2010년 데이터를 통해 2011년 이후의 데이터를 예측하는 것으로 볼 수 있습니다.


테스트셋의 모양은 아래와 같이 생겼습니다. 당연한 이야기지만 트레이닝셋과 구조가 같습니다.

print(X_test_t)
[[[ 1.06265011]
  [ 0.87180554]
  [ 0.84048091]
  [ 0.86220767]
  [ 0.88363094]
  [ 0.89302107]
  [ 0.92552046]
  [ 0.89993326]
  [ 0.83505683]
  [ 0.77259579]
  [ 0.56926634]
  [ 0.61423187]]


....


model.predict를 통해 테스트셋의 X에 대한 예측값 y_hat을 얻을 수 있습니다.

y_pred = model.predict(X_test_t)
print(y_pred)
[[ 0.82410765]
 [ 0.85221326]
 [ 0.88795143]
 [ 0.90008551]
 [ 0.90281236]
 [ 0.90063977]
 [ 0.89379823]
 [ 0.88957471]
 [ 0.88779473]

...


Keras 모델 저장하고 불러오기


/* by 3months. 2017.7.19 */


keras를 통해 MLP, CNN 등의 딥러닝 모델을 만들고, 이를 학습시켜서 모델의 weights를 생성하고 나면 이를 저장하고 싶을 때가 있습니다. 특히 weights 같은 경우는 파일 형태로 저장해놓는 것이 유용한데, 파이썬 커널을 내리는 순간 애써 만든 weights 가 모두 메모리에서 날라가 버리기 때문입니다. keras에서는 모델과 weights의 재사용을 위해 이를 파일형태로 저장하는 라이브러리를 제공하며, 이를 통해 모델과 weights를 파일 형태로 저장하고 불러올 수가 있습니다.


Keras에서 만든 모델을 저장할 때는 다음과 같은 룰을 따릅니다.

  • 모델은 JSON 파일 또는 YAML 파일로 저장한다.
  • Weight는 H5 파일로 저장한다.


아래는 모델을 저장하고 불러오는 실습 코드입니다.



라이브러리 임포트

from keras.models import Sequential
from keras.layers import Dense
from keras.callbacks import ModelCheckpoint
import matplotlib.pyplot as plt
import numpy
import pandas as pd


데이터 로드

url = "https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']

dataframe = pd.read_csv(url, names=names)
array = dataframe.values

X = array[:,0:8]
Y = array[:,8]


모델 생성

# create model
model = Sequential()
model.add(Dense(12, input_dim=8, kernel_initializer='uniform', activation='relu'))
model.add(Dense(8, kernel_initializer='uniform', activation='relu'))
model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))

# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])


모델을 JSON 파일 형식으로 만들어 저장하기

model_json = model.to_json()
with open("model.json", "w") as json_file : 
    json_file.write(model_json)


Weight를 h5 파일 포맷으로 만들어 저장하기

model.save_weights("model.h5")
print("Saved model to disk")


저장된 JSON 파일로 부터 모델 로드하기

from keras.models import model_from_json json_file = open("model.json", "r") loaded_model_json = json_file.read() json_file.close() loaded_model = model_from_json(loaded_model_json)


로드한 모델에 Weight 로드하기

loaded_model.load_weights("model.h5") print("Loaded model from disk")


모델 컴파일 후 Evaluation

loaded_model.compile(loss="binary_crossentropy", optimizer="rmsprop", metrics=['accuracy'])

# model evaluation
score = loaded_model.evaluate(X,Y,verbose=0)

print("%s : %.2f%%" % (loaded_model.metrics_names[1], score[1]*100))


오늘 모 워크샵에서 강의를 듣던 중 아래 github의 가상환경이 굉장히 잘 되어있어서 공유합니다. zero_to_deep_learning 이라는 외국 강의가 있는데 이곳에서 사용하는 것이라고 합니다. 이외에도 다양한 예제파일이 있는데 매우 유용하네요.


https://github.com/Dataweekends/zero_to_deep_learning_udemy


방법은 해당 깃허브 폴더를 clone한 후, yaml 파일에 정의된 아나콘다 가상환경을 만들고 이 가상환경을 activate 시킨다음에 파이썬을 사용하시면 됩니다.

Keras에서는 Theano Backend와 Tensorflow Backend 둘 중 하나를 골라서 사용할 수 있습니다. 둘 중 어느것을 Backend로 사용하더라도 별 차이는 없습니다. 아주 약간의 차이가 있는데 예를 들어 이미지를 input으로 줄 때 차원값의 순서가 바뀌기도 합니다.


Windows를 사용하는 유저의 경우, Keras를 설치하였다면 사용자 폴더 아래에 .keras 폴더가 있습니다. 이 폴더 아래에 keras.json 파일이 있는데 이것을 수정하시면 Backend를 바꿀 수 있습니다. 물론 Backend도 설치가 되어있어야합니다. 즉 Theano나 Tensorflow를 설치하여야합니다.


파일 경로

C:\Users\(사용자이름)\.keras\keras.json


Theano

{
    "image_dim_ordering": "th",
    "epsilon": 1e-07,
    "floatx": "float32",
    "backend": "theano"
}


Tensorflow

{
    "image_dim_ordering": "channels_last",
    "epsilon": 1e-07,
    "floatx": "float32",
    "backend": "tensorflow"
}


keras.json 파일을 위와같이 수정하면 각각 Theano backend와 tensorflow backend로 구동되어집니다.

/**

날짜 : 2017.1.22

작성자 : 3개월

제목 : MNIST 데이터로 CNN Training 해보기

*/



1. 패키지 로드 & 데이터 읽기


""" Simple Convolutional Neural Network for MNIST """
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
K.set_image_dim_ordering('th')
import cPickle, gzip, numpy

# Load the dataset
f = gzip.open('mnist.pkl.gz', 'rb')
train_set, valid_set, test_set = cPickle.load(f)
f.close()


필요한 패키지들을 불러오고 데이터들을 불러옵니다.

mnist.pkl.gz는 

https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/data/mnist.pkl.gz 

에서 다운로드 후 코드와 같은 폴더에 붙여 넣으시면 됩니다.


# train_set 은 튜플로 두 개의 ndsarray를 원소로 가지고 있음
print train_set
print type(train_set)
print len(train_set)

# 튜플을 이렇게 둘로 나눌 수 있음
X_train, y_train = train_set
X_test, y_test = test_set

print type(X_train)
print len(X_train)
print len(y_train)
print X_train
print y_train


이제 MNIST 데이터를 읽어들였고, training set과 test set이 준비 완료되었습니다. 하지만 cnn에서는 x vector의 형태를 알맞게 고치는 preprocessing 작업이 필요합니다.  


2. 데이터 preprocessing


""" In Keras, the layers used for two-dimensional convolutions expect pixel values with the dimensions [pixels][width][height]. """
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28).astype('float32') X_test = X_test.reshape(X_test.shape[0], 1, 28, 28).astype('float32') # normalize inputs from 0-255 to 0-1 X_train = X_train / 255 X_test = X_test / 255 # one hot encode outputs y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) num_classes = y_test.shape[1] # fix random seed for reproducibility seed = 7 numpy.random.seed(seed)


위와 같이 numpy의 reshape함수를 이용하여 X vector를 [pixels][width][height] 형태로 바꿔줍니다. (이 때 X_train.shape = (50000L, 784L) 라서 X_train.shape[0] = 50000 입니다.)


  • keras에서 cnn을 구현할 때 [pixels][width][height] 형태로 input을 받습니다. (Theano Backend의 경우)

piexels는 흑백이므로 1을 입력하고 MNIST데이터는 28x28 손글씨 이미지이므로 width = 28, height = 28을 입력합니다. 만약 컬러라면 3을 넣어야합니다. 이제 모든 training 데이터와 test 데이터의 준비는 끝났습니다.


3. CNN 모델 


def cnn_model():
    # create model
    model = Sequential()
    model.add(Convolution2D(32, 5, 5, border_mode='valid', input_shape=(1, 28, 28), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(127, activation='relu'))
    model.add(Dense(num_classes, activation='softmax'))
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model


CNN 모델을 구축하여보겠습니다. 

위 모델은 Convolution Layer-ReLU-Pooling Layer-(Dropout)-Fully Connected Network로 이어지는 구조이며 기본적인 CNN의 구조입니다.


  • Convolution2D(32,5,5...)에서 32는 feature map의 갯수라 할 수 있고 5,5는 5x5 필터 사이즈를 의미합니다. 
  • border_mode는 zero-padding에 관한 세팅입니다. valid는 valid convolution을 의미하여 padding을 주지 않습니다. 만약 same인 경우 same convolution이며 zero-padding을 넣어 convolution 결과의 사이즈과 인풋과 같게 합니다.


4. Training & Test


# build the model
model = cnn_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))



이제 CNN을 트레이닝해보겠습니다. validation set은 test set으로 대체하였고, epoch=10, batch_size=200으로 하였습니다. verbose는 로깅에 관한 세팅으로 개념을 이해할 때는 무시하셔도 좋습니다.





error는 validation error을 기준으로 하며 마지막 epoch의 validation error에서 (1-0.9370)*100을 하여 6.3%가 됩니다. 앞서 MLP로 training하였을때는 7% 대에 error를 보였지만 CNN을 통해서 error rate를 낮출 수 있었습니다.






/**

Keras Mnist Learning Using Multi Layer Perceptron

작성자 : 3개월

날짜 : 2017.1.20

코드하이라이터 : http://markup.su/highlighter/

*/


1. 데이터 읽기


import cPickle, gzip, numpy

# Load the dataset
f = gzip.open('mnist.pkl.gz', 'rb')
train_set, valid_set, test_set = cPickle.load(f)
f.close()


mnist.pkl.gz는

https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/data/mnist.pkl.gz 

에서 다운로드 후 코드와 같은 폴더에 붙여 넣으시면 됩니다.


cPickle.load(f)를 하면 train_set, valid_set, test_set이 알아서 나뉘어집니다.


# train_set 은 튜플로 두 개의 ndsarray를 원소로 가지고 있음
print train_set
print type(train_set)
print len(train_set)

# 튜플을 이렇게 둘로 나눌 수 있음
X_train, y_train = train_set
X_test, y_test = test_set

print type(X_train)
print len(X_train)
print len(y_train)
print X_train
print y_train


train_set을 위와 같이 X_train, y_train 으로 나눌 수 있습니다.

train_set은 2개의 원소(X, Y)를 갖고 있는 '튜플' 인데 튜플인 경우 저러한 문법이 가능합니다.


2. Multi Layer Perceptron 구현


CNN을 활용하기 전에 Multi Layer Perceptrons을 이용하여 데이터셋을 러닝해봅니다. universal approximation theorem에 의해 사실 이 MLP로도 이미지 classification을 포함한 이 세상에 존재하는 모든 문제를 해결할 수 있습니다. (다만 데이터가 부족할뿐) 


# multi-layer perceptron
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.utils import np_utils


패키지를 임포트합니다.


seed = 7
numpy.random.seed(seed)


계속 실행하더라도 동일한 결과를 갖기 위해 numpy random seed를 설정해줍니다.


print type(X_train)
print type(y_train)


타입은 두 개 모두 ndarray입니다. X_train은 784*50000 2차원 배열, y_train은 길이가 50000인 1차원 배열입니다. 784는 MNIST 데이터가 28*28 =784 픽셀 흑백 손글씨 이미지이기 때문에 나온 숫자이고 이를 일렬로 쭉 늘어놓은 것입니다. 또한 50000은 데이터의 갯수입니다. 


# normalize inputs from 0-255 to 0-1
X_train = X_train / 255
X_test = X_test / 255


흑백 이미지 데이터는 픽셀 하나당 0-255까지의 숫자값을 가지므로 이를 255로 나누면 0-1 사이로 normalize됩니다.


# one hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)

# y_test 의 column을 클래스의 갯수 지정 : 10개
num_classes = y_test.shape[1]
num_pixels = X_train.shape[1]


위와 같이 y 값들을 one hot encoding 합니다.

또 아래 MLP 모델을 구축할 때 쓰는 변수들 num_classes, num_pixels를 정의합니다.


# define baseline model
def baseline_model():
    # create model
    model = Sequential()
    model.add(Dense(num_pixels, input_dim=num_pixels, init='normal', activation='relu'))
    model.add(Dense(num_classes, init='normal', activation='softmax'))
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

def good_model():
    # create model
    model = Sequential()
    model.add(Dense(400, input_dim=num_pixels, init='normal', activation='relu'))
    model.add(Dense(100, init='normal', activation='relu'))
    model.add(Dense(num_classes, init='normal', activation='softmax'))
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model


위와 같이 두 개의 MLP를 만들었습니다.

baseline_model은 히든 레이어가 한 개인 네트워크이고, good_model은 히든 레이어가 두 개인 네트워크입니다.


  • keras의 경우 input layer는 생략하며 첫 번째 히든 레이어에 "input_dim=인풋 레이어의 노드 수"를 지정하는 식으로 네트워크를 구성합니다.
  • 히든 레이어가 많고, 한 레이어당 노드 수가 적을 수록 overfitting이 적어져 generalization이 잘된다고 알려져있습니다.

데이터를 통해 위 두 개의 네트워크를 훈련하고 테스트해보겠습니다.



3. Training & Test


히든 레이어 한 개짜리 MLP


# build the model
model = baseline_model()
# Fit the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))


첫 번째 모델인 baseline_model을 train하고 test하는 코드입니다. 

validation set은 test set으로 대체하였습니다. 

실행시 아래와 같이 10번 epoch을 돌면서, training accuracy, loss와 validation accuracy, loss를 출력합니다. 



error는 validation accuracy를 기준으로하며 (1-0.9232)*100 = 7.68% 입니다.



히든 레이어 두 개짜리 MLP (더 Deep 한 모델)


# build the model
model2 = good_model()
# Fit the model
model2.fit(X_train, y_train, validation_data=(X_test, y_test), nb_epoch=10, batch_size=200, verbose=2)
# Final evaluation of the model
scores = model2.evaluate(X_test, y_test, verbose=0)
print("Baseline Error: %.2f%%" % (100-scores[1]*100))


두 번째 모델인 good_model을 기준으로 training 과 test를 합니다.




위와 같이 Error가 7.54%로 첫 번째 네트워크보다 accuracy가 다소 높은 것을 알 수 있습니다.


4. 결론


MLP로 MNIST 데이터를 training하고 test 해보았습니다. MNIST와 같이 이미지 사이즈가 작고 흑백인 이미지에는 MLP도 꽤 괜찮은 accuracy를 내준다는 것을 알 수 있습니다. 하지만 이미지의 사이즈가 커지고 class의 갯수가 많아질 수록 CNN(Convolutional Neural Network)과 같은 이미지 처리에 최적화된 네트워크를 쓰는 것이 훨씬 효율적일 것입니다. 또한 training할 때 layer와 갯수와 layer당 node수를 적절히 선택하는 것이 중요하며 보통 이 사이즈는 try & error로 구하는 경우가 많습니다. 물론 네트워크를 구성하고 training 해본 경험이 많다면 어느정도의 layer와 node수를 선택해야하는지에 대해 어느정도 직감을 가질 수 있습니다.