본문 바로가기

파이썬/머신러닝

[#E18] CNN을 이용한 MNIST 데이터 분류

Convolution Neural Network (CNN) 은 이미지 분석에 사용되는 인공신경망의 한 종류이므로 이를 MNIST 데이터 분류에도 사용할 수 있습니다.


먼저 다음과 같이 데이터를 불러오고, 파라미터를 설정합니다.


1
2
3
4
5
6
7
8
9
10
import tensorflow as tf
import random
 
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
 
# hyper parameters
learning_rate = 0.001
training_epochs = 15
batch_size = 100
total_batch = int(mnist.train.num_examples / batch_size)
cs


학습은 총 15 epoch 동안 진행되며, 효율적인 학습을 위해 batch_size = 100으로 설정합니다. (MNIST 데이터 갯수는 784)


이제 데이터를 담을 변수 X, Y를 설정합니다.


1
2
3
4
5
= tf.placeholder(tf.float32, [None, 784])
X_img = tf.reshape(X, [-128281])   # img 28x28x1 (black/white)
 
= tf.placeholder(tf.float32, [None, 10])
 
cs


이미지 데이터 X는 X_img처럼 CNN에서 사용할 수 있는 형태로 reshape합니다. 이 shape는 모든 이미지가 28X28X1의 구조를 가진 데이터를 의미합니다.


Y의 출력데이터는 1~ 9 이므로 10이 됩니다.


이제 FCLayer (Full Connected Layer)에 연결하기 전에 Convolution Layer와 Pool Layer를 생성, 연결합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# L1 ImgIn shape=(?, 28, 28, 1)
W1 = tf.Variable(tf.random_normal([33132], stddev=0.01))
#    Conv     -> (?, 28, 28, 32)
#    Pool     -> (?, 14, 14, 32)
L1 = tf.nn.conv2d(X_img, W1, strides=[1111], padding='SAME')
L1 = tf.nn.relu(L1)
L1 = tf.nn.max_pool(L1, ksize=[1221],
                    strides=[1221], padding='SAME')
 
# L2 ImgIn shape=(?, 14, 14, 32)
W2 = tf.Variable(tf.random_normal([333264], stddev=0.01))
#    Conv      ->(?, 14, 14, 64)
#    Pool      ->(?, 7, 7, 64)
L2 = tf.nn.conv2d(L1, W2, strides=[1111], padding='SAME')
L2 = tf.nn.relu(L2)
L2 = tf.nn.max_pool(L2, ksize=[1221],
                    strides=[1221], padding='SAME')
L2_flat = tf.reshape(L2, [-17 * 7 * 64]) # -> 3136
cs


W1은 3X3X1 의 구조를 가진 필터 32개를 의미합니다. stride는 1X1, padding은 SAME으로 설정되어있으므로 output 크기는 원본 크기와 같은 28X28이 됩니다.


이제 max_pool을 진행하는데, strides가 2X2 이고 padding이 same으로 설정되어있으므로 output 크기는 ksize(커널 사이즈)를 고려하면 공식에 의해 원본의 절반 크기인 14X14가 됩니다.


공식 : ((N - F) / strides) + 1


이제 완성된 레이어를 다음 레이어에 연결합니다. W2는 3X3X32 ( 32 = 이전 필터의 갯수 ) 구조의 필터를 64개 사용합니다.


따라서 최종적으로 완성된 output의 구조는 7X7X64입니다.


이제 완성된 레이어를 FCLayer에 연결하면 되는데, 그 전에 값을 이용할 수 있게끔 모든 데이터를 펼치는 작업이 필요합니다. 이것은 위와 같이 reshape 메소드를 이용해 쉽게 구현할 수 있습니다.


이제 FCLayer에 연결하기 위한 3136개의 데이터를 가진 N (-1) 개의 데이터셋이 완성되었습니다. 이것은 다음과 같이 FCLayer에 연결 및 학습할 수 있습니다.


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
# Final FC 7x7x64 inputs -> 10 outputs
W3 = tf.get_variable("W3", shape=[7 * 7 * 6410],
                     initializer=tf.contrib.layers.xavier_initializer())
= tf.Variable(tf.random_normal([10]))
logits = tf.matmul(L2_flat, W3) + b
 
# define cost/loss & optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    logits=logits, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
 
# initialize
sess = tf.Session()
sess.run(tf.global_variables_initializer())
 
# train my model
print('Learning started. It takes sometime.')
for epoch in range(training_epochs):
    avg_cost = 0
 
    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))
cs


테스트 및 정확도 체크는 아래의 코드를 참고하세요.


1
2
3
4
5
# Test model and check accuracy
correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print('Accuracy:', sess.run(accuracy, feed_dict={
      X: mnist.test.images, Y: mnist.test.labels}))
cs


전체 소스코드는 여기에서 볼 수 있습니다.