거의 한달만에 다시 작성하네요... ㅎㅎ

코딩시간은 기존에 해뒀던 자료이용써서 5분인데...

 

Keras와 CNN 모델로 Mnist데이터 학습시키기

0. 시작전에

- Keras는 Tensorflow를 사용하는 라이브러리입니다. 따라서 Keras설치시 Tensorflow를 먼저 설치해야합니다.

- Keras와 Tensorflow 설치는 다루지 않습니다.

- 이전 Tensorflow로 CNN조지기 편을 보신 후 와주시면 좀 더 이해하기 좋습니다.

2019/05/30 - [머신러닝/CNN] - [딥러닝 CNN] 1. CNN이란?

2019/05/31 - [머신러닝/CNN] - [딥러닝 CNN] 2. mnist데이터 CNN으로 조지기(with, Tensorflow)

1. 시작

1) 주피터 노트북을 켜주시고, 아래와 같이 라이브러리와 데이터를 불러와줍니다.

이전에 Tensorflow편에서 다뤘던 Mnist자료를 그대로 사용했습니다.

 

 

2) 다음으로 아래와 같이 변수들을 설정해주었습니다.

 - IMG_CHANNELS : 이미지 채널의 수를 말합니다. (ex, rgb = 3)

 - IMG_ROWS, IMG_COLS : 이미지의 가로, 세로 픽셀의 수를 말합니다.

 - BATCH_SIZE : Batch 사이즈를 설정합니다.

 - EPOCH : Epoch의 수를 설정합니다.

 - NB_CLASSES : Y값이 몇개의 값을 갖고 있는 배열인지를 의미합니다. 우리는 0~9까지 One-hot결과를 Y값으로 사용하기 때문에 10으로 설정해주었습니다.

 - VERBOSE : Keras의 학습 단계에서 진행상태를 어떻게 표시할 것인지를 설정해주는 것입니다.

         (0 = silent, 1 = progress bar, 2 = one line per epoch.)

 - VALIDATION_SPLIT : 학습시 데이터를 일부 나눠서 Validation으로 사용할 비율을 의미합니다.

         (mnist데이터에 validation data가 별도로 존재하기는 하지만, 그냥 Train데이터의 20%를 사용했습니다.)

 - OPTIM : 옵티마이저를 어떤것으로 사용할 것인지를 의미합니다.

 

 

3) 데이터 셋팅하기

 

학습하기 좋은 상태로 데이터를 만들어줍니다.

X데이터 = [ 55000개의 이미지, 28x28의 크기, 1개의 채널 ] 을 의미합니다.

 

이미지를 학인해보면 위와같은것을 볼 수 있습니다.

배열에 One-hot으로 0~9까지의 값이 나타나는 것을 볼 수 있습니다.

 

 

4) 모델 구축하기

모델은 정말 단순하게 만들었습니다.

 

Convolution 단계 하나를 거친 후 바로 Flatten해서 바로 하나의 네트워크를 거쳐 Y값으로 나가는 정~~~~말 간단한 모델입니다.

 

 

5) 학습시키기

 

간단한 모델을 사용해도 이정도 정확도... ( Adam의 힘인가... )

맥북에서 학습시켰더니 역시 CPU버전이라 그런지 느리더군요....;;

 

 

6) 결과 확인하기

 

evaluate 함수를 이용해서 최종적으로 test accuracy를 확인해보니 98.7% 정도가 나오네요.

>> 양호

 

X_test 데이터중 하나를 뽑아서 확인해보니 위와같은 결과를 볼 수 있었습니다.

 

누가봐도 6인 데이터고, 모델도 예쁘게 6이라고 잘 예측한 것을 볼 수 있었습니다.

 

착하다 ㅎㅎ

 

 

2. 마무리

mnist 데이터 자체가 너무 잘 만들어진(?) 데이터여서 CNN을 이용하면 어떻게 해도 90%이상의 Accuracy를 얻을 수 있습니다.

그러니 여러분들도 한번 자기만의 방법으로 모델을 만들어보시기 바랍니다. ( 옵티마이저를 변경하는 것만으로도 차이가 크니 Adam추천 )

 

Keras로 모델을 구현할 때 저는 Dense를 사용했는데, 다른 방법도 존재합니다. 그부분은 다음에 다루겠습니다.

 

이 다음에는 어떤 이미지를 학습할까 고민중되네요.

Keras로 조지는 편은 다음에 이어서 올리겠습니다.

 

TensorFolw와 CNN 모델로 Mnist데이터 학습시키기

 

0. 시작전에

- TensorFlow 설치와 Keras설치에 관한것은 여기서 다루지 않습니다.

- CNN에 대한 부분은 이전 게시글을 참고해주세요.

- Keras만 갖고놀다가 TensorFlow를 잡으니 Python하다가 C언어하는 느낌이네요.

- CNN으로 조지기라고 적어두고, 내가 조져진 게시물...

 

 

1. 데이터 다운로드

일단 시작은 기본 라이브러리 호출과 데이터 다운로드부터 시작하겠습니다.

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./data/", one_hot=True)

TensorFlow는 tf라는 이름으로 불러와주었습니다.

그리고 위와같은 방법으로 데이터를 다운로드해서 mnist라는 변수에 담아주었습니다.

 

<주의>

위와 같이 코드를 실행하면 현재 파이썬파일과 함께있는 data라는 폴더에 mnist파일이 저장됩니다. data라는 폴더가 없을 경우 애러가 발생할 수 있습니다.

 

파이썬 파일과 폴더는 한 폴더에

위와같이 해당 코드를 실행하면 4개의 파일이 data의 폴더에 저장됩니다.

 

2. 데이터 확인하기

mnist 데이터를 보게되면 아래와 같이 "test", "train", "validation"이라는 3개의 데이터셋이 존재하는 것을 볼 수 있습니다.

  • TRAIN DATA : 학습을 시키는 용도의 데이터
  • VALIDATION DATA : 학습시킨 모델을 검증하는 데이터
  • TEST DATA : 최종적으로 학습시킨 모델이 판단할 데이터

Validation은 최종적으로 Test데이터를 통해서 결과를 도출하기전에 최종적으로 확인하는 용도라고 생각해주시기 바랍니다.

 

그럼 mnist.train 이하에는 어떤 데이터가 있는지 확인해보겠습니다.

mnist 데이터

위와깉이 몇개의 데이터가 보이는데 중요한건 "images"와 "labels"라고 할 수 있습니다.

 

실제 학습시킬 데이터와 그 정답이니까요.

 

한번 출력해서 확인해보겠습니다.

 

먼저 labels 부분의 5번째 데이터를 보게되면 9번째 자리에 1이 표시되어있는 것을 볼 수 있습니다.

 

이러한 형태를 One-Hot이라고해서 오로지 특정 위치 하나에만 1이 존재함으로 그 자리의 값을 특정하는 것을 말합니다.

 

위의 경우 맨 앞이 0, 마지막이 9가 되는 형태고 9번째 자리가 1인것을보면 Label은 8을 의미하고 보이시는 것 처럼 이미지도 8을 띄우고 있습니다.

 

다음으로 데이터의 크기를 확인해보겠습니다.

 

데이터의 크기 확인하기

label은 0~9까지 10개의 자리를 차지하기 때문에 10으로 나눠준 값이 총 이미지의 갯수라고 볼 수 있습니다.

 

  • train : 55000개
  • validation : 5000개
  • test : 10000개

3. 모델 구축하기

tf.set_random_seed(777)
learning_rate = 0.001
training_epochs = 10
batch_size = 100

X = tf.placeholder(tf.float32, [None, 784])
X_img = tf.reshape(X, [-1, 28,28, 1])
Y = tf.placeholder(tf.float32, [None, 10])

일단 위와같이 초기상태를 만들어주었습니다.

 

placeholder는 사용자와 모델간의 데이터 이동이 가능한 변수(?)같은 녀식입니다.

 

X 는 이미지데이터가 들어갈 공간입니다. mnist데이터는 2차원 이미지가 1차원 형태로 되어있습니다. (...;;)

 

그래서 784크기의 이미지가 X에 들어간 후 reshape를 통해서 28x28의 형태로 변형시키는 과정이 필요합니다.

 

또한 최종적으로 출력되는 Y는 One-Hot출력되기 때문에 10개의 공간을 설정해주었습니다.

 

W1 = tf.Variable(tf.random_normal([3, 3, 1, 32], stddev=0.01))
L1 = tf.nn.conv2d(X_img, W1, strides=[1, 1, 1, 1], padding="SAME")
L1 = tf.nn.elu(L1)
L1 = tf.nn.max_pool(L1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
# 14 x 14

W2 = tf.Variable(tf.random_normal([3, 3, 32, 64], stddev=0.01))
L2 = tf.nn.conv2d(L1, W2, strides=[1, 1, 1, 1], padding="SAME")
L2 = tf.nn.elu(L2)
L2 = tf.nn.max_pool(L2, ksize=[1, 1, 1, 1], strides=[1, 1, 1, 1], padding="SAME")
# 14 * 14

W3 = tf.Variable(tf.random_normal([3, 3, 64, 128], stddev=0.01))
L3 = tf.nn.conv2d(L2, W3, strides=[1, 1, 1, 1], padding="SAME")
L3 = tf.nn.elu(L3)
L3 = tf.nn.max_pool(L3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
# 7 * 7

L4_flat = tf.reshape(L3, [-1, 7*7*128])

 

그리고 대충 Convolution과 Max_pooling을 반복하는 구조를 대충 만들었습니다.

 

W(Weight)의 stddev는 랜덤한 값의 설정할 때의 표준편차입니다.

conv2d는 2차원 이미지에대한 Convolution을 의미합니다.

Padding = "SAME"은 입출력 이미지의 크기가 동일하다는 것을 말합니다.

Activation Function은 elu로 설정해주었습니다.

 

그냥 별생각없이 대충 만들어봤습니다. mnist데이터 자체가 간단한 데이터라 아마 잘 될꺼라는 믿음...으로 만들었습니다.

(gpu환경이 아니시고 컴퓨터의 사양에 자신이 없으시다면 절절하게 조정이 필요합니다.)

 

최종적으로 3개의 Conv와 Pooling 후 Flatten 과정을 수행하게됩니다.

 

이제 일반 DNN형태를 만들겠습니다.

 

hidden1 = tf.layers.dense(L4_flat, 300, name="hidden1",activation=tf.nn.elu)

hidden2 = tf.layers.dense(hidden1, 100, name="hidden2",activation=tf.nn.elu)

logits = tf.layers.dense(hidden2, 10, name="outputs")

이것도 뭐... 간단하게 만들어봤습니다.

 

아마 잘 될꺼라는 믿음으로...

 

중간 숫자 300, 100, 10은 출력의 갯수를 말합니다.

 

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

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

for epoch in range(training_epochs):
    avg_cost=0
    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!")

마지막으로 학습과정입니다.

 

저 코드를 직접 짠 기억은 없는데, 저장된 자료들중에 mnist 관련자료에 있어서 갖고왔습니다...

(아마 sung Kim님의 코드가아닐까합니다... 존경합니다.)

 

scoftmax cross entropy에 Ver2가 생겨서 적용해봤습니다.

 

Cost Function은 reduce mean을 사용했습니다.

 

optimizer는 가장 배신을 덜하는 Adam을 사용했습니다.

 

 

4. 학습

10Epoch에 cost가 0.01정도까지 떯어지네요. 일단 흠...

 

좋습니다. 테스트해서 어느정도 결과가 나오는지 확인해보겠습니다.

 

corrent_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(corrent_prediction, tf.float32))
print("Accuracy: ", sess.run(accuracy, feed_dict={X : mnist.test.images, Y : mnist.test.labels}))

실행결과 99%확률로 맞추네요~

 

잘맞추네요...;;

 

sess.close()
tf.reset_default_graph()

끝나면 위의 코드를 실행해서 초기화시켜주세요.

 

역시 Keras가 쉽습니다...;;

CNN 기초정리

원래는 mnist 데이터를 다루려고 했는데, 그래도 CNN 기초정리는 해야겠어서 잠깐 살짝 다루고 넘어가겠습니다.

 

0. 시작 전에

CNN에 대해서 깊게 설명하려면 일단 기존 DNN의 개념부터 시작해야 해서 아주~ 가볍게 설명하고 넘어가겠습니다.

혹시 추가 질문이나 문제 있는 부분은 글 남겨주세요~

 

1. CNN이란?

Convolutional Neural Network의 약자로 일반 Deep Neural Network에서 이미지나 영상과 같은 데이터를 처리할 때 발생하는 문제점들을 보완한 방법입니다.

 

어떤 문제가 있었나?

DNN은 기본적으로 1차원 형태의 데이터를 사용합니다. 쉽게 생각하면 iris데이터를 생각해보시면 됩니다.(다뤄보지 않았다면... 크흠...)

 

iris데이터를 보게 되면 Columns으로 꽃받침과 꽃잎의 길이 등이 데이터로 오게 되는데 아래와 같습니다.

 

Index 꽃받침길이 꽃받침너비 꽃잎길이 꽃잎너비 꽃의종류(Target)
1 5.1 3.5 1.4 0.2 setosa

이러한 형태의 데이터가 많이 존재하는데, 여기서 꽃받침과 꽃잎의 정보를 input데이터(=X)로하고, 꽃의 종류를 output데이터(=Y)로 설정하여 학습을 하게 됩니다

 

그리고 학습된 모델에게 꽃받침과 꽃잎에 대한 정보를 넣음으로 꽃의 종류를 맞추게 하는 모델이 되게 됩니다.

 

Iris 데이터에 대한 설명은 여기까지이고, 이러한 데이터를 1차원 데이터라고 부르는 이유는 데이터가 하나의 row로 표현되기 때문입니다.

 

하지만, 이미지는 어떤가요? 480x480 같은 형태로 표현되는 이미지는 하나의 row로 표현되지 않습니다. 물론 한 줄로 표현할 수는 있겠죠. 다만, 이미지 데이터를 하나의 row로 변환하게 되는 순간, 데이터는 큰 손실을 갖게 됩니다.

 

예를 들어 아래와 같은 강아지 사진이 있다고 봅시다.

 

귀엽...;;

이런 사진 데이터를 한 줄로 표현한다면...?

 

아래와 같은 한 줄이 됩니다... 위에서부터 1px씩 잘라서 우측에 붙이는 형태죠.

 

한줄된 강아지...ㅠㅠ

 

실제로는 더 작은 숫자들의 집합으로 이루어진 한 줄 데이터가 되겠지만, 의미적으로 봐주세요.

 

저 한 줄로 표현된 이미지와 기존의 이미지를 비교해보면 DNN으로 이미지를 학습시킬 때의 문제를 알 수 있습니다.

 

이미지 데이터는 한 점을 기준으로 그 주변 점들이 모여 하나의 객체(?)가 됩니다.

 

위 이미지에서 보면 이미지의 특정 픽셀(이미지 데이터에서 매우 작은 한 점)들이 모여 강아지라는 객체를 만들게 되는데, 한 줄로 된 row데이터에서는 이러한 연간 관계가 제거된다는 문제가 있습니다.

 

말료표현하기 어렵네요...

 

그럼 CNN에서는 어떻게 극복했을까?

 

제가 설명하기 좋은 자료를 찾기가 힘들어서... 대충 그렸습니다... ㅋㅋ

 

위와 같은 이미지가 있다고 생각해봅시다. 다음에 작업할 데이터도 숫자 이미지니 까요.

 

이 이미지는 더 자세하게 보면 아래와 같은 상태로 볼 수 있습니다.

위의 이미지의 빨간색 네모칸 하나를 1픽셀로 생각해주시고, 한 픽셀에는 흰색 또는 회색이 들어있다고 생각해주세요.

(네모칸에 회색 또는 흰색 중 많이 차지하는 녀석이 들어있다고 가정해주세요.)

위와 같은 이미지에 회색이 들어있는 픽셀은 숫자로 1이 들어있고, 흰색에는 0이 들어있다고 생각해봅시다. 그럼 아래와 같은 그림이 됩니다.

 

모든 이미지들은 기본적으로 위와 유사하게 표현됩니다. 물론 포맷(압축) 방식에 따라서 차이가 있겠지만, 우리가 다루는 대부분의 이미지는 1개의 픽셀이 RGB를 의미하는 3개의 색상 값을 갖고 있어서 이 값을 통해서 1픽셀의 색이 결정되는 형태입니다.

(즉, 한 개 픽셀도 3개의 차원으로 구성된다는 것이죠...;; 지금은 간단히 0 또는 1의 값이 있다고 합시다. 자세한 건 나중에)

 

CNN에서는 이 이미지의 한 픽셀과 주변 픽셀들의 연관관계를 유지시키며 학습시키는 것을 목표로 합니다.

 

CNN은 일단 하나의 이미지로부터 픽셀 간의 연관성을 살린 여러 개의 이미지를 생성하는 것에서 시작합니다.

 

방법은 아래와 같습니다. 3x3의 크기로 이미지를 뽑아내서 마찬가지로 3x3크기의 랜덤값을 갖고 있는 데이터와 각 픽셀을 곱해서 더해줍니다.

 

이때 랜덤값을 갖고 있는 3x3데이터를 필터라고 부릅니다.

 

계산해보면 각 필터의 값에 따라서 4, 15, 12와 같은 서로 다른 값이 발생하는 것을 알 수 있습니다.

즉, 9개의 픽셀로부터 1개의 값이 생성되며, 빨간색 칸을 한 칸씩 옮겨가며 이 값들을 하나씩 생성하게 되면 12x12 이미지에서 필터 하나가 10x10 크기의 이미지를 생성하게 됩니다.

(빨간색이 1칸씩 움직이지 않게 할 수 도있습니다. strides라는 값을 통해서 이것을 설정할 수 있습니다.)

 

필터가 3개라면 10x10 이미지 3개가 생성되겠죠.(이미지의 각 픽셀에는 계산된 값이 들어갑니다.)

 

그럼 12x12 이미지가 10x10으로 줄어드는데 괜찮은 건가?라는 의문이 들 수 있습니다.

이에 대해서는 확실하게 문제다! 문제가 아니다!라는 확실한 그건 없습니다만, 추측하기에 어쨌든 손실되는 부분이 발생한다고 생각하는 경우가 많기 때문에 이러한 문제를 해결하기 위해서 padding이라는 값을 주게 됩니다.

 

padding이란 원래 이미지의 양옆에 0 값을 갖는 데이터를 추가하여 위와 같은 방법을 취한 후에도 원래의 크기와 동일한 이미지를 유지하도록 해주는 방법입니다.

 

이러한 일련의 과정을 CNN에서는 Convolution이라고 합니다. CNN의 핵심에 해당하는 부분이죠.

 

 

Convolution이 CNN의 한 부분이라면, 그 외의 부분도 있겠죠?

Pooling이라는 녀석과, Flatten이라는 과정이 존재합니다.

 

Pooling?

Pooling은 CNN의 문제점 중 하나를 교정해주는 작업입니다.

CNN의 문제점... 시작하자마자 문제네요...

 

위에서 Convolution이라는 과정을 통해서 많은 수의 이미지를 생성한 것은 좋은데... 너무 많아졌다는 게 문제입니다.

 

하나의 이미지에서 Convolution이라는 과정을 거칠 때마다 5배씩 이미지가 생성되는데, 이미지의 크기도 줄지 않고...

 

그래서 도달한 게 Pooling이라는 과정입니다.

 

이미지를 분석하는 데 있어서 과연 Null 값과 유사한, 즉 correlation이 낮은 영역은 없을까? 하는 의문이 들지 않나요?

 

사실 존재 여부를 떠나서 사람이 그것을 판단하는 건 쉽지 않은 일입니다.

 

따라서, Convolution과 유사한 과정인데, 이미지를 5배씩 뻥튀기시키지 말고, 1개의 이미지에 1개의 출력을 만들면서 동시에 기존 이미지에 Padding 없이 Filter만 적용해서 크기를 줄이는 방법을 Pooling이라고 합니다.

 

Flatten은?

 

간단합니다. 아래를 봐주세요.

 

전체 CNN의 과정입니다.

대충 전체적인 느낌이 오시나요?

 

Colvoltuion과  Pooling을 반복해주면 이미지의 숫자는 많아지면서 크기는 점점 줄어들게 됩니다.

 

이것은 최종적으로 도출된 nxn이미지는 이미지라는 의미보다는 특정 이미지에서 얻어온 하나의 특이점 데이터가 된다는 것입니다.

 

그 말 곧, 이것은 2차원이 아닌 1차원의 Row 데이터로 취급해도 무관한 상태가 된다는 의미이기도 합니다.

 

따라서 하나의 이미지로부터 다양한 특이점들을 뽑아내고 이것을 1차원의 데이터로 변형하는 것 이게 Flatten입니다.

 

위의 이미지를 보면 이해하실 수 있습니다~~!!! 제발...

 

Flatten과정을 거치면 이후에는 그냥 DNN과 동일하게 만들어진 네트워크를 통해서 Output을 출력하게 됩니다.

 

간단한 듯 아닌듯하죠?

 

아직은 어렵지만, 이다음에 Tensorflow와 mnist 데이터를 이용해서 분석하는 실전으로 한번 더 복습하면 됩니다.

+ Recent posts