목차
자주 잊어버리는 딥러닝 기초 내용을 여러 포스팅에 걸쳐 간단하게 정리해보려 한다. 다룰 내용은 크게 아래와 같다.
- Introduction
- Elements of ML
- Multi-layer Perceptron
- Model Selection
- CNN
- GNN
- RNN
이번 포스팅에서는 RNN에 대해 간략히 알아보자.
Introduction
Recurrent Neural Network(RNN)는 sequential data를 다루는 데 특화된 딥러닝 네트워크이다.
Sequential Data
Sequential data에는 다음과 같은 종류가 있다.
- Time-series data
- Text data
- Reinforcement learning/planning (control problem)
- Image frames in video
- Music, speech, dialogue ...
흔하지는 않지만, image data 또한 pixel의 sequential data로 생각해볼 수 있다. Sequential model인 transformer가 최근 vision 분야에서도(뿐만 아니라 머신러닝 전반적으로) 많이 사용되고 있다.
Sequential data를 다루기 어려운 이유는 길이가 일정하지 않기 때문이다. 입력의 길이가 일정하지 않아 weight, bias가 정해져야 하는 MLP를 사용할 수 없다. (parameter를 공유하는 CNN은 1d convolution 연산을 통해 사용 가능하다. 단, 마지막 layer에서 Fully Connected Layer를 사용할 수 없다는 문제점이 있다.)
그리고 sequential data는 non-i.i.d.이다. 즉, 순서가 매우 중요하여 순서를 바꾸면 완전히 다른 data가 된다. (GNN은 permutation invariance 성질을 가지므로 사용이 불가능하다.)
Principles(Inductive Biases) in RNN
RNN은 sequentiality, temporal invariance라는 principle을 갖는다. (inductive bias이기도 하다.)
Sequentiality는 non-i.i.d. data를 다루기 위해 순차적으로 입력을 다루어야 한다는 성질을 말한다.
예를 들어, 문장을 입력으로 주었을 때 문장의 단어(token)는 순차적으로 다룬다. (위에서도 언급했듯, 순서를 바꾸면 의미가 완전히 바뀐다.)
Temporal Invariance는 sequence의 순서가 바뀌어도 결과는 바뀌지 않는다는 의미이다. 여기서 temporal(time) 개념은 sequence의 순서 개념으로, NLP에서 문장의 순서이다.
예를 들어, 현재 문장을 이해하는 데 과거의 문장의 의미는 영향이 없다. 따라서 문장의 순서를 바꾸는 건 결과에 영향을 주지 않는다.
Fig 1에서와 같이, CNN에서는 동일한 parameter를 공유하는 filter가 공간적으로 독립적으로 움직이면서 정보를 추출해내므로 spatial invariance 성질을 가졌는데, RNN에서는 시간적으로 t-1에서의 연산과 t에서의 연산이 동일한 parameter를 갖고 독립적으로 연산하므로 서로 영향을 주지 않는다.
Recurrent Neural Network (RNN)
Sequential data를 다루기 위한 가장 간단한 모델로부터, RNN까지 알아보면서 RNN의 주요 개념을 알아보자.
먼저 conditionally independent model은 각 시간 마다 독립적으로 input에 대한 연산을 수행한다.
\( \mathbf{o}_t = f_{w_o} (\mathbf{x}_t) \)
이 모델로는 sequentiality를 갖는 데이터를 다룰 수 없다. 순서 정보를 반영하지 못하기 때문이다. (달리 말하면, 순서가 바뀌어도 output이 똑같기 때문이다.)
따라서 이전 데이터의 정보를 반영하기 위해 autoregressive model을 고안했다.
Autoregressive model은 정해진 길이의 sequential data를 input으로 받아 이전의 정보를 현재 연산에 반영해준다.
\( \mathbf{o}_t = f_{w_o} (\mathbf{x}_t, \mathbf{x}_{t-1}, \dots, \mathbf{x}_{t-l} \)
- \(l\) : data의 (고정된) 길이
하지만 text 등을 다루기 위해서는 long-term dependency(단어가 멀리 떨어져 있어도 정보를 반영할 수 있어야 함)를 반영해줄 수 없다.
따라서 hidden state를 활용하여 이전 data의 정보를 계속적으로 반영하는 latent autoregressive model을 고안했다.
Latent autoregressive model은 hidden state를 활용하여 long-term dependency를 반영(다양한 길이의 sequence 다룸)하였다.
\( \mathbf{h}_t = f_{w_h} (\mathbf{x}_t, \mathbf{h}_{t-1}) \)
\( \mathbf{o}_t = g_{w_o} (\mathbf{h}_t) \)
- \(\mathbf{h}\) : hidden state로, 이전 시간까지의 모든 input 정보를 갖고 있다.
마지막으로, recurrent neural network(RNN)는 latent autoregressive model에 learnable parameter를 추가한 모델이다.
\( \mathbf{h}_t = \phi({W_{hx} \mathbf{x}_t + W_{hh} \mathbf{h}_{t-1} + b_h) \)
\( \mathbf{o}_t = W_{oh} \mathbf{h}_t + b_o \)
이때, layer 별로 \(W_{hx}, W_{hh}, W_{oh} \)는 서로 다른 시간(step)에 따라 공유된다. (마치 CNN에서 서로 다른 pixel 위치에 따라 kernel paramter를 공유한 것과 같은 개념이다.)
Backpropagation Through Time
RNN에서의 backpropagation 과정을 수식으로 알아보면서 RNN의 문제점을 알아보자. 간단히 표현하기 위해 latent autoregressive model 수식을 사용한다.
\( \mathbf{h}_t = f_{w_h} (\mathbf{x}_t, \mathbf{h}_{t-1}) \)
\( \mathbf{o}_t = g_{w_o} (\mathbf{h}_t) \)
전체 loss function은 다음과 같이 나타낼 수 있다.
\( \mathcal{L}(x, y, w_h, w_o) = \sum\limits_{t=1}^T l(y_t, o_t) \)
- \(x, y\) : 각각 input, 정답 sequence
- \(w_h, w_o\) : 각각 hidden state, output의 update에 사용되는 weight
- \(y_t, o_t\) : 각각 시간 t에서의 정답과 output
\(w_h\)에 대한 gradient를 구해보자.
Chain rule에 의해,
\( \begin{align*} \cfrac{\partial \mathcal{L}(x, y, w_h, w_o)}{\partial w_h} &= \sum\limits_{t=1}^T \cfrac{\partial l(y_t, o_t)}{\partial w_h} \\ &= \sum\limits_{t=1}^T \cfrac{l(y_t, o_t)}{\partial o_t} \cfrac{\partial o_t}{\partial w_h} \\ &= \sum\limits_{t=1}^T \cfrac{\partial l(y_t, o_t)}{\partial o_t} \cfrac{\partial g(h_t, w_h)}{\partial w_h} \quad \because o_t = g(h_t), \; h_t = f_{w_h}(\cdots) \\ &= \sum\limits_{t=1}^T \cfrac{\partial l(y_t, o_t)}{\partial o_t} \cfrac{\partial g(h_t, w_h)}{\partial h_t} \cfrac{\partial h_t}{\partial w_h} \end{align*} \)
여기서, 함수의 입력으로 함수가 들어갈 때의 편미분 \( \cfrac{\mathrm{d} f(y(x), x)}{\mathrm{d} x} = \cfrac{\partial f}{\partial y} \cdot \cfrac{\partial y}{\partial x} + \cfrac{\partial f}{\partial x} \)에 의해
\( \cfrac{h_t}{w} = \cfrac{\partial f(x_t, h_{t-1}, w)}{\partial w} + \cfrac{\partial f(x_t, h_{t-1}, w)}{\partial h} \cfrac{h_{t-1}}{\partial w} \)인데, 식에서 \(\cfrac{\partial{h_{(t-\dots)}}}{\partial w}\) 부분이 반복된다. 따라서 이 식을 반복적으로 적용하면 최종 gradient는 다음과 같이 나타낼 수 있다.
\( \cfrac{\partial h_t}{\partial w_h} = \cfrac{\partial f(x_t, h_{t-1}, w_h)}{\partial w_h} + \sum\limits_{i=1}^{t-1} \left( \prod\limits_{j=i+1}^t \cfrac{\partial f(x_j, h_{j-1}, w_h)}{\partial h_{j-1}} \right) \cfrac{\partial f(x_i, h_{i-1}, w_h)}{\partial w_h} \)
여기서 주목할 부분은 \( \prod \left( \cdots \right) \)부분이다.
이 backpropagation 과정을 모두 사용하는 경우를 full backpropagation through time이라 하는데, 만약 sequence가 길어지게 되면 \( \cfrac{\partial f(x_j, h_{j-1}, w_h)}{\partial h_{j-1}} \) term이 많이 곱해질 것이고, 이 term의 norm(크기)이 1보다 작을 경우 gradient vanishing, 1보다 클 경우 gradient explode가 발생할 것이다. 따라서 학습이 매우 느리고 어렵다는 단점이 있다.
따라서 다음과 같은 방법으로 이 문제를 해결한다.
- Truncated BPTT : Gradient cutting이라고도 하며, 특정 time step 이후로는 sum을 하지 않는다. 즉, 위 식에서 \(\sum\limits_{i=1}^{t-1}\)이 아닌 \(\sum\limits_{i=t-k}^{t-1}\)을 사용한다.
- 이로 인해 모델은 long-term보다는 short-term dependency의 영향을 더 많이 받게 된다.
- PyTorch에서는 'detach'로 구현한다.
- Randomized BPTT
또는 gradient clipping을 사용하여 gradient explosion 현상을 막아줄 수 있다.
\( \mathbf{g} \leftarrow \min \left( 1, \cfrac{\xi}{\lVert \mathbf{g} \rVert} \right) \mathbf{g} \)
최근댓글