[NLP] Long Short-Term Memory (LSTM), Gated Recurrent Unit (GRU)
🧚🏻♀️참고
이 포스트는 Boostcourse의 ‘자연어처리의 모든 것’을 듣고 정리한 포스트입니다.
| Long Short-Term Memory (LSTM)
LSTM
LSTM은 RNN의 gradient vanishing/exploding과 long-term dependency를 해결하기 위해 고안된 방법이다.(RNN에 대해 궁금하다면 여기로) 정보를 변형없이 멀리까지 전달하는 것이 핵심 아이디어인데, 이를 위해 LSTM에서는 변형하지 않은 정보를 다음 state로 전달하는 cell state를 사용한다.
\[\begin{align} RNN & : h_t = f_W(h_{t-1}, x_t)\\ LSTM & : {(c_t, h_t)} = LSTM(c_{t-1}, h_{t-1}, x_t) \end{align}\]위의 그림은 LSTM의 구조를 나타낸 그림이다. hidden state vector만 다음 시점으로 전달되는 RNN과 달리 LSTM은 cell state vector(\(c_t\))와 hidden state vector(\(h_t\))가 다음 시점으로 전달된다. \(c_t\)는 보다 완성된 정보를 담고 있으며, 이를 가공하여 \(h_t\)를 만든다. 즉, \(h_t\)는 필터링 된 정보가 담긴 벡터라고 할 수 있다. 이렇게 만들어진 \(h_t\)는 output layer의 입력으로 전달되어 output을 계산하는 데에 사용된다.
LSTM의 Gates
LSTM의 구조를 자세히 보면 총 4개의 게이트, Input, Forget, Output, Gate gate로 이루어져있다. 이 게이트들은 정보를 얼마나 가져올지 조절하는 역할을 수행한다.
입력으로 주어진 \(h_{t-1}, x_t\)는 선형변환을 마친 뒤 4개의 벡터로 분할되는데, 이 벡터들은 각각 sigmoid나 tanh 함수와 연산된다. 연산을 마친 벡터들은 정보 반영 비율과 같다고 생각하면 된다. 이게 무슨 말인가 싶다면 아래에서 조금 더 자세히 살펴보자.
Forget gate
\[{f_t = \sigma(W_f \cdot[h_{t-1}, x_t]+b_f)}\]Forget gate는 이전 시점에서 전달 된 정보 중 일부를 지워버리는(잊어버리는) 게이트이다. Forget gate의 벡터 \(f_t\)는 sigmoid 함수와 연산된 벡터로, 0-1 사이의 값을 가진다. 이 값들은 \({c_{t-1}}\)의 정보 중 어느 정도를 기억할지 결정하는 확률로 작용하며, \({c_{t-1}}\)과 element-wise로 곱해진다.
Input gate와 Gate gate
\[\begin{align} i_t & = \sigma(W_i \cdot[h_{t-1}, x_t]+b_i) \\ \tilde{C_t} & = tanh(W_c \cdot[h_{t-1}, x_t]+b_c) \\ C_t & = f_t \cdot C_{t-1} + i_t \cdot \tilde{C_t} \end{align}\]Input gate와 Gate gate는 현재 정보를 얼마나 반영할지 결정하는 게이트이다. Input gate의 벡터 \(i_t\)는 \(f_t\)와 마찬가지로 sigmoid 함수를 통과한 벡터이다. 그와 달리 Gate gate의 \(\tilde{C_t}\)는 tanh 함수와 연산되어 -1과 1 사이의 값을 가진다. 이 두 벡터들은 element-wise로 곱해짐으로써 입력된 정보 중에서 기억할 정보의 양을 결정한다. 최종적으로 이전 시점 정보 중에서 필요한 부분만 남긴 \(f_t \cdot C_{t-1}\)와 더하여 현재 시점의 cell state vector \(C_t\)를 완성한다.
그러니까 수식 (5)는 {이전 시점 정보 + 현재 시점 정보}를 나타낸 식이라고 보면 된다.
Output gate
\[\begin{align} o_t &= \sigma(W_o \cdot[h_{t-1}, x_t]+b_o) \\ h_t & = o_t \cdot tanh(C_t) \end{align}\]Output gate는 \(h_t\)를 만드는 데에 활용된다. sigmoid 함수를 통해 연산된 Output gate의 벡터는 tanh를 통과한 \(C_t\)을 일정한 비율만큼 작게 만든다. 이 과정을 통해 \(h_t\)는 \(C_t\)의 필터링 된 정보를 갖게 된다. 이렇게 만들어진 \(h_t\)는 다음 시점이나 output layer로 전달된다.
| Gated Recurrent Unit (GRU)
GRU는 LSTM을 경량화한 모델로, LSTM에 비해 계산 속도가 빠르고 메모리는 적게 들지만, 성능은 비슷하다는 장점을 가진다.
GRU의 구조는 LSTM과 크게 다르지 않다. 다만 LSTM과 달리 hidden state vector 하나만을 활용하며, 2개의 게이트(Update gate, Reset gate)를 사용한다는 특징을 가진다.
\[\begin{align} z_t &= \sigma(W_z \cdot[h_{t-1}, x_t]) \\ r_t &= \sigma(W_r \cdot[h_{t-1}, x_t]) \\ \tilde{h_t} & = tanh(W \cdot[r_t\cdot h_{t-1}, x_t]) \\ h_t & = (1-z_t)\cdot h_{t-1} + z_t\cdot \tilde{h_t} \end{align}\]게이트의 수가 줄어들면서 생긴 가장 큰 차이는, 이전과 현재 정보의 가중평균으로 \(h_t\)를 연산한다는 점이다. 수식(11)은 [이전 시점의 정보 + 현재 시점의 정보]를 계산하는 식으로 LSTM의 수식(5)와 같은 역할을 한다. LSTM에서는 Input, Forget gate를 이용하여 연산했지만 GRU에서는 Update gate(\(z_t\)) 하나만으로 두 정보의 반영 비율을 결정한 것을 확인할 수 있다. 이렇게 GRU는 LSTM과 비슷하면서도 다르게 작동한다.
| Backpropagation in LSTM/GRU
RNN은 매 시점마다 동일한 가중치가 곱해지기 때문에 gradient vanishing/exploding 문제가 발생했다. 그러나 LSTM과 GRU는 매번 곱해지는 가중치가 다르고, 필요한 정보는 더하기 때문에 gradient 문제가 발생하지 않는다. 또, 멀리 정보를 전달하는 것도 가능해지면서 long-term dependency도 어느 정도 해결되었다.
댓글남기기