티스토리 뷰

반응형

이전 포스팅에서는 tensorflow를 이용해서 여러개의 레이어를 쌓고 


그것을 통해 MNIST 손글씨 숫자인식을 구현해보았는데요,


CNN(Convolutional Neural Network)을 통해 더욱 높은 정확도를 구현해보겠습니다.


기본적으로 CNN이란 이전의 일반적인 네트워크랑 달리 필터라는 것을 사용합니다. 


이미지는 사실 2차원으로 구성된 데이터이기 때문에 이를 1차원으로 나열하면 이미지의 특성을 알아차리기 쉽지 않습니다.


2차원의 특성을 살리고자 CNN모델이 개발이 되었고 어떻게 구현하는지 살펴보겠습니다.



위 그림은 가장 기본적인 모델로 Convolutional LayerPooling Layer를 두개를 연달아 놓은 후 


그 데이터를 1차원으로 만들어 주고 Fully Connected Layer로 10개의 출력을 갖게 한 후


앞서 배운 Softmax에 통과 시키는 모델입니다.



Convolutional Layer란 일정 크기의 필터를 Striding하면서 계산한 결과를 모아놓은 것인데요. (Striding : 한칸씩 옆으로 이동)


예를들어 5X5 이미지가 있다면 3X3 의 필터를 각각의 행과 열에 해당하는 곳에 곱하여 9개를 모두 더한 값이 됩니다.


아래 이미지처럼 노란색박스가 필터가 되고 안에 원소를 모두 곱하여 더한 결과는 4가 되어 1행 3열에 4가 적히게 됩니다.




Pooling Layer란 아래 그림처럼 2x2필터라면 그중 가장 큰 값을 취하여 크기를 줄이는 Layer입니다.


사용하는 이유는 앞선 Convolution Layer를 통과시키면 feature가 늘어나


연산량이 굉장히 크게 늘어나는데 그렇게 되면 Overfitting 가능성이 늘어나기 때문에 이를 줄이기 위함도 있고


또한 아래와 같은 이미지에서 구간별로 가장 강한 특징만 뽑기 위함도 있습니다.


아래 그림은 max pooling으로 이외에도 다양한 pooling기법이 있습니다.


이후에는 앞선 포스팅에서 배운 ReLU라는 Activation function을 이용하여 출력을 내보내고


이떄 shape이 2차원이기 때문에 이를 1차원으로 평평하게 만들어줍니다.


그럼 Fully Connected Layer를 사용할 수 있고 10개의 출력을 통해 0~9를 표현하게되고,


각각의 값을 softmax로 어떤 숫자가 나올지 결정하게 됩니다.


이를 tensorflow 소스코드로 살펴보겠습니다.


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
31
32
33
34
35
36
import tensorflow as tf
 
class CNN:
    def __init__(self,sess):
        self.sess = sess
        self.build_net()
 
    def build_net(self):
        self.X = tf.placeholder(tf.float32,[None,784])
        X_img = tf.reshape(self.X,[-1,28,28,1])
        self.Y = tf.placeholder(tf.float32,[None,10])
 
        L1 = tf.layers.conv2d(X_img, 64, [3,3], padding='SAME', activation=tf.nn.relu)
        L1 = tf.layers.max_pooling2d(L1, [2,2], [2,2],padding='SAME')
        
        L2 = tf.layers.conv2d(L1, 64, [3,3], padding='SAME', activation=tf.nn.relu)
        L2 = tf.layers.max_pooling2d(L2, [2,2], [2,2], padding='SAME')
        
        L3 = tf.layers.flatten(L2)
        self.logits = tf.layers.dense(L3,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.001).minimize(self.cost)
 
        self.predicted = tf.argmax(self.logits,1)
        is_correct = tf.equal(self.predicted, tf.argmax(self.Y,1))
        self.accuracy = tf.reduce_mean(tf.cast(is_correct,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 get_accuracy(self, x_data,y_data):
        return self.sess.run(self.accuracy, feed_dict={self.X:x_data,self.Y:y_data})
 
    def prediction(self,x_data):
        return self.sesss.run(self.predicted, feed_diec={self.X:x_data})
cs


위와 같이 데이터 X를 X_img 라는 변수에 2차원데이터로 reshape해줍니다.


L1 은 conv을 통해 3x3크기 filter를 64개 이용해서 64개의 결과를 출력합니다.


padding은 입력과 출력의 크기가 같도록 원래 이미지의 테두리에 0을 씌워주는 역할을 합니다.


activation_fn 로 relu를 사용하였고, max_pool을 통해 2칸씩 stride하며 2x2크기중 가장 큰 값만을 취합니다.


pool에서의 padding='SAME'을 통해 원래 크기를 반으로 줄입니다.


이후 flatten을 통해 2차원 이미지를 1차원으로 펴줍니다. 


이후는 이전 포스팅과 같게 FC와 softmax로 구현하였습니다.


여기까지는 네트워크를 구성한 것이고 학습은 아래와 같습니다.


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
31
32
import tensorflow as tf
import numpy as np
import cnn_module as cnn
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("../MNIST_data/", one_hot=True)
 
sess = tf.Session()
model = cnn.CNN(sess)
sess.run(tf.global_variables_initializer())
 
batch_size = 100
total_batch = int(mnist.train.num_examples/batch_size)
 
for epoch in range(10):
    c_avg = 0
    for i in range(total_batch):
        xs, ys = mnist.train.next_batch(batch_size)
        c,_ = model.train(xs,ys)
        c_avg+=c/total_batch
 
    print('Epoch:',epoch+1,'Avg:',c_avg)
 
acc_flag = True
 
if acc_flag:
    arr_c=[]
    for i in range(10):
        xs,ys = mnist.test.next_batch(1000)
        arr_c.append(model.get_accuracy(xs,ys))
    
    print('Acc:',np.mean(arr_c))
 
cs


이전 포스팅과 같고 총 10의 에폭으로 출력결과는 다음과 같습니다.



98%의 정확도로 기존 DNN의 91%에 비해 무려 7%나 상승했습니다. 


간단한 네트워크임에도 불구하고 CNN을 통해 굉장히 높은 정확도를 얻어낼 수 있습니다.




소스코드 : https://github.com/JeonJeongMin/tensorflow-examples/blob/master/Supervised%20Learning/CNN/CNN03_MNIST_class.ipynb


이미지 출처 : http://research.binus.ac.id/airnd/2018/03/deep-learning-for-image-classification-with-keras-step-by-step-tutorial/

                  https://hunkim.github.io/ml/



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