11-1. ConvNet의 Conv 레이어 만들기

2020. 7. 3. 01:00AI/모두를 위한 딥러닝

이 포스트는 모두를 위한 딥러닝 - Tensor Flow를 정리한 내용을 담았습니다.
누구나 이해할 수 있는 수준으로 설명하고자 하였으며 LAB의 코드는 TF2.0에 맞추어 재작성되었습니다.

 

우리는 이전 포스트에서 CNN(Convolutional Neural Network, 합성곱 신경망)에 대해 잠깐 알아보았습니다. 아래의 CNN의 구조를 다시 보면 입력이 부분 부분으로 나뉘어 진행하다 합쳐지는 모습을 볼 수 있습니다. 이를 이해하기 위해서 우리는 CNN이 시작된 실험부터 살펴보겠습니다.

그림 1.1. CNN 구조
그림 2.1. 고양이 실험(1)

위는 CNN의 시작이라고 할 수 있는 고양이 실험 과정입니다. LeCun 교수님은 Hubel & Wiesel의 고양이 인지 실험에서 아이디어를 얻어 1989년 논문 "Backpropagation applied to handwritten zip code recognition"에서 CNN을 처음 소개하였는데, 우리는 고양이의 뇌파 실험에 대해 알아보겠습니다. 고양이 실험은 고양이가 그림이나 사물을 볼 때 읽어 들이는 뉴런들이 한 번에 동작하는 것이 아니라 그림이나 사물의 부분마다 다른 뉴런들이 활성화된다는 것을 알아낸 실험입니다. 다시 설명하면 고양이는 그림을 한눈에 인식하는 것이 아니라, 전체를 작은 부분들로 나누어 보며 작은 부분들을 합쳐 전체를 인식하는 것입니다. 예를 들어보겠습니다.

그림 2.2. 고양이 실험(2)

위 그림을 보면 고양이는 A가 적힌 그림을 빨간색 네모들로 나누어 보고 있습니다. 자세히 보면 네모들이 겹쳐져 있는 것을 볼 수 있는데, 이렇게 겹쳐진 많은 부분들이 합쳐 전체 이미지, A를 이루고 있습니다. 이를 다른 말로 저수준의 패턴(모서리, 얼룩 등)이 합쳐져 고수준의 복잡한 패턴(텍스쳐, 사물)에 반응한다고 표현하며, 이때 고양이의 뇌는 전체 뉴런이 활성화되는 것이 아니라, 그림의 부분 부분마다 다른 뉴런들이 활성화되고 있습니다. 이 실험에서 아이디어를 얻어 CNN의 구조를 만들었으며, 핵심은 이미지를 부분 부분으로 잘라내어 다른 입력으로 진행하는 것이며, 이때 학습이 진행하는 층을 Convolution layer라고 합니다. 결과적으로 CNN은 Convolutioin layer(CONV)로 이루어진 네트워크이며, 나누어 학습하던 것을 최종적으로 Fully Connected layer(FC)를 통해 예측값을 얻습니다. 실제로 아래 그림은 CNN 과정을 도식화하여 표현한 것으로, ReLU와 Fully Connected layer는 이미 이전 포스트에서 살펴보았으므로 이번에는 ConV layer에 대해 중점적으로 살펴보겠습니다. 

그림 1.2. CNN 과정

먼저 CNN과 Fully Connected NN의 다른 점을 살펴보겠습니다. 기존의 Fully Connected layer만으로 구성된 네트워크(FC)는 입력 데이터가 1차원 배열로 한정되었습니다. 하지만 실제로 한 장의 컬러 이미지는 3차원 데이터로, FC에서는 사진 데이터를 1차원으로 평면화하여 저장해야 했습니다. 이 과정에서 이미지의 공간 정보가 손실되는 등으로 인해 이미지에 대한 정보가 부족해져 네트워크 학습이 비효율적이고 정확도가 다소 낮았습니다. 하지만 CNN에서는 3차원 이미지를 그대로 입출력 데이터로 사용할 수 있고, 추출한 이미지의 특징을 모으고 강화하는 Pooling layer 등을 통해 효율적인 학습을 하며 마지막에만 FC를 추가하여 (물론 이 과정에서는 이미지 형태의 데이터를 배열 형태로 만드는 Flatten layer를 필요로 합니다.) 이미지를 분류하여 정확도를 높일 수 있습니다. 이 과정들은 위의 CNN 과정을 말로 풀어 설명한 것으로, 아래에서 Convolution layer를 만드는 과정부터 앞으로 천천히 알아볼 것이므로 위의 설명을 이해하지 못하셨더라도 걱정하지 않으셔도 됩니다. 

그림 3.1. Convoultion

이제 Convolution layer의 한 예제를 보며 Convolution(합성곱)에 대해 알아보겠습니다. 입력으로 들어오는 3차원 이미지의 크기는 32X32으로, 위의 그림 3.1에서는 컬러 이미지이므로 RGB정보를 가지는 차원을 곱하여 표현했습니다(32X32X3). 잠시 짚고 넘어가면 컬러 이미지는 R, G, B값을 갖는 3차원 데이터로, RGB 3개의 채널로 구성됩니다. 반면 흑백 명암만을 표현하는 흑백 이미지는 2차원 데이터로 1개 채널로 구성되는데, 위의 그림 3.1. 에서는 흑백 이미지로 보이지만 컬러 이미지로 가정하고 진행하겠습니다. 고양이 실험과 같이 CNN에서는 전체 이미지를 일부분으로 나누어 처리하는데, 이때 나눠진 이미지를 filter라고 합니다(또는 Kernel이라고도 부릅니다). filter의 사이즈는 5X5로, 이후부터는 filter의 사이즈가 변하지 않고 일정한 사이즈로 전체 이미지를 나누어 처리합니다. 이 filter에 Wx+ b 식을 이용하여 하나의 값을 얻으며 이 과정을 Convolution(합성곱 연산)이라고 합니다. 합성곱 처리 결과로부터 만들어진 이미지를 Feature Map 혹은 Activation Map이라고 하는데, 먼저 합성곱 연산에 대해 살펴보겠습니다.

                                    그림 3.2. Convolution에서 Feature Map을 만드는 과정                                        출처:  http://deeplearning.stanford.edu/wiki/index.php/Feature_extraction_using_convolution

 

그림 3.3. Convolution 연산 과정 (WX + b)

위의 그림 3.2를 보면,  5X5 이미지의 일부분 3X3 filter를 만들어 한 칸씩 이동하며 filter의 weight과 이미지를 곱하는 연산을 합니다(WX). bias를 0으로 가정했을 때, 오른쪽에 보이는 3X3 사이즈의 Feature map이 완성된 것을 볼 수 있습니다. 그림 3.3에서 계산 과정을 더욱 자세히 보겠습니다. 4X4의 입력과 3X3사이즈의 filter가 있을 때, filter를 한 칸씩 이동하며 곱 연산을 한 뒤(WX) bias를 더해 2X2 사이즈의 Feature map을 만들었습니다. 과정을 다시 보면, 그림 3.1에서는 5x5 이미지에서 3X3 filter를 한 칸씩 이동했을 때 3X3 사이즈의 Filter map을 얻고, 그림 3.2에서는 4X4 이미지에서 3X3 filter를 한 칸씩 이동했을 때 2X2 사이즈의 Filter map을 얻은 모습을 볼 수 있습니다. 그렇다면 우리는 전체 이미지 사이즈와 filter 사이즈, 그리고 이동하는 칸 수의 정보들로 Filter map의 사이즈를 계산할 수 있음을 알 수 있습니다. 미리 얘기하자면 이동하는 칸 수를 stride라고 하며, 이때 전체 이미지 사이즈를 N, filter 사이즈를 F로 놓으면 Filter map의 사이즈는 (N - F) / stride + 1입니다. 아래의 그림 3.4를 보면, 7X7의 이미지에서 3X3 filter를 한 칸씩 이동했을 때 (7 - 3)/1 + 1 = 5, 5X5 사이즈의 Feature map을 얻음을 알 수 있습니다. 또한 위의 공식은 아래 그림에서 stride = 3일 때를 보면 2.33으로, 3칸씩 이동했을 때는 Feature map을 얻지 못한다는 것도 미리 알 수 있습니다.

그림 3.4. Feature map의 사이즈

이런 식으로 stride를 늘리고 filter를 몇 번씩 할 때마다 Feature map의 크기가 작아지는 것은 좋은 것일까요? Feature map의 크기가 작아지는 것은 본 이미지의 정보를 잃어버리는 문제를 불러옵니다. 정보를 잃어버린다는 뜻은 Convolution 연산을 할 때마다 이미지의 사이즈가 줄어들어 가장자리의 정보들이 포함되지 않으므로, 이러한 문제점을 방지하고자 합성곱 연산 전에 선 처리하는 작업을 하며 이 작업을 Padding(패딩)이라고 합니다. 자세히 말해 Padding이란 입력 데이터 주변을 특정 값(hyper-parameter)으로 채워 공간적(spatial) 크기를 조절하는 것을 말합니다. 주로 hyper-parameter를 0으로 하는 zero-padding을 많이 사용하며, 덮는 층(pixel)을 얼마나 두껍게 할지를 조절해 Feature map을 원하는 사이즈로 조절할 수 있습니다. 뿐만 아니라 기존의 방식은 Convolution 연산 시 모서리의 정보들이 한 번만 연산되어 정확도에 문제점이 있었는데, padding은 이러한 문제점도 방지해 줍니다. 아래의 그림은 위의 설명을 모두 포함하여 나타내고 있습니다.

그림 3.5. padding 과정
그림 3.5. padding을 안할 시의 연산횟수
그림 3.6. pixel을 조절해 Feature map 사이즈를 원래의 이미지 사이즈로 조절

물론 입력 데이터의 높이와 폭이 다를 수도 있습니다. 입력 데이터가 위처럼 NXN형태의 정사각형이 아닌 경우의 Feature map 사이즈를 구하는 공식은 다음과 같습니다. 입력 데이터의 높이와 폭을 H와 W, filter의 높이와 폭을 FH, FW, stride와 padding pixel 사이즈를 S와 P로 둘 때 Output Height(OH) = (H + 2P - FH)/S + 1, Output Weight(OW) = (H + 2P + FW)/S + 1, 단, OH와 OW는 자연수여야만 함.

식 1.1. Feature map 사이즈를 구하는 일반적인 공식

이제 CNN의 주요 용어에 대해서는 어느 정도 익히셨으리라 기대합니다. 그렇다면 마지막으로 filter가 둘 이상일 때의 activation map을 살펴보겠습니다. convolution layer는 filter의 개수에 따라 서로 다른 이미지를 출력할 것입니다. 이는 각각의 필터의 weight이 모두 다르기 때문인데, 따라서 filter를 2개 사용하면 activation map의 깊이는 2가 될 것이고 filter를 6개 사용하면 activation map의 깊이는 6이 될 것입니다. 깊이를 다른 말로 채널이라고 하는데, 이를 정리하면 convoultion layer에 유입되는 입력 데이터에는 한 개 이상의 필터가 적용되며, 한 개 필터는 Feature map의 채널이 됩니다. 즉, convolution layer에 n개의 필터가 적용된다면 출력 데이터는 n개의 채널을 갖게 되며, 이러한 방법을 이용해 우리는 균형 잡힌 결과를 얻을 수 있습니다. 

그림 3.7. 6개의 filter로 만들어진 activation maps
그림 3.8 convolution layer를 여러번 거칠 때

마지막으로 convolution layer를 여러 번 거치면 어떻게 되는지 보겠습니다. 그림 3.8은 convolution layer를 여러 번 거칠 때 이미지 사이즈의 변화 과정을 나타내는데, padding을 선 처리하지 않았을 때 이미지의 크기는 점점 작아지는 것을 확인할 수 있습니다. 하지만 이미지의 크기가 작아짐과 동시에 깊이가 넓어짐이 보이는데, 실제로 다음 포스트에서 소개하는 CNN을 적용한 이미지 분류 사이트를 보면 convolution layer를 거칠 때마다 그림이 작아지고 거칠어지는 것을 확인할 수 있습니다. 우리에게 중요한 점은 얼마나 이미지를 잘 분류하고 판단하는가이기 때문에, 이미지의 크기가 작아지는 것에 너무 신경 쓰지 않아도 됩니다.