이미지의 특징은 개별 픽셀값뿐 아니라 이웃한 픽셀들이 이루는 모양에도 담겨 있다. 합성곱 신경망(Convolutional Neural Network, CNN)은 작은 영역의 관계를 살피고, 같은 계산을 여러 위치에 반복해 이미지의 특징을 학습하는 신경망이다.
다층 퍼셉트론으로 MNIST를 분류할 때는 이미지를 한 줄로 펼쳐 입력했다. 펼치는 연산이 픽셀값 자체를 없애는 것은 아니다. 다만 완전연결층은 이웃한 픽셀을 묶어 처리하거나, 같은 계산을 여러 위치에서 공유하도록 설계되어 있지 않다. 합성곱은 이런 이미지의 구조를 연결 방식에 반영한다.
합성곱(Convolution)은 작은 가중치 묶음을 입력 위에서 이동시키며, 겹치는 값끼리 곱한 뒤 더하는 연산이다. 이 가중치 묶음을 커널(Kernel) 또는 필터(Filter)라고 한다. 한 위치에서 계산한 값이 출력의 한 칸이 되고, 위치별 결과를 모으면 특성 맵(Feature map)이 된다.
커널의 원소는 학습할 가중치이다. 학습 과정에서 손실을 줄이는 방향으로 바뀌므로, 어떤 모양에 반응할지를 사람이 모두 정해 줄 필요는 없다. 편향을 사용한다면 필터마다 편향 하나를 두고, 그 필터가 만든 모든 위치의 결과에 같은 값을 더한다.
핵심은 가중치 공유(Weight sharing)이다. 필터를 이동할 때마다 새 가중치를 만드는 것이 아니라 같은 가중치를 다시 사용한다. 따라서 한 위치에서 배운 모양을 다른 위치에서도 찾을 수 있고, 위치마다 별도의 가중치를 두는 방식보다 매개변수를 줄일 수 있다. 이것이 이미지의 이동이나 회전에 대한 예측을 항상 같게 만든다는 뜻은 아니다.
PyTorch의 nn.Conv2d는 커널을 뒤집지 않고 적용하는 교차상관(Cross-correlation)을 계산한다. 딥러닝에서는 이 연산도 관례적으로 합성곱이라고 부른다. 또한 nn.Conv2d 자체에는 ReLU가 포함되지 않으므로, 비선형 변환이 필요하면 활성화 함수를 별도로 연결한다.
채널(Channel)은 같은 위치에 놓인 서로 다른 종류의 값을 구분하는 축이다. 입력 이미지에서는 흑백의 밝기 한 종류가 1개 채널이고, RGB의 세 색 성분은 3개 채널이다. 중간 특성 맵의 채널은 색 성분에 한정되지 않고, 서로 다른 필터가 계산한 결과를 담는다.
일반적인 합성곱에서는 필터 하나가 입력의 모든 채널을 함께 사용한다. 각 채널의 작은 영역과 해당 가중치를 곱해 더하고, 채널별 결과까지 합쳐 출력값 하나를 만든다. 따라서 필터 하나가 출력 채널 하나를 만들며, 필터 수가 출력 채널 수가 된다. 여기서는 입력 채널을 그룹으로 나누지 않는 groups=1을 기준으로 한다.
입력 채널 수가 , 출력 채널 수가 , 커널의 높이와 너비가 각각 , 이면 가중치 개수는 다음과 같다.
편향을 사용하면 여기에 출력 채널 수만큼 매개변수가 추가된다. 이 식에는 이미지의 높이와 너비가 들어가지 않는다. 이미지가 커지면 같은 필터를 적용할 위치와 계산량은 늘어나지만, 필터 크기와 채널 수가 같다면 학습할 가중치 개수는 그대로이다.
스트라이드(Stride)는 필터를 한 번에 몇 칸씩 이동할지 정하는 값이다. 이동 간격이 커지면 필터를 적용하는 위치가 줄어들어 출력의 높이와 너비가 작아질 수 있다.
패딩(Padding)은 입력의 가장자리에 값을 덧붙이는 방법이다. 주로 0을 채우는 제로 패딩을 사용하며, 경계에서 계산할 범위와 출력 크기를 조절한다. 패딩을 넣는다고 언제나 입력과 출력 크기가 같아지는 것은 아니다. 커널 크기와 스트라이드를 함께 고려해야 한다.
한 방향의 입력 길이를 , 커널 길이를 , 양쪽 각각의 패딩 폭을 , 스트라이드를 라 하면 출력 길이 는 다음과 같다. 커널 원소 사이를 띄우지 않는 dilation=1 기준이다.
바닥 함수 는 계산값 이하의 가장 큰 정수를 뜻한다. 식은 패딩을 포함한 입력 안에 커널이 들어가는 시작 위치의 수를 센다. 높이와 너비에 각각 적용하면 출력의 공간 크기를 구할 수 있다.
풀링(Pooling)은 각 채널의 작은 영역을 대표값 하나로 바꾸는 연산이다. 최대 풀링(Max pooling)은 영역에서 가장 큰 값을, 평균 풀링(Average pooling)은 평균값을 사용한다. 두 방식 모두 학습할 가중치가 없으며, 채널별로 계산하므로 채널 수를 유지한다.
보통 풀링은 특성 맵의 높이와 너비를 줄이는 데 사용한다. 이후 처리할 값의 수는 줄지만, 영역 안의 세부 값과 위치 정보도 일부 사라진다. 따라서 크기를 줄이는 정도는 필요한 정보가 얼마나 남는지와 함께 생각해야 한다.
예를 들어 한 영역의 값이 1, 3, 2, 4라면 최대 풀링의 결과는 4이고 평균 풀링의 결과는 2.5이다. 최대 풀링이 그 영역의 가장 큰 반응을 남긴다면, 평균 풀링은 전체 값의 수준을 반영한다.
PyTorch의 이미지 배치는 일반적으로 (N, C, H, W) 순서이며, 각각 배치 크기·채널 수·높이·너비이다. 흑백 28×28 이미지 한 장에 3×3 필터 8개를 적용한다고 하자. 스트라이드 1, 패딩 1이면 출력 길이는 이다.
| 단계 | 설정 | 출력 모양 |
|---|---|---|
| 입력 | 흑백 이미지 한 장 | (1, 1, 28, 28) |
| 합성곱 | 필터 8개, 크기 3×3, 스트라이드 1, 패딩 1 | (1, 8, 28, 28) |
| ReLU | 각 값에 활성화 함수 적용 | (1, 8, 28, 28) |
| 최대 풀링 | 영역 2×2, 스트라이드 2, 패딩 0 | (1, 8, 14, 14) |
합성곱의 가중치는 개이고, 편향 8개를 더하면 학습할 매개변수는 80개이다. ReLU와 최대 풀링은 여기에 학습할 매개변수를 추가하지 않는다.
이 흐름에서 합성곱은 입력으로부터 8개 채널의 특징을 만들고, 풀링은 그 채널들을 유지한 채 공간 크기를 줄인다. 출력값의 개수와 학습할 가중치의 개수를 구분하면 각 층이 하는 일을 이해하기 쉽다.