0. word2vec과 그 한계
이전에 추론 기반 NLP에서 word2vec의 CBOW와 skip-gram에 대해서 알아보았다. 단어를 unique한 id로 나타낸 이후, Embedding표현으로 변환한 이후, 주위의 단어들(즉 문맥)을 입력으로 target을 추론하는 단방향 신경망 유형 즉, feed forward 유형의 인공 신경망의 구조와 적용에 대해 알아보았다.
하지만 이 word2vec에는 문제점이 존재했다. 단방향 신경망이다 보니, 시계열 데이터를 적절히 다루지 못하였고, 이러한 문제점을 해결하기 위해 순환 신경망 즉 Recurrent Neural Network(RNN)이 등장하게 되었다. 왜 word2vec이 시계열 데이터를 잘 처리하지 못했는가?는 word2vec의 구조를 보면 알 수 있다.
이러한 형태를 띄는데, 두개의 단어가 하나의 은닉층에 순서를 고려하지 않은채로 들어가기 때문에 복잡한 문장에서 문맥에 적절한 값을 도출하지 못하게 된다. 이를 해결하기 위해 word2vec의 은닉층을 맥락을 고려하여 각 입력에 대한 나열(혹은 연결, concat)로 치환할 수 있으나 이는 매개변수 증가와 비유동성으로 인해 영구적인 해결책은 될 수 없다.
1. RNN
과거의 데이터를 순환하고 현재 데이터를 갱신함으로서 문맥을 표현하는 방식이다.
ht라는 추론을 위해 데이터 xt와 RNN으로 부터 순환된 데이터를 입력을 필요로 하는 모습을 볼 수 있다. 다음 RNN의 식을 보면 이에 대한 이해가 쉽게 될것이다.
이렇게 얻은 ht를 바탕으로, Affine 변환 (즉, 선형 변환)을 거치고, softmax로 score를 확률값(혹은 가능도)로 표현한 이후, 추론을 하면 된다. 이처럼 추론이 매우 간단하지만, 이런 RNN에서의 키워드는 학습 과정에 있다. 추론으로 얻은 Loss를, 순환 구조를 띄는 RNN 계층을 역으로 전파하면서 파라미터를 수정해야하기 때문이다. 이 과정에서 길게 연결된 RNN에 역전파를 계속 흘리면 레이어가 많이 쌓인 네트워크에서 처럼 Gradient vanishing / explosion이 발생하게 된다. 이를 RNN의 연결을 블록단위로 잘라서 Loss를 흘리는 Truncated RNN이나, 차후 서술할 Gate를 활용한 RNN으로 해결하였다. 하지만 우선 문제의 간단화를 위해 어떻게 흐름별 역전파가 되는지가 아닌, 하나의 흐름에서 흘러들어온 Loss로 어떻게 파라미터를 업데이트하는지 부터 알아보자.
위의 RNN식을 Computational graph로 나타내면 다음과 같다.
dL/dx를 얻기 위해서는 흘러들어온 dL/df와 현재 식 f에 대한 x의 미분인 df/dz를 곱하면 되었던 것을 기억하면 어떻게 각 파라미터가 미분값을 알 수 있고, 그 미분값을 바탕으로 파라미터를 업데이트 할 수 있다.
이처럼 학습된 RNN을 이용하여 만든 Language Model을 RNNLM이라고 한다. 이 과정에서 Score를 변환하는 퍼블렉시등 몇가지 추가 사항이 있지만 중요하지 않다고 판단하여 넘어가고자 한다.
2. LSTM
1번에서 RNN이 어떻게 학습될지에 대해 알아보았다. 하지만 순환하는 빈도가 많아지면 Gradient vanishing / explosion문제가 발생하므로 이를 해결해야 함을 언급하였는데, 이것이 그를 해결하는 방법이다. 우선 왜 순환을 반복하면 Gradient vanishing / explosion이 발생할까? 레이어가 깊은 일반 네트워크와 마찬가지로 순환(혹은 Backprop)을 할 때마다 일정 범위의 수가 곱해지기 때문이다. RNN에서는 tanh이 그 문제이다. 다음은 tanh와 그 미분이다.
일반 네트워크에서 sigmoid로 인해 발생하는 gradient vanishing / explosion을 ReLU를 사용함으로서 해결한 것과 같이 RNN에서도 이 방법을 채택하여 성능을 높일 수 있다. 하지만 RNN에서는 이를 치부하더라도 순환 과정에서 Wh의 행렬 곱이 동일하게 계속 발생한다.
때문에 근본적으로 이러한 구조 자체가 바뀌어야 한다. 그 방법 중 하나로는 RNN에 게이트를 추가함으로서 동일한 행렬의 행렬곱을 없애는 방법이다.
LSTM(Long Short Term Memory)의 키워드는 게이트를 추가함으로서 역전파 과정에서 동일 행렬의 행렬곱을 없애 학습을 돕는다는 것이다. 추가된 gate는 이전 상태 소실량을 결정하는 forget gate와 현재 새로 추가된 정보의 수용량을 결정하는 input gate와 다음 상태로의 전파량을 결정하는 output gate가 있다. 그렇다면 이 gate들이 어떻게 Gradient vanishing / explosion 문제를 해결한다는 것일까? 아래는 LSTM의 미분 과정이다.
시행마다 다른 값인 추가된 게이트를 원소별 곱해지므로, Gradient vanishing / explosion문제가 사라지게 된다. 간단히 0.1이 계속 곱해지던 기존 문제에서 (0.1 * 0.4) * (0.1 * 0.6) * (0.1 * 0.9) ... 문제와 같이 변환되므로 같은 값의 곱셈으로 인한 gradient의 vanishing / explosion이 사라진다고 보면 될 것 같다.
3. Reference
https://curt-park.github.io/2017-04-03/why-is-lstm-strong-on-gradient-vanishing/
https://ratsgo.github.io/natural%20language%20processing/2017/03/09/rnnlstm/