✳️ how-conv-work
Interactive Note · How AI Works

합성곱(Convolution)은
실제로 무엇을 하는가

"뒤집고, 밀고, 곱하고, 더한다." 신호 스무딩부터 CNN의 특징 추출까지, 전혀 달라 보이는 문제들이 전부 이 한 연산으로 수렴합니다. 수학적 정의가 왜 그렇게 생겼는지, 그 결과가 무엇을 의미하는지를 브라우저에서 직접 실험하며 확인합니다.

모든 데모는 순수 JavaScript로 이 페이지 안에서 계산됩니다 — 서버도, 라이브러리도 없습니다.

Section 1

§1정의 — 뒤집고, 밀고, 곱하고, 더한다

두 함수 f와 g의 합성곱은 이렇게 정의됩니다.

(f ∗ g)(t) = ∫−∞∞ f(τ) · g(t − τ) dτ 연속 신호 버전 — τ 위를 훑으면서 f와 "뒤집어서 t만큼 민 g"를 곱해 적분
(f ∗ g)[n] = Σm f[m] · g[n − m] 이산 신호 버전 — 이 페이지의 모든 데모는 이 식을 그대로 계산합니다

수식이 낯설다면 g[n − m] 하나만 뜯어보면 됩니다. m이 커질수록 n − m은 작아지므로, g를 좌우로 뒤집은 것이고, n이 커지면 뒤집힌 g가 통째로 오른쪽으로 밀립니다. 그래서 출력의 n번째 값 하나를 계산하는 과정은 항상 네 단계입니다.

  1. 뒤집기(flip) — 커널 g를 좌우 반전해 g[−m]을 만든다.
  2. 밀기(shift) — 뒤집은 커널을 n만큼 밀어 g[n − m]을 만든다.
  3. 곱하기(multiply) — 겹치는 자리끼리 f[m] · g[n − m]을 계산한다.
  4. 더하기(sum) — 전부 더한 값이 출력 y[n] 하나가 된다. n을 1 옮겨 반복.
핵심 직관: 출력의 각 점 y[n]은 "입력을 그 위치 주변에서 커널이 정한 가중치로 섞은(가중합한) 값"입니다. 커널을 무엇으로 두느냐에 따라 같은 연산이 평균이 되고, 미분이 되고, 메아리가 되고, 엣지 검출기가 됩니다.
Section 2

§2직접 밀어 보기 — 1D 합성곱 기계

아래 슬라이더가 정의식의 n입니다. 위 그래프의 파란 막대가 입력 f, 주황 윤곽이 뒤집혀서 n 위치에 와 있는 커널 g[n − m]입니다. 가운데 보라 막대가 자리별 곱, 그 합이 아래 그래프의 출력 y[n] 한 점이 됩니다.

1D 합성곱 기계
신호와 커널을 바꿔 가며 재생해 보세요. "뒤집기" 스위치를 끄면 §4에서 다룰 교차상관(cross-correlation)이 됩니다.
입력 f[m] 커널 g[n−m] (뒤집혀 밀린 상태) 자리별 곱 출력 y[n]

커널을 차분 [−1 0 +1]로 바꿔 보세요. 신호가 평평한 곳에서는 출력이 0에 가깝고, 신호가 급하게 변하는 곳에서만 출력이 튑니다 — 같은 기계가 변화 감지기가 됐습니다. 비대칭 램프 커널에서 "뒤집기"를 껐다 켜면 출력이 달라지는 것도 확인해 보세요.

Section 3

§3그래서 수학적으로 무슨 의미인가

합성곱은 하나의 연산이지만, 커널과 보는 관점에 따라 서로 다른 네 가지 얼굴을 가집니다. 이 노트의 나머지 절이 각각을 실험으로 다룹니다.

① 이동하는 가중평균 (필터). 커널의 합이 1이면 y[n]은 n 주변 값들의 가중평균입니다. 평평한 커널은 스무딩(저역통과), 부호가 갈리는 커널은 미분(고역통과)이 됩니다. — §2에서 이미 봤습니다.

② 시스템의 응답 (중첩 원리). 선형이고 시간에 불변인 시스템(LTI)은 "임펄스 하나에 어떻게 반응하는가"만 알면 모든 입력에 대한 출력을 알 수 있고, 그 출력이 정확히 입력과 임펄스 응답의 합성곱입니다. — §4

③ 독립인 것을 더할 때 생기는 분포. 독립 확률변수 X + Y의 분포는 각 분포의 합성곱입니다. 주사위를 여러 개 던지면 종 모양이 나오는 이유가 여기 있습니다. — §5

④ 주파수 영역의 곱셈. 시간 영역에서의 합성곱은 주파수 영역에서 단순 곱셈이 됩니다 (합성곱 정리). "커널이 어떤 주파수를 살리고 죽이는가"로 필터를 읽을 수 있게 됩니다. — §6

왜 하필 "뒤집기"인가? 다항식 곱셈을 떠올리면 자연스럽습니다. (f₀ + f₁x + f₂x²)(g₀ + g₁x)에서 xⁿ의 계수는 지수의 합이 n이 되는 쌍끼리 곱해 더한 Σ fmgn−m — 정확히 합성곱입니다. 한쪽 인덱스가 커지면 다른 쪽은 작아져야 하니, 한쪽을 뒤집어 맞대는 모양이 저절로 나옵니다. 확률(§5)에서도 X + Y = n이 되려면 X = m일 때 Y = n − m이어야 하는 것과 같은 구조입니다.
Section 4

§4임펄스 응답 — 합성곱이 어디에나 나타나는 이유

어떤 시스템(방의 울림, 카메라 렌즈의 흐림, 스프링의 진동…)이 선형(입력을 2배 하면 출력도 2배, 입력을 더하면 출력도 더해짐)이고 시간 불변(오늘 치나 내일 치나 반응이 같음)이라고 합시다. 임의의 입력은 "크기가 다른 임펄스들의 나열"로 쪼갤 수 있으므로, 임펄스 하나에 대한 반응 h만 알면 전체 출력은 각 임펄스가 만든 반응을 겹쳐 더한 것 — 즉 y = f ∗ h 입니다. 합성곱의 정의가 아니라 중첩 원리의 결과로 합성곱이 튀어나오는 겁니다.

아래 캔버스를 클릭해서 임펄스를 놓아 보세요 (드래그한 높이만큼 크기가 정해집니다). 각 임펄스가 메아리(임펄스 응답)를 만들고, 회색 굵은 선이 그 합 = 합성곱입니다.

중첩 놀이터 — 클릭해서 임펄스 놓기
임펄스 응답 h = 감쇠 진동(메아리). 임펄스를 겹쳐 놓으면 응답도 그대로 겹쳐집니다.
입력 임펄스 f 각 임펄스가 만든 응답 (h를 밀고 스케일) 합 = f ∗ h
이것이 §1 정의의 "물리적 독해"입니다: y[n] = Σm f[m] · h[n − m] — "n 시점의 출력은, 과거 m 시점에 들어온 입력 f[m]이 (n − m)만큼 시간이 지난 뒤 남긴 흔적 h[n − m]들의 총합이다."
Section 5

§5주사위를 더하면 — 확률분포의 합성곱

독립 확률변수 X, Y에 대해 P(X + Y = n) = Σm P(X = m) · P(Y = n − m). 합이 n이 되는 모든 조합을 더한 것 — 정의 그대로 합성곱입니다. 주사위 1개의 분포는 평평하지만, 개수를 늘릴수록(= 합성곱을 반복할수록) 분포가 종 모양으로 수렴합니다. 이것이 중심극한정리의 시각적 실체입니다: 가우시안은 "합성곱을 반복했을 때의 고정점"입니다.

주사위 합의 분포 = 균등분포의 반복 합성곱
합이 각 값이 될 확률 (막대 위 숫자 = 경우의 수)
Section 6

§6합성곱 정리 — 시간에서 밀며 곱하기 = 주파수에서 그냥 곱하기

ℱ(f ∗ g) = ℱ(f) · ℱ(g) 푸리에 변환을 거치면 합성곱이 (주파수별) 곱셈이 된다 — 아래에서 실제 DFT로 검증합니다

커널의 푸리에 변환 |ℱ(g)|는 "이 필터가 각 주파수를 몇 배로 통과시키는가"라는 주파수 응답입니다. 이동평균 커널의 주파수 응답은 고주파에서 0에 가깝습니다 — 그래서 노이즈(고주파)가 죽고 스무딩이 됩니다. 차분 커널은 반대로 저주파를 죽입니다 — 그래서 변화(고주파)만 남습니다.

아래에서 노이즈 낀 신호에 커널을 합성곱한 뒤, 세 스펙트럼을 비교합니다. 출력 스펙트럼(초록 막대)이 입력 스펙트럼 × 커널 응답(점선)과 정확히 일치하는 것을 확인하세요.

DFT로 검증하는 합성곱 정리
|ℱ(f)| 입력 스펙트럼 |ℱ(g)| 커널 주파수 응답 |ℱ(f∗g)| 출력 스펙트럼 |ℱ(f)|·|ℱ(g)| (곱)
덤: 이 정리 덕분에 긴 합성곱은 FFT로 O(n log n)에 계산할 수 있고, 큰 수의 곱셈(자릿수 배열의 합성곱!)도 FFT로 빨라집니다. 합성곱 ↔ 곱셈의 다리인 셈입니다.
Section 7

§72차원으로 — 이미지 필터

차원을 올려도 정의는 그대로입니다. 커널이 3×3 창이 되어 이미지 위를 훑으며, 각 위치에서 창 안의 픽셀 × 커널 값을 전부 곱해 더한 것이 출력 픽셀 하나가 됩니다.

y[i, j] = Σa Σb x[i−a, j−b] · k[a, b]

출력 이미지 위에 마우스를 올려 보세요. 그 픽셀 하나가 어떤 3×3 곱셈-덧셈에서 나왔는지 오른쪽 패널에 계산 과정이 그대로 표시됩니다. 커널 값은 직접 수정할 수도 있습니다.

3×3 이미지 합성곱 — 커널을 바꾸면 필터의 성격이 바뀝니다
입력 x (96×96, 회색조)
∗
커널 k — 직접 수정 가능
합=9 → 자동으로 9로 나눔
출력 y = x ∗ k — 마우스를 올려 보세요
출력 이미지 위에 마우스를 올리면
그 픽셀의 계산 과정이 여기 표시됩니다.

같은 "곱하고 더하기"인데 커널만 바꾸면 — 흐려지고(블러 = 2D 가중평균 = 저역통과), 또렷해지고(샤픈 = 원본 + 고주파), 윤곽만 남습니다(Sobel = 방향별 미분). §2~§6에서 본 1D의 의미들이 그대로 2D로 올라온 것입니다. Sobel처럼 커널 합이 0인 필터는 평평한 영역을 0(회색으로 표시)으로 보내고 변화만 남깁니다.

Section 8

§8채널 — conv가 채널 수를 마음대로 바꿔 주는 이유

여기까지는 채널이 1개(흑백)인 척했습니다. 하지만 실제 입력은 채널이 여러 장입니다 — RGB 이미지는 3장, ResNet 중간층의 특징맵은 64장, 256장씩 쌓여 있습니다. "1×1 conv로 채널을 256 → 64로 줄인다"가 이해되지 않는다면, 십중팔구 아래 사실을 빠뜨렸기 때문입니다.

오해 바로잡기: "3×3 커널"은 사실 3×3짜리 종이 한 장이 아니라 3×3×Cin짜리 벽돌입니다. 커널은 입력의 모든 채널을 한꺼번에 뚫고 들어가 공간 방향으로도, 채널 방향으로도 곱해서 전부 더합니다. 그래서 커널 하나가 만드는 출력은 입력 채널 수와 무관하게 항상 딱 1장입니다.
yc′[i, j] = Σc=1Cin Σa Σb xc[i−a, j−b] · kc′,c[a, b] 채널 c에 대한 합(Σc)이 추가됐을 뿐 — 출력 채널 c′ 하나는 "입력 전 채널의 가중합" 1장

그럼 출력 채널 수는 어디서 오는가? 이런 벽돌(필터)을 몇 개 꽂느냐에서 옵니다. 필터를 64개 두면 출력이 64장, 256개 두면 256장. 즉 출력 채널 수 Cout은 입력에서 계산되는 값이 아니라 설계자가 고르는 필터 개수입니다. "conv가 채널 수를 바꿔 준다"는 말의 실체는 "필터 개수를 원하는 만큼 두면 그게 곧 새 채널 수"라는 뜻입니다.

필터 개수 = 출력 채널 수 — 눈으로 보는 형태 변환
Cin, Cout, K를 바꿔 보세요. 필터 하나(주황 벽돌)는 항상 입력 전 채널을 관통하고, 출력 1장을 만듭니다.

1×1 conv — 공간은 안 보고 채널만 섞는 "픽셀별 완전연결층"

K = 1로 줄이면 커널은 1×1×Cin, 즉 이웃 픽셀은 전혀 안 보고 같은 위치의 채널 벡터(길이 Cin)에 가중치를 곱해 더하기만 합니다. 필터 Cout개를 모으면 각 픽셀 위치마다 Cout×Cin 행렬 곱 하나 — 모든 픽셀에 똑같이 적용되는 작은 완전연결층입니다. 그래서 1×1 conv는 순수한 채널 수 변환기가 됩니다.

아래에서 실제로 해 보세요. RGB 이미지(Cin = 3)에 1×1 필터 1개(가중치 딱 3개)를 적용해 출력 채널 1장을 만드는 데모입니다. 슬라이더가 곧 필터의 학습 파라미터입니다 — 가중치를 어떻게 두느냐에 따라 "밝기 채널", "빨강−초록 대비 채널" 같은 새로운 채널이 합성됩니다.

1×1 conv 채널 믹서 — 3채널을 1채널로
출력 위에 마우스를 올리면 그 픽셀의 채널 벡터 · 가중치 계산이 표시됩니다.
입력 x — RGB, Cin=3
xR
xG
xB
× 1×1 필터 w (파라미터 3개)
wR0.33
wG0.33
wB0.33
= 새 채널 1장 →
출력 y = wRxR + wGxG + wBxB
출력 위에 마우스를 올려 보세요

이게 전부입니다. ResNet bottleneck의 1×1 conv, 64필터는 위 데모의 필터를 64개로 늘리고 Cin을 256으로 늘린 것뿐입니다: 각 픽셀에서 길이 256짜리 채널 벡터에 64×256 행렬을 곱해 길이 64짜리 벡터를 만듭니다. 채널을 "버려서" 줄이는 게 아니라, 256개 전부의 가중합으로 새 채널 64개를 합성하는 것 — 그래서 정보를 압축하면서 줄일 수 있고, 반대로 필터를 256개 두면 다시 늘릴 수도 있습니다. 비싼 3×3 conv를 좁은 채널(64)에서만 돌리고 1×1로 줄였다 늘리는 것이 bottleneck 구조이고, 지름길(shortcut)의 차원을 맞출 때 쓰는 projection도 같은 1×1 conv입니다.

→ 이 구조만 따로 다룬 자료: ResNet Bottleneck에서 1×1 conv의 역할

Section 9

§9CNN — 커널을 손으로 만들지 않고 학습시킨다

§7에서 우리는 Sobel 같은 커널을 사람이 설계했습니다. CNN의 아이디어는 단순합니다: 커널의 9개(또는 그 이상) 숫자를 학습 가능한 파라미터로 두고, 역전파로 데이터에서 배우게 하자. 실제로 학습된 CNN의 첫 층에서는 Sobel과 놀랍도록 닮은 엣지/색 검출 커널이 저절로 나타납니다.

합성곱을 쓰는 이유는 수학적 성질 그대로입니다:

① 파라미터 공유 — 96×96 이미지를 완전연결층으로 처리하면 위치마다 다른 가중치가 필요하지만, 합성곱은 같은 3×3 커널 하나를 모든 위치에 재사용합니다 (9,216픽셀 → 파라미터 9개).
② 평행이동 등변성(equivariance) — 시간 불변성(§4)의 공간 버전. 입력이 옆으로 밀리면 출력 특징맵도 그대로 밀립니다. "고양이는 어디에 있어도 고양이"라는 사전 지식을 구조에 심은 것.
③ 지역성 — 각 출력은 작은 창만 봅니다. 층을 쌓으면 수용 영역(receptive field)이 점점 넓어져 엣지 → 무늬 → 부위 → 물체로 추상화가 올라갑니다.

마지막 퍼즐 한 조각: 출력 크기입니다. 패딩 P를 두르고 스트라이드 S로 건너뛰며 커널 K를 밀면 —

스트라이드 · 패딩 놀이터
주황 창이 커널, 오른쪽이 출력 특징맵. ▶를 누르면 커널이 훑는 순서대로 출력이 채워집니다.
입력 (점선 = 패딩)
출력 특징맵

한 가지 고백: 딥러닝 프레임워크의 Conv2d는 §1의 정의에서 뒤집기를 생략합니다 (즉 수학적으로는 교차상관). 커널을 어차피 학습하기 때문에, 뒤집힌 커널을 배우면 그만이라 결과적으로 아무 차이가 없기 때문입니다. §2에서 뒤집기 스위치를 꺼 봤다면 이미 감이 올 겁니다.

# PyTorch로 §7의 Sobel X를 그대로 재현
import torch, torch.nn.functional as F
sobel_x = torch.tensor([[-1., 0., 1.],
                        [-2., 0., 2.],
                        [-1., 0., 1.]]).view(1, 1, 3, 3)
y = F.conv2d(x, sobel_x, padding=1)   # 이름은 conv지만 실은 교차상관!
Section 10

§10이해했는지 확인하기