Backpropagation Through Time (BPTT) 이해하기

BPTT는 RNN에서 시간적 의존성을 따라 Gradient를 역전파하는 알고리즘이다. 이 글에서는 BPTT의 원리와 계산 방법을 설명한다.

RNN은 이전 시점의 Hidden State를 이용해 현재 Hidden State를 계산한다.

\[a_t=Ux_t+Vh_{t-1}+b\] \[h_t=\tanh(a_t)\]

여기서 $U,V,b$는 학습 가능한 파라미터이며, 모든 시점에서 동일하게 사용된다.

BPTT(Backpropagation Through Time)는 RNN을 시간 방향으로 펼친 뒤, 각 시점에 걸쳐 Gradient를 역전파하는 과정이다.

1. RNN을 시간 방향으로 펼치기

세 시점에 걸친 RNN을 생각해 보자.

도형을 불러오는 중…

각 Hidden State는 다음 시점의 계산에 사용된다.

\[h_0\rightarrow h_1\rightarrow h_2\rightarrow h_3\]

Language Modeling처럼 모든 시점에서 예측을 수행한다면 전체 Loss는 다음과 같이 정의할 수 있다.

\[L=L_1+L_2+L_3\]

여기서 중요한 것은 $V$가 세 시점에 모두 등장한다는 점이다.

따라서 $V$에 대한 전체 Gradient를 구하려면 각 시점에서 $V$가 Loss에 미친 영향을 모두 합해야 한다.

2. 우리가 구하려는 Gradient

목표는 다음과 같다.

\[\frac{\partial L}{\partial V}\]

하지만 $V$는 $a_1,a_2,a_3$를 계산하는 데 반복해서 사용된다.

따라서 각 시점에서의 기여를 합하면

\[\frac{\partial L}{\partial V} = \left.\frac{\partial L}{\partial V}\right|_{t=1} + \left.\frac{\partial L}{\partial V}\right|_{t=2} + \left.\frac{\partial L}{\partial V}\right|_{t=3}\]

가 된다.

여기서 각 항은 해당 시점에서 사용된 $V$가 전체 Loss에 미치는 기여를 의미한다.

이를 계산하려면 먼저 각 $a_t$에 대한 전체 Loss의 Gradient가 필요하다.

\[\frac{\partial L}{\partial a_1}, \qquad \frac{\partial L}{\partial a_2}, \qquad \frac{\partial L}{\partial a_3}\]

왜 $a_t$일까?

$V$가 직접 사용되는 연산이

\[a_t=Ux_t+Vh_{t-1}+b\]

이기 때문이다.

따라서 $a_t$까지 역전파된 Gradient를 알면, Chain Rule을 이용해 해당 시점의 $V$에 대한 기여를 구할 수 있다.

이제 이 Gradient들을 마지막 시점부터 계산해 보자.

3. 마지막 시점부터 역전파하기

먼저 $a_3$에 대한 Gradient를 구한다.

\[\frac{\partial L}{\partial a_3}\]

$a_3$는 $h_3$를 통해 $L_3$에 영향을 준다. 반면 이전 시점의 $L_1,L_2$에는 영향을 주지 않는다.

따라서 Chain Rule에 의해

\[\frac{\partial L}{\partial a_3} = \frac{\partial L_3}{\partial h_3} \frac{\partial h_3}{\partial a_3}\]

이다.

$h_3=\tanh(a_3)$이므로

\[\frac{\partial h_3}{\partial a_3}=1-h_3^2\]

이다. 위 식은 이해를 위해 Scalar RNN으로 쓴 것이며, 벡터 RNN에서는 원소별 미분을 적용한다.

결국

\[\frac{\partial L}{\partial a_3} = \frac{\partial L_3}{\partial h_3}(1-h_3^2)\]

를 얻는다.

여기까지는 일반적인 Backpropagation과 다르지 않다.

이번에는 $a_2$를 살펴보자

$a_2$를 선택하는 이유는 현재 Loss와 미래 Loss에 동시에 영향을 주는 중간 시점이기 때문이다.

$a_2$는 $h_2$를 거쳐 두 경로로 Loss에 영향을 준다.

도형을 불러오는 중…

첫 번째는 현재 시점의 Loss로 이어지는 경로다.

\[a_2\rightarrow h_2\rightarrow L_2\]

두 번째는 미래 시점의 Loss로 이어지는 경로다.

\[a_2\rightarrow h_2\rightarrow a_3\rightarrow h_3\rightarrow L_3\]

따라서 두 경로의 Gradient를 합산해야 한다.

\[\begin{aligned} \frac{\partial L}{\partial a_2} ={}& \frac{\partial L_2}{\partial h_2} \frac{\partial h_2}{\partial a_2}\\ &+ \frac{\partial L_3}{\partial h_3} \frac{\partial h_3}{\partial a_3} \frac{\partial a_3}{\partial h_2} \frac{\partial h_2}{\partial a_2} \end{aligned}\]

두 항에서 공통으로 등장하는 $\partial h_2/\partial a_2$를 묶으면

\[\frac{\partial L}{\partial a_2} = \left( \frac{\partial L_2}{\partial h_2} + \frac{\partial L_3}{\partial h_3} \frac{\partial h_3}{\partial a_3} \frac{\partial a_3}{\partial h_2} \right) \frac{\partial h_2}{\partial a_2}\]

가 된다.

여기서 이미 계산한 결과를 활용할 수 있다.

\[\frac{\partial L_3}{\partial h_3} \frac{\partial h_3}{\partial a_3} = \frac{\partial L}{\partial a_3}\]

또한 Scalar RNN에서는

\[\frac{\partial a_3}{\partial h_2}=v\]

이고,

\[\frac{\partial h_2}{\partial a_2}=1-h_2^2\]

이다.

따라서

\[\boxed{ \frac{\partial L}{\partial a_2} = \left( \frac{\partial L_2}{\partial h_2} + v\frac{\partial L}{\partial a_3} \right)(1-h_2^2) }\]

를 얻는다.

이 식에서 중요한 점은 다음 시점의 Gradient를 재사용한다는 것이다.

4. Delta의 등장

앞에서 반복적으로 등장한 미분을 다음처럼 정의하자.

\[\delta_t=\frac{\partial L}{\partial a_t}\]

그러면 방금 유도한 식을 간단하게 표현할 수 있다.

\[\delta_2= \left( \frac{\partial L_2}{\partial h_2} +v\delta_3 \right)(1-h_2^2)\]

같은 방식으로 $t=1$에서도

\[\delta_1= \left( \frac{\partial L_1}{\partial h_1} +v\delta_2 \right)(1-h_1^2)\]

가 된다.

이를 벡터 RNN으로 일반화하면 다음과 같다.

\[\boxed{ \delta_t= \left( \frac{\partial L_t}{\partial h_t} + V^\top\delta_{t+1} \right) \odot(1-h_t^2) }\]

여기서 각 항의 의미는 다음과 같다.

  • $\partial L_t/\partial h_t$: 현재 시점의 Loss가 전달하는 Gradient
  • $V^\top\delta_{t+1}$: 미래 시점에서 전달되는 Gradient
  • $1-h_t^2$: Tanh의 Derivative

$\delta_{t+1}$에는 이미 그 이후의 Loss에 대한 영향이 포함되어 있다.

따라서 역전파는 마지막 시점부터 시작해, 이전 시점으로 이동하며 계산한 Gradient를 재사용할 수 있다.

5. 공유 가중치의 Gradient 계산

이제 처음의 목표였던 $\partial L/\partial V$로 돌아가자.

각 시점에서는

\[a_t=Ux_t+Vh_{t-1}+b\]

를 계산한다.

해당 시점에서 $V$에 대한 Gradient 기여는

\[\delta_t h_{t-1}^\top\]

이다.

따라서 전체 Gradient는

\[\boxed{ \frac{\partial L}{\partial V} = \sum_{t=1}^{T}\delta_t h_{t-1}^\top }\]

가 된다.

여기서 두 가지 계산이 이루어진다.

첫째, $\delta_t$를 역순으로 계산하며 미래 Loss의 영향을 반영한다.

둘째, 동일한 $V$를 사용한 모든 시점의 Gradient 기여를 합산한다.

이것이 BPTT의 핵심이다.

6. LSTM에도 적용할 수 있을까?

LSTM도 이전 State를 다음 시점으로 전달하고, 동일한 파라미터를 여러 시점에서 사용한다.

따라서 BPTT가 그대로 적용된다.

다만 Vanilla RNN은 Hidden State $h_t$를 중심으로 계산하지만, LSTM은 Hidden State $h_t$와 Cell State $c_t$를 함께 사용한다.

\[c_t=f_t\odot c_{t-1}+i_t\odot\tilde c_t\] \[h_t=o_t\odot\tanh(c_t)\]

따라서 LSTM에서는 두 State를 통한 Gradient 경로와 Gate의 Gradient까지 계산해야 한다.

BPTT의 원리는 동일하지만, 각 시점의 계산 그래프가 더 복잡하다.

7. Vanishing Gradient

BPTT에서는 Gradient가 여러 시점을 지나며 Recurrent Weight와 Activation Derivative를 반복적으로 곱한다.

이 과정에서 Gradient가 작아지면 Vanishing Gradient, 커지면 Exploding Gradient 문제가 발생할 수 있다.

LSTM은 Cell State와 Gate를 사용해 장기적인 Gradient 전달을 개선하도록 설계되었다.

정리

BPTT를 이해하는 데 중요한 것은 세 가지다.

  1. 각 Hidden State는 현재 Loss와 미래 Loss에 모두 영향을 줄 수 있다.
  2. Chain Rule을 이용해 Gradient를 마지막 시점부터 역전파한다.
  3. 동일한 파라미터를 여러 시점에서 사용하므로 Gradient 기여를 합산한다.

Vanilla RNN과 LSTM 모두 같은 원리로 학습한다. 차이는 시간에 따라 역전파해야 하는 내부 계산 구조에 있다.