본문 바로가기

etc/FastCampus 챌린지

[패스트캠퍼스 수강 후기] 컴퓨터비전인강 100% 환급 챌린지 36 회차

728x90
반응형

MNIST CNN 모델


우리가 만들고자 하는 모델은 두개의 컨볼루셔널 레이어(Convolutional layer)과, 마지막에 풀리 커넥티드 레이어 (fully connected layer)을 가지고 있는 컨볼루셔널 네트워크 모델(CNN) 이다.
모델의 모양을 그려보면 다음과 같다.


입력 데이타

입력으로 사용되는 데이타는 앞의 소프트맥스 예제에서 사용한 데이타와 동일한 손으로 쓴 숫자들이다. 각 숫자 이미지는 28x28 픽셀로 되어 있고, 흑백이미지이기 때문에 데이타는 28x28x1 행렬이 된다. (만약에 칼라 RGB라면 28x28x3이 된다.)

컨볼루셔널 계층

총 두 개의 컨볼루셔널 계층을 사용했으며, 각 계층에서 컨볼루셔널 필터를 사용해서, 특징을 추출한다음에, 액티베이션 함수 (Activation function)으로, ReLu를 적용한 후, 맥스풀링 (Max Pooling)을 이용하여, 주요 특징을 정리해낸다.
이와 같은 컨볼루셔널 필터를 두개를 중첩하여 적용하였다.

마지막 풀리 커넥티드 계층

컨볼루셔널 필터를 통해서 추출된 특징은 풀리 커넥티드 레이어(Fully connected layer)에 의해서 분류 되는데, 풀리 커넥티드 레이어는 하나의 뉴럴 네트워크를 사용하고, 그 뒤에 드롭아웃 (Dropout) 계층을 넣어서, 오버피팅(Overfitting)이 발생하는 것을 방지한다.  마지막으로 소프트맥스 (Softmax) 함수를 이용하여 0~9 열개의 숫자로 분류를 한다.

학습(트레이닝) 코드

이를 구현하기 위한 코드는 다음과 같다.

코드
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data

tf.reset_default_graph()

np.random.seed(20160704)
tf.set_random_seed(20160704)

# load data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)

# define first layer
num_filters1 = 32

x = tf.placeholder(tf.float32, [None, 784])
x_image = tf.reshape(x, [-1,28,28,1])

W_conv1 = tf.Variable(tf.truncated_normal([5,5,1,num_filters1],
                                         stddev=0.1))
h_conv1 = tf.nn.conv2d(x_image, W_conv1,
                      strides=[1,1,1,1], padding='SAME')

b_conv1 = tf.Variable(tf.constant(0.1, shape=[num_filters1]))
h_conv1_cutoff = tf.nn.relu(h_conv1 + b_conv1)

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

# define second layer
num_filters2 = 64

W_conv2 = tf.Variable(
           tf.truncated_normal([5,5,num_filters1,num_filters2],
                               stddev=0.1))
h_conv2 = tf.nn.conv2d(h_pool1, W_conv2,
                      strides=[1,1,1,1], padding='SAME')

b_conv2 = tf.Variable(tf.constant(0.1, shape=[num_filters2]))
h_conv2_cutoff = tf.nn.relu(h_conv2 + b_conv2)

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

# define fully connected layer
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*num_filters2])

num_units1 = 7*7*num_filters2
num_units2 = 1024

w2 = tf.Variable(tf.truncated_normal([num_units1, num_units2]))
b2 = tf.Variable(tf.constant(0.1, shape=[num_units2]))
hidden2 = tf.nn.relu(tf.matmul(h_pool2_flat, w2) + b2)

keep_prob = tf.placeholder(tf.float32)
hidden2_drop = tf.nn.dropout(hidden2, keep_prob)

w0 = tf.Variable(tf.zeros([num_units2, 10]))
b0 = tf.Variable(tf.zeros([10]))
k = tf.matmul(hidden2_drop, w0) + b0
p = tf.nn.softmax(k)

#define loss (cost) function
t = tf.placeholder(tf.float32, [None, 10])
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(k,t))
train_step = tf.train.AdamOptimizer(0.0001).minimize(loss)
correct_prediction = tf.equal(tf.argmax(p, 1), tf.argmax(t, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

# prepare session
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()

# start training
i = 0
for _ in range(1000):
   i += 1
   batch_xs, batch_ts = mnist.train.next_batch(50)
   sess.run(train_step,
            feed_dict={x:batch_xs, t:batch_ts, keep_prob:0.5})
   if i % 500 == 0:
       loss_vals, acc_vals = [], []
       for c in range(4):
           start = len(mnist.test.labels) / 4 * c
           end = len(mnist.test.labels) / 4 * (c+1)
           loss_val, acc_val = sess.run([loss, accuracy],
               feed_dict={x:mnist.test.images[start:end],
                          t:mnist.test.labels[start:end],
                          keep_prob:1.0})
           loss_vals.append(loss_val)
           acc_vals.append(acc_val)
       loss_val = np.sum(loss_vals)
       acc_val = np.mean(acc_vals)
       print ('Step: %d, Loss: %f, Accuracy: %f'
              % (i, loss_val, acc_val))

saver.save(sess, 'cnn_session')
sess.close()

데이타 로딩 파트

그러면 코드를 하나씩 살펴보도록 하자.
맨 처음 블럭은 데이타를 로딩하고 각종 변수를 초기화 하는 부분이다.
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data

#Call tf.reset_default_graph() before you build your model (and the Saver). This will ensure that the variables get the names you intended, but it will invalidate previously-created graphs.

tf.reset_default_graph()

np.random.seed(20160704)
tf.set_random_seed(20160704)

# load data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)

Input_data 는 텐서플로우에 내장되어 있는 MNIST (손으로 쓴 숫자 데이타)셋으로, read_data_sets 메서드를 이요하여 데이타를 읽었다. 데이타 로딩 부분은 앞의 소프트맥스 MNIST와 같으니 참고하기 바란다.

여기서 특히 주목해야 할 부분은 tf.reset_default_graph()  인데, 주피터 노트북과 같은 환경에서 실행을 하게 되면, 주피터 커널을 리스타트하지 않는 이상 변수들의 컨택스트가 그대로 유지 되기 때문에, 위의 코드를 같은 커널에서 tf.reset_default_graph() 없이, 두 번 이상 실행하게 되면 에러가 난다. 그 이유는 텐서플로우 그래프를 만들어놓고, 그 그래프가 지워지지 않은 상태에서 다시 같은 그래프를 생성하면서 나오는 에러인데, tf.reset_default_graph() 메서드는 기존에 생성된 디폴트 그래프를 모두 삭제해서 그래프가 중복되는 것을 막아준다. 일반적인 파이썬 코드에서는 크게 문제가 없지만, 컨택스트가 계속 유지되는 주피터 노트북 같은 경우에는 발생할 수 있는 문제이니, 반드시 디폴트 그래프를 리셋해주도록 하자

첫번째 컨볼루셔널 계층


728x90
반응형