4. CNN 5강 - 합성곱 신경망 기초
해설글
작성 · 4분 읽기 · 조회수 —
들어가며
드디어 CNN의 핵심인 합성곱(Convolution) 연산을 배웠다. 이전까지는 이미지를 1차원으로 펴서(flatten) 처리했는데, 이러면 이미지의 공간 정보가 완전히 사라진다. “옆에 있는 픽셀이 뭔지”를 모르게 되는 거다.
CNN은 이미지의 공간성을 보존하면서 특징을 추출한다는 점에서 이전 신경망과 근본적으로 다르다.
이번 강의 내용을 필터 → 출력 크기 → 수용 영역 순으로 따라가며 정리해본다.
선형 분류의 한계
이전 강의까지 배운 신경망은 tensor를 계산하면서 W를 Back Propagation으로 Optimization한다. 하지만 선형 분류로 이미지를 분류하는 건 무리가 있다.
처음엔 픽셀 값을 쭉 펴서 가중치만 잘 곱하면 되겠지 싶었는데, 실제로는 그렇지 않았다. 색상 histogram 분포가 공간적 특징과 결합되어야 의미를 파악할 수 있지만, 선형 분류는 이미지를 1차원으로 펴서 공간성을 파괴한다.
그래서 특성을 잘라 붙이는 게 아니라, 이미지의 end-to-end 네트워크를 설계해야 한다.
CNN의 구성 요소
CNN은 Convolution, Subsampling, Pooling 등의 기법을 사용한다. AlexNet이 이 구조로 ImageNet 경쟁에서 우승하면서 딥러닝 시대가 열렸다.
요즘에는 ViT(Vision Transformer)가 나와서 CNN을 안 쓰는 경우도 있지만, 여전히 많이 쓰인다.
Convolution Layer의 연산 과정
이 부분이 처음에 가장 헷갈렸다. 하나씩 뜯어보자.
필터가 슬라이딩한다는 것
- 32 $\cdot$ 32 $\cdot$ 3 크기의 이미지를 5 $\cdot$ 5 $\cdot$ 3 크기의 필터로 convolution한다
- convolution은 필터가 이미지 위를 슬라이딩하면서 겹치는 영역의 내적값을 구하는 것이다
출력 채널은 필터 개수로 결정된다
| 입력 | 필터 | 출력 |
|---|---|---|
| 32 $\cdot$ 32 $\cdot$ 3 | 5 $\cdot$ 5 $\cdot$ 3 (1개) | 28 $\cdot$ 28 $\cdot$ 1 |
| 32 $\cdot$ 32 $\cdot$ 3 | 5 $\cdot$ 5 $\cdot$ 3 (n개) | 28 $\cdot$ 28 $\cdot$ n |
즉 필터를 n개 사용하면 출력은 28 $\cdot$ 28 $\cdot$ n이 된다.
결국 무엇을 측정하는 연산인가
결국 “내 이미지가 각 필터의 패턴과 얼마나 비슷한지”를 측정하는 연산이다. 처음에는 “필터가 뭘 감지하는 건지” 감이 안 잡혔는데, 초기 레이어의 필터를 시각화하면 가로선, 세로선, 대각선 같은 단순한 패턴을 감지한다는 걸 알 수 있다.
필터의 학습과 하이퍼파라미터
“그러면 어떤 패턴을 감지하는 필터를 만들어야 하나?” — 이건 우리가 정하는 게 아니다.
Back propagation과 optimization이 필터를 학습하면서 모델이 직접 배운다. 우리가 정하는 건 하이퍼파라미터, 즉 필터 크기와 필터 개수뿐이다.
| 항목 | 누가 정하나 |
|---|---|
| 필터 크기 (예: 5 $\cdot$ 5) | 사람 (하이퍼파라미터) |
| 필터 개수 (n) | 사람 (하이퍼파라미터) |
| 필터의 가중치 (어떤 패턴을 볼지) | 모델 (학습으로 결정) |
이 역할 분담이 명확하게 이해되니까 CNN의 구조가 훨씬 납득이 갔다.
Mini-batch와 입출력 텐서
이미지를 mini-batch로 처리하기 위해 여러 이미지를 묶으므로:
- 입력: N $\cdot$ 3 $\cdot$ 32 $\cdot$ 32 (배치 크기 × 채널 × 높이 × 너비)
- 출력: N $\cdot$ n $\cdot$ 28 $\cdot$ 28 (배치 크기 × 필터 개수 × 높이 × 너비)
텐서의 규격: (H $\cdot$ W $\cdot$ C $\cdot$ N) = (높이 $\cdot$ 너비 $\cdot$ 채널 수 $\cdot$ 미니배치 수)
이 차원 순서를 정확히 아는 게 중요하다. 실제 구현할 때 shape 에러의 90%가 여기서 나온다.
다음 레이어 필터의 깊이
여기서 헷갈리기 쉬운 포인트가 있다.
다음 레이어 필터의 depth(깊이)는 이전 레이어 출력의 채널 수와 같아야 한다.
위 예시에서 첫 번째 conv 출력이 28 $\cdot$ 28 $\cdot$ n이면, 두 번째 레이어의 필터는 5 $\cdot$ 5 $\cdot$ n이 된다. 그리고 그 필터가 몇 개인지에 따라 다음 출력의 깊이가 정해진다.
처음에는 필터의 깊이를 내가 정해야 하나 싶었는데, 이전 출력 채널 수에 맞춰 자동으로 결정되는 거였다.
활성화 함수와 Padding
Conv 연산만 하면 두 가지 문제가 생긴다.
| 문제 | 원인 | 해결 |
|---|---|---|
| 비선형성 부족 | Conv 연산 자체가 선형 연산 | ReLU 추가 |
| 크기 축소 | 매 레이어마다 출력이 작아짐 | 입력 테두리에 zero padding 추가 |
zero padding으로 입력 테두리를 0으로 채우면 출력 크기를 유지할 수 있다.
Receptive Field (수용 영역)
이 개념이 CNN에서 “왜 깊은 게 좋은가?”를 설명한다.
- 첫 번째 conv의 출력은 필터 크기만큼의 국소 영역만 반영한다
- 하지만 레이어를 쌓으면 쌓을수록, 마지막 feature map의 각 원소가 반영하는 입력 영역이 점점 넓어진다
즉, 깊은 네트워크는 비선형성뿐만 아니라 더 넓은 맥락을 볼 수 있다는 내재적 장점이 있다.
Stride
stride는 필터가 한 번에 몇 칸씩 이동하는지를 의미한다. stride=2면 한 칸 건너뛰고 연산한다.
stride를 쓰면:
- 수용 영역을 효과적으로 확장할 수 있다
- 다운샘플링 효과가 있어서 연산량이 줄어든다
단순히 연산량을 줄이는 것 이상의 의미가 있다는 걸 이번에 알았다.
stride는 그냥 연산 줄이는 트릭정도로만 생각했던 게 오해였다.
헷갈리기 쉬운 포인트
1. “출력 크기 계산 공식이 자꾸 헷갈린다”
공식은 다음과 같다.
\[\text{Output} = \frac{\text{Input} + 2 \times \text{Padding} - \text{Filter}}{\text{Stride}} + 1\]예를 들어 입력 32, 패딩 2, 필터 5, 스트라이드 1이면:
\[\frac{32 + 4 - 5}{1} + 1 = 32\]패딩 덕분에 입력과 출력 크기가 같아진다. 이게 same padding이다.
| Input | Padding | Filter | Stride | Output |
|---|---|---|---|---|
| 32 | 2 | 5 | 1 | 32 (same) |
이 공식은 그냥 외울 수밖에 없다.
2. “필터가 정확히 뭘 감지하는지 모르겠다”
처음에는 나도 이게 추상적으로 느껴졌다. 하지만 학습된 필터를 시각화해보면:
| 레이어 위치 | 감지하는 특징 |
|---|---|
| 첫 레이어 (저수준) | 가로선 / 세로선 / 색상 경계 |
| 깊은 레이어 (고수준) | 눈 / 코 / 바퀴 같은 의미 단위 |
학습이 알아서 필터를 만들어낸다.
3. “padding을 하면 가장자리에 0을 넣는 건데, 그게 학습에 영향을 안 주나?”
영향이 아예 없지는 않지만, 대부분의 경우 무시할 수준이다. 0이 들어가면 해당 영역의 내적값이 작아지기는 하는데, 네트워크가 학습하면서 이를 보정하는 방향으로 가중치가 조정된다.
4. “stride를 1이 아닌 값으로 하면 패딩으로 same size를 유지할 수 있나?”
없다. same padding이 되려면 stride가 반드시 1이어야 한다. stride > 1이면 무조건 출력이 작아진다.
정리하며
CNN의 핵심은 한 줄로 정리된다.
필터를 슬라이딩하면서 이미지의 공간적 특징을 보존하며 추출한다.
그리고 레이어를 쌓을수록 receptive field가 넓어져서 더 큰 맥락을 이해하게 된다. 다음 강의에서는 이 conv layer를 어떻게 조합해서 실제 아키텍처(VGGNet, ResNet 등)를 만드는지 배운다.