MNIST 학습 모델 만들기

실습 환경은 Python 3.6과 tensorflow 1.5이다.

 

MNIST

출처: 위키백과

 

손으로 쓴 숫자 이미지를 모아 둔 데이터셋. 데이터가 잘 정제되어 있어, 학습자들에게 머신러닝 학습의 기초로 쓰인다.

 


 

1.  데이터셋 읽어 오기

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

# read MNIST data
mnist = input_data.read_data_sets("./mnist/data/", one_hot=True)

다음과 같이 간단하게 데이터를 읽어올 수 있다.

 

 

2. 신경망 모델 구성

MNIST 손글씨 이미지는 28x28 pixel로 이루어져 있다. 즉, 784개의 특징(X)으로 이루어져 있다.

label data(Y)로는 0부터 9까지의 숫자인 10개의 결괏값이 존재한다. 따라서 입력층은 784개, 출력층은 10개의 노드로 구성된다고 볼 수 있다.

따라서, 플레이스홀더는 다음과 같이 구성된다.

X = tf.placeholder(tf.float32, [None, 784])
Y = tf.placeholder(tf.float32, [None, 10])

데이터를 학습할 때에는 일반적인 컴퓨터의 성능을 고려하여 데이터를 적당한 크기로 쪼개 학습하는 미니배치를 사용한다.

플레이스홀더 X와 Y의 첫 번째 차원을 None으로 두는 이유는 이것 때문이다. None의 값에 따라 한 번에 학습시킬 MNIST 이미지의 개수가 정해진다.

 

계층의 구성은 아래와 같다.

# 은닉층 1
W1 = tf.Variable(tf.random_uniform([784, 256], stddev=0.01))
L1 = tf.nn.relu(tf.matmul(X, W1))

# 은닉층 2
W2 = tf.Variable(tf.random_uniform([256, 256], stddev=0.01))
L2 = tf.nn.relu(tf.matmul(L1, W2))

# 출력층
W3 = tf.Variable(tf.random_uniform([256, 10], stddev=0.01))
model = tf.matmul(L2, W3)

stddev=0.01은 표준편차가 0.01인 정규분포 내 임의의 값을 반환한다.

 

다음으로, 손실과 최적화를 수행한다.

# 손실
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=model, labels=Y))

# 최적화
optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)

 

 

3. 학습

학습을 진행하기에 앞서, 데이터의 구분에 대해 잠깐 짚고 넘어가도록 하자.

학습 데이터는 반드시 학습 데이터테스트 데이터로 나누어져야 한다. 이는 과적합 현상(학습 데이터의 예측률은 높으나, 실제 데이터의 예측률이 저조한 현상)을 예방하기 위함이다.

 

MNIST 데이터셋은 6만 개의 train data와 1만 개의 test data를 제공한다. 이는 각각 mnist.train과 mnist.test를 통해 사용할 수 있다.

 

이제 정말 학습을 실행해보자.

init = tf.global_variables_initializer()

sess = tf.Session()
sess.run(init)

변수를 초기화하고 세션을 만든다.

 

아까도 말했듯, 우리는 저조한 컴퓨터 성능으로 어떻게든 학습을 돌리기 위해 미니배치를 이용해야 한다. 따라서 미니배치의 크기를 지정하고 이로부터 미니배치의 총 개수를 얻는다.

# 미니배치 크기
batch_size = 100
# 미니배치의 총 개수
total_batch = int(mnist.train.num_examples / batch_size)

 

학습을 15회 수행한다.

for epoch in range(15):
    total_cost = 0

    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        _, cost_val = sess.run([optimizer, cost], feed_dict={X: batch_xs, Y: batch_ys})

        total_cost += cost_val

    print('Epoch:', '%04d'%(epoch+1),
          'Avg. cost =', '%.3f'%(total_cost/total_batch))

여기서 학습은 epoch(에포크)라고 부르는데, 이는 학습 데이터의 전체를 한 바퀴 돈다는 의미를 갖는다.

중첩 반복문 내에서는 미니배치의 개수만큼 학습이 진행된다. 매 학습마다 에포크와 평균 손실을 출력하여 변화를 확인할 수 있도록 했다.

 

is_corerct = tf.equal(tf.argmax(model, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_corerct, tf.float32))
print("정확도:", sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels}))

정확도도 확인해보자.

 

학습을 수행한 결과는 다음과 같았다.

Epoch: 0001 Avg. cost = 0.399 
Epoch: 0002 Avg. cost = 0.151 
...(중략)
Epoch: 0014 Avg. cost = 0.013 
Epoch: 0015 Avg. cost = 0.011
정확도: 0.9799 

정확도가 상당히 높은 것을 알 수 있다.