역전파를 처음 공부할 때 가장 막혔던 부분이 있습니다. "오차를 왜 거꾸로 보내는 거지?"였습니다. 앞으로 계산해서 예측을 만들었는데, 왜 다시 뒤로 돌아가야 하는지 직관적으로 이해가 안 됐습니다. 그런데 손으로 직접 편미분을 하나씩 계산해 보니 이해가 됐습니다. 각 가중치가 최종 오차에 얼마나 기여했는지를 알아야 그만큼 수정할 수 있으니까요.
결국 역전파는 "네가 이 오차에 얼마나 책임이 있는가"를 수학적으로 계산하는 과정입니다. 아무리 복잡한 신경망이라도 연쇄법칙 하나로 이게 가능합니다. 층이 100개든 1000개든 방식은 동일합니다. 오늘은 그 원리를 실제 숫자와 함께 처음부터 끝까지 따라가 보겠습니다.

순전파 — 현재 지식으로 일단 풀어보기
학습의 첫 단계는 순전파(Forward Pass)입니다. 입력 데이터가 입력층에서 출력층 방향으로 흘러가면서 예측값을 만들어냅니다. 각 층에서 가중치와 행렬 곱을 하고, 활성화 함수를 통과하고, 다음 층으로 넘어가는 과정의 반복입니다.
처음 가중치는 무작위로 초기화됩니다. Xavier 초기화나 He 초기화 같은 방법을 쓰지만 어쨌든 정답을 모르는 상태에서 시작합니다. 그래서 첫 예측은 거의 항상 엉망입니다. 고양이 사진을 넣었는데 "개일 확률 87%"가 나오는 식이죠. 이 엉망진창인 첫 예측이 있어야 역전파가 시작됩니다. 얼마나 틀렸는지 알아야 얼마나 고쳐야 할지 계산할 수 있으니까요.
h1 → [W2, b2] → ReLU → h2
h2 → [W3, b3] → Softmax → ŷ (예측값)
각 층: y = activation(Wx + b)
순전파 중 각 층의 출력값을 저장해둬야 한다
→ 역전파 때 이 값들이 필요하기 때문
중요한 점이 하나 있습니다. 순전파를 진행하면서 각 층의 중간 출력값을 반드시 저장해둬야 합니다. 역전파에서 미분을 계산할 때 이 값들이 필요하기 때문입니다. PyTorch가 자동으로 연산 그래프를 기록해 두는 이유가 바로 이겁니다.
손실 함수 — 얼마나 틀렸는가
순전파가 끝나면 예측값 ŷ과 실제 정답 y를 비교합니다. 이 차이를 하나의 숫자로 요약하는 게 손실 함수(Loss Function)입니다. 이 숫자가 클수록 모델이 많이 틀렸다는 뜻이고, 0에 가까울수록 예측이 정확하다는 뜻입니다.
분류 문제: Cross-Entropy = -∑ y·log(ŷ)
예시: 정답=1(고양이), 예측=0.2
MSE = (1-0.2)² = 0.64
Cross-Entropy = -log(0.2) = 1.61
→ 크로스 엔트로피가 틀릴수록 기울기가 더 크다
→ 분류 문제에 크로스 엔트로피를 쓰는 이유
분류 문제에 MSE보다 크로스 엔트로피를 쓰는 이유가 있습니다. 모델이 완전히 틀렸을 때 크로스 엔트로피의 기울기가 훨씬 크게 나옵니다. 기울기가 커야 경사하강법이 빠르게 수정 방향으로 움직입니다. MSE는 이 상황에서 기울기가 작아져서 학습이 느려지는 문제가 있습니다. 이 내용은 앞서 엔트로피 글에서 자세히 다뤘습니다.
연쇄법칙 — 역전파의 수학적 엔진
손실값을 줄이려면 각 가중치를 어느 방향으로 얼마나 수정해야 할지 알아야 합니다. 문제는 가중치가 수억 개라는 점입니다. 각각을 따로 계산하면 불가능합니다. 이걸 효율적으로 해결하는 게 연쇄법칙(Chain Rule)입니다.
신경망은 함수가 겹겹이 쌓인 합성 함수입니다. L = f3(f2(f1(x))) 형태입니다. 연쇄법칙은 이런 합성 함수의 미분을 각 단계 미분값의 곱으로 분해합니다. 이 덕분에 출력층에서 시작해서 한 층씩 거슬러 올라가며 모든 가중치의 기울기를 계산할 수 있습니다.
L: 손실함수 (최종 오차)
ŷ: 출력층 예측값
h: 은닉층 출력
w: 구하고 싶은 가중치
층이 3개면:
dL/dw1 = dL/dh3 × dh3/dh2 × dh2/dh1 × dh1/dw1
→ 각 층의 국소 미분을 곱하기만 하면 된다
→ 층이 100개여도 방식은 동일
연쇄법칙이 강력한 이유는 각 층이 자신의 국소 미분만 계산하면 된다는 점입니다. 출력층은 자기 바로 앞 층에 대한 미분만, 은닉층은 자기 앞뒤 관계만 알면 됩니다. 이 국소 미분값들을 뒤에서 앞으로 순서대로 곱해나가면 어떤 가중치든 전체 오차에 대한 기울기를 구할 수 있습니다.
실제 숫자로 역전파 계산해보기
말로만 하면 추상적이니 실제로 계산해 보겠습니다. 입력 x=2, 가중치 w1=0.5, w2=0.3, 정답 y=1인 2층 신경망입니다. 활성화 함수는 없다고 가정합니다.
h = w1 × x = 0.5 × 2 = 1.0
ŷ = w2 × h = 0.3 × 1.0 = 0.3
L = (y - ŷ)² = (1 - 0.3)² = 0.49
[역전파 — 연쇄법칙 적용]
dL/dŷ = -2(y - ŷ) = -2 × 0.7 = -1.4
w2에 대한 기울기:
dŷ/dw2 = h = 1.0
dL/dw2 = dL/dŷ × dŷ/dw2 = -1.4 × 1.0 = -1.4
w1에 대한 기울기 (연쇄법칙):
dŷ/dh = w2 = 0.3
dh/dw1 = x = 2
dL/dw1 = dL/dŷ × dŷ/dh × dh/dw1
= -1.4 × 0.3 × 2 = -0.84
[가중치 업데이트 — 학습률 α=0.1]
w2 = 0.3 - 0.1 × (-1.4) = 0.44
w1 = 0.5 - 0.1 × (-0.84) = 0.584
손실 재계산:
h = 0.584 × 2 = 1.168
ŷ = 0.44 × 1.168 = 0.514
L = (1 - 0.514)² = 0.236 ← 0.49에서 줄었다
한 스텝 만에 손실이 0.49에서 0.236으로 절반 가까이 줄었습니다. 이 과정을 수천 번 반복하면 손실이 거의 0에 수렴합니다. 실제 모델은 가중치가 수억 개지만 각 가중치마다 이 계산을 하는 방식은 동일합니다. 다만 수억 개를 행렬 연산으로 한꺼번에 처리하는 것뿐입니다.
기울기 소실 문제와 해결책
역전파의 가장 큰 문제는 기울기 소실(Vanishing Gradient)입니다. 연쇄법칙으로 미분값을 계속 곱하다 보면 숫자가 점점 작아져서 앞쪽 층에 도달하기 전에 0에 가까워지는 겁니다. 앞쪽 층의 기울기가 0에 가까우면 가중치 업데이트가 거의 이루어지지 않아서 그 층은 사실상 학습이 멈춥니다.
10층 신경망에서 앞쪽 층의 기울기:
0.25 × 0.25 × ... × 0.25 (10번)
= 0.25^10 ≈ 0.000001 (사실상 0)
→ 앞쪽 층은 기울기를 거의 못 받는다
→ 학습이 뒤쪽 층에만 집중되는 현상 발생
이 문제를 해결하기 위해 여러 방법이 개발됐습니다. 가장 효과적인 건 ReLU 활성화 함수입니다. ReLU의 미분은 0 또는 1이기 때문에 기울기가 소실되지 않습니다. 다만 음수 구간에서 기울기가 0이 되는 "뉴런 사망(Dying ReLU)" 문제가 생겨서 이를 보완한 Leaky ReLU, ELU 같은 변형도 나왔습니다.
ReLU: f'(x) = 1 (x>0), 0 (x≤0) → 소실 없음
추가 해결책:
Xavier 초기화: 입력 뉴런 수에 맞게 가중치 초기화
He 초기화: ReLU에 최적화된 초기화 방식
Batch Normalization: 층마다 출력 분포를 정규화
Residual Connection: 기울기가 직접 흐르는 지름길 추가
ResNet이 2015년에 152층이라는 극단적으로 깊은 네트워크를 학습시킬 수 있었던 이유가 Residual Connection 덕분입니다. 기울기가 중간층을 건너뛰어 직접 앞쪽 층으로 전달되는 지름길을 만든 겁니다. 기울기 소실 문제와의 싸움이 딥러닝 발전의 역사 중 하나입니다.
가중치 업데이트 — 반성을 수치로
모든 가중치의 기울기를 구했으면 경사하강법으로 업데이트합니다. 기울기의 반대 방향으로 학습률만큼 이동하는 겁니다. 기울기가 음수면 가중치를 늘리고, 양수면 줄입니다. 이 방향으로 이동해야 손실이 줄어드니까요.
Adam 같은 최적화 알고리즘은 기본 경사하강법에 두 가지를 더합니다. 모멘텀은 이전에 이동했던 방향의 관성을 유지해서 안장점을 통과하게 합니다. 적응적 학습률은 가중치마다 학습률을 다르게 조정해서 더 빠르게 수렴하게 합니다. 현재 대부분의 딥러닝 코드에서 기본 optimizer로 Adam을 쓰는 이유입니다.
역전파 학습 단계를 정리하면 이렇습니다.
| 단계 | 수학적 작업 | 핵심 포인트 |
|---|---|---|
| 1. 순전파 | 입력 → 출력 행렬 곱 | 중간값을 저장해야 역전파에 쓴다 |
| 2. 손실 계산 | 손실 함수 적용 | 분류는 크로스 엔트로피, 회귀는 MSE |
| 3. 역전파 | 연쇄법칙으로 기울기 계산 | 기울기 소실 여부 확인 필수 |
| 4. 기울기 확인 | 파라미터별 dL/dw 계산 | 어떤 가중치가 오차의 주범인지 파악 |
| 5. 가중치 갱신 | w = w - α × dL/dw | 학습률이 너무 크면 발산, 작으면 느림 |
PyTorch에서 역전파가 동작하는 방식
PyTorch는 순전파 중에 연산 그래프(Computation Graph)를 자동으로 기록합니다. 어떤 텐서가 어떤 연산을 거쳐 결과를 만들었는지 추적하는 겁니다. loss.backward()를 호출하는 순간 이 그래프를 역방향으로 따라가며 연쇄법칙을 자동으로 계산합니다.
optimizer.zero_grad() # 이전 기울기 초기화
output = model(x) # 순전파 (연산 그래프 기록)
loss = criterion(output, y) # 손실 계산
loss.backward() # 역전파 (연쇄법칙 자동 계산)
optimizer.step() # 가중치 업데이트
→ 4줄 코드 뒤에 이 글에서 다룬 모든 수학이 있다
optimizer.zero_grad()가 첫 줄인 이유도 이제 이해가 됩니다. PyTorch는 기울기를 누적해서 저장하기 때문에 매 스텝 시작 전에 초기화해 줘야 이전 배치의 기울기가 섞이지 않습니다. 이 한 줄을 빠뜨리면 기울기가 계속 쌓여서 학습이 이상하게 됩니다. 코드 한 줄의 의미를 알고 쓰는 것과 모르고 쓰는 것, 문제가 생겼을 때 차이가 납니다.
이 연재에서 다룬 미분, 편미분, 연쇄법칙, 경사하강법, 행렬 연산이 역전파 하나에 모두 모입니다. 라이프니츠의 dy/dx가 현대 딥러닝의 loss.backward()로 이어지는 흐름, 이게 이 연재 전체가 말하고 싶었던 것입니다.
'데이터 과학 수학' 카테고리의 다른 글
| 손실 함수(Loss Function)의 종류와 선택, 평균제곱오차(MSE)부터 교차 엔트로피까지 (0) | 2026.04.11 |
|---|---|
| 훈련 99% 검증 67%, 과적합을 잡는 L1·L2 규제의 원리 (0) | 2026.04.10 |
| 머신러닝의 엔진, 행렬 연산과 선형대수학이 필수적인 이유 (0) | 2026.04.08 |
| 데이터의 뼈대만 남기다, 주성분 분석(PCA)의 마법과 원리 (0) | 2026.04.07 |
| 공간의 변하지 않는 축, 고윳값과 고유벡터의 기하학적 의미 (0) | 2026.04.06 |