8. MNIST 손글씨 이미지 분류하기


MNIST 이미지 데이터셋

MNIST 손글씨 이미지 데이터셋.


MNIST 데이터셋은 위 그림과 같이 0에서 9까지 10가지로 분류될 수 있는 손글씨 숫자 이미지 70,000개로 이루어져 있습니다.

각 이미지는 28×28 픽셀로 구성되고 각 픽셀은 아래와 같이 0~255 사이의 숫자 행렬로 표현됩니다.

[[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   3  18  18  18 126 136 175  26 166 255 247 127   0   0   0   0]
[  0   0   0   0   0   0   0   0  30  36  94 154 170 253 253 253 253 253 225 172 253 242 195  64   0   0   0   0]
[  0   0   0   0   0   0   0  49 238 253 253 253 253 253 253 253 253 251  93  82  82  56  39   0   0   0   0   0]
[  0   0   0   0   0   0   0  18 219 253 253 253 253 253 198 182 247 241   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0  80 156 107 253 253 205  11   0  43 154   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0  14   1 154 253  90   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0 139 253 190   2   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0  11 190 253  70   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0  35 241 225 160 108   1   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0  81 240 253 253 119  25   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0  45 186 253 253 150  27   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  16  93 252 253 187   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0 249 253 249  64   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0  46 130 183 253 253 207   2   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0  39 148 229 253 253 253 250 182   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0  24 114 221 253 253 253 253 201  78   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0  23  66 213 253 253 253 253 198  81   2   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0  18 171 219 253 253 253 253 195  80   9   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0  55 172 226 253 253 253 253 244 133  11   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0 136 253 253 253 212 135 132  16   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]]

이러한 60,000개의 이미지는 인공 신경망의 훈련 (Training)에 사용되고, 10,000개의 이미지는 테스트 (Test)에 사용됩니다.

이번 페이지에서는 Dense 층들로 구성되는 완전 연결된 인공신경망 (Fully-Connected Neural Network)을 이용해서 MNIST 데이터셋을 분류해 보겠습니다.



예제

import tensorflow as tf

# 1. MNIST 데이터셋 임포트
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 2. 데이터 전처리
x_train, x_test = x_train/255.0, x_test/255.0

# 3. 모델 구성
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])

# 4. 모델 컴파일
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 5. 모델 훈련
model.fit(x_train, y_train, epochs=5)

# 6. 정확도 평가
test_loss, test_acc = model.evaluate(x_test, y_test)
print('테스트 정확도:', test_acc)


설명

0. tensorflow 불러오기

import tensorflow as tf

tensorflow 라이브러리를 불러옵니다.


1. MNIST 데이터셋 임포트

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

tensorflow에서 직접 MNIST 손글씨 이미지 데이터셋을 불러와서 사용합니다.

load_data() 함수는 x_train, y_train, x_test, y_test 네 개의 NumPy 어레이를 반환합니다.

x_train, x_test는 28×28 픽셀의 각 손글씨 이미지 데이터이고, y_train, y_test는 분류에 사용되는 0~9 사이의 레이블 값을 갖습니다.


2. 데이터 전처리

x_train, x_test = x_train/255.0, x_test/255.0

0~255.0 사이의 값을 갖는 픽셀값들을 0~1.0 사이의 값을 갖도록 변환합니다.


3. 모델 구성

model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])

tf.keras.models.Sequential()을 이용해서 인공신경망 모델을 구성합니다.

입력층 (Input layer)에서 Flatten()을 이용해서 28×28 픽셀의 값을 784개의 1차원 배열로 변환합니다.

다음 두 개의 뉴런 층 (Neuron layer)은 Dense()를 이용해서 완전 연결된 층 (Fully-connected layer)를 구성합니다.

각 층은 512개와 10개의 인공 뉴런 노드를 갖고 활성화 함수 (activation function)로는 각각 ReLU (tf.nn.relu)와 소프트맥스 (tf.nn.softmax)를 사용합니다.



4. 모델 컴파일

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

다음은 모델 컴파일 단계입니다. 학습 과정에서 손실 함수 (Loss function)를 줄이기 위해 사용되는 optimizer로는 Adam (Adaptive Momentum estimation)을 사용합니다.

손실 함수는 ‘sparse_categorical_crossentropy’를 지정하고, 평가 지표로는 정확도 (accuracy)를 사용합니다.

정확도는 테스트 이미지 중 올바르게 분류한 비율을 의미합니다.


5. 모델 훈련

model.fit(x_train, y_train, epochs=5)

model.fit() 메서드에 학습 데이터와, 레이블, 에포크를 순서대로 입력하면, 학습이 이루어집니다.

에포크(epoch)는 60,000개의 전체 학습 데이터를 몇 번 반복해서 학습할지를 의미합니다.


학습 과정은 아래와 같이 이루어지며, 학습 데이터에 대한 정확도가 출력됩니다.

Epoch 1/5
   32/60000 [..............................] - ETA: 9:14 - loss: 2.2976 - acc: 0.0938
  384/60000 [..............................] - ETA: 54s - loss: 1.6364 - acc: 0.5182
  832/60000 [..............................] - ETA: 28s - loss: 1.2119 - acc: 0.6478
 1280/60000 [..............................] - ETA: 20s - loss: 1.0081 - acc: 0.7055
 1728/60000 [..............................] - ETA: 17s - loss: 0.8794 - acc: 0.7373
 ...
 58368/60000 [============================>.] - ETA: 0s - loss: 0.2022 - acc: 0.9390
58784/60000 [============================>.] - ETA: 0s - loss: 0.2013 - acc: 0.9392
59232/60000 [============================>.] - ETA: 0s - loss: 0.2006 - acc: 0.9395
59744/60000 [============================>.] - ETA: 0s - loss: 0.1997 - acc: 0.9398
60000/60000 [==============================] - 8s 138us/step - loss: 0.1992 - acc: 0.9399

...

Epoch 5/5
   32/60000 [..............................] - ETA: 13s - loss: 0.0490 - acc: 0.9688
  480/60000 [..............................] - ETA: 7s - loss: 0.0152 - acc: 0.9938
  928/60000 [..............................] - ETA: 7s - loss: 0.0124 - acc: 0.9957
 1312/60000 [..............................] - ETA: 7s - loss: 0.0168 - acc: 0.9947
 1728/60000 [..............................] - ETA: 7s - loss: 0.0145 - acc: 0.9959
...
58656/60000 [============================>.] - ETA: 0s - loss: 0.0281 - acc: 0.9911
59072/60000 [============================>.] - ETA: 0s - loss: 0.0282 - acc: 0.9911
59520/60000 [============================>.] - ETA: 0s - loss: 0.0281 - acc: 0.9911
59968/60000 [============================>.] - ETA: 0s - loss: 0.0281 - acc: 0.9911
60000/60000 [==============================] - 7s 122us/step - loss: 0.0282 - acc: 0.9911


6. 정확도 평가

test_loss, test_acc = model.evaluate(x_test, y_test)
print('테스트 정확도:', test_acc)

model.evaluate()를 이용해서 10,000개의 테스트 샘플에 대해 손실 (loss)과 정확도 (accuracy)를 평가합니다.

결과는 아래와 같습니다.

테스트 정확도: 0.9802

간단한 인공신경망과 다섯 번 에포크의 학습만으로 98.02%의 정확도로 MNIST 이미지를 분류할 수 있음을 알 수 있습니다.


Matplotlib을 이용해서 에포크에 따른 정확도 (accuracy)와 손실 (loss) 값을 확인할 수 있습니다.

loss, accuracy = [], []
for i in range(10):
    model.fit(x_train, y_train, epochs=1)
    loss.append(model.evaluate(x_test, y_test)[0])
    accuracy.append(model.evaluate(x_test, y_test)[1])

print(accuracy)

1회의 에포크마다 model.evaluate()의 loss, accuracy 값을 저장합니다.

결과는 아래와 같습니다.

_images/MNIST_accuracy_loss.png

그림. 에포크에 따른 MNIST 패턴 인식 정확도와 손실.


이렇게 학습한 모델을 사용한 손글씨 인식 GUI 프로그램은 아래의 페이지를 참고하세요.


이전글/다음글