[DL] CS231n Lecture 10: Recurrent Neural Networks

Date:     Updated:

카테고리:

태그:

1. RNN Examples

Image

  • one to one : 지금까지 배웠던 Network의 형태이다. (Vanilla Neural Network)

  • one to many : Image Captioning (image -> sequence of words)
    입력은 이미지와 같은 단일 입력이지만 출력은 caption과 같은 가변 출력이다.

  • many to one : Sentiment Classification (sequence of words -> sentiment)
    가변적인 입력을 받고 그 문장이 긍정인지 부정인지 평가를 한다.

  • many to many : Machine Translation seq of words -> seq of words 예를 들어 영어를 프랑스어로의 번역을 생각해보면 입력과 출력의 길이가 다를 것이다. 그렇기 때문에 가변적인 입/출력이 가능한 모델이 필요하다.

  • many to many : Video classification on frame level 입력은 비디오와 같은 가변 입력이고 각 프레임마다 출력값이 나와야 하는 상황인 경우이다.

정리를 하면 Recurrent Neural Networks는 가변 길이의 데이터를 다루기 위해 필요한 하나의 방법이다. 또한 입/출력의 길이가 고정된 상황에서도 효과적으로 동작한다.

2. Recurrent Neural Network (RNN)

Image

RNN에는 내부에 hidden state를 가지고 있다. 이 hidden state는 RNN이 새로운 입력을 불러들일 때마다 매번 업데이트 된다. hidden state는 모델에 feedback되고 이후에 또 다시 새로운 입력 x가 들어온다.

RNN의 동작 방식은

  1. 입력 값이 들어온다.
  2. hidden state가 업데이트된다.
  3. 출력 값을 내보낸다.

Image

동작 방식을 수식으로 나타낼 수 있다. 함수 f는 이전 상태의 hidden state인 \(h_{t-1}\) 와 현재 상태의 입력인 \(x_t\)를 입력으로 받는다. 그리면 함수 f의 출력이 업데이트 된 hidden state인 \(h_t\) 가 된다.

그리고 다음 state에서는 \(h_t\)와 \(x_{t+1}\)가 입력이 된다.

RNN에서는 출력 값을 가지려면 \(h_t\)를 입력으로 하는 FC-layer를 추가해야한다. Fc-layer는 매번 업데이트되는 Hidden state(\(h_t\))를 기반으로 출력 값을 결정한다.

중요한 사실은 함수 f와 파라미터 W는 매 스텝마다 동일하다는 것이다.

이해하기 쉽게 Computational Graph로 표현을 하면 다음과 같다.

Image

매번 h와 x는 값이 달라지지만 W는 같은 값을 사용한다.

각 시퀀스마다 Ground truth label이 있다고 하면 각 스텝마다 개별적으로 \(y_t\)에 대한 Loss를 계산해볼 수 있다. RNN의 최종 Loss는 각 개별 Loss들의 합이다.

나머지의 경우들도 다음과 같이 표현해볼 수 있다.

Image Image

2.1 Sequence to Sequence

Image

예를 들어 machine translation에서 사용할 수 있는 Sequence to Sequence모델의 경우 가변 입력과 가변 출력을 가지는 모델이다. 이 모델을 many to one 모델과 one to many 모델의 결합으로 볼 수 있다.

그러면 이 모델은 encoder와 decoder 구조 두 개의 스테이지로 구성된다.

English sentence 같은 가변 입력을 받으면 encorder는 final hidden state를 통해 전체 sentence를 하나의 벡터로 요약한다.

이 요약된 하나의 벡터를 decoder의 입력으로 넣어 가변 출력인 다른 언어로 번역된 문장을 출력할 수 있다. 위 그림처럼 가변 출력은 매 스텝마다 적절한 단어를 출력한다.

보통 RNN은 Language modeling 문제에서 많이 사용을 한다. 이때 해결하고 싶은 것은 어떻게 자연어를 만들어낼지 이다.

예를 들어 문자를 출력하는 모델이라면 매 스텝에 어떻게 문자를 생성해 낼지를 풀어야 한다. 단어를 출력하는 모델이라면 매 스텝 어떻게 단어를 생성해 낼 지를 풀어야한다.

간단한 예제로 charactre level language model이 있다.

Image

Image

hello라는 sequence를 학습시킨다고 할 때 입력으로 hell를 입력하면 o를 예측해야한다. 하지만 현재 예제에서는 h를 입력했을 때 o의 예측치가 가장 높게 나왔으므로 Loss가 낮다. 다음 입력인 e를 넣으면 이전의 hidden layer와 함께 새로운 hidden layer를 만들어내고 output을 예측한다. 이런 과정을 반복한다.

모델을 다양한 문장으로 학습시킨다면 모델은 이전 문장의 문맥을 참고해서 다음 문자가 무엇일지를 학습해야 한다.

Image

Test Time일 때 softmax 함수를 통해 확률 분포로 만들었다. 이때 운이 좋게 13% 확률로 e를 출력했다. 이때 출력된 e를 다음 입력으로 넣어준다. 이처럼 확률 분포에서 샘플링하는 방법을 사용하면 일반적으로는 모델에서의 다양성을 얻을 수 있다.

이런 모델의 경우 시퀀스 스텝마다 출력값이 존재한다. 이 출력값들의 Loss를 계산해 final loss를 얻는데 이를 backpropagation through time이라고 한다. 이 경우 forward pass의 경우에는 전체 시퀀스가 끝날 때 까지 출력값이 생성된다. 반대로 backward pass에서도 전체 시퀀스를 가지고 Loss를 계산해야 한다.

하지만 이 시퀀스가 매우 길다면 문제가 될 수 있다. 실제로는 truncated backpropagation을 통해 backprob을 근사시키는 방법을 사용한다.

Image

이 방법의 아이디어는 입력 시퀀스가 엄청나게 길어서 무한대라고 할지라도 Train time에 한 스텝을 일정 단위로 자른다 대략 100 정도로 그리고 100 스텝만 forward pass를 하고 이 sub sequence의 loss를 계산한다. 그리고 gradient step을 진행한다.

이 과정을 반복하는데 이전 batch에서 계산한 hidden states는 계속 유지한다. 다음 Batch의 forward pass를 계산할 때는 이전 batch를 활용하지만 gradient step은 현재 batch 에서만 진행한다.

3. Image captioning

Image

Image captioning에서의 Caption은 가변길이이다. 즉, Caption마다 다양한 시퀀스 길이를 가지고 있다. 그래서 여기에 RNN Language Model이 적합하다.

먼저 모델에는 입력 이미지를 받기 위한 CNN이 있다. CNN은 요약된 이미지 정보가 들어있는 Vector를 출력한다. 그리고 Vector는 RNN의 초기 Step의 입력으로 들어간다. 최종적으로 RNN에서 Caption에 사용할 문자들을 step마다 만들어낸다.

softmax scores를 사용하지 않고 4096차원의 벡터를 출력으로 한다. 이 벡터는 전체 이미지 정보를 요약하는데 사용된다.

Image

RNN Language model처럼 모델이 문장을 생성해 내기에 앞서 초기 값을 넣어줘야한다. 이 경우에는 입력이 특별한게 모델에게 START 토큰을 주면서 시작해야한다. 그러면 START부터 시작을 해서 한 단어씩 Sampling을 한다. 그렇게 step마다 단어를 뽑게된다.

Image

이전까지 RNN 모델은 두 개의 가중치 행렬을 입력으로 받았다. 하나는 현재 스텝의 입력이고 다른 하나는 이전 스텝의 Hidden state를 조합해 다음 hidden state를 얻었다. 하지만 이제는 이미지 정보도 더해줘야 한다. 가장 쉬운 방법은 세번째 가중치 행렬을 추가하는 것이다.

다음 hidden state를 계산할 때마다 모든 스텝에 이 이미지 정보를 추가한다.

Image

이제 Step마다 출력으로 Vocabulary에서 샘플링을 통해 단어를 출력한다. 그리고 그 단어를 다시 다음 step의 입력을 넣어주는 것을 반복한다.

앞서 START 토큰을 통해 시작한 것 처럼 끝낼 때도 END 토큰을 통해 끝을 낸다. Training time에는 모든 caption의 마지막에는 END 토큰을 삽입한다. 그렇게 되면 네트워크가 학습하는 동안에 시퀀스의 끝에 토큰을 넣어야 한다는 것을 학습할 수 있다.

이 과정은 supervised learning으로 진행되고 그래서 모델 학습을 위해서는 natural language caption을 가지고 있는 이미지가 필요하다. 가장 큰 데이터셋은 아마 Microsoft COCO 데이터 셋일 것이다.

3.1 Image Captioning with Attention

Image

Attention이라는 모델은 Caption을 생성할 때 이미지의 다양한 부분을 집중해서 볼 수 있다.

Image

CNN으로 벡터 하나를 만드는게 아니라 각 벡터가 공간정보를 가지고 있는 grid of vector를 만들어낸다.

그리고 Forward pass시에 매 스텝 vocabulary에서 샘플링할 때 모델이 이미지에서 보고싶은 위치에대한 분포또한 만들어낸다. 이미지의 각 위치에 대한 분포는 Train time에 모델이 어느 위치를 봐야하는지에 대한 정보이다.

첫번째 hidden state(h0)는 이미지 위치에 대한 분포(a1)를 계산한다. 이 분포를 다시 벡터 집합 (LxD Features)과 연산하여 이미지 attention(z1)을 생성한다.

이 요약된 벡터(z1)은 다음 스텝의 입력으로 들어간다. 그렇게 되면 두개의 출력이 생기는데 하나는 vocabulary의 각 단어들의 분포(d1), 이미지 위치에 대한 분포(a2)이다. 이것을 반복하면 매 스텝마다 2개의 출력이 생성된다.

Image

caption을 만들 때 마다 이미지 내에 다양한 곳들에 attention을 주는 것을 볼 수 있다.

soft attention : 모든 특징과 모든 이미지 위치간의 weighted combination

hard attention : 모델이 각 타임 스텝마다 한 곳만을 보도록 제한한 경우

Image

Image captioning 뿐만 아니라 Visual Question Answering도 해결할 수 있다.

4. Multilayer RNNs

지금까지 본 RNN은 모두 single layer였다. 이것을 multi layers로 만들 수도 있다.

Image

3-Layer RNN일때 입력은 첫번째 RNN으로 들어가서 첫번째 hidden state를 만들어낸다. 이렇게 만들어진 hidden state 시퀀스를 다른 RNN의 입력으로 넣을 수 있다. 그러면 또 다른 hiddn state가 만들어지고 이것을 반복하면 RNN layer를 쌓을 수 있다.

RNN을 사용할 때 문제점이 있다.

Image

가장 기본적인 RNN인데, backpropagation을 할 때 h0를 구하기 위해선 local gradient와 upstream gradient가 필요하다. 하지만 upstream gradient를 구하기 위해선 다음 step에서의 gradient가 필요하고 그렇게 끝까지 간다. 즉, h0의 gradient를 구하기 위해서는 모든 RNN cells를 거쳐야 한다.

그리고 곱해지는 값이 1보다 크면 gradient exploding problem이 발생하고 1보다 작으면 gradient vanishing problem이 발생한다.

Image

gradient exploding problem은 Gradient clipping 기법을 사용한다.

gradient를 계산하고 gradient의 L2 norm이 임계값보다 큰 경우 gradient가 최대 임계값을 넘지 못하도록 조종해준다. (그닥 좋은 방법은 아니지만, 실제로 많이 사용한다)

하지만 gradient vanishing problem을 해결하기 위해선 더 복잡한 RNN 아키텍쳐를 필요로 한다. 그래서 등장한 것이 LSTM이다.

5. Long Short Term Memory(LSTM)

LSTM은 vanishing & expolding gradients 문제를 완화시키기 위해서 등장했다. gradient clipping 같은 방법을 쓰지 말고, gradient가 잘 전달되도록 아키텍쳐 자체를 디자인한 경우이다.

Image

기존의 Vanilla RNN은 hidden state가 있었고 매 스텝마다 재귀적인 방법으로 hidden state를 업데이트 했다. LSTM은 한 Cell 당 두개의 Hidden state가 있다. 하나는 hidden state와 유사한 개념인 \(h_t\)이고 나머지는 Cell state로 LSTM 내부에만 존재하고 밖에 노출되지 않는 변수이다.

Image

LSTM은 마찬가지로 h와 x를 입력으로 받는다. 앞선 RNN은 두 입력을 concat해서 행렬곱 연산으로 hidden state를 직접 구했던 반면에 LSTM은 이전 hidden state와 입력을 받아서 쌓아 놓는다. 그리고 4개의 gates의 값을 계산하기 위한 커다란 가중치 행렬을 곱한다.

4개의 gate는 i, f, o, g이다.

i : input gate : Cell에서의 입력 \(x_t\)에 대한 가중치

f : forget gate : 이전 스텝의 Cell 정보를 얼마나 잊을지(기억할지)에 대한 가중치

o : output gate : \(c_t\)를 얼마나 밖에 드러낼 지에 대한 가중치

g : gate gate(?) : input cell을 얼마나 포함할지 결정하는 가중치

각 gate는 다른 non-linearity를 사용한다. i/f/o gate는 sigmoid를 사용해 0~1 사이이고, g gate는 tanh를 사용해 -1 ~ 1 사이의 값을 갖는다.

Image

입력 \(h_{t-1}\)와 \(x_t\)는 stack되어 4개의 gate를 구하기 위한 W와 곱해진다.

\(f \odot c_{t-1}\) : f는 sigmoid 함수를 거쳐 0~1 사이의 값이다. 즉 f=0이면 이전 스텝의 Cell state를 완전히 잊고, f=1이라면 이전 Cell state를 완전히 사용한다.

\(i \odot g\) : cell state의 각 element에 대해서 사용하고 싶으면 i=1, 아니면 i=0이다. g는 tanh로 -1~1 사이의 값을 갖는다.

정리를 해보면 \(c_t\)는 먼저 이전 Cell state를 사용을 하지 안할지를 결정한다. (\(f \odot c_{t-1}\))

그리고 각 스텝마다 1까지 Cell state의 각 요소를 증가시키거나 감소시킬 수 있다. (\(i \odot g)\)

즉, Cell state의 각 요소는 값이 줄었다가 늘었다 할 수 있다.

Image

LSTM이 등장했던 이유는 gradient 계산시의 문제점 때문이었다. 이제 다시 gradient를 계산해보면

Cell state에서 내려오는 Upstream gradient는 +를 거치지만 +는 그저 두 갈래로 복사된다. 따라서 gradient는 upstream gradient와 forget gate의 element wise multiplication(\(\odot\)) 이다.

즉, Cell state backprob = upstream gradient \(\odot\) forget gate

이렇게 되면 두가지 좋은 점이 있다.

  1. forget gate와 곱해지는 연산이 matrix multiplication이 아니라 element-wise multiplication이다. full matrix multiplication 보다는 element wise multiplication이 더 낫다.
  2. element wise multiplication을 통해 매 스텝 다른 값의 forget gate와 곱해질 수 있다. Vanilla RNN의 경우에는 동일한 가중치 행렬 (\(h_t\))만을 계속 곱했다. 이는 exploding/vanishing gradient문제를 일으켰다. 하지만 LSTM에서는 곱해지는 forget gate가 스텝마다 계속 변한다. 이를 통해 문제들을 쉽게 해결할 수 있다.

Image

vanilla RNN의 backward pass에서는 매 스텝 gradient가 tanh를 거쳐야 했다.

LSTM의 최종 hidden state \(h_t\)에서 가장 첫 Cell state인 \(C_0\)까지 backprob 할때 RNN처럼 매 스텝 tanh를 거치는 것이 아니라 한번만 거치면 된다.

이처럼 LSTM은 backprob할 때 방해를 덜 받을 수 있다. LSTM에서도 vanishing gradient의 위험은 존재하지만 Vanilla RNN만큼 심하진 않다.

맨 위로 이동하기

DL 카테고리 내 다른 글 보러가기

댓글남기기