티스토리 뷰

반응형

0. 들어가면서

합성곱 신경망(CNN)인 Convolution Neural Network의 기본 연산중 하나인 Pooling 연산에 대해 알아보자. 아래의 블로그를 통해 Convolution 연산에 대해 알아 보고 동작 원리도 알아 보았다. 

han-py.tistory.com/230

han-py.tistory.com/231

 

 

 

 

정리하면 Convolution 연산 후에 Activation Function(ReLU)를 활용해 -1를 0으로 바꿔주는 것 까지 알아 보았다. 이렇게 Convolution layer 하나를 구성한 이 후에 출력값(output feature)을 이용해서 다시 Convolution layer를 하나 구성해서 입력으로 넣어 주거나 Pooling layer를 넣어서 Pooling layer에 입력을 넣어 줄 수 있다. 이번엔 Pooling layer에 대해 알아보자.

 

 

 

 

1. Pooling

Pooling연산에서 가장 많이 사용 되는 것은 Max PoolingAverage Pooling이다.

 

 

1.1 Max Pooling

 

https://medium.com/@hobinjeong/cnn%EC%97%90%EC%84%9C-pooling%EC%9D%B4%EB%9E%80-c4e01aa83c83

왼쪽 그림은 convolution layer에서 나온 출력값이라고 생각하면 된다. 그리고 왼쪽은 3개의 채널 중에 하나의 채널만 나타낸 거라고 생각해 주면 된다. Pooling연산 자체가 채널별로 따로 진행을 하기 때문에 pooling 출력값도 3개의 채널이 나온다고 보면된다. 즉 Pooling을 하더라도 채널 수는 변하지 않는다.

 

위의 개산과정을 보면 filters는 2x2를 썼고 stride가 2인 경우이기 때문에 왼쪽 그림에서 색별로 계산을 했다는 것을 알 수 있다. 그리고 Max Pooling은 위의 그림 기준으로 같은 색의 4개의 숫자 중에 가장 큰 숫자를 뽑는 것이다. 중요한 포인트를 뽑아 size를 줄였다는 의미에서 Max Pooling을 SubSampling이라고도 한다.

 

 

1.2 Average Pooling

 이름에서 알 수 있듯이 Max Pooling은 4개의 숫자중에 가장 큰 값을 뽑았다면, Average Pooling은 4개의 숫자를 평균을 내는 것이다. 위의 값을 Average Pooling을 하면 결과값은 아래와 같을 것이다.

3.25         5.25

 

 

2             2

 

일반적으로는 Max Pooling을 많이 쓴다. 왜냐하면 convolution 연산의 결과로 나온 feature map이기 때문에 값이 클 수록 의도하고자 한 특징에 가까운 것이기 때문이다. 크면 좋기 때문에 큰걸 사용한다.

 

 

 

 

2. 코드작성(tf.keras.layers.MaxPool2D)

우리는 tf.keras.layers에 있는 MaxPool2D라는 API를 사용할 것이다. 클래스로 이루어져 있기 때문에 아래의 init 메세지를 보면 아래와 같이 이루어져 있다.

__init__(
    pool_size=(2, 2),
    strides=None,
    padding='valid',
    data_format=None,
    **kwargs
)

위의 코드를 보면 알 수 있듯 기본값은 정해져있다.

  • pool_size : [integer( 2 ) or tuple( (2,2) )]   
  • strides : [integer, tuple] : 앞에서 배운 것과 같다.
  • padding : 앞과 동일하게 valid와 same이 있다.
  • data_format : 앞과 동일하게 channels_last(batch, height, width, channels)와 channels_first가 있다. 

헷갈리면 복습하고 오자!

우선 import 부터 진행하자

import numpy as np
import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
image = tf.constant([[[[4],[3]],
                      [[2], [1]]]], dtype=np.float32)
pool = keras.layers.MaxPool2D(pool_size=(2,2), strides=1,
                              padding='VALID')(image)

4      3

 

2      1

위와 같이 tf.constant를 통해 만든 것이다. 그리고 이것을 keras.layers.MaxPool2D를 통해서 pooling을 하는 것이다. 이때 VALID로 패딩을 하지 않았기 때문에 아래와 같이 4라는 숫자가 하나가 나온다.

 

이젠 padding을 SAME으로 바꿔서 진행해보자.

  image = tf.constant([[[[4], [3]],
                        [[2],[1]]]], dtype=np.float32)
  pool = keras.layers.MaxPool2D(pool_size=(2,2), strides=1,
                                padding='SAME')(image)

패딩이 아래그림과 같이 자동으로 1줄씩 오른쪽과 왼쪽이 추가 될 것이다.

 

위와 같이 결과가 2x2가 나오게 된다.

 

 

 

 

 

3. 적용

이제 convolution 연산과 pooling을 각각 알아보았다. 두개를 연결해 보자.

즉, convolution연산 후에 pooling연산을 하여 layer를 2개를 쌓아보자. 

이떄 사용한 데이터 set은 MNIST data set을 사용할 것이다.

 

3.1 데이터 불러오기

mnist = keras.datasets.mnist
class_names = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.astype(np.float32) / 255.
test_images = test_images.astype(np.float32) / 255.

keras.datasets.mnist를 통해 데이터를 읽어올 것이다.

load_data()를 통해 train_images, train_labels, test_images, test_labels로 분리를 해준다.

train_images와 test_images는 각각 255로 나눠서 0에서 1사이의 값으로 스케일링을 해준다.

그리고 train_images중에 0번 이미지를 한 장 본 것이다.

 

3.1 convolution Layer 적용하기

위에서 나온 data에 convolution 연산을 적용해 보자.

img = img.reshape(-1, 28, 28, 1)
img = tf.convert_to_tensor(img)
weight_init = keras.initializers.RandomNormal(stddev=0.01)
conv2d = keras.layers.Conv2D(filters=5, kernel_size=3, strides=(2,2),
                             padding='SAME', kernel_initializer=weight_init)(img)

image = img.reshape(-1, 28, 28, 1)

우선은 image를 convolution연산에 집어 넣기 위해서 4차원의 연산으로 바꿔줘야한다. -1은 자동으로 배치값이 들어가게 되는데 우리는 한장만 쓰기 때문에 자동으로 1이 들어간다.

 

tf.convert_to_tensor(img)

위에서 데이터 타입은 numpy.ndarray타입으로 리턴이 되는데, 그것을 API로 집어넣기 위해서는 tensor로 바꿔주는 작업을 해줘야한다. (ndarray는 np.array로 구현한 것이 맞다. type을 쳐보면 ndarray라고 뜬다.)

 

keras.initializers.RandomNormal

converter filter initializers는 RandomNormal 사용

 

 

 

 

5개의 채널의 feature map을 하나씩 출력해 보자.

feature_maps = np.swapaxes(conv2d, 0, 3)
for i, feature_map in enumerate(feature_maps):
  plt.subplot(1, 5, i+1), plt.imshow(feature_map.reshape(14,14), cmap='gray')
plt.show()

 

 

 

 

 

3.2 Pooling Layer - Output Feature Maps

이어서 맥스  풀링 연산을 해보자.

pool = keras.layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2),
                              padding='SAME')(conv2d)
feature_maps = np.swapaxes(pool, 0, 3)
for i, feature_map in enumerate(feature_maps):
  plt.subplot(1, 5, i+1), plt.imshow(feature_map.reshape(7, 7), cmap='gray')

 위와 같이 pool_size와 strides를 조절해서 크기가 14x14에서 7x7로 줄어들 것이다. 결과는 아래의 그림을 보자

 

여기까지가 convolution layer와 pooling layer를 붙여서 한 실습이다.

 

 

 

3.3 Fully Connected(Dense) Layer

CNN을 구성하는 layer는 세개다. convolution layer, pooling layer, fully Connected layer다. fully connected layer는 Dense랑 비슷하기 때문에 어떻게 연결이 되는지만 알아보자.

 

왼쪽과 같이 pooling으로 나온 결과같을 일렬로 벡터처럼 쭉 핀다. 그리고 그것을 전부 fully connect를 해서 한줄로 만들면 된다. Dense와 비슷하다. 위의 그림처럼 만약 고양이와 개를 구분하는거라면 2개의 결과값으로 내보내면 된다. 마지막 2개의 출력을 softmax를 통과 시키면 확률이 나오게 된다. 위 그림과 달리 여러개의 layer가 나올 수도 있다는 점을 인지하자.

 

 

지금까지 CNN의 동작원리와 실습에 대해 배워보았다. 다음은 MNIST 데이터 셋을 활용하여 전체 CNN을 만들어 볼 것이다. 그리고 학습도 해보자.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함