콘텐츠로 이동

역전파 (Backpropagation)

핵심 요약: 역전파(Backpropagation)는 출력의 오차(Error)를 역방향으로 전파하여 각 가중치(Weight)를 업데이트하는 알고리즘이다. 연쇄 법칙(Chain Rule)을 사용해 “이 가중치가 오차에 얼마나 기여했는가”를 효율적으로 계산하며, 모든 현대 딥러닝 학습의 근간이다.

역전파(Backpropagation)는 신경망의 가중치를 학습하기 위한 핵심 알고리즘이다. 손실 함수의 기울기(gradient)를 출력층에서 입력층 방향으로 효율적으로 계산하며, 이를 통해 각 파라미터가 손실에 얼마나 기여하는지 파악한다. 역전파는 미적분의 연쇄 법칙(chain rule)에 기반하며, 현대 딥러닝 프레임워크의 자동 미분(automatic differentiation) 시스템의 근간이다.

일상적 비유: 역전파는 시험에서 답을 틀린 후 어디서 실수했는지 역추적하는 과정과 같다. 최종 점수(손실)가 나쁘면, 마지막 문제부터 거꾸로 올라가며 “이 단계에서 얼마나 틀렸는가”를 확인한다. 각 단계의 “지역 기울기(local gradient)“를 체인처럼 연결하여, 맨 처음 입력 단계까지 실수의 원인을 추적하는 것이 역전파의 핵심이다.


역전파의 역사는 아이디어의 재발견과 실증의 이야기이다.

  1. 수학적 기초 (1960~70년대): 역전파의 수학적 원리인 연쇄 법칙(chain rule)의 효율적 적용은 제어 이론과 최적화 분야에서 이미 연구되고 있었다. Seppo Linnainmaa(1970)가 자동 미분의 역방향 모드를 최초로 기술했고, Paul Werbos(1974)가 박사 논문에서 신경망에 역전파를 적용할 수 있음을 제안했다.

  2. Rumelhart, Hinton, Williams의 1986년 논문: “Learning representations by back-propagating errors”라는 제목으로 Nature에 발표된 이 논문이 역전파를 세상에 널리 알렸다. 이 논문의 핵심 기여는 역전파가 은닉층의 유용한 표현(representation)을 자동으로 학습할 수 있음을 실험적으로 보여준 것이다. 사람이 특징(feature)을 수동으로 설계할 필요 없이, 네트워크가 데이터에서 스스로 의미 있는 내부 표현을 발견했다.

  3. 역사적 의의: 이 논문은 1969년 Minsky의 XOR 비판 이후 위축되었던 신경망 연구를 부활시킨 결정적 전환점이었다. “다층 네트워크는 학습시킬 수 없다”는 비관론을 실증적으로 반박했으며, 이후 30년간 이어지는 딥러닝 혁명의 씨앗이 되었다.


역전파의 수학적 기반이다.

단변수: dzdx=dzdydydx\frac{dz}{dx} = \frac{dz}{dy} \cdot \frac{dy}{dx}

다변수: Lw=iLziziw\frac{\partial L}{\partial w} = \sum_{i} \frac{\partial L}{\partial z_i} \cdot \frac{\partial z_i}{\partial w}

직관: 각 연산의 “로컬 기울기(local gradient)“를 체인처럼 연결하여 전체 기울기를 구한다.

예제: f(x)=(2x+3)2f(x) = (2x + 3)^2에서 dfdx\frac{df}{dx}를 구하자.

  • u=2x+3u = 2x + 3, f=u2f = u^2
  • dfdu=2u\frac{df}{du} = 2u, dudx=2\frac{du}{dx} = 2
  • dfdx=dfdududx=2u2=4(2x+3)\frac{df}{dx} = \frac{df}{du} \cdot \frac{du}{dx} = 2u \cdot 2 = 4(2x + 3)

2층 네트워크(입력 → 은닉 → 출력)에서 역전파를 1단계 따라가 보자.

  • 순전파(Forward Pass): 입력 x=1.0x = 1.0, 가중치 w1=0.5w_1 = 0.5, w2=0.8w_2 = 0.8

    • 은닉층(Hidden Layer): h=x×w1=1.0×0.5=0.5h = x \times w_1 = 1.0 \times 0.5 = 0.5
    • 출력층: y^=h×w2=0.5×0.8=0.4\hat{y} = h \times w_2 = 0.5 \times 0.8 = 0.4
  • 오차 계산: 실제값 y=1.0y = 1.0, 예측값 y^=0.4\hat{y} = 0.4

    • 손실(Loss) = (yy^)2=(1.00.4)2=0.36(y - \hat{y})^2 = (1.0 - 0.4)^2 = 0.36
  • 역전파(Backward Pass): 출력에서 입력 방향으로 기울기(Gradient)를 전파

    • Ly^=2(y^y)=2(0.41.0)=1.2\frac{\partial L}{\partial \hat{y}} = 2(\hat{y} - y) = 2(0.4 - 1.0) = -1.2
    • Lw2=Ly^×h=1.2×0.5=0.6\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial \hat{y}} \times h = -1.2 \times 0.5 = -0.6w2w_2증가시켜야 한다
    • Lw1=Ly^×w2×x=1.2×0.8×1.0=0.96\frac{\partial L}{\partial w_1} = \frac{\partial L}{\partial \hat{y}} \times w_2 \times x = -1.2 \times 0.8 \times 1.0 = -0.96w1w_1증가시켜야 한다
  • 가중치 업데이트 (학습률(Learning Rate) η=0.1\eta = 0.1):

    • w20.80.1×(0.6)=0.86w_2 \leftarrow 0.8 - 0.1 \times (-0.6) = 0.86
    • w10.50.1×(0.96)=0.596w_1 \leftarrow 0.5 - 0.1 \times (-0.96) = 0.596

이 과정을 수천~수만 번 반복하면 모델이 점점 정확해진다.

수학적 연산을 방향 비순환 그래프(DAG, Directed Acyclic Graph)로 표현한 것이다. DAG란 화살표 방향이 있고, 순환(루프)이 없는 그래프 구조를 말한다.

  • 노드: 연산 (덧셈, 곱셈, 활성화 함수 등)
  • 엣지: 데이터 흐름 (텐서)

2. 계산 그래프 (Computational Graph) 다이어그램 Forward mode vs Reverse mode differentiation:

  • Forward mode: 입력 수만큼 패스 필요
  • Reverse mode (역전파): 출력 수만큼 패스 필요

신경망의 손실은 스칼라이므로, reverse mode에서는 1회 패스로 모든 파라미터에 대한 기울기를 계산할 수 있다. 이것이 역전파가 신경망에 효율적인 이유이다.

3. 역전파 알고리즘 단계별 과정

섹션 제목: “3. 역전파 알고리즘 단계별 과정”

Step 1: Forward pass — 모든 중간 활성화 값 저장

z[l]=W[l]a[l1]+b[l],a[l]=σ(z[l])\mathbf{z}^{[l]} = \mathbf{W}^{[l]} \mathbf{a}^{[l-1]} + \mathbf{b}^{[l]}, \quad \mathbf{a}^{[l]} = \sigma(\mathbf{z}^{[l]})

Step 2: 출력층에서 손실의 기울기 계산

δ[L]=Lz[L]\delta^{[L]} = \frac{\partial L}{\partial \mathbf{z}^{[L]}}

Step 3: 역방향으로 각 층의 기울기를 chain rule로 전파

δ[l1]=(W[l])Tδ[l]σ(z[l1])\delta^{[l-1]} = (\mathbf{W}^{[l]})^T \delta^{[l]} \odot \sigma'(\mathbf{z}^{[l-1]})

Step 4: 파라미터 기울기 계산 및 업데이트

LW[l]=δ[l](a[l1])T\frac{\partial L}{\partial \mathbf{W}^{[l]}} = \delta^{[l]} \cdot (\mathbf{a}^{[l-1]})^T

wwηLww \leftarrow w - \eta \frac{\partial L}{\partial w}

3. 역전파 알고리즘 단계별 과정 다이어그램 메모리 요구: forward pass에서 저장한 중간 활성화 값이 메모리를 차지한다. 깊은 네트워크에서는 이것이 메모리 병목이 된다.

4. 자동 미분 (Automatic Differentiation)

섹션 제목: “4. 자동 미분 (Automatic Differentiation)”
방법정확도효율성비고
수치 미분 (Numerical)근사값느림 (파라미터당 2회 forward)디버깅용
기호 미분 (Symbolic)정확수식 폭발 (expression swell)수학 소프트웨어
자동 미분 (Automatic)정확효율적딥러닝 프레임워크

구현 방식:

  • Define-and-run (정적 그래프): TensorFlow 1.x — 그래프를 먼저 정의하고 나중에 실행
  • Define-by-run (동적 그래프): PyTorch, TF2 Eager — 실행하면서 그래프를 구성

PyTorch autograd 예시:

x = torch.tensor(2.0, requires_grad=True)
y = x ** 2 + 3 * x
y.backward()
print(x.grad) # 2*2 + 3 = 7.0

Gradient accumulation: GPU 메모리가 부족할 때, 큰 배치를 작은 미니배치로 나누어 기울기를 누적한 후 한 번에 업데이트한다.

실용 팁: 추론(inference) 시 torch.no_grad() 또는 @torch.inference_mode()를 사용하여 불필요한 기울기 계산과 메모리 사용을 방지하라.

역전파로 계산한 기울기를 사용하여 파라미터를 업데이트하는 다양한 전략이 있다.

wwηLw \leftarrow w - \eta \nabla L

vβv+Lv \leftarrow \beta v + \nabla L wwηvw \leftarrow w - \eta v

골짜기(ravine) 형태의 손실 표면에서 진동을 감소시킨다.

가장 널리 사용되는 최적화 알고리즘(Optimizer). Momentum(관성 — 이전 기울기 방향을 기억)과 RMSProp(파라미터별 학습률 적응)을 결합했다.

mt=β1mt1+(1β1)gtm_t = \beta_1 m_{t-1} + (1-\beta_1) g_t vt=β2vt1+(1β2)gt2v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2 m^t=mt1β1t,v^t=vt1β2t\hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t} wwηv^t+ϵm^tw \leftarrow w - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t

Weight decay를 L2 regularization과 분리한다 (decoupled weight decay). Adam에서 weight decay가 적응적 학습률과 상호작용하는 문제를 해결한다.

Optimizer 비교:

Optimizer적응적 학습률Momentum주요 특징
SGD없음없음단순, 일반화 우수
SGD+Momentum없음있음수렴 안정화
AdaGrad있음없음희소 데이터에 유리, 학습률 단조 감소
RMSProp있음없음AdaGrad 개선
Adam있음있음범용적, 빠른 수렴
AdamW있음있음Adam + 올바른 weight decay
스케줄러설명사용 시나리오
Step Decay일정 에폭마다 학습률 감소전통적 방법
Cosine Annealing코사인 함수로 학습률 감소일반적으로 우수
Warmup초반에 학습률을 0에서 점진적 증가Transformer 학습
One-Cycle학습률을 올렸다가 내림빠른 수렴
Cyclical LR학습률을 주기적으로 변화지역 최솟값 탈출

구현의 정확성을 확인하기 위한 디버깅 도구이다. 자동 미분의 결과를 수치 미분과 비교한다.

LwL(w+ϵ)L(wϵ)2ϵ\frac{\partial L}{\partial w} \approx \frac{L(w + \epsilon) - L(w - \epsilon)}{2\epsilon}

두 값의 상대 오차가 10710^{-7} 이하면 구현이 올바르다고 판단할 수 있다.

기울기 폭발을 방지하기 위한 기법이다.

  • 값 클리핑 (Value Clipping): 각 기울기 요소를 [c,c][-c, c] 범위로 제한
  • 노름 클리핑 (Norm Clipping): 기울기 벡터의 노름이 임계값을 초과하면 스케일링

gcggif g>c\mathbf{g} \leftarrow \frac{c}{\|\mathbf{g}\|} \mathbf{g} \quad \text{if } \|\mathbf{g}\| > c

특히 RNN 학습에서 필수적이다.

Checkpoint Gradient (Gradient Checkpointing)

섹션 제목: “Checkpoint Gradient (Gradient Checkpointing)”

메모리 절약 기법으로, 모든 중간 활성화를 저장하는 대신 일부만 저장하고, 역전파 시 필요한 값을 다시 계산한다. 메모리 사용량을 O(n)O(\sqrt{n})으로 줄일 수 있지만, 계산 시간이 증가한다.


역전파는 모든 신경망 학습에서 사용된다. 실무적 선택은 주로 최적화 알고리즘에 집중된다:

  • 기본값: AdamW (대부분의 상황에서 좋은 출발점)
  • 컴퓨터 비전 (CNN): SGD + Momentum + Cosine Annealing이 종종 최고 성능
  • Transformer / LLM: AdamW + Warmup + Cosine Decay
  • 정밀 튜닝이 필요한 경우: SGD가 일반화 성능에서 Adam보다 우수할 수 있음

Adam이 실패하고 SGD+Momentum이 더 나았던 사례

섹션 제목: “Adam이 실패하고 SGD+Momentum이 더 나았던 사례”

“Adam을 쓰면 된다”는 것이 일반적인 실무 조언이지만, 항상 그런 것은 아니다. 특히 NLP와 컴퓨터 비전의 특정 상황에서 Adam이 오히려 SGD+Momentum보다 일반화 성능이 떨어지는 현상이 보고되어 왔다.

대표적 사례: Wilson et al. (2017)의 연구 “The Marginal Value of Adaptive Gradient Methods in Machine Learning”에서, 이미지 분류(CIFAR-10, ImageNet)와 특정 NLP 과제에서 Adam이 학습 손실은 빠르게 줄였지만, 테스트 정확도에서 SGD+Momentum에 뒤처지는 현상이 관찰되었다. Adam의 적응적 학습률이 파라미터마다 다른 속도로 학습하면서, 일부 파라미터가 너무 빠르게 수렴하여 날카로운 최솟값(sharp minima)에 빠지기 쉬웠기 때문이다. 날카로운 최솟값은 학습 데이터에서는 손실이 낮지만, 새로운 데이터에 대한 일반화 성능이 떨어진다.

실무 교훈:

  • Adam은 빠른 프로토타이핑과 초기 실험에 탁월하다
  • 최종 성능을 극대화해야 할 때는 SGD+Momentum + Cosine Annealing 조합이 더 나을 수 있다
  • AdamW(weight decay를 분리)가 기존 Adam의 일반화 문제를 상당 부분 해결했다
  • Transformer 계열에서는 AdamW + Warmup이 사실상 표준이다
  • 결론: “최고의 optimizer”는 없으며, 과제와 아키텍처에 따라 실험이 필요하다

  1. “Adam의 기본 하이퍼파라미터가 항상 최적”: β1=0.9\beta_1=0.9, β2=0.999\beta_2=0.999, ϵ=108\epsilon=10^{-8}이 기본이지만, 특히 ϵ\epsilon 값이 학습 안정성에 큰 영향을 줄 수 있다. Transformer에서는 β2=0.98\beta_2=0.98이 자주 사용된다.

  2. 역전파를 수동으로 구현해야 한다: 현대 프레임워크(PyTorch, TensorFlow)가 자동 미분을 제공하므로, 수동 구현은 교육 목적을 제외하면 불필요하다. 그러나 원리를 이해하는 것은 디버깅에 필수적이다.

  3. 학습률을 고정: 학습률 스케줄러를 사용하지 않으면 최적 성능에 도달하기 어렵다. 특히 Transformer에서 warmup은 학습 안정성을 위해 필수적이다.

  4. 기울기 체크 무시: 커스텀 레이어나 손실 함수를 구현할 때 기울기 체크를 하지 않으면 미묘한 버그가 성능 저하로 이어질 수 있다.

  5. 추론 시 기울기 모드 유지: torch.no_grad()를 사용하지 않으면 불필요한 메모리 사용과 느린 추론 속도가 발생한다.