CNN
위 사진처럼 방송국 CNN은 아니니 걱정하지 말자.
사실, 개인적으로 CNN을 볼 떄, 방송국보다는 NN이 먼저 생각나게 되었다는 것에 감사한다..
하여튼, 이번에는 CNN 을 보도록 하자.
CNN의 아이디어는 고양이 실험에서 시작되었다.
고양이에게 어떤 그림을 보여주니, 그림을 읽어주는 뉴런이 모두 다 적용되는 게 아니라, 어떤 부분이냐에 따라 뉴런이 입력을 나누어 받는 것이다.
따라서, 하나의 이미지가 있으면, 어떻게 잘라서 각각의 입력으로 넘기는 데, 그 층을 Convolution Neural Network라 한다. 그리고 ReLU 층을 넣고, 또다시 Conv 층, ReLU 층을 넣어도 되고 이후, POOL
이라는 층을 넣을 수도 있다.
위 사항들을 반복하고, Fully Connected Neural Network
Labeling읋 하여 softmax classifier
를 붙여 결과를 보인다.
32 x 32 x 3 (width x height x depth(RGB)) 의 이미지가 있다고 하자.
고양이 실험처럼 일단, small area만 먼저 처리하자.
여기서 처리를 filter
라는 개념으로 말한다.
32 x 32 x 3 => 5 x 5 x 3 filter
이 filter는 궁극적으로 한 값을 만들어 낸다. ( one number )
즉, 한 점만 뽑아내는 것이다.
이 것을 WX + b 로 만든다.
그럼 다음과 같을 것이다.
W1x1 + W2x2 + W3x3 + W4x4 + W5x5 + b
즉, weight이 어떤 숫자로 만들어내는지 결정하는 filter의 값이라 생각하면 좋다.
ReLU(WX + b)
를 붙여 ReLU를 적용하면 되기도 하다.
그럼 이 small area를 옆어로 넘기면서, 밑으로 내리면서 같은 weight를 가지고 filtering한 값들을 얻을 수 있다.
그럼 몇 개가 생길것인가? 간단한 산수이다.
7 x 7 이고 3 x 3 filter 라고 하자.
그럼 간단히 5 x 5가 된다. 한칸씩 움직일 때를 말하는 데, 이 것을 stride 라고 하고 여기선 stride = 1
이라고 한다.
2칸씩 욺직인다면, stride가 2라면 3 x 3 이 될 것이다.
그럼, (N - F) / stride + 1
이다.
N과 F는 원래 이미지 크기, filter 크기이다.
만약 7 x 7을 3 x 3 으로 stride 1로 하는데 pad를 1 pixel을 준다면 출력이 어떻게 될 것인가?
즉, 7 x 7에 padding이 들어가 9 x 9가 되고( 그림을 그려보면 알 수 있다. 양 옆으로 1pixel이 들어간다. ), 이를 3 x 3 filtering 하면 기존과 같이 7 x 7 이 된다.
그래서 보통 padding을 해서 입력과 출력의 사이즈가 같아지게 만들어 사용하w고 있다.
이게 하나의 Convolution layer를 만드는 방법인데,
filter를 여러개 한다면 어떻게 될까?
즉, filter 5 x 5 x 3 을 여러개를 해서, weight이 다르니 결론적으로 depth가 깊어지게 됬을 것이다.
따라서, 32 x 32 x 3 image에 6개의 5 x 5 x 3 filter를 적용하면 결과로 activation maps
가 나오는데, 28 x 28 x 6 이 나온다.
이 것을 여러번 할 수도 있다.
그럼 weight에 사용되는 갯수는 몇개인가를 알수 있는데,
5 x 5 x 3이 6개 있으니, 450개 일 것이다.
그럼 Max pooling
을 알아보자.
Pooling layer 는 간단히, sampling
이라고 생각하자.
image가 있고, conv layer가 있을 것인데, depth에 있어서, 한 layer만 뽑아낸다.
그리고, resize
하여, 작게 만든다. (sampling, pooling)
그 값을 다시 쌓는다. 즉, depth에 따라 각 layer를 전부 적용해서 합친다.
max pooling은 이미지로 보면 쉬운데, https://youtu.be/2-75C-yZaoA?t=210 이 곳을 참조 하자.
간단히, 큰 값만 뽑아내 sampling 하는 것이다.
그러면 Fully Connected Layer (FC layer)
를 알아보자.
즉, input을 conv -> ReLU -> POOL 등으로 구현한다. 뭘 먼저하냐의 순서는 크게 의미 없다.
어쨌든, 3 x 3 x 10이라는 마지막 layer가 나왔을 때, softmax classifier가 나올 것이다.
그럼 실습을 해보자.
순서는 다음과 같다.
- input file
- subsampling
- Convolution
- subsampling
- fully-connected
여기서 1번이 5 x 5 convolution
이 될 것이고, 2~5 번이 feature extraction
이 될 것이다. 그리고 마지막 6번이 classification
or regression
과정이다.
먼저, 간단한 3 x 3 x 1 이미지를 연습하자. filter는 2 x 2 x 1 로 한다.
먼저 이미지를 만들어보자.
sess = tf.InteractiveSession()
image = np.array([[[1],[2],[3]]],[[4],[5],[6]],[[7],[8],[9]], dtype=np.float32)
print(image.shape)
# (1, 3, 3, 1)
# n = 1 개 3 x 3 x 1
plt.imshow(image.reshape(3,3), cmap='Grays')
위와같이 이미지를 만들 수 있을 것이고,
이제 filter를 정의하고, 이를 각 부분별로 더하여 새로운 sample을 만들어야 한다.
weight = tf.constant([[[1.],[1.]],[[1.],[1.]]])
print("weight.shape", weight.shape)
conv2d = tf.nn.conv2d(image, weight, strides=[1,1,1,1], padding='VALID')
conv2d_img = conv2d.eval()
print('conv2d_img.shape', conv2d_img.shape)
conv2d_img = np.swapaxes(conv2d_img, 0, 3)
for i, one_img in enumerate(conv2d_img):
print(one_img.reshape(2,2))
plt.shbplot(1,2,i+1), plt.imshow(one_img.reshape(2,2), cmap='gray')
이렇게 conv2d
라는 함수로 쉽게 계산할 수 있다.
이제 padding
을 알아보자.
padding을 same으로 한다면, 원래 이미지와 같게 만들어준다.
그럼 필터의 갯수도 늘려보자.
weight = tf.constant([[[[1.,10.,-1.]],[[1.,10.,-1.]]],
[[[1.,10.,-1]],[[1.,10.,-1.]]]])
print("weight.shape", weight.shape)
conv2d = tf.nn.conv2d(image, weight, strides=[1,1,1,1], padding='SAME')
conv2d_img = conv2d.eval()
print('conv2d_img.shape', conv2d_img.shape)
conv2d_img = np.swapaxes(conv2d_img, 0, 3)
for i, one_img in enumerate(conv2d_img):
print(one_img.reshape(3,3))
plt.shbplot(1,2,i+1), plt.imshow(one_img.reshape(2,2), cmap='gray')
위 처럼 필터를 3개로 늘려서 진행도 가능하다.
weight.shape가 (2, 2, 1, 3)
이 나올텐데, 마지막 3이 filter의 갯수가 된다.
물론 결과도 여러개 나온다.
그리고 Max pooling
을 해보자.
주어진 이미지의 size, stride, padding만 주면 된다.
pool = tf.nn.max_pool(image, ksize=[1,2,2,1], strides=[1,1,1,1], padding='SAME')
print(pool.shape)
print(pool.eval())
보통 max-pooling이 CNN과 잘 어울리므로 자주 쓰인다.
일단 전체적으로 진행해보려는 것은 MNIST 다.
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# Check out https://www.tensorflow.org/get_started/mnist/beginners for
# more information about the mnist dataset
# hyper parameters
learning_rate = 0.001
training_epochs = 15
batch_size = 100
# input place holders
X = tf.placeholder(tf.float32, [None, 784])
X_img = tf.reshape(X, [-1, 28, 28, 1]) # img 28x28x1 (black/white)
Y = tf.placeholder(tf.float32, [None, 10])
# L1 ImgIn shape=(?, 28, 28, 1)
# 3 x 3 x 1 의 32개 filter
W1 = tf.Variable(tf.random_normal([3, 3, 1, 32], stddev=0.01))
# Conv -> (?, 28, 28, 32)
# Pool -> (?, 14, 14, 32)
# stride 1 로 할 것
L1 = tf.nn.conv2d(X_img, W1, strides=[1, 1, 1, 1], padding='SAME')
L1 = tf.nn.relu(L1)
# stride 2 로 할 것
L1 = tf.nn.max_pool(L1, ksize=[1, 2, 2, 1],
strides=[1, 2, 2, 1], padding='SAME')
'''
Tensor("Conv2D:0", shape=(?, 28, 28, 32), dtype=float32)
Tensor("Relu:0", shape=(?, 28, 28, 32), dtype=float32)
Tensor("MaxPool:0", shape=(?, 14, 14, 32), dtype=float32)
'''
# max pool 하고 나온 값 # of filters = 32
# L2 ImgIn shape=(?, 14, 14, 32)
W2 = tf.Variable(tf.random_normal([3, 3, 32, 64], stddev=0.01))
# Conv ->(?, 14, 14, 64)
# Pool ->(?, 7, 7, 64)
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')
L2 = tf.reshape(L2, [-1, 7 * 7 * 64])
'''
Tensor("Conv2D_1:0", shape=(?, 14, 14, 64), dtype=float32)
Tensor("Relu_1:0", shape=(?, 14, 14, 64), dtype=float32)
Tensor("MaxPool_1:0", shape=(?, 7, 7, 64), dtype=float32)
Tensor("Reshape_1:0", shape=(?, 3136), dtype=float32)
'''
# Final FC 7x7x64 inputs -> 10 outputs
W3 = tf.get_variable("W2", shape=[7 * 7 * 64, 10],
initializer=tf.contrib.layers.xavier_initializer())
b = tf.Variable(tf.random_normal([10]))
hypothesis = tf.matmul(L2, W3) + b
# define cost & optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
logits=hypothesis, 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 stared. It takes sometime.')
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)
sess.run(optimizer, feed_dict={
X: batch_xs, Y: batch_ys})
avg_cost += sess.run(cost,
feed_dict={X: batch_xs, Y: batch_ys}) / total_batch
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))
print('Learning Finished!')
이제 CNN 소스를 좀 관리해보자.
Python의 클래스로 관리해 보려고 한다.
import tensorflow as tf
# import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
tf.set_random_seed(777) # reproducibility
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# Check out https://www.tensorflow.org/get_started/mnist/beginners for
# more information about the mnist dataset
# hyper parameters
learning_rate = 0.001
training_epochs = 15
batch_size = 100
class Model:
def __init__(self, sess, name):
self.sess = sess
self.name = name
self._build_net()
def _build_net(self):
with tf.variable_scope(self.name):
# dropout (keep_prob) rate 0.7~0.5 on training, but should be 1
# for testing
self.keep_prob = tf.placeholder(tf.float32)
# input place holders
self.X = tf.placeholder(tf.float32, [None, 784])
# img 28x28x1 (black/white)
X_img = tf.reshape(self.X, [-1, 28, 28, 1])
self.Y = tf.placeholder(tf.float32, [None, 10])
# L1 ImgIn shape=(?, 28, 28, 1)
W1 = tf.Variable(tf.random_normal([3, 3, 1, 32], stddev=0.01))
# Conv -> (?, 28, 28, 32)
# Pool -> (?, 14, 14, 32)
L1 = tf.nn.conv2d(X_img, 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')
L1 = tf.nn.dropout(L1, keep_prob=self.keep_prob)
'''
Tensor("Conv2D:0", shape=(?, 28, 28, 32), dtype=float32)
Tensor("Relu:0", shape=(?, 28, 28, 32), dtype=float32)
Tensor("MaxPool:0", shape=(?, 14, 14, 32), dtype=float32)
Tensor("dropout/mul:0", shape=(?, 14, 14, 32), dtype=float32)
'''
# L2 ImgIn shape=(?, 14, 14, 32)
W2 = tf.Variable(tf.random_normal([3, 3, 32, 64], stddev=0.01))
# Conv ->(?, 14, 14, 64)
# Pool ->(?, 7, 7, 64)
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')
L2 = tf.nn.dropout(L2, keep_prob=self.keep_prob)
'''
Tensor("Conv2D_1:0", shape=(?, 14, 14, 64), dtype=float32)
Tensor("Relu_1:0", shape=(?, 14, 14, 64), dtype=float32)
Tensor("MaxPool_1:0", shape=(?, 7, 7, 64), dtype=float32)
Tensor("dropout_1/mul:0", shape=(?, 7, 7, 64), dtype=float32)
'''
# L3 ImgIn shape=(?, 7, 7, 64)
W3 = tf.Variable(tf.random_normal([3, 3, 64, 128], stddev=0.01))
# Conv ->(?, 7, 7, 128)
# Pool ->(?, 4, 4, 128)
# Reshape ->(?, 4 * 4 * 128) # Flatten them for FC
L3 = tf.nn.conv2d(L2, W3, strides=[1, 1, 1, 1], padding='SAME')
L3 = tf.nn.relu(L3)
L3 = tf.nn.max_pool(L3, ksize=[1, 2, 2, 1], strides=[
1, 2, 2, 1], padding='SAME')
L3 = tf.nn.dropout(L3, keep_prob=self.keep_prob)
L3_flat = tf.reshape(L3, [-1, 128 * 4 * 4])
'''
Tensor("Conv2D_2:0", shape=(?, 7, 7, 128), dtype=float32)
Tensor("Relu_2:0", shape=(?, 7, 7, 128), dtype=float32)
Tensor("MaxPool_2:0", shape=(?, 4, 4, 128), dtype=float32)
Tensor("dropout_2/mul:0", shape=(?, 4, 4, 128), dtype=float32)
Tensor("Reshape_1:0", shape=(?, 2048), dtype=float32)
'''
# L4 FC 4x4x128 inputs -> 625 outputs
W4 = tf.get_variable("W4", shape=[128 * 4 * 4, 625],
initializer=tf.contrib.layers.xavier_initializer())
b4 = tf.Variable(tf.random_normal([625]))
L4 = tf.nn.relu(tf.matmul(L3_flat, W4) + b4)
L4 = tf.nn.dropout(L4, keep_prob=self.keep_prob)
'''
Tensor("Relu_3:0", shape=(?, 625), dtype=float32)
Tensor("dropout_3/mul:0", shape=(?, 625), dtype=float32)
'''
# L5 Final FC 625 inputs -> 10 outputs
W5 = tf.get_variable("W5", shape=[625, 10],
initializer=tf.contrib.layers.xavier_initializer())
b5 = tf.Variable(tf.random_normal([10]))
self.logits = tf.matmul(L4, W5) + b5
'''
Tensor("add_1:0", shape=(?, 10), dtype=float32)
'''
# define cost/loss & optimizer
self.cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
logits=self.logits, labels=self.Y))
self.optimizer = tf.train.AdamOptimizer(
learning_rate=learning_rate).minimize(self.cost)
correct_prediction = tf.equal(
tf.argmax(self.logits, 1), tf.argmax(self.Y, 1))
self.accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
def predict(self, x_test, keep_prop=1.0):
return self.sess.run(self.logits, feed_dict={self.X: x_test, self.keep_prob: keep_prop})
def get_accuracy(self, x_test, y_test, keep_prop=1.0):
return self.sess.run(self.accuracy, feed_dict={self.X: x_test, self.Y: y_test, self.keep_prob: keep_prop})
def train(self, x_data, y_data, keep_prop=0.7):
return self.sess.run([self.cost, self.optimizer], feed_dict={
self.X: x_data, self.Y: y_data, self.keep_prob: keep_prop})
# initialize
sess = tf.Session()
m1 = Model(sess, "m1")
sess.run(tf.global_variables_initializer())
print('Learning Started!')
# train my model
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)
c, _ = m1.train(batch_xs, batch_ys)
avg_cost += c / total_batch
print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.9f}'.format(avg_cost))
print('Learning Finished!')
# Test model and check accuracy
print('Accuracy:', m1.get_accuracy(mnist.test.images, mnist.test.labels))
이렇게 진행이 될 수 있다.
이는 클래스를 활용한건데, tansorflow에 layers 라는 것이 있다.
우리가 쓰던 conv2d 나 dense 같은 것이 이것에 속한다.
원래라면 숫자가 매우 많이 나오는데, 그때 layers를 사용하여 수를 좀 줄이는 것이다.
그럼 앞서 배웠던 Ensemble(앙상블) 을 적용해볼 수 있을 것이다.
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data
tf.set_random_seed(777) # reproducibility
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
# Check out https://www.tensorflow.org/get_started/mnist/beginners for
# more information about the mnist dataset
# hyper parameters
learning_rate = 0.001
training_epochs = 20
batch_size = 100
class Model:
def __init__(self, sess, name):
self.sess = sess
self.name = name
self._build_net()
def _build_net(self):
with tf.variable_scope(self.name):
# dropout (keep_prob) rate 0.7~0.5 on training, but should be 1
# for testing
self.training = tf.placeholder(tf.bool)
# input place holders
self.X = tf.placeholder(tf.float32, [None, 784])
# img 28x28x1 (black/white), Input Layer
X_img = tf.reshape(self.X, [-1, 28, 28, 1])
self.Y = tf.placeholder(tf.float32, [None, 10])
# Convolutional Layer #1
conv1 = tf.layers.conv2d(inputs=X_img, filters=32, kernel_size=[3, 3],
padding="SAME", activation=tf.nn.relu)
# Pooling Layer #1
pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2],
padding="SAME", strides=2)
dropout1 = tf.layers.dropout(inputs=pool1,
rate=0.7, training=self.training)
# Convolutional Layer #2 and Pooling Layer #2
conv2 = tf.layers.conv2d(inputs=dropout1, filters=64, kernel_size=[3, 3],
padding="SAME", activation=tf.nn.relu)
pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2],
padding="SAME", strides=2)
dropout2 = tf.layers.dropout(inputs=pool2,
rate=0.7, training=self.training)
# Convolutional Layer #3 and Pooling Layer #3
conv3 = tf.layers.conv2d(inputs=dropout2, filters=128, kernel_size=[3, 3],
padding="SAME", activation=tf.nn.relu)
pool3 = tf.layers.max_pooling2d(inputs=conv3, pool_size=[2, 2],
padding="SAME", strides=2)
dropout3 = tf.layers.dropout(inputs=pool3,
rate=0.7, training=self.training)
# Dense Layer with Relu
flat = tf.reshape(dropout3, [-1, 128 * 4 * 4])
dense4 = tf.layers.dense(inputs=flat,
units=625, activation=tf.nn.relu)
dropout4 = tf.layers.dropout(inputs=dense4,
rate=0.5, training=self.training)
# Logits (no activation) Layer: L5 Final FC 625 inputs -> 10 outputs
self.logits = tf.layers.dense(inputs=dropout4, units=10)
# define cost/loss & optimizer
self.cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
logits=self.logits, labels=self.Y))
self.optimizer = tf.train.AdamOptimizer(
learning_rate=learning_rate).minimize(self.cost)
correct_prediction = tf.equal(
tf.argmax(self.logits, 1), tf.argmax(self.Y, 1))
self.accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
def predict(self, x_test, training=False):
return self.sess.run(self.logits,
feed_dict={self.X: x_test, self.training: training})
def get_accuracy(self, x_test, y_test, training=False):
return self.sess.run(self.accuracy,
feed_dict={self.X: x_test,
self.Y: y_test, self.training: training})
def train(self, x_data, y_data, training=True):
return self.sess.run([self.cost, self.optimizer], feed_dict={
self.X: x_data, self.Y: y_data, self.training: training})
# initialize
sess = tf.Session()
# 여러 모델들
models = []
num_models = 2
for m in range(num_models):
models.append(Model(sess, "model" + str(m)))
sess.run(tf.global_variables_initializer())
print('Learning Started!')
# train my model
for epoch in range(training_epochs):
avg_cost_list = np.zeros(len(models))
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)
# train each model
for m_idx, m in enumerate(models):
c, _ = m.train(batch_xs, batch_ys)
avg_cost_list[m_idx] += c / total_batch
print('Epoch:', '%04d' % (epoch + 1), 'cost =', avg_cost_list)
print('Learning Finished!')
# Test model and check accuracy
test_size = len(mnist.test.labels)
predictions = np.zeros(test_size * 10).reshape(test_size, 10)
for m_idx, m in enumerate(models):
print(m_idx, 'Accuracy:', m.get_accuracy(
mnist.test.images, mnist.test.labels))
p = m.predict(mnist.test.images)
predictions += p
ensemble_correct_prediction = tf.equal(
tf.argmax(predictions, 1), tf.argmax(mnist.test.labels, 1))
ensemble_accuracy = tf.reduce_mean(
tf.cast(ensemble_correct_prediction, tf.float32))
print('Ensemble accuracy:', sess.run(ensemble_accuracy))
다음은 RNN을 배워보자.