개요

21편으로 텍스트와 멀티모달 이야기를 한 바퀴 돌았다. 이번 글부터는 영상(이미지) 모델이다. 그런데 시작하기 전에 솔직하게 밝힐 게 있다.

CNN은 이미 7편에서 한 번 다뤘다.

그때는 “MLP로는 이미지가 잘 안 된다, 그래서 CNN이 있다” 정도의 지도였다. 이번엔 그 지도 위를 실제로 걸어본다. 필터가 한 칸씩 어떻게 움직이는지, 크기가 왜 줄어드는지, 층을 쌓으면 무엇이 넓어지는지, 그리고 연산량과 메모리가 어느 층에서 터지는지까지 본다.

교육 자료는 대외비라 슬라이드 이미지나 예제 데이터는 싣지 않는다. 개념 흐름만 내가 이해한 방식으로 재구성했고, 그림은 전부 생성했다.


1. 왜 이미지에는 다른 구조가 필요한가

가장 단순한 신경망(FCN, 완전연결 신경망)에 사진을 넣으려면 먼저 한 줄로 펴야 한다.

FCN과 CNN의 입력 방식 차이

32×32 컬러 사진 한 장은 숫자 3×32×32 = 3072개다. 이걸 한 줄로 펴서 10개 클래스로 분류하려면 가중치가 10×3072개 필요하다. 숫자만 보면 “그래도 되겠는데?” 싶다.

문제는 개수가 아니라 잃어버리는 것이다.

한 줄로 펴는 순간, 어느 화소가 어느 화소 옆에 있었는지가 사라진다.

더 쉬운 비유로

퍼즐 500조각을 다 맞춰놓은 상태에서 사진을 보면 강아지가 보인다. 그런데 그 조각들을 한 줄로 세워 상자에 담으면? 조각은 하나도 안 잃어버렸는데 강아지는 사라진다. 조각 하나하나의 색은 그대로지만, 옆에 뭐가 있었는지를 버렸기 때문이다.

이미지에서 의미는 대부분 “옆”에서 나온다. 눈은 검은 점 하나가 아니라 검은 점 주위에 흰자가 있고 그 위에 눈썹이 있는 배치다. 그래서 이미지 모델은 처음부터 가로·세로·채널이라는 3차원 모양을 유지한 채 계산한다. 그것이 CNN이다.


2. 합성곱 — 도장 하나로 사진 전체를 훑는다

합성곱(Convolution)은 말은 어려운데 하는 일은 아주 단순하다.

작은 도장(필터)을 사진 위에서 한 칸씩 옮기며 찍고, 찍힌 자리의 점수를 적는다.

합성곱 연산과 출력 해상도

한 번 찍을 때 하는 계산은 곱셈과 덧셈뿐이다. 필터가 덮은 자리의 숫자와 필터 값을 하나씩 곱해서 전부 더한다. 수식으로는 이렇게 쓴다.

$$ y = \mathbf{w}^{T}\mathbf{x} + b $$

  • x : 필터가 지금 덮고 있는 이미지 조각
  • w : 필터의 값(학습되는 값)
  • b : 편향, 결과 전체를 살짝 올리거나 내리는 값

3×5×5 필터라면 한 번 찍는 데 곱셈이 3×5×5 = 75번이다. 그렇게 찍은 점수를 자리마다 모아 놓은 것이 특징 맵(feature map)이다.

여기서 반드시 짚고 가야 할 것

필터의 깊이는 항상 입력의 채널 수와 같다. 입력이 3채널이면 필터도 3채널짜리다. 도장을 찍을 때 종이 두께만큼 잉크가 배어드는 것과 같다. 그래서 필터 하나가 만들어내는 특징 맵은 채널이 몇 개든 항상 한 장이다.

크기는 왜 줄어드는가

도장은 종이 안쪽에서만 찍을 수 있다. 가장자리에 걸치면 찍을 자리가 모자라니까. 그래서 출력이 입력보다 작아진다.

출력 해상도 = (입력 해상도 − 필터 해상도) ÷ 스트라이드 + 1

32×32 이미지에 5×5 필터를 스트라이드 1로 굴리면 (32−5)+1 = 28이 된다. 이 한 줄이 CNN 구현에서 가장 자주 터지는 지점이다. 층마다 크기를 잘못 계산해 다음 층과 모양이 안 맞는 일이 정말 흔하다.

크기를 지키고 싶다면 — 패딩

패딩의 효과

가장자리에 0을 한 줄 둘러주면(제로 패딩) 도장을 끝까지 찍을 수 있어서 크기가 유지된다. 패딩까지 넣은 완전한 공식은 이렇다.

$$ W’ = \frac{W - K + 2P}{S} + 1 $$

W는 입력 크기, K는 커널 크기, P는 패딩, S는 스트라이드다. 3×3 필터에 패딩 1이면 크기가 그대로 유지되는데, 요즘 구조가 3×3에 패딩 1을 기본값처럼 쓰는 이유가 이거다.


3. 필터 여러 개 — 관심사가 여러 개

필터 하나는 관심사 하나다. 어떤 필터는 세로선에, 어떤 필터는 색이 바뀌는 경계에 크게 반응한다. 그래서 실제 층에는 필터를 여러 개 둔다.

필터 개수와 출력 채널

필터 개수 = 출력 채널 수

3×32×32 입력에 3×5×5 필터 6개를 쓰면 출력은 6×28×28이다. 실제 코드에서는 여기에 배치(N장씩 묶어서 처리)까지 붙어서 이런 모양이 된다.

항목 모양
입력 배치 N × C_in × H × W
필터 C_out × C_in × K × K
편향 C_out × 1
출력 배치 N × C_out × H’ × W’

처음 CNN 코드를 보면 숫자 네 개가 어지럽게 붙어 있는데, 결국 “몇 장을, 몇 채널로, 얼마나 큰 그림으로” 세 가지를 적어둔 것뿐이다.


4. 쌓기 — 그런데 그냥 쌓으면 헛수고다

층을 여러 개 쌓으면 모델이 강해질 것 같다. 그런데 여기 함정이 하나 있다.

합성곱은 선형 연산이다. 선형 연산을 아무리 쌓아도 결국 하나의 선형 연산으로 합쳐진다.

$$ W_{all} = W_3 W_2 W_1 $$

층을 3개 쌓았는데 결과가 층 1개짜리와 같은 표현력이라면, 계산만 3배 하고 얻은 게 없다. 그래서 층 사이마다 비선형 함수를 끼운다. 대표가 ReLU다.

합성곱(선형) + ReLU(비선형) 를 한 블록으로 묶어서 쌓는다

이 조합이 되어야 비로소 “깊게 쌓을수록 복잡한 패턴을 배운다”는 말이 성립한다. 6편·7편에서 본 비선형 이야기가 여기서 그대로 다시 나온다. 이름만 이미지로 바뀌었다.


5. 수용영역 — 깊이의 진짜 의미

층을 쌓으면 뭐가 좋아지는가? 답이 수용영역(Receptive Field)이다.

수용영역의 확장

수용영역 = 출력의 한 칸이 원본 이미지에서 실제로 들여다본 범위

첫 층의 한 칸은 3×3만 본다. 그런데 그 위층의 한 칸은 “3×3을 본 칸들”을 3×3만큼 모아 보므로 원본 기준 5×5를 본다. 층이 깊어질수록 이 범위가 계속 넓어진다.

더 쉬운 비유로

그림에 코를 박고 보면 붓 자국만 보인다. 한 발 물러나면 눈과 코가 보이고, 더 물러나면 “아, 사람 얼굴이구나” 한다. 한 발 물러나는 것이 층을 하나 쌓는 것이다.

그래서 CNN의 깊이는 단순히 “파라미터를 늘린다”가 아니라 “모델의 시야를 넓힌다”는 뜻이다. 이미지 분류처럼 전체 맥락이 필요한 작업에서는 이 시야 확보가 성능을 좌우한다.

문제는 이걸 층 쌓기만으로 하려면 고해상도 이미지에서 층이 너무 많이 필요하다는 점이다. 그래서 다른 손잡이들이 등장한다.


6. 해상도를 줄이는 두 가지 방법

풀링과 스트라이드 합성곱

풀링 — 배울 값이 없는 요약

2×2 조각마다 가장 큰 값만 남기면(맥스 풀링) 해상도가 절반이 된다. 얻는 게 두 가지다.

  1. 연산량 절감. 224×224를 112×112로 줄이면 그 뒤 계산이 약 4배 싸진다. 자료 기준으로 1.85 GFLOPS → 0.46 GFLOPS다
  2. 위치 변화에 대한 강건성. 고양이가 몇 화소 오른쪽으로 움직여도, 가장 큰 값을 고르는 결과는 잘 안 바뀐다

풀링은 학습하는 값이 하나도 없다. 그냥 규칙이다.

스트라이드 합성곱 — 배우면서 건너뛰기

필터를 1칸이 아니라 2칸씩 옮기면 출력이 절반이 된다. 풀링과 효과는 비슷한데 결정적인 차이가 있다.

풀링은 정해진 규칙, 스트라이드 합성곱은 줄이는 방식까지 학습한다

그래서 요즘 고도화된 구조에서는 “합성곱 + 풀링” 두 층을 스트라이드 합성곱 한 층으로 대체하는 흐름이 있다. 정보 손실도 상대적으로 적다.


7. 필터는 대체 뭘 배우나

학습이 끝난 필터를 그림으로 그려보면 모델이 뭘 봤는지 짐작할 수 있다. 자료에 나온 비교가 인상적이었다.

모델 필터가 배운 것
선형 모델 카테고리별 전형적인 모습 한 장 (템플릿)
FCN 여러 장의 템플릿
CNN 엣지, 색 경계 같은 지역적 조각

선형 모델은 “말이란 대충 이렇게 생겼다”는 흐릿한 사진 한 장을 외운다. 말이 왼쪽을 보든 오른쪽을 보든 그 한 장으로 맞춰야 하니 잘 될 리가 없다.

CNN은 부품을 배운다. 선, 모서리, 색 경계. 그리고 위층에서 그 부품을 조합한다. 부품이니까 어디에 있든 재사용된다. 이게 가중치 공유가 주는 진짜 이득이다.


8. 정리하면 CNN의 기본 골격

합성곱 → 활성화 → 풀링 → (반복) → 완전연결층

부품 하는 일 학습하는 값
합성곱 필터로 지역 특징 추출 있음 (필터·편향)
활성화(ReLU) 비선형성 부여 없음
풀링 해상도 축소, 위치 강건성 없음
스트라이드 합성곱 축소 + 특징 추출 동시에 있음
완전연결층 특징을 조합해 클래스 점수 있음

여기서 자주 나오는 오해 하나를 짚고 넘어가자.

“CNN도 마지막에 완전연결층을 쓰니까, 결국 화소를 한 줄로 펴는 것 아닌가?”

편다. 하지만 그건 마지막 출력 단계에서만 일어나는 보조 과정이다. CNN의 본질은 그 전까지 2차원 구조를 유지한 채 지역 특징을 뽑아온 과정에 있다. 처음부터 펴버리는 FCN과는 완전히 다르다.


정리

  • 이미지를 한 줄로 펴면 이웃 관계가 사라진다. CNN은 3차원 모양을 유지한다
  • 합성곱 = 필터를 옮기며 내적. 출력 = (입력 − 필터) ÷ 스트라이드 + 1
  • 패딩으로 크기를 지키고, 필터 개수로 출력 채널 수를 정한다
  • 합성곱만 쌓으면 선형 하나와 같다. 반드시 비선형(ReLU)과 짝지어 쌓는다
  • 깊이의 의미는 파라미터가 아니라 수용영역 = 시야 확보
  • 해상도 축소는 풀링(규칙) 또는 스트라이드 합성곱(학습)
  • 필터가 배우는 건 템플릿이 아니라 어디서든 재사용되는 부품이다

참고 자료

한줄 평

  • 7편에서 “CNN은 필터를 굴린다” 한 줄로 넘어갔던 걸 딥하게 들어오니 이해가 조금 더 쉬워진 것 같다.