LSTM(Long Short-Term Memory): Gate를 도입해 RNN의 한계를 완화한 모델
우리는 유튜브에서 자동 자막을 보거나, 번역 앱으로 외국어 문장을 번역하는 등 기계가 생성한 언어를 자주 접합니다. 이전 글에서 우리 언어인 자연어처럼 시간에 따른 의미가 변하는 데이터를 시퀀스라고 하고, 이를 다루는 딥러닝 모델로 RNN이 있다고 했습니다. RNN은 전통적인 ANN과 달리 순환구조를 통해 연속된 데이터를 처리하는 데에 적합합니다. 그러나 RNN에도 한계가 존재했는데, 바로 기울기 소실로 인한 장기 의존성 문제였습니다. 오늘은 RNN의 이 한계를 극복하기 위한 대안으로 제시된 게이트라는 개념과, 이를 적용한 LSTM의 구조를 뜯어보겠습니다.
정보의 전달 정도를 조절하는 Gate(게이트)
옛날 목욕탕에는 온수와 냉수의 밸브가 따로 마련되어있는 곳이 있었습니다. 적당히 따뜻한 물을 쓰기 위해서는, 온수와 냉수의 밸브를 각각 얼마나 열지 미세하게 조절해야 했죠.
물을 조절하는 밸브
게이트는 이 밸브와 비슷한 역할을 합니다. 게이트라는 밸브를 조절함으로써 불필요한 정보를 제거하고, 중요한 정보만을 선택적으로 넘기게 됩니다. 이때, 어떤 밸브를 얼마나 열어야 하는가에 대한 결정 역시 다른 가중치들처럼 모델의 학습 과정에서 결정됩니다.
RNN의 한계를 극복하기 위해 이 게이트라는 매커니즘이 어떻게 활용되는지 보겠습니다.
아래와 같은 문장이 있습니다.
귀여운 강아지를 출근길에서 만났다. 오늘 하루 종일 기분이 (____)
빈칸을 유추하기 위해서는 문장의 맨 처음에 등장한 “귀여운 강아지”라는 정보를 알고 있어야 하죠.
RNN의 장기 기억 소실 문제
이 문장을 RNN에 입력하면, 빈칸을 유추해야 할 즈음엔 “귀여운 강아지”라는 단어의 면적인 붉은 면적이 모델의 기억(memory)에는 아주 조금밖에 남아있지 않습니다. 단순한 순환구조를 반복하며 기억이 누적되면서, 기울기 소실(Gradient Vanishing) 문제가 발생하기 때문이죠.
여기서 게이트를 도입하면, 새로 입력된 정보나 기존의 기억에서 어떤 데이터를 얼마나 유지할지를 조절할 수 있습니다. 마치 밸브를 조절하듯이, 중요한 정보는 남기고 불필요한 정보는 제거하는 데에 게이트가 사용되는 것입니다.
이제부터 소개할 LSTM과 GRU 구조는 이 게이트 메커니즘을 도입해 RNN의 한계를 극복합니다. 먼저, 기존의 RNN에 게이트를 추가해 보며 LSTM의 구조를 설명하겠습니다.
RNN의 구조 다시 되짚어보기
새로운 구조의 모델을 소개하기 전에, 이전 글에서 설명한 RNN의 구조를 다시 짚어보겠습니다. 기존 RNN은 아래의 구조를 가지고 있습니다.
RNN 뉴런의 구조
시점 t의 입력값($x_t$)과 직전 은닉상태($h_{t-1}$)를 활용하여 현 시점의 은닉상태($h_t$)를 계산해내는 이 동그란 노드가 하나의 RNN 노드입니다. RNN 모델은 이 하나의 노드를 반복 순환하며 시계열 데이터를 처리합니다.
RNN 노드 내부 동작
RNN 노드 내부의 동작을 달리 표현하면 위와 같습니다. 회색 영역이 RNN 노드라고 한다면, 이 노드에는 $x_t$가 입력되고, 직전 노드에서 내부적으로 전달받은 $h_{t-1}$와 함께 $h_t$를 연산해 냅니다.
이제부터 이 RNN 노드 구조에 셀 상태와 게이트가 추가된 LSTM 구조를 알아보겠습니다.
LSTM (Long Short-Term Memory) 간단히 훑어보기
LSTM의 구조는 아래와 같습니다. 하나씩 먼저 간략히 소개한 후, 각 게이트를 자세히 살펴보겠습니다.
LSTM 노드 내부 구조의 개요(좌)와 동작(우)
$c_t$ (Cell State, 셀 상태)
- 셀 상태는 과거부터 현재의 $t$시점까지 장기 기억을 저장하는 메모리 역할을 합니다.
- 이전 노드로부터 전달된 셀 상태($c_{t-1}$)에서 불필요한 정보를 제거(Forget Gate)하고, 새로운 정보를 반영(Input Gate)해 갱신됩니다.
$h_t$ (Hidden State, 은닉상태)
- 현재 $t$시점의 셀 상태($c_t$)에서 중요한 정보를 강조해서 담고있는 값입니다.
- 현재의 출력으로 사용되어, 모델의 예측을 수행하는 데에 직접적인 영향을 줍니다.
Forget Gate, 망각 게이트 → $f_t$
$$ f_t = \sigma {(W_h^{(f)}h_{t-1} + W_x^{(f)}x_t+b^{(f)})} $$
- 과거의 정보 중 어떤 정보를 잊을지(망각할지) 결정하는 게이트입니다.
- Sigmoid(시그모이드) 함수를 통과해 값의 범위는 (0, 1) 사이이며, 0이면 정보를 완전히 잊고 1이면 그대로 유지합니다.
$\tilde{c}_t$ (Cell State Candidate, 새로운 정보 후보)
$$ \tilde{c}\substack{t} = \mathrm{tanh}(W_h^{(c)}h_{t-1} + W_x^{(c)}x_t+b^{(c)}) $$
- 장기 기억인 셀 상태($c_t$)에 반영될 가능성이 있는 새로운 정보 후보입니다.
- tanh 함수를 사용하여 값의 범위가 (-1, 1)로 조정됩니다.
Input Gate, 입력 게이트 → $i_t$
$$ i_t = \sigma {(W_h^{(i)}h_{t-1} + W_x^{(i)}x_t+b^{(i)})} $$
- 새로 입력된 정보 후보($\tilde{c}_t$)가 장기 기억을 담당하는 셀 상태(c_t)에 얼마나 반영될지를 결정하는 게이트입니다.
- Sigmoid(시그모이드) 함수를 통과해 값의 범위는 (0,1) 사이이며, 불필요한 정보는 0에 가깝고 중요한 정보는 1에 가깝습니다.
- 새로 입력된 정보 후보($\tilde{c}_t$)에 곱해져 실제로 셀 상태(c_t)에 반영될 정보가 결정됩니다.
Output Gate, 출력 게이트 → $o_t$
$$ o_t = \sigma {(W_h^{(o)}h_{t-1} + W_x^{(o)}x_t+b^{(o)})} $$
- 셀 상태($c_t$)에서 어떤 정보를 은닉상태($h_t$)로 내보낼지를 결정하는 게이트입니다.
- 은닉상태($h_t$)가 각 게이트의 출력값이 되기 때문에 출력 게이트라고 부릅니다.
- Sigmoid 함수를 사용하여 (0,1) 범위의 값을 출력하며, 중요한 정보만 출력되도록 조절합니다.
장기 기억을 보관하기 위한 Cell State (셀 상태)
셀 상태(Cell State)는 RNN과 비교했을 때, LSTM의 가장 특징적인 개념 중 하나입니다. 셀 상태는 장기적인 정보를 보존하는 ‘기억’의 역할을 하며, 필요에 따라 정보를 유지하거나 삭제할 수 있도록 조절됩니다. 이를 통해 RNN의 기울기 소실 문제를 완화하고, 보다 긴 시퀀스에서도 효과적인 학습이 가능합니다.
잠깐! RNN에서 은닉상태($h_t$)가 기억(메모리)을 담당한다고 했는데 왜 굳이 셀 상태($c_t$)가 필요한 걸까요?
LSTM은 Long Short-Term Memory의 약자로, 장기 기억과 단기 기억 모두를 관리하는 모델입니다. 셀 상태가 도입됨으로써, 은닉상태는 현재 시점($t$)의 정보에 초점을 맞춘 단기 기억을 담당하고, 셀 상태는 전체적인 장기 기억을 유지하는 역할을 합니다.
셀 상태의 갱신: $c_{t-1}$ → $c_t$
셀 상태 역시 은닉상태와 마찬가지로 이전 시점의 셀 상태($c_{t-1}$)를 전달받아, 현재($t$ 시점) 입력 정보를 반영한 새로운 셀 상태($c_t$)로 갱신됩니다.
LSTM의 셀 상태 갱신
LSTM의 구조를 보면, 셀 상태가 갱신될 때 이전 시점의 은닉상태($h_{t-1}$)와 현재 시점의 입력($x_t$)이 반영됨을 알 수 있습니다. 이때 망각 게이트(forget gate)와 입력 게이트(input gate)를 통해 기존 정보 중 불필요한 일부가 제거되고, 새로운 정보가 선택적으로 추가되어 셀 상태가 갱신됩니다.
셀 상태를 갱신할 때 활용되는 두 개의 게이트, 망각 게이트(forget gate)와 입력 게이트(input gate)를 알아보겠습니다.
Forget gate, 망각 게이트
셀 상태가 담고있는 장기 기억은 불필요한 정보는 포기하고, 중요한 정보는 더 강하게 기억하는 것이 중요합니다. 이번에 설명할 게이트는, 보다 효율적인 기억을 위해 불필요한 정보를 잊게해주는 게이트, 바로 망각 게이트(Forget gate)입니다.
LSTM의 Forget Gate 개요
위 구조에서 $c_{t-1}$에 곱해지는 $f_t$가 바로 $t$시점의 forget gate에서 계산된 값입니다. 이 forget gate 내부의 작업을 수식으로 표현해보면 아래와 같습니다.
LSTM의 Forget Gate 내부 계산
각 단계별로 살펴볼까요?
STEP (1): $Z_f = W_h^{(f)}h_{t-1} + W_x^{(f)}x_t+b^{(f)}$
먼저, 이전 노드까지의 셀 상태($c_{t-1}$)에서 얼마나 많은 불필요한 정보를 제거할 것인지 구해야겠죠.
‘어떤 정보가 불필요한 정보인가?’를 표현한 값이 STEP (1)에서 계산됩니다.
이는 현 입력($x_t$)과 이전 은닉상태($h_{t-1}$)로부터 구합니다. 이전 은닉상태와 현재 입력된 새로운 값 모두를 고려해서 어떤 정보를 버릴 것인지 결정하는 것이죠.
그런데 잘 살펴보면, 이 계산은 우리가 지금까지 해왔던 선형 변환과 동일합니다.
다만, 여기서 사용되는 가중치와 편향은 모두 이 forget gate의 값을 계산하는 데에만 쓰이기 때문에, 매개변수(가중치와 편향) 모두에 forget의 $f$를 첨자로 달아 $W_x^{(f)}$, $W_h^{(f)}$, $b^{(f)}$로 씁니다. Forget gate에서 사용되는 매개변수임을 표시하는 것이죠.
그리고 이 매개변수들로 계산한 가중합을 $Z_f$라고 하겠습니다.
STEP (2): $ f_t = \sigma (Z_f) $
이제 선형 변환 결과인 $Z_f$에 적절한 활성화 함수를 적용해서 forget gate의 계산값인 $f_t$를 계산할 것입니다. 그렇다면 어떤 활성화 함수가 가장 적합할까요?
Forget gate는 과거의 기억, 즉 이전 셀 상태($c_{t-1}$) 중 어느 정도를 버릴지(혹은 망각할지)를 결정하는 역할을 합니다. 즉, 망각의 비율을 조절하는 과정이라고 볼 수 있습니다. 이 비율은 0%에서 100%까지, 즉 0.0에서 1.0 사이의 값을 가지게 됩니다. 따라서, $Z_f$를 이 범위로 변환하기 위해 sigmoid 함수를 적용하는 것이 적절합니다.
예전 글에서 설명했듯이, sigmoid 함수는 입력값이 어떤 실수든지 출력값을 0과 1 사이로 한정하는 특성을 가지고 있기 때문에, 망각의 비율을 표현하기에 적합한 활성화 함수입니다.
이제 sigmoid 함수를 활성화 함수로 적용하면, ‘얼마나 망각할 것인지’를 표현한 값이 계산됩니다. 이 값을 forget gate 값이라고 하며, 시점 $t$에서의 forget gate 값을 $f_t$로 표시합니다.
STEP (3): $f_t \times c_{t-1}$
Forget gate의 마지막 단계는 앞서 계산한 망각할 비율 $f_t$를 이전 노드까지 누적되었던 과거의 기억인 $c_{t-1}$에 곱해주는 것입니다.
이로써 불필요한 정보를 잊어버리도록 갱신된 셀 상태를 구했습니다. Forget gate에서 사용된 매개변수와 값들을 정리해보면 다음과 같습니다.
- $W_h^{(f)}$, $W_x^{(f)}$: Forget gate의 선형 변환에서 각각 $h$와 $x$에 곱해지는 가중치
- $b^{(f)}$: Forget gate의 선형 변환에서 더해지는 편향
- $Z_f$: Forget Gate의 선형 변환 계산 결과
- $\sigma$: Forget Gate의 비선형 변환에서 사용되는 활성화 함수인 sigmoid 함수
- $f_t$: 망각할 정보를 값으로 표현한, Forget Gate 계산값
Cell State Candidate, 새로운 정보 후보: $\tilde{c}_t$
과거의 기억인 셀 상태에서 불필요한 정보를 제거했으니, 이제는 새로운 입력을 셀 상태에 추가해야겠죠? 그러기 위해서는 먼저, 새로 추가될 정보의 후보군들을 계산해내는 과정이 필요합니다. 이 과정은 입력 게이트 전에 선행되는 과정으로, ‘게이트’는 아닙니다. 새로운 정보의 경중을 따지기 전에, 먼저 새 정보들을 가져오는 단계입니다.
LSTM의 candidate 개요
새로운 정보들을 후보군으로 가져온다 해서 이 정보는 candidate의 $c$를 따 $\tilde{c}_t$라고 합니다. 이 값을 구하는 과정을 보겠습니다.
LSTM의 candidate 내부 계산
STEP (1): $Z_c = W_h^{(c)}h_{t-1} + W_x^{(c)}x_t+b^{(c)}$
Forget gate에서처럼 새로운 정보 후보군들을 계산하기 위해 현재 입력된 값($x_t$)은 물론, 직전 노드에서의 기억($h_{t-1}$)을 참고해 선형변환을 진행합니다. 여기서 사용되는 매개변수들은 후보군을 구하는 이 단계에서만 사용되기 때문에 마찬가지로 첨자로 $c$를 붙이고, 선형 변환 결과는 $Z_c$라고 합니다.
STEP (2): $ \tilde{c}_t = \mathrm{tanh}(Z_c)$
다음 단계로, 선형 변환값인 $Z_c$에 비선형을 더하는 활성화 함수를 적용해야하는데, 이 때 sigmoid 함수가 아닌 tanh 함수가 사용되었습니다. 그 이유는 두 함수의 출력값 범위가 다르기 때문입니다. Sigmoid 함수의 출력값은 (0, 1) 범위의 값을 가지지만, tanh 함수의 출력값은 (-1, 1) 범위를 가지므로 양수와 음수 정보를 모두 표현할 수 있습니다. $\tilde{c}_t$는 ‘어떤 정보를 선택하겠다’라는 결정이 반영되지 않은 값입니다. 따라서 굳이 비율을 나타내는 (0, 1) 범위로 한정시킬 필요가 없습니다. 오히려 tanh 함수를 통해 (-1, 1) 범위로 제한해, 음수 값의 정보도 살리는 것이 좋습니다.
이런 이유로 $\tilde{c}_t$는 tanh 함수를 통해 완성됩니다. 이 값이 바로 ‘셀 상태(기억)에 반영할 새로운 정보들의 후보군’을 표현한 값입니다.
STEP (3): $c_t$에 더하기
새로운 정보는 셀 상태에 반영되어야 하므로, $c_{t-1}$을 갱신하는 과정에서 $\tilde{c}_t$를 더합니다. 하지만 새로운 정보를 무분별하게 받아들이면, 기억을 효율적으로 운용할 수 없겠죠?
Input Gate, 입력 게이트
$\tilde{c}_t$를 더하기 전에, 새로운 정보 후보군들 중 정말로 반영할 값만 골라내는 과정이 필요합니다. 새로운 정보 후보군에 ‘어떤 정보가 중요하게 기억되어야하는가’를 표현하기 위해 Input Gate(입력 게이트)를 거쳐야 합니다.
LSTM의 Input Gate 개요
위 구조에서 앞서 계산한 $\tilde{c}_t$에 곱해지는 $i_t$가 바로 input gate에서 계산된 값입니다. 새로운 정보 후보군인 $\tilde{c}_t$에 곱해져, 그 중 어떤 정보만 기억에 반영할 것인가를 결정하죠.
LSTM의 Input Gate 내부 계산
STEP (1): $Z_i = W_h^{(i)}h_{t-1} + W_x^{(i)}x_t+b^{(i)}$
Input gate에서도 역시 고유의 매개변수를 사용해 선형 변환 결과로 $Z_i$를 계산해냅니다.
STEP (2): $i_t = \sigma(Z_i)$
$Z_i$가 통과할 활성화 함수는 forget gate에서와 마찬가지로 sigmoid 함수입니다. 여기서 계산된 input gate의 값인 $i_t$는 이 다음 단계에서 새로운 정보 후보군이었던 $\tilde{c}_t$에 곱해져, 후보군 중 셀 상태에 반영할 정보의 비중을 결정하게되기 때문입니다.
따라서 이 단계에서 결과값의 범위를 (0, 1)로 한정하는 sigmoid함수를 거쳐, ‘새로운 정보 후보군 중 어떤 정보를 중요하게 볼 것인가’를 표현한 값인 $i_t$가 계산됩니다.
STEP (3): $i_t \times \tilde{c}_t$
Input gate의 값 $i_t$는 앞서 말한대로 $\tilde{c}_t$에 곱해져 기억에 반영할 새로운 정보를 완성합니다.
여기까지, 셀 상태를 갱신하는 과정을 정리해보면 다음과 같습니다.
LSTM의 셀 상태 갱신 개요(좌)와 내부 계산(우)
Forget gate를 통과하며 이전 노드에서 전달받은 셀 상태$(c_{t-1}$)에서 불필요한 정보를 제거($f_t \times c_{t-1}$)합니다.
그 후 새로 입력받은 정보 후보군($\tilde{c}_t$) 중 중요하게 반영할 값을 추려내($i_t \times \tilde{c}_t$) 더합니다.
이로써 현재 노드에서 입력된 새로운 정보까지 반영한 현재 노드의 셀 상태($c_t$)를 완성합니다.
Output Gate, 출력 게이트
현재 노드의 셀 상태($c_t$)가 갱신되었으니, 이를 바탕으로 현재 노드의 출력인 은닉상태($h_t$)를 계산해낼 차례입니다.
LSTM의 Output Gate 개요
위 그림을 보면, 갱신된 셀 상태 $c_t$를 tanh함수에 통과시킵니다. 이를 통해 $c_t$를 (-1, 1)의 안정적인 범위로 변환합니다. 이제 변환된 $c_t$에서 현재 시점($t$)을 기준으로 중요한 정보를 강조해 은닉상태 $h_t$를 출력해야합니다. Output gate에서 계산된 값인 $o_t$가 ‘어떤 정보를 강조해 은닉상태로 출력할 것인지’를 표현하게 됩니다. 최종적으로 $o_t$를 변환된 $c_t$에 곱해 $h_t$를 구할 수 있게되죠.
이 과정을 수식을 포함한 그림과 함께 단계별로 살펴보겠습니다.
LSTM의 Output Gate 내부 계산
STEP (1): $\mathrm{tanh}(c_t)$
먼저, 갱신된 셀 상태인 $c_t$를 비선형 변환 해야합니다.
앞에서 $\tilde{c}_t$를 구했을 때와 마찬가지로 여기서도 활성화 함수로 sigmoid 함수가 아닌 tanh 함수를 씁니다. 역시 결과값의 범위를 sigmoid 함수로 도출되는 (0, 1)이 아닌 tanh 함수로 도출되는 (-1, 1)로 설정하기 위함입니다.
LSTM에서 $h_t$는 이후 노드의 여러 게이트를 계산하는 데 활용되기 때문에, 양수 값만을 출력하는 sigmoid 함수보다 음수 값까지 포함할 수 있는 tanh 함수를 사용해야 더 풍부하고 효과적인 정보 전달이 가능합니다.
STEP (2): $Z_o = W_h^{(o)}h_{t-1} + W_x^{(o)}x_t+b^{(o)}$
STEP (1)에서 $c_t$는 비선형 변환을 거쳤을 뿐, 현재 시점($t$)에서 강조할 정보가 무엇인지는 반영되지 않았습니다. 현재 시점에서 어떤 정보를 강조할지 역시 직전 노드의 은닉상태($h_{t-1}$)와 현재 노드의 입력값($x_t$)를 바탕으로 구해야합니다. Output gate에서만 사용되는 고유의 매개변수를 사용해 $h_{t-1}$과 $x_t$를 선형 변환한 값을 $Z_o$라고 하겠습니다.
STEP (3): $o_t = \sigma (Z_o)$
$Z_o$를 sigmoid 함수에 통과시켜 비선형한 값이 바로 ‘현 시점에서 어떤 정보를 강조해 출력할 것인가’를 표현한 output gate의 값, $o_t$가 됩니다.
STEP (4): $h_t = o_t \times \mathrm{tanh}(c_t)$
Output gate의 값 $o_t$를 갱신되어 비선형 변환된 셀 상태($\mathrm{tanh}(c_t)$)에 곱해주면 비로소 현재(시점 $t$) 노드에서 중요한 정보를 반영한 출력인 은닉상태($h_t$)가 계산됩니다.
마무리하며…
이처럼 LSTM은 RNN의 한계를 완화하기 위해 셀 상태와 3개의 게이트(Forget Gate, Input Gate, Output Gate)를 활용하여 정보의 흐름을 조절합니다. 이를 통해 장기 의존성 문제를 완화하고, 시퀀스 데이터에 대해 보다 효과적인 학습이 가능해졌습니다.
하지만 LSTM은 구조가 복잡하여 계산량이 많고 학습 속도가 느릴 수도 있다는 단점도 있습니다. 이를 보완하기 위해 등장한 것이 바로 GRU입니다. GRU는 LSTM과 유사한 기능을 수행하면서도 더 단순한 구조를 가지며, 연산 효율성을 높인 모델입니다. 다음 글에서는 GRU가 LSTM과 어떻게 다른지, 그리고 GRU가 어떤 장점을 가지는지에 대해 알아보겠습니다.