본문 바로가기

Theory/DeepLearning

[Keras] MNIST 데이터 셋을 이용한 필기 글씨에 대한 CNN Tutorial

최근 딥러닝 관련 학습이 남녀노소(^^) 자신의 전공분야를 떠나서 마구마구 인기를 끌고 있죠. 저도 꽤 예전부터 기초부터 익히려 했으나(ㅠㅠ) 그 놈의 게으름을 그냥 뜨문뜨문 공부했더니 정리가 잘 되지 않은 함정에 빠졌죠. 더구나 너무나 좋은 툴들이 범람하고, 그 너무나 좋은 툴들이 또 너무나 빠르게 버전 업로드가 이뤄지고 있어서, 이제는 그나마 간신히 이해한 것 조차 의미가 없어질까바 또 그것도 걱정인 참.. 황당한 시대에 살고 있습니다.^^. 지금까지는 텐서플로우를 이용해서 단층신경망으로 MNIST 필기 숫자를 인식하고[바로가기] accruracy가 한 90%쯤 나와서 좋아하다가^^, 다시 조금 더 깊은 신경망을 적용하고, 가중치를 초기화하는 부분을 Xavier 방법을 사용[바로가기] accuracy가 97.5%쯤 나와서 더~ 좋아했었죠^^ 여기까지는 텐서플로우를 사용했는데요. 갑자기 텐서플로우에서 케라스(KERAS)의 간결함에 빠져서-라고 쓰고, 공부하기 쉬워서^^ 다시 케라스로 타이타닉 생존자 분석[바로가기]을 했었죠^^

사실, MNIST와 같은 이미지 분석에는 Convolutional Neural Network를 사용한다는 것을 알고 있습니다만, 제가 블로그에 글을 쓰는 습관이 그러해서 미뤄두고 있었는데요. 오늘은 그걸 올릴려는 거죠^^. 그런데, Keras가 마음에 들어서, 텐서플로우로 잘 따라오다가, 오늘 CNN을 이용한, MNIST 손글씨 판독은 케라스로 수행하기로 했습니다.^^.

언제나 그랬지만, 오늘도 역시 Adventures in machine learning의 Keras tutorial[바로가기]에 나온 Keras 튜토리얼로 학습했습니다. 아주 일부의 내용을 수정하거나, 혹은 추가했습니다.

뭐 그렇다는 거죠^^ 오늘도 필요한 모듈을

import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)

import sys
import tensorflow as tf
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers.convolutional import Conv2D, MaxPooling2D
import numpy as np
np.random.seed(7)

print('Python version : ', sys.version)
print('TensorFlow version : ', tf.__version__)
print('Keras version : ', keras.__version__)

import하구요~

저는 얼마전부터 텐서플로우는 1.5.0에서 멈췄고, keras는 2.1.5에서 멈춰있습니다.^^

img_rows = 28
img_cols = 28

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()

input_shape = (img_rows, img_cols, 1)
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

batch_size = 128
num_classes = 10
epochs = 12

y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

그리고, keras에서 제공하는 MNIST데이터를 받고, 사용할 수 있게 train과 test 데이터를 만들어 줍니다.

이제 중요한 CNN의 구조인데요.

출처 : Adventures in machine learning

처음에 언급한, Adventures machine learning에서 제공하는 Keras tutorial에서 제시한 구조를 학습할 겁니다. 정말 keras가 마음에 드는 것은, 위 구조와 

model = Sequential()
model.add(Conv2D(32, kernel_size=(5, 5), strides=(1, 1), padding='same',
                 activation='relu',
                 input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Conv2D(64, (2, 2), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(1000, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.summary()

이 코드가 너무 쉽게 눈에 들어온다는 거죠^^

넵.. 입출력 관계와 층구조를 바로 알 수 있지만~~~ 극도로 이쁜걸 좋아하다보니...

from IPython.display import SVG
from keras.utils.vis_utils import model_to_dot
%matplotlib inline

SVG(model_to_dot(model, show_shapes=True).create(prog='dot', format='svg'))

이 코드로 다시 보면...

이렇네요^^

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
hist = model.fit(x_train, y_train,
                 batch_size=batch_size,
                 epochs=epochs,
                 verbose=1, 
                 validation_data=(x_test, y_test))

그리고, 그저 이렇게.. fit~을 시작합니다. 킁..

에휴..  한 epoch하는데 1분이라늬ㅠㅠ. 저의 맥북은 비록 2015 mid이지만 그래도 2.2GHz의 Core i7인데.. 이딴것 보다.. GPU가 필요한가봅니다.ㅠㅠ. 이제 조만간... 어마어마한 음성 데이터를 만져야하는 운명에 점점 다가가는데... 장비의 사양이 몹시 걱정이지요^^

score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

여하튼 test 데이터에 대한 accuracy는 

99.34%입니다. 이 정도면.. 테스트 데이터 10000개 중에서 66개만 틀렸다는 거죠^^ 그냥 수작업으로 결과를 확인하고 싶다면...

n = 0
plt.imshow(x_test[n].reshape(28, 28), cmap='Greys', interpolation='nearest')
plt.show()

print('The Answer is ', model.predict_classes(x_test[n].reshape((1, 28, 28, 1))))

정도의 코드면

요런 결과를 얻을 수 있겠습니다.^^ 그러나 66개 데이터에 대해 랜덤하게 한 16개 정도 팍팍 틀린아이들을 확인하고 싶다면...

import random

predicted_result = model.predict(x_test)
predicted_labels = np.argmax(predicted_result, axis=1)

test_labels = np.argmax(y_test, axis=1)

wrong_result = []

for n in range(0, len(test_labels)):
    if predicted_labels[n] != test_labels[n]:
        wrong_result.append(n)

samples = random.choices(population=wrong_result, k=16)

count = 0
nrows = ncols = 4

plt.figure(figsize=(12,8))

for n in samples:
    count += 1
    plt.subplot(nrows, ncols, count)
    plt.imshow(x_test[n].reshape(28, 28), cmap='Greys', interpolation='nearest')
    tmp = "Label:" + str(test_labels[n]) + ", Prediction:" + str(predicted_labels[n])
    plt.title(tmp)

plt.tight_layout()
plt.show()

이런 코드면 괜찮지 않을까 합니다.

흠.. 저정도라면 저도 못 맞출것 같은 아이도 있네요. 뭐 아무튼.. 오늘은 케라스로 CNN을 투토리얼 해 보았습니다.~~~~~~^^

반응형