loading

cs231n 내용 요약 (9) - CNN(Convolutional neural network)


Lecture summary

Published on November 10, 2022 by JunYoung

AI Deep learning cs231n

19 min READ

들어가며…

이전까지의 글을 통해 길고 긴 여정을 거쳐 신경망에 대한 내용을 정리할 수 있었다. 딥러닝은 머신러닝의 한 방법론이라고 볼 수 있는 neural network를 확장시켜 보다 깊은 레이어층을 학습하고자 했던 연구였고, 그 연구가 많은 발전을 이루어 현재 AI가 사업의 대부분을 구성하는 세상이 되었다. 사실 딥러닝을 처음 공부했을 때는 공부해도 되는 분야인지 막막하기도 했었고, 공부하다보면 최근 논문이나 연구로 올수록 앞으로 내가 이 분야에서 대학원 생활을 통해 얻을 수 있는게 과연 얼마나 있을까라는 생각을 많이 하게 된다. 그럼에도 불구하고 더 늦지 않게 이 분야를 공부하기 시작했다는 점이 다행스럽다고 생각될 때도 많고 진로를 택한 이후로 ‘괜히 했다’ 같은 후회는 해보지 않았던 것 같다. 아무튼 이번 게시글에서 다룰 내용은 2010년 초중반 이후 활발하게 발전할 수 있었던 딥러닝의 기본인 CNN에 대해서 알아보도록 하고, 도대체 왜 해당 아키텍쳐가 컴퓨터 비전에서 큰 각광을 받을 수 있었는지 정리해보도록 하겠다.


Convolutional neural network

이른바 CNN이라고 불리는 네트워크 구조는 딥러닝에서 자주 활용되는 구조로 알려져있다. 그렇다면 대체 convolutional neural network가 어떻게 딥러닝에서 자주 활용될 수 있었을까? 우선 CNN에 대해서 보기 전에 수학적으로 정의된 convolution 연산에 대해 살펴보면 다음과 같다.


Convolution in $1D$ signal

두 개의 함수 $f$와 $g$가 있을 때, 두 함수의 합성곱을 표현하는 용어가 convolution이며 수학 기호로는 $f * g$로 표시한다. 합성곱 연산은 두 함수 $f$와 $g$ 가운데 하나의 함수를 $y$축 대칭 및 shift시킨 후, 다른 함수에 곱한 결과를 적분하는 것을 의미한다. 말로는 표현이 어렵기 때문에 식으로 살펴보면,

[ f * g(t) = \int_{-\infty}^\infty f(\tau) g(t - \tau) d \tau
] 위와 같이 표현 가능하다. Convolution된 함수를 $t$에 대한 새로운 함수 $h(t)$라고 생각하면, $t$는 $x$축으로 평행이동한 거리를 의미한다. Convolution 연산은 commutable(교환 법칙이 성립)하므로 다음 공식이 성립한다.

[ f * g(t) = \int_{-\infty}^\infty f(t - \tau) g(\tau) d \tau
] 그림을 보게 되면 추가적으로 autocorrelation, cross-correlation이라는 연산도 정의되어있는데, 각각은 함수 사이의 연관성을 측정하는 지표로, cross-correlation은 서로 다른 두 함수, autocorrelation은 동일한 함수에 대한 지표로 작용한다. Autocorrelation은 cross-correlation 식과 동일하며 correlation을 구하는 두 함수가 서로 같은 특수한 경우로 생각하면 된다. 연속이며 실수 범위의 신호 $f$와 $g$에 대해서,

[ f \star g(t) = f \ast g(-t) = \int^\infty_{-\infty} f(\tau) g(t+\tau) d \tau ]

위와 같으며,

[ g \star f(t) = g \ast f(-t) = \int^\infty_{-\infty} g(\tau) f(t+\tau) d \tau = \int^\infty_{-\infty} g(t - \tau) f(t) d \tau
]

convolution과는 다르게 commutable하지 않은 것을 볼 수 있다. 물론 autocorrelation의 경우에는 commutable 특징이 그대로 유지된다. 1차원에서 convolution 연산이 가지는 수학적 의미를 그대로 이해한 채로 CNN을 보게 되면 어떤 점에서 차이가 있고, 어떠한 맥락에서 convolutional neural network로 정의되었는지 확인할 수 있다.


다시 돌아와서, CNN

Convolutional neural network는 기존에 다뤘던 모든 neural network 구조와 연산 방법만 다를 뿐 맥락은 서로 유사하다. 이전에 본 perceptron 기반 MLP는 다음과 같은 구조를 가지고 있었다.

딥러닝 네트워크는 위의 perceptron을 하나의 단위로 여러 node로 구성된 각 layer와 다수의 노드를 포함한 여러 layer로 구성된 구조였다. 즉 학습 가능한 weight와 bias를 가지고 있다고 요약할 수 있다(붉은색으로 표시된 부분). 각 뉴런은 input을 받아들인 뒤 parameter인 weight, bias와 연산을 진행한 후 non-linearity 연산 gate로 표현된 activation function을 거치게 된다. 전체 네트워크는 score라는 output을 내보내는 미분 가능한 함수로서, loss function(SVM/Softmax 등등)을 최소화하는 방향으로 학습된다. Convolutional neural network도 convolution layer를 일종의 weight, bias가 포함된 neuron으로 생각하면 같은 메커니즘으로 작동한다. 하지만 convolutional neural network(CNN)는 input이 image라는 explicit assumption이 추가되었다는 점이 차이가 되겠다. 이러한 explicit assumption을 통해 architecture가 가질 수 있는 property가 생기게 되었고, 더 적은 parameter 수를 가지고도 높은 성능을 기대할 수 있는 네트워크를 만들게 되었다.


신경망 아키텍쳐

일반적인 neural network 구조를 보면 앞서 말했던 것과 동일하게 input을 single vector로 받아들인 뒤, 여러 hidden layer를 통해 dimension을 늘이고 줄이는 형태로 변형을 가한다. 각 hidden layer는 neuron 여러 개로 구성되며, 각 뉴런은 이전 layer의 모든 neuron과 fully connected된 구조를 가진다. 그리고 각 layer에서의 node는 서로 연산을 공유하지 않고 독립적인 연산을 진행한다. 마지막 layer는 output layer로써 task에 맞게끔 score를 output으로 도출하는 역할을 한다.
이러한 MLP(regular neural network) 구조는 차원 수가 급증하게 되면 scalability가 떨어진다. 예를 들어 CIFAR-10과 같은 dataset은 비교적 resolution이 작은 편에 속하는데($32 \times 32 \times 3$), 그마저도 첫번째 hidden layer가 input으로 받아들여야하는 차원 수가 $3072$가 된다. 물론 이 숫자만 보게 되면 그렇게 많지 않은 연산량이라고 생각될 수 있지만 ImageNet 데이터셋과 같이 resolution이 $224 \times 224 \times 3$이 된다면 $150,528$의 weight를 계산해야한다. 그리고 기억해야할 것이, input dimension만 이정도가 되고 output dimension까지 고려하면 weight와 bias에 필요한 parameter의 수가 급증하게 될 것이다. 딥러닝을 구현하기 위해서는 여러 레이어가 필요하고, 충분한 representation을 학습하기 위해서는 각 layer에 충분히 많은 수의 node를 할당해야할 것이다. 따라서 fully-connected layer로 구성한 기존 neural network 구조는 연산 복잡도도 높으며 fully-connected된 특징 때문에 overfitting의 위험성도 높다. 이런 측면에서 3차원의 구조를 가진 neuron, 즉 CNN은 image를 input으로 받아들인다는 explicit한 assumption과 아키텍쳐를 특정 구조로 제한한다는 점에서 얻는 이점이 있다. 기존 네트워크와는 다르게 각 layer는 input에 무관한 3개의 차원 정보인 width, height, depth를 가진다. 예를 들어 input image가 CIFAR-10이라면 input image에 대한 width, height, depth는 각각 $32$, $32$ 그리고 $3$임을 알고있는데, 이렇게 image modality가 가질 수 있는 차원에 대한 정보를 CNN의 각 layer도 가질 수 있다는 컨셉이다. 따라서 연산 구조를 보게 되면 이전의 neural network 연산이 진행되었던 것과 같이 input의 모든 부분을 연산에 포함시키지 않는 것을 확인할 수 있고, fully-connected 구조에서 벗어나면서 image에 대한 연산 overfitting을 방지할 수 있었다. 그리고 연산이 fully-connected manner에서 벗어나 input dimension에 무관하게 진행될 수 있으므로 parameter 수도 감소하게 되었다. 물론 마지막 layer의 output은 task에 따라 기존 neural network의 output size와 동일하게 생성되어야 한다.


How CNN calculate output feature for each hidden layer?

2D convolution 연산 과정을 나타내면 다음과 같다. 예를 들어 고양이 이미지를 분류하는 task에서, $H \times W \times 3$의 고양이 RGB 이미지가 있다고 생각해보자.

기존 방식은 위와 같은 RGB image data를 $1$차원 벡터로 확장시킨 후 여러 층의 hidden layer를 통과시키는 과정이었다(좌측 이미지 참고).

그러나 convolution layer에서는 이러한 flatten 과정 없이 원래의 이미지 dimension에 바로 연산이 가능한 convolutional kernel(filter)를 적용하게 된다. RGB 픽셀을 확대해서 나타내보면 우측 그림과 같다. Convolution 연산에서 사용되는 filter의 크기는 input과는 무관하기 때문에, 3차원 텐서 형태를 가지는 이미지에 그대로 적용될 수 있다. 각 픽셀 별로 연산에 사용되는 kernel을 표현한 그림이 위와 같다. 각 kernel은 해당 크기에 상응하는 학습 가능한 parameter 수를 가진다.

CIFAR-10 dataset에 대한 예시를 입체적으로 표현한 것이 위의 그림과 같다. 옅은 분홍색으로 표현된 $32 \times 32 \times 3$ 크기의 텐서가 input image이고, 그 안에 들어있는 짙은 분홍색으로 표현된 작은 3차원 텐서가 convolution kernel에 해당한다. Convolution kernel은 filter가 커버하는 input 범위에 대한 cross-correlation 연산을 진행하고(자세한 연산은 뒤에서 언급하도록 하겠다) 모든 kernel에 대한 연산 결과를 output dimension에 맞게 추출한 것이 우측에 보이는 파란색 output tensor에 해당한다. Convolution 연산이 진행되는 방식과 convolution 연산 대신 cross-correlation을 언급한 이유에 대해 서술하면 다음과 같다.

Convolution 연산은 kernel size, stide 그리고 padding이라는 기본 hyperparameter를 가진다. 위의 그림은 padding $= 1$, stride $= 1$ 그리고 kernel size $= 3$인 경우에 해당된다. 청록색으로 표현된 격자가 convolution 연산을 진행한 후 출력된 output을 의미하고, 아래에 있는 파란색의 격자가 input이다. 파란색의 격자 바깥쪽에 점선으로 된 부분이 바로 padding이다.

Kernel

실질적으로 convolution filter가 input에 적용될 범위를 나타내며, kernel은 필터 자체와 같은 의미를 가진다. 따라서 위의 그림에서는 kernel이란 움직이는 회색 영역에 해당되며, 이때의 kernel size는 $3$임을 알 수 있다. 물론 filter의 kernel size가 무조건 spatial하게 동일해야하는 것은 아니다(가로, 세로가 같은 길이를 가질 필요는 없다).

Padding

Input에 대해 외곽 부분(점선으로 그려진 부분)이 padding이라고 앞서 이미 설명했었다. Padding은 input 기준으로 constant value를 붙이는 zero-padding과 같은 방법이 있기도 하며, extrapolated padding 등 다양한 방식이 존재한다. Padding $= 1$이라는 의미는 input에 대해 상하좌우 모두 $1$칸씩 spatial dimension을 늘림을 의미하고, 이를 실제로 그림 상에서 확인해볼 수 있다. Padding도 kernel size와 마찬가지로 상하좌우 모두 동일할 필요는 없다.

Stride

Input에 padding이 추가된 영역을 포함하여 kernel은 stride만큼 움직이며 연산을 진행한다. 위의 예시에서는 $3 \times 3$의 kernel size를 가진 필터가 stride $= 1$씩 옮겨가며 연산을 진행하는 것을 볼 수 있다.

하지만 여기서 짚고 넘어가야할 점은 convolution 연산은 앞서 본 1D convolution 계산과는 다르게 input과 filter가 서로 역방향으로 연산되는 것이 아닌, 같은 방향에서 내적이 이루어지는 것을 확인할 수 있다. 그리고 위의 예시에서는 평면에 대해서 연산이 진행되는 것처럼 보이지만 사실 단일 channel에 대한 연산이 아닌, 모든 channel을 커버하는 하나의 filter가 존재하는 것이다.

따라서 실제 연산 과정은 위와 같다. 검은색으로 표현한 것이 $3 \times 3$ kernel size를 가지는 filter를 의미하고, stride $= 1$만큼 이동하면서 연산이 진행되는데, 각 채널마다 $3 \times 3$ 크기의 kernel이 적용되기 때문에 filter의 실제 크기는 RGB 채널을 모두 커버하는 $3 \times 3 \times 3$의 3D tensor가 된다. 앞서 convolutional neural network의 각 뉴런은 width, height 그리고 depth를 가진다고 했었는데 지금 보이는 필터의 kernel size가 곧 width와 height를 대표하는 값이며 input image 혹은 feature map의 channel size가 필터의 depth라고 할 수 있다. 연산이 진행되는 과정을 예시로 들면 다음과 같다.

RGB value는 임의로 채운 값이고 필터도 마찬가지로 임의로 채운 값이다. 각 채널별로 필터가 곱해진 뒤 모두 더하는 형태로 inner projection이 진행되며, 이렇게 각 채널별로 더해진 값들이 다시 모두 더해져서 해당 영역에서의 filter가 적용된 output value는 $7 + 15 + 4 = 26$이 된다. 추가로 만약 bias가 존재한다면, output value는 $26 + \text{bias}$ 꼴이 된다. 실제로 필터가 어떠한 역할을 하는지 시각화해보기 위해 toy code를 colab에서 작성해보았다. 우선 본인이 업로드하고 싶은 이미지를 업로드하면 된다. 나는 구글에서 쉽게 얻을 수 있는 아래와 같은 고양이 이미지를 업로드했다.

이미지를 numpy array로 가져오기 위해 필요한 모듈 그리고 시각화에 필요한 모듈을 정의하였다. 그리고 $0$부터 $255$까지의 값을 가지는 image를 normalize 하였다.

import cv2
from google.colab.patches import cv2_imshow
import numpy as np

image = cv2.imread("cat.jpg")
image = image/255.0 # Normalize image to 0 ~ 1

만약 google colab이 아닌 로컬에서 돌리고 싶거나 jupyter notebook을 이용한다면 google.colab.patches 대신 단순히 cv2.imshow 메소드를 사용하는 것을 추천한다. 그런 뒤 numpy array에 대한 convolution 함수를 다음과 같이 구성하였다.

def conv2d(image, out_channels, kernel, padding=0, strides=1):
    # Build kernel according to input image size
    image_height, image_width, image_channel = image.shape
    if type(kernel) == int:
        kernel_channel, kernel_height, kernel_width = image_channel, kernel, kernel
    elif type(kernel) == tuple or type(kernel) == list:
        kernel_channel, kernel_height, kernel_width = image_channel, kernel[0], kernel[1]

    kernel = np.random.randn(kernel_channel, kernel_height, kernel_width)

    # Calculate output shape according to input image size and filter size
    output_height = int(((image_height - kernel_height + 2 * padding) / strides) + 1)
    output_width= int(((image_width - kernel_width + 2 * padding) / strides) + 1)
    output_channel = out_channels
    output = np.zeros((output_height, output_width, output_channel))

    # padding(zero-padding) on input
    if padding != 0:
        image = np.pad(image, ((padding, padding), (padding, padding), (0, 0)), 'constant', constant_values=0)
    
    # calculate 2d convolution
    for c in range(output_channel):
        output_per_channel = np.zeros((output_height, output_width))
        for h in range(output_height):
            if (h * strides + kernel_height) <= image.shape[0]:
                for w in range(output_width):
                    if (w * strides + kernel_width) <= image.shape[1]:
                        output_per_channel[h][w] = np.sum(
                            image[h*strides : h*strides + kernel_height, w*strides : w*strides + kernel_height, :] * kernel
                        ).astype(np.float32)

            output[: ,:, c] = output_per_channel

    
    return output

예외처리 없이 간단하게 구성하였다. 모든 convolution layer는 정규 분포로 초기화되며, 본인은 총 3개의 convolutional hidden layer가 있는 네트워크를 구상하였다. 각 convolution 사이에는 leakyrelu 메소드를 다음과 같이 정의하여 activation function으로 사용하였다. LeakyReLU는 $0$보다 작은 value에 $0.1$의 scaling을 주도록 구성하였다.

def np_leakyrelu(image):
    return np.where(image<0, 0.1*image, image)

각각의 hidden layer에서의 output을 구하고, 이를 normalize하여 시각화가 가능하게끔 해주었다.

hidden1 = conv2d(image, 3, 3, 1, 1)
hidden2 = conv2d(np_leakyrelu(hidden1), 3, 3, 1, 1)
hidden3 = conv2d(np_leakyrelu(hidden2), 3, 3, 1, 1)

hidden1 = (hidden1 - np.min(hidden1))/(np.max(hidden1) - np.min(hidden1))*255.0
hidden2 = (hidden2 - np.min(hidden2))/(np.max(hidden2) - np.min(hidden2))*255.0
hidden3 = (hidden3 - np.min(hidden3))/(np.max(hidden3) - np.min(hidden3))*255.0

hidden1, hidden2, hidden3를 모두 시각화하면 다음과 같다.

cv2_imshow(hidden1)
cv2_imshow(hidden2)
cv2_imshow(hidden3)

필터를 전혀 학습하지 않고 random하게 초기화한 상태로도 어느 정도 물체의 윤곽을 잘 추출해내는 것을 확인할 수 있었다. 만약 task에 따라서 filter가 최적화가 되면, 위에 보이는 이미지보다 image에 대한 feature map을 잘 추출할 수 있을 것이라고 생각되었다.


Why is it convolution, not correlation?

Discrete signal $x$와 $h$가 있다고 생각해보자. 앞서 봤었던 one-dimensional convolution과는 다르게 discrete signal로 가정한 이유는 convolutional neural network가 digitized image dataset에 적용되기 때문이다. Height에 대한 dimension은 $i$라는 index를 따라가고, Width에 대한 dimension은 $j$라는 index를 따라간다고 생각해보자.

[ y(m, n) = x(m, n) \ast h(m, n) = \sum_{j = -\infty}^\infty \sum_{i = -\infty}^\infty x(i, j) \cdot h(m-i, n-j) ]

첫번째 이미지가 input에 해당되고 두번째 이미지가 kernel value라고 생각해보자. Kernel의 중앙 부분을 $0$이라고 생각한다면 예를 들어 $y(-1, -1)$을 구하는 과정은,

이와 같이 뒤집어진 kernel filter가 적용되어야하는 것이다. 그러나 실제로 연산이 진행되는 과정을 보면 뒤집힌 필터에 대한 inner projection 연산이 아닌, 단순히 곱해져서 더하는 형태로 구성된다. 물론 본인이 위에서 구현한 numpy를 활용한 conv2d 메소드 예시도 단순히 필터에 곱하는 방식을 사용하였다. 만약 정의대로 한다면, 해당 연산은 $x(m, n) \ast h(m, n)$이 아닌 $x(m, n) \ast h(-m, -n)$이 적절하다. 그리고 이 연산은 앞서 one-dimension의 경우에도 설명했었지만 commutable하지 않은 cross-correlation 식에 더 부합한다. 사실 이 내용은 그렇게 중요하지는 않지만, 그대로 convolution 연산에 대해 근본적인 의문을 가질 수 있기 때문에 짚고 넘어가고 싶었다.


Calculate output tensor shape

Convolution 연산을 활용한 network를 구성하기 위해서는 각 레이어에서 특정 convolution이 적용되었을 때의 output dimension을 알아야할 필요성이 있다. 일반화된 식을 pytorch 공식 홈페이지에서 소개하지만(참고 링크), 이 글에 보다 자세히 옮기면 다음과 같다. 만약 input tensor의 shape이 $H_\text{in} \times W_\text{in} \times C_\text{in}$이라고 하고, output tensor shape이 $H_\text{out} \times W_\text{out} \times C_\text{out}$이라고 해보자.
Convolution filter의 크기(kernel size)와는 상관없이 output channel dimension이 $C_\text{out}$가 되어야하기 때문에 filter의 개수는 $C_\text{out}$이어야 한다. 그리고 각 필터는 마찬가지로 크기와는 무관하게 input tensor의 모든 채널을 커버해야하므로 필터의 depth는 $C_\text{in}$이 된다. 따라서 정해지지 않은 필터의 크기를 제외하고 필터의 개수과 depth를 고려한 convolutional filter의 tensor shape($H \times W \times C$)과 parameter 수는 다음과 같다.

[ (\text{kernel size} \times \text{kernel size} \times C_\text{in}) \times C_\text{out}
]

소괄호 내부에 있는 것이 filter의 shape가 되고, 소괄호 전체에 곱해진 값이 필터 전체 갯수가 된다. 따라서 bias를 포함하지 않는 convolutional layer의 parameter 수는 위와 같이 계산할 수 있다. 만약 bias가 포함된다면 각 channel 마다의 bias가 포함되므로 parameter 수는 다음과 같이 증가한다.

[ (\text{kernel size} \times \text{kernel size} \times C_\text{in} + 1) \times C_\text{out}
]

지금까지는 kernel size를 정해놓지 않고 단순히 convolutional layer 하나에서의 parameter 수에 대해서 언급했었고, 실질적으로 필터가 적용되었을 때의 output tensor shape에 대해 계산하면 다음과 같다.

[ \begin{aligned} H_\text{out} =& \left( \frac{H_\text{in} + 2p - k}{s} + 1 \right) \newline W_\text{out} =& \left( \frac{W_\text{in} + 2p - k}{s} + 1 \right) \end{aligned}
]

위의 식에서는 dilation같은 특별한 convolution에 대한 output shape은 무시하였다. Notation에서의 $s$는 stride, $p$는 padding 그리고 $k$는 kernel size를 의미한다.


Another modules in CNN

물론 convolutional neural network에도 convolution 연산이 선형 연산이 되기 때문에 non-linearity gate나 pooling layer 등등 다른 형태의 module이 보조적으로 사용된다. 그 중 대표적으로 자주 사용되는 일부 레이어들에 대해 소개하도록 하겠다.

Non-linearity

AlexNet이 ImageNet 대회에서 CNN 구조로 우승했을 적에 sigmoid 대신 ReLU를 적용함으로써 빠른 성능 수렴을 얻을 수 있었다고 언급했다.

이렇듯 ReLU와 같은 non-linearity를 사용함으로써 연산 과정에서 더 많은 노드를 통한 feature extraction이 가능하다.

Pooling layer

Pooling layer는 spatial dimension을 줄여주는 역할을 한다. 보통 convolution 연산들 뒤에 붙어 $H$, $W$의 차원 수를 줄이는 역할을 수행한다. Understanding based task(image classification)는 이미지 전체의 정보를 low resolution에 semantic 정보로 수용하는 것이 보다 연산 효율적이기도 하고, 실제로 성능 향상에 더 도움이 되기 때문이다. 그리고 task specific한 부분을 제외하고도 연산 효율성에 대해 언급하자면, convolutional neural network과 fully connected layer에 비해 input node에 대해 가지는 참조 범위가 작은 만큼 filter의 개수를 증가시켜 representation power를 늘리는 경향이 있는데 만약 spatial dimension이 그대로 유지되면 연산량이 레이어가 지날수록 급증하는 문제가 발생하고, 결론적으로는 MLP에 비해 가지는 장점인 parameter efficiency가 사라지게 된다. 따라서 high level feature를 사용하는 classification이 아닌 segmentation task에서도 이와 같은 연산 효율성을 보장하기 위해 pooling 연산을 통해 downsampling을 진행한 후, upsampling을 하는 방식을 채택하였다. 물론 이와 같은 구조에서는 coarse feature가 복구하지 못하는 image signal들이 있기 때문에(일종의 aliasing) 이를 보조하고자 제안된 방법들이 있다. 해당 내용들은 본문의 주제에서 벗어나기 때문에 넘어가도록 하겠다.

Fully connected layer head

Convolutional neural network에서도 score function에 대한 loss function은 동일하게 적용하기 위해 마지막 feature map을 flatten한 뒤 fully connected layer를 적용하거나 global average pooling 이후 fully connected layer를 적용하는 방법을 사용한다.

앞서 소개한 여러 module들을 포함시킨 대략적인 CNN의 구조는 위와 같다. Convolutional neural network에서 convolution layer와 fully connected layer는 학습 가능한 parameter를 가지지만 ReLU나 Pooling layer는 학습 가능한 parameter를 가지지 않는다.


Max pooling vs Average pooling

Pooling은 아래 그림과 같이 output feature map의 spatial dimension을 줄여주는 역할을 한다. Pooling은 2D dimensional signal 특성상 low filtering을 진행하는 것과 같으며, 이미지에서의 frequency는 해상도와 관련이 있기 때문에 downsampling을 진행할수록 fine-feature보다 coarse-feature가 생성된다.

그런데 pooling을 진행하는 과정은 앞서 설명했던 것과 같이 parameter를 필요로 하지 않기 때문에 사용할 수 있는 방법은 max pooling이 진행되는 영역에서 최댓값을 뽑아내는 것과 평균을 취하는 방법 두 방법을 생각해볼 수 있다. 아마 low-level image 신호처리와 관련된 수업을 들어본 사람이라면 pooling 방식이 이미지의 resolution을 줄이는 방법과 관련이 있다는 것을 알 것이다.

일반적으로 convolution layer 사이에는 max-pooling을 사용하는데, 이는 평균을 취하는 것보다는 주된 feature(하이라이트되는)를 feature를 취하기 때문이라고 분석할 수 있다. 물론 task마다의 차이는 있겠지만 학습된 filter가 적용되면 feature map은 오브젝트의 큰 윤곽부터 시작해서 디테일한 outline을 추출하게 되고, 사실상 classification이나 object detection 그리고 segmentation 등 다양한 downstream task를 해결하는데 보다 도움이 되는 signal value는 최대치 근처의 다른 noise가 아닌 부각되는 부분들이기 때문이다.


Useful baseline models

CNN을 기반으로 딥러닝이 발전되던 당시 최고 성능을 보인 ResNet는 그 구조를 확장시켜 ResNext, ConvNext를 포함한 다양한 task에서 backbone 구조로 채택될 정도로 인기가 많은 편이다. 이외에도 CNN 기반 컴퓨터 비전 딥러닝의 시작을 열 수 있었던 AlexNet, VGGNet 그리고 GoogleNet 등등 여러 중요한 preliminary는 논문을 읽어보는 것을 추천한다. 물론 AlexNet 이전에도 더 근본 논문인 LeNet도 있다.
아키텍쳐 논문은 CNN baseline들과 Transformer baseline들을 모두 읽다보면 거의 비슷한 구조를 대부분 공유한다는 점을 알 수 있게 된다. 이외에도 network 구조를 효율적으로 찾고자 했던 efficientNet 논문이나 정해진 receptive field 모양을 가진 convolution의 한계를 해결하고자 한 deformable convolution, astrous pyramid pooling network 등등 여러 모듈과 관련된 논문들도 읽어보면 좋다.

A n o t h e r p o s t i n c a t e g o r y