머신러닝

3-3 Two Hidden Layers NN MNIST 문자인식률 계산

coding art 2019. 12. 26. 17:19
728x90

 

 

 

MNIST 문제에 하나의 은닉층(Neural Layer)을 가지는 뉴럴 네트워크를 적용해 보자. MNIST 문제는 머신 러닝 연구에서 알고리듬 적용 대상 일순위로서 수많은 연구가 이루어졌으며 이미 99.7% 이상의 인식률을 성취하고 있다.

한편 뉴럴 네트워크 형태를 기본으로 하는 CNN(Convolutionary Neural Network) 딥 러닝(Deep Learning)에 의해서 98.5% 의 인식률을 넘어가 버리기 때문에 머신 러닝을 배우면서도 간과해버리는 알고리듬 중에 하나가 바로 순수한 뉴럴 네트워크 구성에 의해서 즉 CNN 과 같은 특수한 기법 적용 없이 어느 정도 높은 인식률을 얻어낼 수 있는가 평가해 볼 필요가 있다.

 

MNIST 문제에 있어서 은닉층이 하나라면 뉴럴 네트워크는 입력층, 은닉층, 출력층으로 구성이 가능하다. 입력층과 은닉층 사이에는 활성화 함수가 있어야 하며 출력층은 그 자제가 활성화 함수인 Softmax 가 사용되므로 은닉층과 출력층 사이에 별도의 활성화 함수를 넣을 필요는 없다. 입력층 다음에 넣게 될 활성화 함수로는 Relu 가 적당하다.

 

뉴럴 네트워크에서 하나의 은닉층을 도입할 경우 Depth 1 이 며 Wide 한 폭 즉 Width를 얼마로 잡느냐에 따라서 인식률이 민감하게 반응하게 된다. MNSIT 문제에서 출력층에서의 분류되는 클라스 수는 09까지의 수에 해당하는 10으로 정해져 있다. Width 의 법위는 10 이상으로서 unlimited 라 볼 수 있으나 현실적으로 CPU GPU를 사용하여 연산을 실행해야 하므로 입력 데이터 784를 기준으로 10900 의 범위를 추천한다. 784를 넘어가게 되면 컴퓨팅 부담이 늘어나지만 가장 높은 인식률을 얻을 수 있다는 점을 미리 지적해 둔다.

아울러 Wide 한계를 900으로 두고 deep=3 3개의 은닉층을 구성하여 실행해 본 결과 은닉층 하나만 사용할 때와 별반 차이가 없없 98% 수준의 인식률이 얻어진다.

 

Gradient Descent Optimizer Adam Optimizer를 사용하느냐에 따라 learning rate 값은 0.1 아니면 0.001 이 된다. Adam Optimizer 가 학습 횟수가 늘어남에 따라 능동적으로 learning rate를 조절하는 기능이 있으나 MNIST 문제에서는 Optimizer 선택에 따른 결과 영향은 미미한 듯하다.

 

 

뉴럴네트워크 코드 구조는 다음과 같이 대단히 간단한 구조를 가진다. 출력을 위한 activation function Softmax를 사용하며 cross entropy cost 함수를 사용한다.

 

다음의 계산 결과를 참조하자. 은닉층을 추가해도 문자 인식률에는 그다지 변화가 없음에 유의하자.

 

MNIST 수기문자 인식에 있어서 CNN을 사용하면 98.5%를 상회하는 인식률이 얻어지지만 2개의 은닉층을 사용하는 아주 간단한 뉴럴 네트워크를 사용해도 불과 그 차이란 것이 0.4%에 불과하다는 점을 지적한다.

항간에 MNIST 머신 러닝에 관한 문헌자료를 서베이 해보면 르칸(LeCUN)이 모든 공적을 다 세운 것으로 오해할 수도 있으나 꼭 그런 것은 아닌 듯하다. 현재의 코드에 사용된 활성화 함수 ReLU만 해도 1980년대 Back Propagation 이론 수립에 많은 기여를 했던 Geoffrey Hinton 교수가 2000년대에 적극적인 활용을 통해 딥러니닝에 큰 기여를 했다는 점이다.

 

관련된 알고리듬들에 관해서는 현재 교보문고 POD 도서로 필자가 펴낸 2권의 저서 많은 부분에서 그 흔적을 찾아 볼 수 있을 것입니다.

 

 

 

#covariance_mnist_gd_2hid_01.py

#MNIST_NN
import tensorflow as tf
import random
import time
from tensorflow.examples.tutorials.mnist import input_data

start_time = time.time()
tf.set_random_seed(777)  #reproducibility

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

#parameters
learning_rate = 0.1
training_epochs = 1
batch_size = 100
dof1 = 900
dof2 = 10

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

W0 = tf.Variable(tf.random_normal([784, dof1], stddev=0.01))
b0 = tf.Variable(tf.random_normal([dof1], stddev=0.01))
W1 = tf.Variable(tf.random_normal([dof1, dof2], stddev=0.01))
b1 = tf.Variable(tf.random_normal([dof2], stddev=0.01))
L1 = tf.matmul(X, W0) + b0
L1 = tf.nn.relu(L1)
hypothesis =(tf.matmul(L1, W1) + b1)
#define cost/loss & optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=hypothesis, labels=Y))
#optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate).minimize(cost)
   
#initialize
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for epoch in range(training_epochs):
    avg_cost = 0
    total_batch = 20000
    #total_batch = int(mnist.train.num_examples / batch_size)
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        feed_dict = {X: batch_xs, Y: batch_ys}
        c, _ = sess.run([cost, optimizer], feed_dict=feed_dict)
        avg_cost += c / total_batch
           
    print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))
    print('Learning Finished!')
       
    #Test model and check accuracy
    correct_prediction = tf.equal(tf.argmax(hypothesis, 1), tf.argmax(Y, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
    print('Accuracy:', sess.run(accuracy, feed_dict={ X: mnist.test.images, Y: mnist.test.labels}))
       
    #Get one and predict
    r = random.randint(0, mnist.test.num_examples - 1)
    print('lr=:', learning_rate)
    print("Label: ", sess.run(tf.argmax(mnist.test.labels[r:r + 1], 1)))
    print("Prediction: ", sess.run(tf.argmax(hypothesis, 1), feed_dict={X: mnist.test.images[r:r + 1]}))
       
end_time = time.time()
print( "Completed in ", end_time - start_time , " seconds")