[Deep Learning]Recurrent Neural Network(RNN)

VVie Do
Dovvie
Published in
8 min readMar 4, 2021

1. RNN 개념 및 등장 배경

Recurrent Neural Network(RNN)은 신경망의 일종입니다. RNN이 다른 신경망과 어떻게 다른지 알아보기 위해 일반적인 신경망 Feed-forward neural network의 학습과정을 살펴보겠습니다. 일반적인 Feed-forward neural network에서는 데이터를 입력하면 입력층에서 은닉층까지 연산이 진행됩니다. 이 때 각 입력 데이터는 서로 독립적으로 학습이 됩니다. 즉, 데이터들의 순서에 상관없이 학습이 되게 되고, 이러한 학습방식은 순서가 있는 데이터(eg. Sequence data, Time series data)의 특성을 네트워크가 효과적으로 이해하지 못하게 됩니다.

이러한 순서가 있는 data를 효과적으로 학습할 수 있는 네트워크가 바로 RNN입니다. RNN은 은닉층에서 나온 결과 값이 다시 해당 은닉층의 input 값으로 들어가게 됩니다. 그래서 RNN은 모든 데이터들이 독립적으로 학습되는 것이 아닌 순서(시간)을 고려하여 학습할 수 있습니다. RNN에서 Recurrent는 ‘반복되는’이라는 의미를 가지는데, 이 이유가 해당 은닉층의 output이 다시 해당 은닉층의 input으로 들어가기 때문입니다.

2. RNN 구조

RNN 기본 구조

RNN의 기본구조는 다음과 같습니다. 녹색 박스는 RNN 구조의 은닉층인 Hidden State를 의미합니다. 빨간 박스는 input, 파란 박스는 output이며 현재 상태에서의 output을 출력하기 위해서는 현재(t시점) input 값과 t-1시점의 Hidden State 출력 값을 input으로 받게 됩니다.

실전적 예제를 통해서 CS231n 강좌의 예제를 들어보겠습니다. 우리는 글자가 주어졌을 때, 다음 글자를 예측하는 모델을 만든다고 합시다. 즉 ‘hell’을 넣으면 ‘o’를 반환하여 최종적으로 ‘hello’를 만들고자 합니다. 일단 우리가 가진 학습데이터는 ‘h’,’e’,’l’,’l’ 총 4개 이며 임베딩을 통해 vector로 바꾸면 [1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]이 됩니다.

처음 인풋(t=1)으로 ‘h’를 나타내는 vector인 [1,0,0,0]이 히든 state의 인풋 값으로 들어갑니다. 이 때 h(0)(t=0 시점의 hidden state 출력값)은 존재하지 않기 때문에 랜덤 값을 넣어주고 이를 바탕으로 h1을 출력합니다. 그리고 해당 h1의 출력 값은 output layer를 거쳐서 최종적으로 하나의 벡터를 출력합니다. 다음 인풋(t=2) ‘l’을 나타내는 vector인 [0,1,0,0]과 h(1)의 출력 값이 다음 input 값으로 들어가게 되고 이러한 과정이 반복되게 됩니다. 이러한 과정을 forward propagation(순전파)라고 합니다.

RNN 또한 다른 신경망처럼 Parameter를 적절히 갱신하기 위해 정답 값이 필요한데, RNN의 경우 바로 다음 글자가 정답이 됩니다. 즉 ‘h’의 다음 정답은 ‘e’가 되고, ‘e’의 다음 정답은 ‘l’이 됩니다. 해당 예에서 ‘e’를 vector로 표현하면 [0,1,0,0] 인데, 그림을 보면 진한 녹색으로 표시된 숫자들이 정답에 해당하는 인덱스를 의미합니다. 이 정보를 바탕으로 Backpropagation을 통해 parameter값들을 수정합니다. 그림에서 볼 수 있듯, 학습이 진행되면서 점점 더 글자 예측을 잘하게 됩니다. output layer의 출력 값을 보면 점점 가장 큰 값과 정답 값 인덱스가 같아지는 것을 볼 수 있는데, 해당 네트워크가 학습을 통해 다음 값을 더욱 잘 예측하게 되는 것을 의미합니다.

추가적으로 갱신되는 파라미터는 인풋 x를 Hidden layer h로 보내는 W_xh, 이전 히든레이어 h에서 다음 히든레이어 h로 보내는 W_hh, 히든레이어 h에서 아웃풋 y로 보내는 W_hy가 바로 parameter입니다.

3. RNN 학습

3.1 RNN Feedforward

RNN 구조에서 데이터가 어떻게 전달되는지 확인하기 위해 Feedforward 과정을 자세히 살펴보겠습니다.

RNN Feedforward

위의 그림처럼, 새로운 인풋 X_t와 인풋 layer의 parameter인 W_xh가 곱해진 값과, t-1 시점의 hidden state 출력 값인 h_(t-1)이 Hidden layer의 input parameter인 W_hh가 곱해진 값, 최종적으로 편향 b_h 까지 총 3개의 값이 Hidden state의 input으로 들어오게 됩니다. 해당 값은 Hidden state의 activation function인 tanh 함수를 거치게 되고 activation function 함수 출력 값이 h_t함수의 출력 값이 됩니다. 추가적으로 h_t함수의 출력 값에 W_hy이 곱해지고 최종적으로 편향 b_y가 더해져서 output으로 출력되게 됩니다. 그리고 h_t 함수의 출력 값은 t+1 시점 Hidden State의 새로운 input 값이 됩니다. 이러한 과정의 반복이 RNN의 Feedforward 과정입니다.

3.2 RNN Backpropagation

다음은 RNN의 학습과정인 Backpropagation(역전파)과정에 대해서 알아보겠습니다. 해당 과정을 이해하기 위해서는 Gradient Descent에 대해서 알고 있어야 하는데, 이를 알고있다는 가정하에 설명드리겠습니다.

RNN Backpropagation

우선 RNN 또한 Backpropagation 기법과 Gradient Descent 알고리즘을 통해 parameter들을 갱신합니다. 최종 output인 y_t의 값에서 Feedforward의 역순으로 가면서 가중치를 갱신합니다. 순서대로 말씀드리면 prediction과 label 값의 차이인 Loss에 대한 gradient인 d(Loss) / d(y_t)가 가장 먼저 계산이 됩니다. 그리고 d(Loss) / d(W_hy)를 구하기 위해 Chain rule을 사용해 {d(Loss) / d(y_t)} * {d(y_t) / d(W_hy)}를 구하게 됩니다. 이러한 chain rule을 모든 parameter에 적용해서 해당 parameter가 Loss에 영향을 미치는 정도를 파악하고 각 parameter들을 Gradient descent 알고리즘을 사용해 업데이트 합니다.

4. RNN 실습

다음은 RNN에 대한 실습을 해보겠습니다. 일반적인 텍스트 데이터가 아닌 이미지 데이터인 MNIST 데이터를 사용하였고, Pytorch를 이용해서 실습하였습니다. 참고자료는 포스팅 가장 아래부분에 있습니다.

4.1 패키지 불러오기 및 Data 준비

4.2 RNN 모델 Class 생성

4.3 학습하기

4.4 결과 시각화

5. RNN 문제점 및 대안.

위에서 언급한 것처럼, RNN은 Backpropagation을 통해 parameter를 갱신하는데, RNN에서도 Backpropagation의 고질적인 문제인 gradient vanishing 문제가 발생합니다. 즉, chain rule에 의해 layer가 깊어질수록 gradient가 점차 줄어들게 되고 이는 input layer에 가까운 layer들의 parameter들이 적절히 학습되지 않는 현상이 발생하게 됩니다.

이러한 문제를 해결하기 위해 CNN과 같은 모델에서는 다른 activation function을 사용하지만 RNN 구조에서는 LSTM이라는 새로운 구조를 제안해 해당 문제를 해결하게 됩니다. 이는 다음 포스팅에서 다루도록 하겠습니다.

틀린 내용이 있거나 궁금한 사항 및 피드백 주실 내용이 있다면 망설이지 마시고 말씀주시면 감사하겠습니다. 긴 글 읽어주셔서 감사합니다.

참고 자료 : https://ratsgo.github.io/natural%20language%20processing/2017/03/09/rnnlstm/

https://www.kaggle.com/kanncaa1/recurrent-neural-network-with-pytorch

--

--