tensorflow의 examples들 중 mnist를 이용해서 간단한 CNN을 구축해 볼 것이다.

우리는 0~9까지 이미지를 구별해 내는 CNN 모델을 구축할 것이다.

이미 만들어진 코드를 참고하여 수행과정에서 나올 수 있는 에러와 추가 설명을 부가하여 설명한다.

 

우선 첫번째로 데이터 셋을 불러온다.

 

1. MNIST 데이터 셋 불러오기

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

가끔 tensorflow의 example module을 불러올 때, tf를 정상적으로 다운로드 받음에도 불구하고

대표적인 'no moduled'에러 같은것이 발생한다.

이유는 tf 버전이 2.0이상이면 tutorial module을 자동으로 다운받지 않기 때문이다.  

그래서 1.14.0버전을 사용할 것을 권장한다.

 

mnist = input_data.read_data_sets('MNIST_data',one_hot=True, reshape=False)

MNIST_data인 data set을 읽어올때는 이미지 그대로 불러오기 위해 reshape=False(numpy에 있는 함수)로 지정해주고 

one_hot coding 형태로 읽어온다.

읽어온 이미지의 사이즈는 28*28*1 이다. 

 

 

One hot incoding은 특정 상수값으로 표현된 Y를 Matrix 형태로 바꿔주는 방법이다.

One hot incoding

 

2. CNN 모델 설정하기

CNN 모델 설정

좋은 모델을 만드는 것은 여러 방법이 있지만 가장 간단히 표현하기 위해

Convultion layer를 2번 거치고 Fully connected Layer로 0~9사이의 값을 판별할 것 이다.

 

CNN의 특징은 일반 뉴럴네트워크를 수행하기 이전에 이미지로부터 Feature를 먼저 뽑아내어서 이를 전달해

NN를 수행하는 것 이다.

Convolution을 수행하는 계층은 크게 두가지로 구성되어져 있다.

(1) Convolution layer는 이미지로부터 특징을 추출하는 Filter 기능을 한다. 

(2) 필터값을 비선형값으로 바꿔주는 Activation 함수로 이루어진다.

 

일단 이미지를 4부분으로 쪼개어서 28*28*1의 이미지를 14*14*4의 형태로만들어 주고 

이를 한번 더 수행해 7*7*8의 형태로 바꾸어 줄 것 이다.

 

 

X= tf.placeholder(tf.float32, shape=[None,28,28,1])
Y_Label = tf.placeholder(tf.float32, shape=[None,10])

입력 데이터는 학습을 위해 계속해서 업데이트 해줘야 하고 

Y_Label 또한 미리 정한 결과를 계속 직접 넣어줄 것이다. 

 

tensorflow에서 데이터 입력 받는 방법중에서 상수와 변수를 입력받는 방법도 있지만

데이터의 형태만 지정하고 실제 데이터는 실행단계에서 입력받을 수 있도록 해주는 방법이 있다.

그것이 placeholder()함수인데

사용법은 아래와 같다.

 

 

placeholder 사용법

데이터의 타입을 무조건 지정해주고 입력데이터의 형태를 주어야한다.

 

우리의 예제에서는 shape이 [None, 28,28,1]의 형태를 띄고 있는데

맨 앞의 None은 앞으로 우리가 배치수행을 할 것이기 때문에 None으로 배치수행할만큼의 데이터 공간을 미리 확보해 주는 것이다.

----------------------------------------------------------------------------------------------------------------------------

* 배치수행이란? 우리가 일반적으로 작업을 수행할때 모두 데이터를 불러놓고 수행하는 방식을 말한다.

온라인 수행은 필요한 데이터를 매번 불러오는 것인데 실제 데이터분석필드에서는 데이터를 불러오기만 해도 

메모리를 모두 할당하고 있는 경우가 많기 떄문에 온라인 수행이 당연해졌다.

----------------------------------------------------------------------------------------------------------------------------

 

3. Convolution layer 생성

 

Convolution + Relu + Maxpooling을 거쳐 28*28*1을 14*14*4의 형태로 변형할 것이다.

 

convolution 후 relu activation 수행, maxpooling을 마지막으로 수행

 

우선 kernel과 bias값을 생성하고 convolution lyaer, activation function, pooling을 수행하는 코드를 작성해 볼 것이다.

Kernel1 = tf.Variable(tf.truncated_normal(shape=[4,4,1,4],stddev=0.1))

kernel은 filter와 같은데 filter는 이미지 특징을 찾아내기 위한 공용 파라메터이다.

일반적으로 4*4나 3*3과 같은 정사각 행렬로 정의하고 

지정된 간격대로 순회하며 채널별로 합성곱을 하는 과정을 convolution이라고 한다.

그리고 convolution을 적용한 input image의 결과물을 Feature Map 또는 activation map이라고 부른다. 

filter를 이용한 convolution과정

filter가 되어줄 variable을 위와같이 설정한 뒤,  kernel을 사용해 convolution한 뒤 같은 사이즈만큼 더해주기 위한 변수를 만들어야한다.

4장을 만들어 주었기 때문에 사이즈는 4로 설정해주어야 한다.

Bias1 = tf.Variable(tf.truncated_normal(shape=[4],stddev=0.1))

 이제 실제 Convolution과정을 수행해보아야 하는데 

아래의 코드를 수행해준다.

Conv1 = tf.nn.conv2d(X, Kernel1, strides = [1,1,1,1],padding='SAME')+ Bias1

입력된 이미지 X에 만들어준 필터 Kernel1을 Convolution 곱해주는데 

filter가 이동하는 간격을 의미한는 stride를 설정하고, 데이터 손실이 얼마나 있을지 고려해 padding을 'SAME'으로 한다. stride는 주로 중앙에 2값을 이용한다. 예를 들어, 2칸씩 이동하는게 목적이라면

stride =[1,2,2,1]의 형태로 준다.

특히 padding을 하는 이유는, 실제 원본의 사이즈 (예를 들면, 5*5)보다 filter를 적용하고 나서 이미지가 

3*3으로 줄어들 수가 있는데 이떄 데이터 손실이 나기 때문에 이부분을 보정해주기 위해서 사용된다.

원래 이미지 주변의 0 값을 넣어주어 입력값의 크기를 인위적으로 키워서 결과값이 작아지는 것을 막는다. 

또한 오버피팅도 방지하는데 원본 데이터에 0값을 넣어 원래의 특성을 희석시켜서 

머신러닝이 트레이닝값에만 정확히 맞아들어가는 것을 방지한다.

Activation1 = tf.nn.relu(Conv1)

convolution을 하고나면 feature맵은 정량적인 값을 갖게 되는데 이를 특징이 '있다 없다'로 표현하기 위해 비선형화를 시키려고 한다. 그것이 activation 함수이다. 

activation함수로 여러가지를 쓰는데 주로 relu함수를 사용한다. 이유는 backpropagation이 제대로 작동하지 않아 에러가 희석되는 현상 ( gradient vanishing)이 일어나기 때문이다. 

Pool1 =tf.nn.max_pool(Activation1, ksize =[1,2,2,1],strides = [1,2,2,1], padding='SAME')

 

4. Fully connected layer 만들기

 

이제 Convolution + Activation Function + Pooling을 모두 수행하여 하나의 layer를 만들고 

우리가 목표했던 2 convolution layer를 거치기 위해 동일한 layer하나를 더 만들어 준다. 

Kernel2 = tf.Variable(tf.truncated_normal(shape=[4,4,4,8],stddev=0.1))
Bias2 = tf.Variable(tf.truncated_normal(shape=[8],stddev=0.1))
Conv2 = tf.nn.conv2d(Pool1, Kernel2, strides = [1,1,1,1],padding='SAME')+ Bias2
Activation2 = tf.nn.relu(Conv2)
Pool2 =tf.nn.max_pool(Activation2, ksize =[1,2,2,1],strides = [1,2,2,1], padding='SAME')

 

마지막으로 convoultion과정을 거친 layer를 기존의 뉴럴네트워크에 넣어 분류한다. 실제로 어떤 이미지인지 판별해주는 구간을 만드는 것이다.

W1 = tf.Variable(tf.truncated_normal(shape=[8*7*7,10]))
B1 = tf.Variable(tf.truncated_normal(shape=[10]))
Pool2_flat = tf.reshape(Pool2,[-1,8*7*7])
OutputLayer = tf.matmul(Pool2_flat,W1)+B1

*matmul 함수: 삼차원 텐서 사이의 행렬곱을 수행해주는 함수 

 

W1과 B1은 일반적인 머신러닝에서 볼 수 있는 단순선형관계를 위한 변수들이다. 

W1d은 8*8*7을 10개 받는 variable이며, B1은 output을 10개로 받기 위해 10개의 Bias를 생성한다.

우선 OuputLayer를 보면 선형관계식으로 나타내는 것을 볼 수있다. 이는 일반적인 머신러닝과 같이 

가장 단순한 선형관계로 설명하려는 목적을 갖고 있기 때문에 '입력값 * W1 + B1'의 형태를 띄는 것이다.

 

 

CNN의 최종모델

위 그림은 우리가 수행한 전체적인 모델 구축과정인데 CNN의 가장 큰 특징인 Dropout Layer를 짚고 넘어가도록 하겠다.

* Dropout Layer란 Fully-connected Layer와 Softmax Function사이의 계층으로 오버피팅을 막기위해

뉴럴 네트워크가 학습중일때 랜덤하게 뉴런을 꺼서 학습을 방해함으로써 학습이 학습용 데이터에 치우치는 현상을 막는다.

 

5. Loss function과 Optimizer설정

 

모델을 학습시킨 후 결과값이 실제값과 얼마나 차이가 나는지 확인하기 위하여 Loss값을 계산해 줍니다.

Loss = tf.reduce_mean(tf.nn.sortmax_cross_entropy_with_logits(labels=Y_label, logits=OupputLayer))

reduce_mean: 열의 평균을 구해주는 함수

softmax_cross_entropy_with_logits: multiclassification에서 사용되는 softmax와 cross_entropy가 내장된 함수, labels= 실제값, logits은 모델의 output값을 주면 된다.

 

*softmax는 multiclassification를 할때 입력받은 값을 0~1사이의 값으로 바꿔주고 총합이 1이 되도록 만드는 함수이다.

분류하고 싶은 class개수만큼 만들어지고 가장 큰 출력값을 받은 것이 확률이 가장 크다.

*cross_entropy는 분류모델에서 사용되는 loss function의 한 종류이다.

 

train_step = tf.train.AdamOptimizer(0.005).minimize(Loss)

Loss함수를 정의하고 Optimization 과정을 거쳐 Loss를 최소화 시켜주어 우리 모델을 최적화할 것이다.

correct_prediction = tf.equal(tf.argmax(OutputLayer,1),tf.argmax(Y_Label,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

그리고 실제 값과 모델이 학습한 값이 동일한지 correct_prediction으로 해주고, 

accuracy에서는 맞거나 틀린것들에 대한 평균을 내준다.

 

6. Run

with tf.Session() as sess:
    print('start....')
    sess.run(tf.global_variables_initializer())
    for i in range(10000):
        trainingData, Y = mnist.train.next_batch(64)
        sess.run(train_step, feed_dict={X:trainingData, Y_Label:Y})
        if i%100:
            print(sess.run(accuracy, feed_dict={X:mnist.test.images, Y_Label:mnist.test.labels}))

C에서 이루어지는 연산이므로 Sess를 얻어와서 진행을 하고 변수들을 tf.global_variables_initializer()을 사용해서 꼭 초기화해주어야 합니다. 

 

위의 코드는 10000번의 학습으로 64개의 배치크기만큼 가져오고 100번마다 test데이터셋을 통해 정확도를 확인한 것입니다. 

 

 

 

 

출처페이지는 

https://coderkoo.tistory.com/13

 

간단한 CNN(Convolutional neural network) 만들어보기

텐서플로우로 간단한 CNN(Convolutional neural network) 만들어보기 이번 글에서는 MNIST 데이터 셋을 이용해서 텐서플로우에서 CNN을 구성해봅니다. 즉, MNIST 데이터셋을 읽어와서 필기체숫자가 0~9 중 무엇인..

coderkoo.tistory.com

 

'데이터분석 > 딥러닝' 카테고리의 다른 글

GAN 모델이란?  (2) 2021.04.06
CNN으로 개와 고양이 분류하기  (1) 2020.02.25
배치학습 vs 온라인학습  (0) 2020.02.12

+ Recent posts