콘텐츠로 이동

역전파 (Backpropagation)

개요

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


핵심 개념

1. 연쇄 법칙 (Chain Rule)

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

단변수: $\(\frac{dz}{dx} = \frac{dz}{dy} \cdot \frac{dy}{dx}\)$

다변수: $\(\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)^2\)에서 \(\frac{df}{dx}\)를 구하자.

  • \(u = 2x + 3\), \(f = u^2\)
  • \(\frac{df}{du} = 2u\), \(\frac{du}{dx} = 2\)
  • \(\frac{df}{dx} = \frac{df}{du} \cdot \frac{du}{dx} = 2u \cdot 2 = 4(2x + 3)\)

2. 계산 그래프 (Computational Graph)

수학적 연산을 방향 비순환 그래프(DAG)로 표현한 것이다.

  • 노드: 연산 (덧셈, 곱셈, 활성화 함수 등)
  • 엣지: 데이터 흐름 (텐서)
graph LR
    x((x)) --> mul1[×]
    w((w)) --> mul1
    mul1 --> add[+]
    b((b)) --> add
    add --> sigma["σ(·)"]
    sigma --> L["Loss"]

    style L fill:#f96,stroke:#333

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

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

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

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

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

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

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

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

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

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

\[\frac{\partial L}{\partial \mathbf{W}^{[l]}} = \delta^{[l]} \cdot (\mathbf{a}^{[l-1]})^T\]
\[w \leftarrow w - \eta \frac{\partial L}{\partial w}\]
graph LR
    subgraph "Forward Pass →"
        A[입력 x] --> B["z⁽¹⁾ = Wx+b"]
        B --> C["a⁽¹⁾ = σ(z⁽¹⁾)"]
        C --> D["z⁽²⁾ = Wa⁽¹⁾+b"]
        D --> E["ŷ = σ(z⁽²⁾)"]
        E --> F[Loss L]
    end

    subgraph "← Backward Pass"
        F --> G["δ⁽²⁾ = ∂L/∂z⁽²⁾"]
        G --> H["δ⁽¹⁾ = W^T δ⁽²⁾ ⊙ σ'"]
        H --> I["∂L/∂W, ∂L/∂b"]
    end

메모리 요구: forward pass에서 저장한 중간 활성화 값이 메모리를 차지한다. 깊은 네트워크에서는 이것이 메모리 병목이 된다.

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()를 사용하여 불필요한 기울기 계산과 메모리 사용을 방지하라.

5. 최적화 알고리즘 (Optimizers)

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

SGD (Stochastic Gradient Descent)

\[w \leftarrow w - \eta \nabla L\]

SGD + Momentum

\[v \leftarrow \beta v + \nabla L$$ $$w \leftarrow w - \eta v\]

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

Adam (Adaptive Moment Estimation)

가장 널리 사용되는 최적화 알고리즘. Momentum과 RMSProp을 결합했다.

\[m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t$$ $$v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2$$ $$\hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t}$$ $$w \leftarrow w - \frac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t\]

AdamW

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

Optimizer 비교:

Optimizer 적응적 학습률 Momentum 주요 특징
SGD 없음 없음 단순, 일반화 우수
SGD+Momentum 없음 있음 수렴 안정화
AdaGrad 있음 없음 희소 데이터에 유리, 학습률 단조 감소
RMSProp 있음 없음 AdaGrad 개선
Adam 있음 있음 범용적, 빠른 수렴
AdamW 있음 있음 Adam + 올바른 weight decay

Learning Rate Schedulers

스케줄러 설명 사용 시나리오
Step Decay 일정 에폭마다 학습률 감소 전통적 방법
Cosine Annealing 코사인 함수로 학습률 감소 일반적으로 우수
Warmup 초반에 학습률을 0에서 점진적 증가 Transformer 학습
One-Cycle 학습률을 올렸다가 내림 빠른 수렴
Cyclical LR 학습률을 주기적으로 변화 지역 최솟값 탈출

상세 내용

기울기 체크 (Gradient Checking)

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

\[\frac{\partial L}{\partial w} \approx \frac{L(w + \epsilon) - L(w - \epsilon)}{2\epsilon}\]

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

Gradient Clipping

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

  • 값 클리핑 (Value Clipping): 각 기울기 요소를 \([-c, c]\) 범위로 제한
  • 노름 클리핑 (Norm Clipping): 기울기 벡터의 노름이 임계값을 초과하면 스케일링
\[\mathbf{g} \leftarrow \frac{c}{\|\mathbf{g}\|} \mathbf{g} \quad \text{if } \|\mathbf{g}\| > c\]

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

Checkpoint Gradient (Gradient Checkpointing)

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


언제 사용하는가

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

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

흔한 오해와 함정

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

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

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

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

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


다른 주제와의 연결