본문 바로가기

파이썬/머신러닝

[#E17] Convolution Neural Network (CNN - 실전편)

이번에는 실제로 텐서플로우에서 Convolution 데이터Pooling이 어떻게 진행되는지에 대해 알아보겠습니다.


먼저 다음과 같이 예시 이미지를 생성합니다.


1
2
3
4
5
6
7
8
9
10
11
12
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

sess = tf.InteractiveSession()
image = np.array([[[[1],[2],[3]],
                   [[4],[5],[6]], 
                   [[7],[8],[9]]]], dtype=np.float32)
print(image.shape) #-> (1331)

#show image
plt.imshow(image.reshape(3,3), cmap='Greys')
cs



해당 이미지는 왼쪽 상단에서부터 차례대로 1, 2, 3 ... 9 의 값을 가지고 있습니다. 이미지의 shape인 (1, 3, 3, 1)은 여기를 고하세요.


그 다음에는 필터를 적용합니다. 필터의 각 weight 값은 편의상 1로 지정했으며, Stride = 1X1입니다.



필터는 image를 훑으며 각각 12, 16, 24, 28의 값을 갖는 output을 생성합니다. filter의 shape (2, 2, 1, 1)는 각각 구조, , 필터의 갯수를 의미합니다.


output의 shape는 마찬가지로 각각 사용한 이미지의 갯수인 1, 2X2 구조, 1가지 색이 됩니다.


이것을 텐서플로우에서 구현하면 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#filter
weight = tf.constant([[[[1.]],[[1.]]],
                      [[[1.]],[[1.]]]])
 
print("weight.shape", weight.shape) # -> (2, 2, 1, 1)
 
                                                           #zero-padded NONE
conv2d = tf.nn.conv2d(image, weight, strides=[1111], padding='VALID')
conv2d_img = conv2d.eval()
 
#print image shape
print("conv2d_img.shape", conv2d_img.shape) # -> (1, 2, 2, 1)
 
#print image
conv2d_img = np.swapaxes(conv2d_img, 03)
for i, one_img in enumerate(conv2d_img):
    print(one_img.reshape(2,2)) # -> [[ 12.  16.], [ 24.  28.]]
    plt.subplot(1,2,i+1), plt.imshow(one_img.reshape(2,2), cmap='gray'# -> show image
cs


[output 1 : 필터 1개를 사용하고, zero-padded를 사용하지 않은 모델]



이제 zero-padded section을 이용해서, 원본과 같은 크기인 3X3 output을 생성해보겠습니다. 이를 그림으로 표현하면 아래와 같습니다. ( 텐서플로우에서 원본 크기가 나오도록 자동으로 zero - paded 영역을 설정합니다 )



이것을 텐서플로우에서 구현하는 방법은 어렵지 않습니다. 단지 conv2d의 padding 속성을 VALID -> SAME으로 바꿔주면 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#filter
weight = tf.constant([[[[1.]],[[1.]]],
                      [[[1.]],[[1.]]]])
 
print("weight.shape", weight.shape) # -> (2, 2, 1, 1)
       
                                                           #zero-padded USE
conv2d = tf.nn.conv2d(image, weight, strides=[1111], padding='SAME')
conv2d_img = conv2d.eval()
 
#print output shape
print("conv2d_img.shape", conv2d_img.shape) # -> (1, 3, 3, 1)
 
#about show image
conv2d_img = np.swapaxes(conv2d_img, 03)
for i, one_img in enumerate(conv2d_img):
    print(one_img.reshape(3,3)) # -> [[ 12.  16.   9.], [ 24.  28.  15.], [ 15.  17.   9.]]
    plt.subplot(1,2,i+1), plt.imshow(one_img.reshape(3,3), cmap='gray')
 
cs


[output 2 : 필터 1개를 사용하고, zero-padded를 사용한 모델]



이번에는 필터를 여러 개 사용하는 모델을 적용합니다. 마찬가지로 2X2X1 shape의 필터 3개를 사용합니다. 따라서 weight의 shape는 (2, 2, 1, 3) 입니다.


각각의 필터의 weight 값은 1, 10, -1이고, 따라서 출력되는 output의 개수도 3개가 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#filter
weight = tf.constant([[[[1.,10.,-1.]],[[1.,10.,-1.]]],
                      [[[1.,10.,-1.]],[[1.,10.,-1.]]]])
 
print("weight.shape", weight.shape) # -> (2, 2, 1, 3)
                                                           #zero-padded USE
conv2d = tf.nn.conv2d(image, weight, strides=[1111], padding='SAME')
conv2d_img = conv2d.eval()
 
#print show image
print("conv2d_img.shape", conv2d_img.shape) # -> (1, 3, 3, 3)
 
#about show image
conv2d_img = np.swapaxes(conv2d_img, 03)
for i, one_img in enumerate(conv2d_img):
    print(one_img.reshape(3,3)) # -> ...
    plt.subplot(1,3,i+1), plt.imshow(one_img.reshape(3,3), cmap='gray')
cs


[output 3 : 필터 3개를 사용하고, zero-padded를 사용한 모델]


 

이제 마지막으로 Pooling하는 방법에 대해서 알아보겠습니다. 이것 또한 텐서플로우에서 제공하는 함수를 이용해서 다음과 같이 간단하게 구현할 수 있습니다.


(1) zero-padded를 적용하지 않은 경우

 

 

1
2
3
4
5
6
image = np.array([[[[4],[3]],
                    [[2],[1]]]], dtype=np.float32)
pool = tf.nn.max_pool(image, ksize=[1221],
                    strides=[1111], padding='VALID')
print(pool.shape)
print(pool.eval())
cs


(2)zero-padded를 적용한 경우

 

 

1
2
3
4
5
6
image = np.array([[[[4],[3]],
                    [[2],[1]]]], dtype=np.float32)
pool = tf.nn.max_pool(image, ksize=[1221],
                    strides=[1111], padding='SAME')
print(pool.shape)
print(pool.eval())
cs

 

이것을 활용해서 MNIST 데이터 또한 Pooling할 수 있습니다. 먼저 Convolution 데이터를 만든 후 Pooling을 진행합니다.


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
29
30
31
32
33
34
35
36
37
38
39
40
41
#load mnist data
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
 
#get only 1 image & reshape it
img = mnist.train.images[0].reshape(28,28)
plt.imshow(img, cmap='gray')
 
sess = tf.InteractiveSession()
 
#reshape image to get color = 1
img = img.reshape(-1,28,28,1)
 
#filter 3X3, count = 5
W1 = tf.Variable(tf.random_normal([3315], stddev=0.01))
 
                                                     #zero-padded USE
conv2d = tf.nn.conv2d(img, W1, strides=[1221], padding='SAME')
print(conv2d)
 
sess.run(tf.global_variables_initializer())
 
#make convoultion data
conv2d_img = conv2d.eval()
 
#print converted images
conv2d_img = np.swapaxes(conv2d_img, 03)
for i, one_img in enumerate(conv2d_img):
    plt.subplot(1,5,i+1), plt.imshow(one_img.reshape(14,14), cmap='gray')
 
#pooling
pool = tf.nn.max_pool(conv2d, ksize=[1221], strides=[
                        1221], padding='SAME')
print(pool)
sess.run(tf.global_variables_initializer())
pool_img = pool.eval()
 
#print pooling image
pool_img = np.swapaxes(pool_img, 03)
for i, one_img in enumerate(pool_img):
    plt.subplot(1,5,i+1), plt.imshow(one_img.reshape(77), cmap='gray')
cs


<convoultion data>


 

<pooling data>



다음 포스트에서는 Convolution Neural Network를 활용한 MNIST 데이터 분류에 대해 알아보겠습니다. 모든 소스 코드는 여기에서 확인할 수 있습니다.