Recurrent Neural Network 1 (Vanilla RNN)

강병민·2024년 3월 21일

NLP study

목록 보기
3/6

RNN이란

순환신경망 RNN: 입력과 출력을 시퀀스 단위로 처리하는 시퀀스 (Sequence) 모델

RNN을 표현한 두 그림- 재귀형태로 표현한 RNN과 시간에 따라 여러 시점으로 보여주는 두 방법

  • x: 입력층, 입력벡터
  • y: 출력층, 출력벡터
  • 초록이: 은닉층, cell, 메모리 셀, RNN 셀

여기서 모든층들은 벡터형태로 존재!
은닉층에서 나온 결과값 -> 출력층(y) + 다시 은닉층

RNN을 뉴런 단위로 시각화

  • 4차원의 입력벡터(뉴런)
  • 2차원의 은닉상태(은닉상태크기 = 2, 은닉층 수와는 다른 의미)
  • 2차원의 출력벡터를 가지고 있다

이 다차원 벡터들은 행렬로 한번에 계산 가능

다양한 형태의 RNN

one‐to‐many: 하나 의 이미지 입력에 대해서 사진의 제목을 출력하는 이미지 캡셔닝 (Image Captioning) 작업에 사용할 수 있다. 사진의 제목은 단어들의 나열이므로 시퀀스 출력

many‐to‐one: 입력 문서가 긍정 적인지 부정적인지를 판별하는 감성 분류 (sentiment classification), 또는 메일이 정상 메일인지 스팸 메 일인지 판별하는 스팸 메일 분류 (spam detection) 등에 사용

many‐to‐many: 챗봇, 번역기, 개체명 인식, 품사 태깅과 같은 작업에 사용

RNN 수식

은닉 상태값과 출력값을 구하는 방법을 알아보자


위 사진과 같이 "입력, 은닉층 재귀, 출력" 세 부분의 가중치가 각각 존재한다
현재 시점을 t 라고 하자
현재 시점 t 에서의 은닉층과 출력층은 다음과 같다

  • 은닉층: ht=tanh(Wxxt+Whht1+b)h_t = \tanh(W_{x}x_t + W_{h}h_{t-1} + b)
  • 출력층: yt=f(Wyht+b)y_t = f(W_{y}h_t + b)

하나의 은닉층이라면 가중치 값은 모든 시점에서 동일
b는 편향, 출력층의 f는 활성화 함수

행렬계산


ht=tanh(Whht1+Wxxt+b)h_t = \tanh( W_{h}h_{t-1}+W_{x}x_t + b) 연산 (은닉 상태값)을 벡터와 행렬 연산으로 표현

  • DhD_h: 은닉 상태의 크기
  • dd: 단어 벡터의 차원 (𝑥t𝑥_t 는 단어 벡터로 간주), 입력 차원- 단어 전처리 할 때 임베딩 벡터의 차원이나 인코딩 차원을 의미

예시

만약 은닉 상태의 크기가 2 ((D_h=2))이고, 입력 벡터의 차원이 3 ((d=3))이라면, (W_x) 행렬은 다음과 같이 2x3 행렬이 됩니다:

Wx=[w11w12w13w21w22w23]W_x = \begin{bmatrix} w_{11} & w_{12} & w_{13} \\ w_{21} & w_{22} & w_{23} \end{bmatrix}

wijw_{ij}: 가중치 행렬의 원소
이 행렬은 입력 벡터 xt=[x1,x2,x3]Tx_t = [x_1, x_2, x_3]^T와 곱해져 은닉층으로의 입력을 생성
곱셈의 결과는 다음과 같이 2차원의 벡터가 된다!

Wxxt=[w11w12w13w21w22w23][x1x2x3]=[w11x1+w12x2+w13x3w21x1+w22x2+w23x3]W_x x_t = \begin{bmatrix} w_{11} & w_{12} & w_{13} \\ w_{21} & w_{22} & w_{23} \end{bmatrix} \cdot \begin{bmatrix} x_1 \\ x_2 \\ x_3 \end{bmatrix} = \begin{bmatrix} w_{11}x_1 + w_{12}x_2 + w_{13}x_3 \\ w_{21}x_1 + w_{22}x_2 + w_{23}x_3 \end{bmatrix}

양방향 순환 신경망 (Bidirectional Recurrent Neural Network)

시점 t에서의 출력값을 예측할 때 이전 시점의 입력뿐만 아니라, 이후 시점의 입력 또한 예측에 기여

ex) 운동을 열심히 하는 것은 [ ]을 늘리는데 효과적이다.

  • 앞의 운동을 열심히 하는 것은 부분만을 봐서는 빈칸을 유추하기 어렵다

양방향 순환 신경망의 구조

  • 두 개의 메모리 셀을 사용
  • 주황색 셀: Forward States, 기존과 같이 이전 시점의 은닉상태값 이용하여 계산
  • 초록색 셀: Backward States, 이후 시점의 은닉상태값 이용하여 계산

깊은 순환 신경망 (Deep Recurrent Neural Network)

다수의 은닉층을 가진 RNN

양방향 순환 신경망에서도 사용 가능


RNN 코드로 구현하기

RNN 층(은닉층) 입력 형태

  • batch_size, timesteps, input_dim 크기의 3D 텐서
  • batch_size: 한 번에 학습하는 데이터의 개수
  • 출력층 부분은 아직 표현 안함

은닉상태 출력

(물론 아냐 출력층 wy,t1w_{y,t-1})

은닉상태 출력 (빨간색 hth_t; yty_t말하는거 아님)

  • 최종 시점의 은닉 상태만을 리턴하고자 한다면 (batch_size, output_dim) 크기의 2D 텐서를 리턴
  • 메모리 셀의 각 시점(time step)의 은닉 상태값들을 모아서 전체 시퀀스를 리턴하고자 한다면 (batch_size, timesteps, output_dim) 크기의 3D 텐서를 리턴
  • RNN 층의 return_sequences 매개 변수에 True를 설정하여 설정이 가능

Keras이용

from tensorflow.keras.layers import SimpleRNN
#RNN 층을 추가
model.add(SimpleRNN(hidden_units))

# 추가 인자를 사용할 때
# model.add(SimpleRNN(hidden_units, input_shape=(timesteps, input_dim)))

# 다른 표기
# model.add(SimpleRNN(hidden_units, input_length=M, input_dim=N))
  • hidden_units = DhD_h, 은닉 상태의 크기를 정의. 메모리 셀이 다음 시점의 메모리 셀과 출력층으로 보내는 값의 크기(output_dim)와도 동일. RNN의 용량(capacity)을 늘린다고 보면 되며, 중소형 모델의 경우 보통 128, 256, 512, 1024 등의 값을 가진다.
  • timesteps = input_length라고 표현하기도 함. 시점의 수. (문장에서 토큰의 수)
  • input_dim = 입력 벡터 xtx_t의 크기.

모델 내부적으로 출력 결과를 어떻게 정의하는지 확인

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import SimpleRNN

model = Sequential()
model.add(SimpleRNN(3, input_shape=(2,10)))
# model.add(SimpleRNN(3, input_length=2, input_dim=10))와 동일함.
model.summary()

결과, 배치사이즈를 표기 안해 None으로 출력, 2D tensor

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn_1 (SimpleRNN)     (None, 3)                 42        
=================================================================
Total params: 42
Trainable params: 42
Non-trainable params: 0
_________________________________________________________________
model = Sequential()
#batch_size를 미리 정의
model.add(SimpleRNN(3, batch_input_shape=(8,2,10))) 
model.summary()

결과 이번에는 입력한 배치사이즈 8 이 나온다

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn_2 (SimpleRNN)     (8, 3)                    42        
=================================================================
Total params: 42
Trainable params: 42
Non-trainable params: 0
_________________________________________________________________
model = Sequential()
#return_sequences=True를 해서 모든 시점의 은닉상태값 가짐 - 차원 추가
model.add(SimpleRNN(3, batch_input_shape=(8,2,10), return_sequences=True))
model.summary()

결과 (8, 2, 3)처럼 3D tensor을 가진다 2인 이유는 input_shape에서 입력 시퀀스의 길이를 2라고 정의함

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn_3 (SimpleRNN)    (8, 2, 3)                 42        
=================================================================
Total params: 42
Trainable params: 42
Non-trainable params: 0
_________________________________________________________________

+Total params의 수가 42인 이유

  • 입력 가중치 WxW_x의 파라미터 개수: 입력 차원 dd (10) * 은닉 상태 크기 DhD_h (3) = 30
  • 은닉 상태 가중치 WhW_h의 파라미터 개수: 은닉 상태 크기 DhD_h (3) * 은닉 상태 크기 DhD_h (3) = 9
  • 편향(bias)의 파라미터 개수: 은닉 상태 크기 DhD_h (3) = 3
  • 총 파라미터 개수 = 30 (입력 가중치) + 9 (은닉 상태 가중치) + 3 (편향) = 42

Vanilla RNN의 단점

  • 출력 결과가 이전의 계산 결과에 의존
  • 비교적 짧은 시퀀스(sequence)에 대해서만 효과를 보임
  • 바닐라 RNN의 시점(time step)이 길어질 수록 앞의 정보가 뒤로 충분히 전달되지 못하는 "장기 의존성 문제(the problem of Long-Term Dependencies)" 현상이 발생

이 문제들을 해결하기 위해 다음 시간에 LSTM과 GRU에 대해 배워보자


점검 퀴즈
RNN 을 제대로 이해했는지 퀴즈를 통해서 확인해보세요! 모델에 대한 설명이 다음과 같을 때, 총 파라미 터 개수를 구해보세요.

  1. Embedding을사용하며,단어집합(Vocabulary)의크기가5,000이고임베딩벡터의차원은100 입니다.
  2. 은닉층에서는SimpleRNN을사용하며,은닉상태의크기는128입니다.
  3. 훈련에사용하는모든샘플의길이는30으로가정합니다.
  4. 이진분류를수행하는모델로,출력층의뉴런은1개로시그모이드함수를사용합니다.
  5. 은닉층은1개입니다.

profile
이것저것 해보는 중

0개의 댓글