07.2 합성곱 계층

CNN에서는 패딩${}^{\text{padding}}$, 스트라이드${}^{\text{stride}}$ 등 CNN 고유의 용어가 등장합니다. 또, 각 계층 사이에는 3차원 데이터같이 입체적인 데이터가 흐른다는 점에서 완전연결 신경망과 다릅니다. 그래서 CNN을 처음 배울 때는 어렵게 느낄지도 모르지만 이 책이 있으니 걱정은 넣어두셔도 좋습니다. 우선 이번 절에서는 CNN에서 사용하는 합성곱 계층의 구조를 차분히 살펴보기로 하겠습니다.

7.2.1 완전연결 계층의 문제점

지금까지 본 완전연결 신경망에서는 완전연결 계층(Affine 계층)을 사용했습니다. 완전연결 계층에서는 인접하는 계층의 뉴런이 모두 연결되고 출력의 수는 임의로 정할 수 있습니다.

완전연결 계층의 문제점은 무엇일까요? 바로 ‘데이터의 형상이 무시’된다는 사실입니다. 입력 데이터가 이미지인 경우를 예로 들면, 이미지는 통상 세로·가로·채널(색상)로 구성된 3차원 데이터입니다. 그러나 완전연결 계층에 입력할 때는 3차원 데이터를 평평한 1차원 데이터로 바꿔줘야 합니다. 사실 지금까지의 MNIST 데이터셋을 사용한 사례에서는 형상이 $(1, 28, 28)$인 이미지(1채널, 세로 28픽셀, 가로 28픽셀)를 1줄로 세운 784개의 데이터를 첫 Affine 계층에 입력했습니다.

이미지는 3차원 형상이며, 이 형상에는 소중한 공간적 정보가 담겨 있죠. 예를 들어 공간적으로 가까운 픽셀은 값이 비슷하거나, RGB의 각 채널은 서로 밀접하게 관련되어 있거나, 거리가 먼 픽셀끼리는 별 연관이 없는 등, 3차원 속에서 의미를 갖는 본질적인 패턴이 숨어 있을 것입니다. 그러나 완전연결 계층은 형상을 무시하고 모든 입력 데이터를 동등한 뉴런(같은 차원의 뉴런)으로 취급하여 형상에 담긴 정보를 살릴 수 없습니다.

한편, 합성곱 계층은 형상을 유지합니다. 이미지도 3차원 데이터로 입력받으며, 마찬가지로 다음 계층에도 3차원 데이터로 전달합니다. 그래서 CNN에서는 이미지처럼 형상을 가진 데이터를 제대로 이해할 (가능성이 있는) 것입니다.

CNN에서는 합성곱 계층의 입출력 데이터를 특징 맵${}^{\text{feature map}}$이라고도 합니다. 합성곱 계층의 입력 데이터를 입력 특징 맵${}^{\text{input feature map}}$, 출력 데이터를 출력 특징 맵${}^{\text{output feature map}}$이라고 하는 식이죠. 이 책에서는 ‘입출력 데이터’와 ‘특징 맵’을 같은 의미로 사용합니다.

7.2.2 합성곱 연산

합성곱 계층에서의 합성곱 연산을 처리합니다. 합성곱 연산은 이미지 처리에서 말하는 필터 연산에 해당하죠. 구체적인 예를 보며 설명하겠습니다.

합성곱 필터 연산 메커니즘 도로시가 칠판에 적힌 이미지 패치와 필터의 원소별 곱의 합($Filter * Image = Output$) 공식을 참조해, $5 \times 5$ 격자판 위에 마법 필터 창을 갖다 대며 한 칸씩 계산해 나가고 있어요.

도로시의 필터 연산 조립

  • 도로시: “아! 이미지의 격자 영역마다 $3 \times 3$ 필터의 가중치를 대고 마주 보는 원소끼리 곱한 뒤 다 더해주는 거네! 이걸 단일 곱셈-누산(FMA)이라고 부르는구나!”
  • 지니: “정확해! 그렇게 슬라이딩하며 한 땀 한 땀 계산해 나가면, 원래 이미지에서 에지나 특정한 시각적 패턴이 강조된 새로운 특징 맵(Feature Map)이 완성되는 거지.”

그림 7-3 합성곱 연산의 예 : 합성곱 연산을 $\circledast$ 기호로 표기

그림 7-3

[그림 7-3]과 같이 합성곱 연산은 입력 데이터에 필터를 적용합니다. 이 예에서 입력 데이터는 세로·가로 방향의 형상을 가졌고, 필터 역시 세로·가로 방향의 차원을 갖습니다. 데이터와 필터의 형상을 (높이${}^{\text{height}}$, 너비${}^{\text{width}}$)로 표기하며, 이 예에서는 입력은 $(4, 4)$, 필터는 $(3, 3)$, 출력은 $(2, 2)$가 됩니다. 문헌에 따라 필터를 커널이라 칭하기도 합니다.

그럼 [그림 7-3]의 합성곱 연산 예에서 어떤 계산이 이뤄지는지 설명하겠습니다. [그림 7-4]는 이 합성곱 연산의 계산 순서를 그려본 것입니다.

합성곱 연산은 필터의 윈도우${}^{\text{window}}$를 일정 간격으로 이동해가며 입력 데이터에 적용합니다. 여기에서 말하는 윈도우는 [그림 7-4]의 회색 $3 \times 3$ 부분을 가리킵니다. 이 그림에서 보듯 입력과 필터에서 대응하는 원소끼리 곱한 후 그 총합을 구합니다(이 계산을 단일 곱셈-누산${}^{\text{fused multiply-add, FMA}}$이라 합니다).* 그리고 그 결과를 출력의 해당 장소에 저장합니다. 이 과정을 모든 장소에서 수행하면 합성곱 연산의 출력이 완성됩니다.


* 옮긴이 _ [그림 7-4]의 첫 번째 그림이라면 (왼쪽 위 원소부터 오른쪽으로 스캔해가며) $1\times2 + 2\times0 + 3\times1 + 0\times2 + 1\times2 + 2\times2 + 3\times1 + 0\times0 + 1\times2 = 15$ 계산을 수행합니다.

그림 7-4 합성곱 연산의 계산 순서

그림 7-4

자, 완전연결 신경망에는 가중치 매개변수와 편향이 존재하는데, CNN에서는 필터의 매개변수가 그동안의 ‘가중치’에 해당합니다. 그리고 CNN에도 편향이 존재합니다. [그림 7-3]은 필터를 적용하는 단계까지만 보여준 것이고, 편향까지 포함하면 [그림 7-5]와 같은 흐름이 됩니다.

그림 7-5 합성곱 연산의 편향 : 필터를 적용한 원소에 고정값(편향)을 더한다.

그림 7-5

[그림 7-5]와 같이 편향은 필터를 적용한 후의 데이터에 더해집니다. 그리고 편향은 항상 하나($1 \times 1$)만 존재합니다. 그 하나의 값을 필터를 적용한 모든 원소에 더하는 것이죠.

7.2.3 패딩

합성곱 연산을 수행하기 전에 입력 데이터 주변을 특정 값(예컨대 0)으로 채우기도 합니다. 이를 패딩${}^{\text{padding}}$이라 하며, 합성곱 연산에서 자주 이용하는 기법입니다. 예를 들어 [그림 7-6]은 $(4, 4)$ 크기의 입력 데이터에 폭이 1인 패딩을 적용한 모습입니다. 폭 1짜리 패딩이라 하면 입력 데이터 사방 1픽셀을 특정 값으로 채우는 것이죠.

그림 7-6 합성곱 연산의 패딩 처리 : 입력 데이터 주위에 0을 채운다(패딩은 점선으로 표시했으며 그 안의 값 ‘0’은 생략했다).

그림 7-6

[그림 7-6]과 같이 처음에 크기가 $(4, 4)$인 입력 데이터에 패딩이 추가되어 $(6, 6)$이 됩니다. 이 입력에 $(3, 3)$ 크기의 필터를 걸면 $(4, 4)$ 크기의 출력 데이터가 생성됩니다. 이 예에서는 패딩을 1로 설정했지만, 2나 3 등 원하는 정수로 설정할 수 있습니다. 만약 [그림 7-5]에 패딩을 2로 설정하면 입력 데이터의 크기는 $(8, 8)$이 되고 3으로 설정하면 $(10, 10)$이 됩니다.

NOTE_ 패딩은 주로 출력 크기를 조절할 목적으로 사용합니다. 예를 들어 $(4, 4)$ 입력 데이터에 $(3, 3)$ 필터를 적용하면 출력은 $(2, 2)$가 되어, 입력보다 2만큼 줄어듭니다. 이는 합성곱 연산을 몇 번이나 되풀이하는 심층 신경망에서는 문제가 될 수 있습니다. 합성곱 연산을 거칠 때마다 크기가 작아지면 어느 시점에서는 출력 크기가 1이 되어버리겠죠. 더 이상은 합성곱 연산을 적용할 수 없다는 뜻이죠. 이러한 사태를 막기 위해 패딩을 사용합니다. 앞의 예에서는 패딩의 폭을 1로 설정하니 $(4, 4)$ 입력에 대한 출력이 같은 크기인 $(4, 4)$로 유지되었습니다. 한 마디로 입력 데이터의 공간적 크기를 고정한 채로 다음 계층에 전달할 수 있습니다.

7.2.4 스트라이드

필터를 적용하는 위치의 간격을 스트라이드${}^{\text{stride}}$라고 합니다.* 지금까지 본 예는 모두 스트라이드가 1이었지만, 예를 들어 스트라이드를 2로 하면 필터를 적용하는 윈도우가 두 칸씩 이동합니다(그림 7-7).

그림 7-7 스트라이드가 2인 합성곱 연산

그림 7-7


* 옮긴이 _ 우리말로는 ‘보폭’이란 뜻입니다.

[그림 7-7]에서는 크기가 $(7, 7)$인 입력 데이터에 스트라이드를 2로 설정한 필터를 적용합니다. 이처럼 스트라이드는 필터를 적용하는 간격을 지정합니다.

그런데 스트라이드를 2로 하니 출력은 $(3, 3)$이 되는군요. 이처럼 스트라이드를 키우면 출력 크기는 작아집니다. 한편, 패딩을 크게 하면 출력 크기가 커졌죠. 이러한 관계를 수식화하면 어떻게 될까요? 이어서 패딩, 스트라이드, 출력 크기를 어떻게 계산하는지 살펴보겠습니다.

패딩과 스트라이드 작용 비유 토토가 격자 테두리에 폭신폭신한 패딩 쿠션을 부지런히 두르고 있고, 스트라이드 보폭을 2로 맞춰 신나게 두 칸씩 건너뛰고 있어요.

토토의 깡충깡충 보폭 특강

  • 토토: “왈왈! 테두리에 패딩(Padding)을 채워두면 가장자리 정보가 사라지는 걸 방지해 주어 출력 크기가 줄어들지 않아! 그리고 보폭(Stride)을 키우면 껑충껑충 건너뛰니까 출력 크기가 쏙 줄어든다 멍!”
  • 도로시: “그렇구나! 테두리 안전바(패딩 $P$)와 발걸음 속도(스트라이드 $S$)를 잘 엮으면 출력 맵의 해상도를 원하는 규격으로 자유롭게 제어할 수 있겠어!”

입력 크기를 $(H, W)$, 필터 크기를 $(FH, FW)$, 출력 크기를 $(OH, OW)$, 패딩을 $P$, 스트라이드를 $S$라 하면, 출력 크기는 다음 식으로 계산합니다.

\(OH = \frac{H + 2P - FH}{S} + 1\) \(OW = \frac{W + 2P - FW}{S} + 1\) [식 7.1]

그러면 이 식을 사용하여 연습을 좀 해봅시다.

예 1 : [그림 7-6]의 예

  • 입력 : $(4, 4)$, 패딩 : 1, 스트라이드 : 1, 필터 : $(3, 3)$ \(OH = \frac{4 + 2 \cdot 1 - 3}{1} + 1 = 4\) \(OW = \frac{4 + 2 \cdot 1 - 3}{1} + 1 = 4\)

예 2 : [그림 7-7]의 예

  • 입력 : $(7, 7)$, 패딩 : 0, 스트라이드 : 2, 필터 : $(3, 3)$ \(OH = \frac{7 + 2 \cdot 0 - 3}{2} + 1 = 3\) \(OW = \frac{7 + 2 \cdot 0 - 3}{2} + 1 = 3\)

예 3

  • 입력 : $(28, 31)$, 패딩 : 2, 스트라이드 : 3, 필터 : $(5, 5)$ \(OH = \frac{28 + 2 \cdot 2 - 5}{3} + 1 = 10\) \(OW = \frac{31 + 2 \cdot 2 - 5}{3} + 1 = 11\)

NOTE_ 일부 판본(초기 인쇄본 등)에서는 예 2와 예 3 수식의 분모가 각각 $S$값인 2와 3 대신 1로 오기되어 있습니다. 여기서는 올바른 수식(분모를 2와 3으로 수정)으로 표기하였습니다.

이상의 예에서처럼 [식 7.1]에 단순히 값을 대입하기만 하면 출력 크기를 구할 수 있습니다. 단, [식 7.1]의 $\frac{H+2P-FH}{S}$와 $\frac{W+2P-FW}{S}$가 정수로 나눠떨어지는 값이어야 한다는 점에 주의해야 합니다. 출력 크기가 정수가 아니면 오류를 내는 등의 대응을 해줘야겠죠.* 덧붙여서, 딥러닝 프레임워크 중에는 값이 딱 나눠떨어지지 않을 때는 가장 가까운 정수로 반올림하는 등, 특별히 에러를 내지 않고 진행하도록 구현하는 경우도 있습니다.


* 옮긴이 _ $OH$와 $OW$는 원소의 개수이니 당연하겠죠.

7.2.5 3차원 데이터의 합성곱 연산

지금까지 2차원 형상을 다루는 합성곱 연산을 살펴봤습니다. 그러나 이미지만 해도 세로·가로에 더해서 채널까지 고려한 3차원 데이터입니다. 이번 절에서는 조금 전과 같은 순서로, 채널까지 고려한 3차원 데이터를 다루는 합성곱 연산을 살펴보겠습니다.

[그림 7-8]은 3차원 데이터의 합성곱 연산 예입니다. 그리고 [그림 7-9]는 계산 순서입니다. 2차원일 때(그림 7-3)와 비교하면, 길이 방향(채널 방향)으로 특징 맵이 늘어났습니다. 채널 쪽으로 특징 맵이 여러 개 있다면 입력 데이터와 필터의 합성곱 연산을 채널마다 수행하고, 그 결과를 더해서 하나의 출력을 얻습니다.

그림 7-8 3차원 데이터 합성곱 연산의 예

그림 7-8


* 옮긴이 _ 합성곱 연산이 아직 잘 이해되지 않는다면, 혹은 내가 이해한 것이 맞는지 궁금하다면 다음 사이트를 들어가 보세요. 웹페이지를 아래로 스크롤해 중간쯤을 보면 합성곱 연산의 ‘움직이는 데모’를 확인하실 수 있습니다. http://cs231n.github.io/convolutional-networks/

그림 7-9 3차원 데이터 합성곱 연산의 계산 순서

그림 7-9

3차원의 합성곱 연산에서 주의할 점은 입력 데이터의 채널 수와 필터의 채널 수가 같아야 한다는 것입니다. 이 예에서는 모두 3개로 일치합니다. 한편, 필터 자체의 크기는 원하는 값으로 설정할 수 있습니다(단, 모든 채널의 필터가 같은 크기여야 합니다). 이 예에서는 필터의 크기가 $(3, 3)$이지만, 원한다면 $(2, 2)$나 $(1, 1)$ 또는 $(5, 5)$ 등으로 설정해도 되는 것이죠. 다시 말하지만, 필터의 채널 수는 입력 데이터의 채널 수와 같도록(이 예에서는 3) 설정해야 합니다.

3차원 합성곱 연산 큐브 지니가 빨간색(R), 초록색(G), 파란색(B) 3개 채널의 입력 큐브 이미지 위에 3개 채널의 필터 스택을 쌓아두고 한꺼번에 채널별 곱셈의 누적 합을 구하는 원리를 시각적으로 묘사하고 있어요.

지니의 3차원 합성곱 채널 매칭 규칙

  • 지니: “도로시, 입력 데이터가 R·G·B 3채널이면, 필터도 반드시 똑같은 3채널 스택을 가져야 해! 채널별로 각각 필터가 합성곱을 수행하고, 그 결과값들을 마지막에 싹 더해주어 최종 1장의 2차원 피처 맵을 만들어 낸단다.”
  • 도로시: “아! 그래서 입력 채널 수 $C$와 필터의 채널 수 $C$는 항상 동일하게 맞추는 게 철칙이구나! 연산된 결과 채널들의 총합으로 하나의 피처 맵이 출력된다는 게 정말 신기해!”

7.2.6 블록으로 생각하기

3차원의 합성곱 연산은 데이터와 필터를 직육면체 블록이라고 생각하면 쉽습니다. 블록은 [그림 7-10]과 같은 3차원 직육면체입니다. 또, 3차원 데이터를 다차원 배열로 나타낼 때는 (채널${}^{\text{channel}}$, 높이${}^{\text{height}}$, 너비${}^{\text{width}}$) 순서로 쓰겠습니다. 예를 들어 채널 수 $C$, 높이 $H$, 너비 $W$인 데이터의 형상은 $(C, H, W)$로 씁니다. 필터도 같은 순서로 씁니다. 예를 들어 채널 수 $C$, 필터 높이 $FH$, 필터 너비 $FW$의 경우 $(C, FH, FW)$로 씁니다.

그림 7-10 합성곱 연산을 직육면체 블록으로 생각한다. 블록의 형상에 주의할 것!

그림 7-10

자, 이 예에서 출력 데이터는 한 장의 특징 맵입니다. 한 장의 특징 맵을 다른 말로 하면 채널이 1개인 특징 맵이죠. 그럼 합성곱 연산의 출력으로 다수의 채널을 내보내려면 어떻게 해야 할까요? 그 답은 필터(가중치)를 다수 사용하는 것입니다. 그림으로는 [그림 7-11]처럼 됩니다.

그림 7-11 여러 필터를 사용한 합성곱 연산의 예

그림 7-11

이 그림과 같이 필터를 FN개 적용하면 출력 맵도 FN개가 생성됩니다. 그리고 그 FN개의 맵을 모으면 형상이 $(FN, OH, OW)$인 블록이 완성됩니다. 이 완성된 블록을 다음 계층으로 넘기겠다는 것이 CNN의 처리 흐름입니다.

이상에서 보듯 합성곱 연산에서는 필터의 수도 고려해야 합니다. 그런 이유로 필터의 가중치 데이터는 4차원 데이터이며 (출력 채널 수, 입력 채널 수, 높이, 너비) 순으로 씁니다. 예를 들어 채널 수 3, 크기 $5 \times 5$인 필터가 20개 있다면 $(20, 3, 5, 5)$로 씁니다.

자, 합성곱 연산에도 (완전연결 계층과 마찬가지로) 편향이 쓰입니다. [그림 7-12]은 [그림 7-11]에 편향을 더한 모습입니다.

그림 7-12 합성곱 연산의 처리 흐름(편향 추가)

그림 7-12

[그림 7-12]에서 보듯 편향은 채널 하나에 값 하나씩으로 구성됩니다. 이 예에서는 편향의 형상은 $(FN, 1, 1)$이고, 필터의 출력 결과의 형상은 $(FN, OH, OW)$입니다. 이들 두 블록을 더하면 편향의 각 값이 필터의 출력인 $(FN, OH, OW)$ 블록의 대응 채널의 원소 모두에 더해집니다. 참고로, 형상이 다른 블록의 덧셈은 넘파이의 브로드캐스트 기능으로 쉽게 구현할 수 있습니다(“1.5.5 브로드캐스트” 참고).

7.2.7 배치 처리

신경망 처리에서는 입력 데이터를 한 덩어리로 묶어 배치로 처리했습니다. 완전연결 신경망을 구현하면서는 이 방식을 지원하여 처리 효율을 높이고, 미니배치 방식의 학습도 지원하도록 했습니다.

합성곱 연산도 마찬가지로 배치 처리를 지원하고자 합니다. 그래서 각 계층을 흐르는 데이터의 차원을 하나 늘려 4차원 데이터로 저장합니다. 구체적으로는 데이터를 (데이터 수, 채널 수, 높이, 너비) 순으로 저장합니다. 데이터가 $N$개일 때 [그림 7-12]를 배치 처리한다면 데이터 형태가 [그림 7-13]처럼 되는 것이죠.

그림 7-13 합성곱 연산의 처리 흐름(배치 처리)

그림 7-13

배치 처리 시의 데이터 흐름을 나타낸 [그림 7-13]을 보면 각 데이터의 선두에 배치용 차원을 추가했습니다. 이처럼 데이터는 4차원 형상을 가진 채 각 계층을 타고 흐릅니다. 여기에서 주의할 점으로는 신경망에 4차원 데이터가 하나 흐를 때마다 데이터 $N$개에 대한 합성곱 연산이 이뤄진다는 것입니다. 즉, $N$회 분의 처리를 한 번에 수행하는 것이죠.

서브목차