티스토리 뷰

반응형

이번에는 tensorflow로 손글씨(MNIST)를 분류하는 것을 구현할 것입니다.


MNIST란 0~9까지의 숫자를 손글씨로 표현한 데이터입니다.


tensorflow로 이 데이터를 쉽게 불러올 수 있습니다.


이전까지 Linear Regression, Logisitc Regression을 통해 선형적인 것과 이항적인 것을 분류하는 것을 했었는데,


이 MNIST데이터는 0~9까지 multi class를 분류해야 합니다.


이를 학습하기 위해 나온 함수는 softmax입니다.


소스를 통해 살펴보겠습니다.


1
2
3
4
5
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
cs


우선 위와같이 각 모듈을 import 해주고


mnist 데이터를 불러옵니다 "MNIST_data/"는 저장할 경로이고 one_hot은 Y데이터를 0~9가 아닌


0 - [1,0,0,0,0,0,0,0,0,0]

1 - [0,1,0,0,0,0,0,0,0,0]

2 - [0,0,1,0,0,0,0,0,0,0]


순으로 불러오는 것을 의미합니다.


이번에는 class로 구현하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class DNN:
    def __init__(self,sess):
        self.sess = sess
        self.network()
        
    def network(self):
        
        self.X = tf.placeholder(tf.float32,[None,784])
        self.Y = tf.placeholder(tf.float32,[None,10])
        
        L1 = tf.layers.dense(self.X,256,activation=tf.nn.relu)
        L2 = tf.layers.dense(L1,256,activation=tf.nn.relu)
        self.logits = tf.layers.dense(L2,10,activation=None)
        
        self.cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=self.logits,labels=self.Y))
        self.optimizer = tf.train.AdamOptimizer(0.01).minimize(self.cost)
        
        self.predicted = tf.argmax(self.logits,1)
        correction = tf.equal(self.predicted, tf.argmax(self.Y,1))
        self.accuracy = tf.reduce_mean(tf.cast(correction,tf.float32))
        
    def train(self,x_data,y_data):
        return self.sess.run([self.cost, self.optimizer],feed_dict={self.X:x_data, self.Y:y_data})
    
    def predict(self,x_data):
        return self.sess.run(self.predicted,feed_dict={self.X:x_data})
    
    def get_accuracy(self,x_test,y_test):
        return self.sess.run(self.accuracy,feed_dict={self.X:x_test,self.Y:y_test})
        
cs


여러 개의 Layer를 사용할 것이므로 DNN이라는 이름의 class를 만들었습니다.


__init__함수를 통해 sess를 불러오고 network를 구성합니다.


이때 MNIST데이터는 28*28의 데이터로 총 784개의 데이터로 구성되어있습니다.


따라서 X의 shape은 [None, 784]로 Y의 shape은 one_hot으로 구성하였기 때문에 [None, 10] 가 됩니다.


256개의 hidden layer를 가지는 두개의 층을 통과하고 


최종적으로 10개의 출력을 내어 logits 이라는 변수에 저장합니다.


이를 tf.nn.softmax_cross_entropy_with_logits_v2(logits=, labels=) 함수를 통과시켜 cost 함수를 만듭니다.


여기서 softmax란 출력의 결과를 확률적으로 표현하게 만든 것을 말합니다.




위의 수식을 보면 한 클래스의 값을 출력된 모든 클래스exp(y_i)값의 총합으로 나눠줍니다. 


따라서 0~1값을 가지게 되며 가장 큰 값을 갖는 것으로 분류하게 됩니다. 


cost 함수는 아래와 같습니다.



여기서 p는 실제 값이고 q는 예측한 값(0~1)입니다. 


예를들어 분류의 경우가 3가지일 때, one-hot 인코딩을 하면 


0-[1 0 0] 1-[0 1 0], 2-[0 0 1] 이렇게 됩니다.


실제 값이 0이고 예측된 값이 [0.9 0.1 0.1]로 올바른 분류를 했다면 cost 값은 1*(-log(0.9))로 0에 가깝습니다.


하지만 실제 값이 0인데 예측된 값이 [0.1 0.9 0.1] 이라면 cost값은 1*(-log(0.1))로 무한대에 가까워집니다.


예측을 올바르게 한 경우 cost는 작아지고 틀리게 한 경우 값이 매우 커져 이를 바탕으로 학습하게 되는 것입니다.


이렇게 학습한 후에 get_accuracy()함수를 통해 정확도를 확인해 보면 아래와 같습니다.


1
2
xs,ys = mnist.test.next_batch(10000)
print('Acc:',model.get_accuracy(xs,ys))
cs

10000개의 test데이터를 한번에 불러와 정확도를 측정하였습니다.

96.82%로 두개의 256층을 갖는 레이어를 통과 시켰음에도 불구하고

굉장히 높은 정확도를 보이는 것을 알 수 있습니다.




반응형
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday