[09.07] NLP - Recurrent Neural Network(RNN) & Language Modeling
RNN
Model 구조
시퀀스 데이터가 입력, 출력으로 주어진 상황에서 각 timestep의 t와 이전 t-1의 모듈에서 계산한 ht-1을 입력으로 받아 현재 timestep에서 ht를 출력으로 내어주는 구조이다.
왜 RNN 인가? → 동일한 파라미터를 가지는 A(Weight)를 공유한다, 이것이 반복적으로 등장하고 매 timestep에서 사용하기 때문에 Recurrent 식으로 들어가기 때문에 RNN이라고 불린다.
현재 hidden state(ht)가 다음 step에서 입력으로 들어가야하고, 이때 다음 step에서 입력값과 같이 계산이 되어 output이 결정이 되어야한다.
(output의 개수는 Task 마다 다르다.)
좀더 구체적으로 정리해보자.
처음에는 이전 hidden state Vector인 ht-1이 들어온다. dimension은 하이퍼파라미터이기 때문에 직접 설정해준다. 그리고 Xt라는 word 임베딩 벡터가 들어올 것이다.
여기서, hidden state의 차원은 2라고 생각하고, 입력 Word 임베딩 벡터 차원은 3이라고 하자.
실제 계산이 되는 부분이다. 하나의 Xt 와 ht-1로 이어진 벡터와 가중치 W 행렬의 곱으로 ht가 계산이 된다. 이때, Xt와 ht-1이 직접적으로 내적을 할때, 계산되는 부분이 두부분으로 나눠지는 것을 알 수 있다. 그래서 각각 따로 Wxh, Whh로 나눠서 수식을 정리할 수 있다.(ht의 dimension == ht-1 dimension)
최종적으로 정리한 식이 위의 식이고, 마지막에 non-linear function을 적용해서 최종적인 예측 Yt값을 구할 수 있게 된다.
RNN Types
1. One-To-One
: 일반적으로 하나의 입력이 들어가고, 하나의 출력이나오는 구조이다. 이는 시퀀스 데이터로 이루어진 것이 아니라 Normal한 형태이다.
2. One-To-Many
: 하나의 입력이 들어가고, 여러개의 출력이 나오는 경우이다. 예를들어, Image Captioning같은 경우 이미지 하나가 들어가면 이 이미지에 대한 단어들을 순차적으로 생성해주는 모델이 있을 수 있다.
3. Many-To-One
: Sentiment Classification 처럼, 문장에 대한 감정을 분석하고자할때, 시퀀스 데이터를 통해 최종적인 출력 한개로 예측할 수 있을 것이다.
4. Many-To-Many
: 예를들어, 기계 번역 같은 경우에, 어떤 문장이 주어진다면 문장을 끝까지 보고나서 새로운 언어의 문장으로 생성하고자 할때, many-to-many형태를 사용한다. 또 다른 경우는 끝까지 보는 것이 아닌, 각 word의 형태소를 분석하는 것처럼, 문장의 단어들이 들어가면 각각의 특징을 예측하는 형태도 존재한다.
Language Model
: '언어 모델'이라고 부르는 Task는, 주어진 문자열이나 단어들의 순서를 바탕으로 다음 단어를 맞추는 Task가 된다. (character level, word level 등등 있다.)
문제 : 'hell' 이 주어진다면 'hello'가 나올 수 있도록 해보자!
학습 : 각각의 Character들이 나올때, 다음 Character를 ground Truth로 설정하고 이를 예측할 수 있도록 학습을 진행시킨다.
Logit : OutputLayer에서 정의된 선형 변환 파라미터 Why라고 하면, 출력 hidden state(ht)와 선형식을 거쳐서 Output Vector를 얻게 된다. 그리고 이 값을 Logit이라고 부르는데, 이전에 봐야할 것은 사전의 크기와 output dimension이 동일해야 한다. 왜냐? 사전에 있는 단어들과 확률값을 비교해서 가장 큰 값을 예측하기 때문, 위의 사진에서 첫번째 output layer의 'e'의 ground truth를 가지는 상황에서 예측은 'o'로 예측했다. 그래서 'e'의 확률값을 높이기 위해서 학습을 진행한다.
추론(Test) : 이 경우는, 첫번째 Character만을 입력으로 주게 된다. 그리고 그 첫번째 예측 값을 알아낸 후, 그 예측값을 다음 State의 입력값으로 넣게 된다.
BPTT(Backpropagation Through Time)
매 TimeStep 마다 outputlayer를 통과시켜 예측 값들이 있을 것이다. 그리고 그 때, Ground Truth값과 비교를 해서 Loss함수를 통해 학습이 진행된다. 자 그런데, 입력값이 길어지면 길어질 수록, 한번에 모든 Loss 및 output Layer 값을 계산할때, 자원의 한계가 존재한다. 그래서 이를 Truncation이라는 방법으로 중간중간 잘라서 학습을 진행한다고 한다.
RNN이 다양한 Task에서 필요로하는 정보를 어떻게 학습할 수 있었고, 어느 부분에 저장하는 가? 를 분석해보자. 결국 RNN에서 필요한 정보를 저장하는 공간은 매 타임에서 Update를 수행하는 ht(hidden state vector)라고 할 수 있다. 이를 분석하는 방법은 Hidden State에 Dimension에 따라서 Node 개수가 다르겠지만, 매 Time 마다 변화하는 Hidden State의 노드의 값들을 보면서 분석을 진행할 수 있다.
⭐️ Vanishing/Exploding Gradient Problem
실제로 Vanilla 한 RNN은 실제로 많이 사용하지는 않는다. 이유는 RNN에서는 동일한 Matrix를 매 TimeStep마다 곱하게 되는데, Whh를 그대로 사용해서 진행될때, Backpropagation시 Gradient 가 기하급수적으로 커지거나 작아지는 경우가 생긴다. 그래서 정보를 잃어버리게 된다는 것이다. (또한 tanh함수를 계속적으로 곱해주는 것도 문제가 될 것이다. → -1 ~ 1까지의 소수점을 계속 곱한다고 생각하면 왜 그런지 알 수 있다.)
여기서 h3에 대한 h1의 편미분 값을 계산해보자. 합성함수 미분에 따라서 전체를 미분시켜줄때, tanh의 기울기는 0~1의 값을 가질 것이다. 이 안에 있는 식을 또 미분해준다면 tanh함수가 0~1 의 값을 곱해줄 것이다. 또한 3이라는 값이 계속 곱해지는 데, 3은 Whh 값을 의미한다. 여기서 Whh를 계속 곱해지기 때문에 이또한 Gradient가 계속 커지거나 작아질 것이다.