순환 신경망(RNN, Recurrent Neural Network)

yousmile·2021년 8월 2일

자연어처리

목록 보기
1/6
post-thumbnail

RNN(Recurrent Neural Network): 입력과 출력을 시퀀스 단위로 처리하는 모델

  • RNN은 은닉층의 노드에서 활성화 함수를 통해 나온 결과값을 출력층 방향으로도 보내면서, 다시 은닉층 노드의 다음 계산의 입력으로 보내는 특징을 가짐

  • 실제로는 편향 bb도 입력으로 존재할 수 있음

  • 셀(cell): 은닉층에서 활성화 함수를 통해 결과를 내보내는 역할을 하는 노드. 이전의 값을 기억하려고 하는 일종의 메모리 역할을 수행하므로 이를 메모리 셀 또는 RNN 셀이라고 표현

  • xx는 입력층의 입력 벡터
  • yy는 출력층의 출력 벡터
  • 은닉 상태(hidden state): 메모리 셀이 출력층 방향으로 또는 다음 시점 t+1의 자신에게 보내는 값

아래와 같이 시점을 펼쳐서 표현도 가능

RNN 형태

RNN 셀의 각 시점 별 입, 출력의 단위는 사용자가 정의하기 나름이지만 가장 보편적인 단위는 '단어 벡터'

  • 일 대 다: 하나의 이미지 입력에 대해서 사진의 제목을 출력하는 이미지 캡셔닝(Image Captioning) 작업에 사용 가능
  • 다 대 일: 스팸 메일 분류, 감성 분류
  • 다 대 다: 개체명 인식, 챗봇, 번역기, 품사 태깅

RNN에 대한 수식

  • hth_{t}: 현재 시점 tt에서의 은닉 상태값

  • 가중치
    WxW_{x}: 입력층에서 입력값을 위한 가중치
    WhW_{h}: 이전 시점 t-1의 은닉 상태값인 ht1h_{t-1}을 위한 가중치

  • 은닉층: ht=tanh(Wxxt+Whht1+b)h_{t} = tanh(W_{x} x_{t} + W_{h}h_{t−1} + b)
    주로 활성화 함수 tanh 쓰이지만 ReLU 사용하는 경우도 있음

  • 출력층: yt=f(Wyht+b)y_{t} = f(W_{y}h_{t} + b)
    ff는 비선형 활성화 함수 중 하나.(sigmoid(이진분류), softmax(다양한 카테고리 중 선택) 등)

RNN의 은닉층 연산을 벡터와 행렬 연산으로 이해할 수 있고 입력은 대부분의 경우에서 단어 벡터로 간주할 수 있음. dd를 단어벡터의 차원, DhD_{h}를 은닉상태의 크기라고 했을 때,
xt:(d×1)x_{t}: (d × 1)
Wx:(Dh×d)W_{x}: (D_{h} × d)
Wh:(Dh×Dh)W_{h}: (D_{h} × D_{h})
ht1:(Dh×1)h_{t-1}: (D_{h} × 1)
b:(Dh×1)b: (D_{h} × 1)

-은닉층 연산(batch size = 1, ddDhD_{h} = 4로 가정)

Keras로 RNN 구현

model.add(SimpleRNN(hidden_size, input_shape=(timesteps, input_dim)))

#다른표기
model.add(SimpleRNN(hidden_size, input_length=M, input_dim=N)) # 단, M과 N은 정수

  • hidden_size = 은닉 상태의 크기를 정의. 메모리 셀이 다음 시점의 메모리 셀과 출력층으로 보내는 값의 크기(output_dim)와도 동일. RNN의 용량(capacity)을 늘린다고 보면 되며, 중소형 모델의 경우 보통 128, 256, 512, 1024 등의 값을 가진다.

  • timesteps = 입력 시퀀스의 길이(input_length)라고 표현하기도 함. 시점의 수.

  • input_dim = 입력의 크기RNN 층은 (batch_size, timesteps, input_dim) 크기의 3D 텐서를 입력으로 받음
    batch_size: 한번에 학습하는 데이터의 개수

  • Tensor 참고

  • 사용자 설정에 따라 두 가지 종류의 출력

  1. 메모리 셀의 최종 시점의 은닉 상태만 리턴(다 대 일): (batch_size, output_dim)크기의 2D 텐서
    (many-to-one)
  2. 메모리 셀의 각 시점의 은닉 상태 값들을 모아 전체 시퀀스 리턴: (batch_size, timesteps, output_dim) 크기의 3D 텐서
    (many-to-many or 다음층에 은닉층이 하나 더 있는 경우)
    -> RNN 층의 return_sequences 매개 변수에 True를 설정하여 설정 가능(defalt 값은 False)

실습

from keras.models import Sequential
from 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()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn_1 (SimpleRNN)     (None, 3)                 42        
=================================================================
Total params: 42
Trainable params: 42
Non-trainable params: 0
_________________________________________________________________

2D 텐서여서 batch_size 알 수 없음
->미리 정의

model = Sequential()
model.add(SimpleRNN(3, batch_input_shape=(8,2,10)))
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn_2 (SimpleRNN)     (8, 3)                    42        
=================================================================
Total params: 42
Trainable params: 42
Non-trainable params: 0
_________________________________________________________________

->return_sequences 매개 변수에 True를 기재하여 출력값으로 (batch_size, timesteps, output_dim) 크기의 3D 텐서를 리턴하도록

model = Sequential()
model.add(SimpleRNN(3, batch_input_shape=(8,2,10), return_sequences=True))
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
simple_rnn_3 (SimpleRNN)    (8, 2, 3)                 42        
=================================================================
Total params: 42
Trainable params: 42
Non-trainable params: 0
_________________________________________________________________

깊은 순환 신경망


은닉층을 다음과 같이 추가하면 됨

model = Sequential()
model.add(SimpleRNN(hidden_size, return_sequences = True)) 
#다음 은닉층 존재하므로 모든 시점에 대해 은닉 상태 값을 다음 은닉층으로 보내줌
model.add(SimpleRNN(hidden_size, return_sequences = True))

양방향 순환 신경망

시점 t에서의 출력값을 예측할 때 이전 시점의 데이터뿐만 아니라, 이후 데이터로도 예측할 수 있다는 아이디어에 기반 ex)빈칸 채우기

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

model = Sequential()
model.add(Bidirectional(SimpleRNN(hidden_size, return_sequences = True), input_shape=(timesteps, input_dim)))

  • 두 개의 메모리 셀 사용
  • 주황색 메모리셀: 앞 시점의 은닉 상태를 전달받아 현재의 은닉 상태 계산
  • 연두색 메모리셀: 뒤 시점의 은닉 상태를 전달받아 현재의 은닉 상태 계산
    -> 두 개의 값 모두 출력층에서 출력값 예측에 사용됨
    -> 양방향 RNN도 다수 은닉층 가질 수 있음
    But 은닉층 추가한다고 무조건 모델의 성능이 좋아지는 것은 아님!

+기울기 소실/폭주 이슈로 인해 LSTM, GRU 등장

딥러닝을 이용한 자연어 처리 입문
https://wikidocs.net/book/2155

0개의 댓글