실습 환경은 Python 3.6과 tensorflow 1.5이다.
CNN(합성곱 신경망)
이미지 인식 분야에 주로 사용되는 신경망. 기본적으로 컨볼루션 계층과 풀링 계층으로 구성된다.
- 컨볼루션(합성곱) 계층
2차원 평면 행렬에서 지정된 윈도우의 값에 가중치와 편향을 적용해 하나의 값으로 압축하는 계층
한 윈도우당, 가중치는 윈도우의 크기와 같은 가중치를 곱해야 한다. 편향은 1개만 있으면 된다.
ex) 28x28 입력층(이미지)에 대하여 3x3의 윈도우를 구성했을 때 필요한 최소 가중치의 개수는 3x3 9개, 편향의 개수는 9개이다.
왜 최소라고 적었냐면, 윈도우가 이동할 때 몇 칸씩 이동하냐에 따라 필요한 윈도우 개수가 달라지기 때문이다. 이 이동 범위를 우리는 스트라이드(stride)라고 부른다.
또한 이 한 윈도우에 필요한 가중치와 편향을 우리는 커널(kernal) 또는 필터(filter) 라고 부른다.
복잡한 특징을 가진 이미지들을 잘 분석하기 위해서, 윈도우 당 여러 개의 커널이 사용된다.
- 풀링 계층
지정된 윈도우 내에서 단순히 한 값을 선택해 다음 계층으로 내보내는 계층
합성곱 신경망을 사용하여 이전의 MNIST 모델을 재구성해보자. 계층 구성과 학습의 일부분만 수정하였다.
2020/07/19 - [개발 일지/ML] - MNIST 학습 모델 만들기
- 계층 구성 with 컨볼루션 계층, 풀링 계층
# 컨볼루션 계층
W1 = tf.Variable(tf.random_normal([3, 3, 1, 32], stddev=0.01))
L1 = tf.nn.conv2d(X, W1, strides=[1, 1, 1, 1], padding='SAME')
L1 = tf.nn.relu(L1)
# 풀링 계층
L1 = tf.nn.max_pool(L1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 은닉층 2
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.relu(L2)
L2 = tf.nn.max_pool(L2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
# 완전 연결 계층: 인접한 계층의 모든 뉴런과 상호 연결
# 직전의 풀링 개수 7*7*64
W3 = tf.Variable(tf.random_normal([7*7*64, 256], stddev=0.01))
L3 = tf.reshape(L2, [-1, 7*7*64])
L3 = tf.matmul(L3, W3)
L3 = tf.nn.relu(L3)
L3 = tf.nn.dropout(L3, keep_prob)
# 출력층
W4 = tf.Variable(tf.random_normal([256, 10], stddev=0.01))
model = tf.matmul(L3, W4)
- 학습: 규격에 맞는 입력값의 재구성
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
batch_size = 100
total_batch = int(mnist.train.num_examples / batch_size)
for epoch in range(15):
total_cost = 0
for i in range(total_batch):
batch_xs, batch_ys = mnist.train.next_batch(batch_size)
# 모델에 입력값을 28x28 형태로 전달하기 위한 이미지 재구성
batch_xs = batch_xs.reshape(-1, 28, 28, 1)
# 학습 시에는 뉴런의 0.8만 사용
_, cost_val = sess.run([optimizer, cost], feed_dict={X: batch_xs,
Y: batch_ys,
keep_prob: 0.8})
total_cost += cost_val
print('Epoch:', '%04d'%(epoch+1),
'Avg. cost =', '%.3f'%(total_cost/total_batch))
is_corerct = tf.equal(tf.argmax(model, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_corerct, tf.float32))
print("정확도:", sess.run(accuracy, feed_dict={X: mnist.test.images.reshape(-1, 28, 28, 1),
Y: mnist.test.labels,
keep_prob: 1}))
학습 속도가 상당히 느리다(이 포스팅을 쓰는 동안 고작 4회 학습하였다).
한참을 기다려 얻어낸 결과는 다음과 같았다.
Epoch: 0001 Avg. cost = 0.356
Epoch: 0002 Avg. cost = 0.109
Epoch: 0003 Avg. cost = 0.074
Epoch: 0004 Avg. cost = 0.057
Epoch: 0005 Avg. cost = 0.047
Epoch: 0006 Avg. cost = 0.039
Epoch: 0007 Avg. cost = 0.034
Epoch: 0008 Avg. cost = 0.029
Epoch: 0009 Avg. cost = 0.025
Epoch: 0010 Avg. cost = 0.022
Epoch: 0011 Avg. cost = 0.018
Epoch: 0012 Avg. cost = 0.016
Epoch: 0013 Avg. cost = 0.015
Epoch: 0014 Avg. cost = 0.014
Epoch: 0015 Avg. cost = 0.013
정확도: 0.9907
기다린 보람이 있었다!
CNN을 이용하지 않은 MNIST 모델의 정확도는 0.9837이었다. 즉, 0.007만큼 정확도가 상승한 것이다.