read

CNN


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가 나올 것이다.

그럼 실습을 해보자.

순서는 다음과 같다.

  1. input file
  2. subsampling
  3. Convolution
  4. subsampling
  5. 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을 배워보자.

Blog Logo

구찌


Published

Image

구찌의 나도한번 해블로그

구찌의 개발 블로그 입니다.

Back to Overview