Just Fighting

RNN 개념정리 본문

ML & DL

RNN 개념정리

yennle 2022. 7. 24. 12:51
728x90

https://wikidocs.net/22886

 

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

RNN(Recurrent Neural Network)은 입력과 출력을 시퀀스 단위로 처리하는 시퀀스(Sequence) 모델입니다. 번역기를 생각해보면 입력은 번역하고자 하는 ...

wikidocs.net

 

< RNN >

- 입력과 출력을 시퀀스 단위로 처리하는 시퀀스 모델 ( 시퀀스 : 단어가 나열된 모델)

- 가장 기본적인 인공 신경망 시퀀스 모델

재귀형태로 표현
여러 시점으로 펼쳐서 표현

- 은닉층의 노드에서 활성화 함수를 통해 나온 결과값을 출력층 방향으로도 보내고,

   다시 은닉층 노드의 다음 계산의 입력으로도 보냄

- 은닉층에서 활성화 함수를 통해 결과를 내보내는 노드를 셀(cell)이라고 함.

- 셀은 이전의 값을 기억하려는 메모리 역할을 수행해 메모리 셀 또는 RNN 셀이라고 표현

- 은닉층의 메모리 셀은 각각의 시점에서 바로 이전 시점의 은닉층의 메모리 셀에서 나온 값을 자신의 입력으로 사용

  >>> 재귀적 활동

- 메모리 셀이 출력층 방향 또는 다음 시점인 t+1의 자신에게 보내는 값을 은닉상태라고 함.

 

- RNN은 입력과 출력의 길이를 다르게 설계할 수 있음

- 일 대 다 : 하나의 입력에 대해 여러 개의 출력의 의미 >> 하나의 이미지에 사진의 제목 출력

- 다 대 일 : 단어 시퀀스에 대해서 하나의 출력을 함. >> 감성분류(입력문서의 긍부정 판별), 스팸메일 분류

- 다 대 다 : 챗봇(사용자 문장 입력 > 대답 문장 출력), 번역기 등

 

은닉층에서는 t시점의 입력에 가중치를 곱한 값과 t-1시점의 은닉상태에 가중치를 곱한 값과 bias 값을 더해준 뒤

하이퍼볼릭탄젠트 함수를 이용해 t시점에서의 은닉상태값을 구한다.

그리고 출력층에서는 t시점의 은닉상태와 가중치가 곱해진 값에 bias를 더해 활성화 함수를 거친 결과값을 계산한다.

 

 

 

< 케라스로 RNN 구현하기 >

hidden_units : 은닉상태의 크기 => 메모리 셀의 용량

input_length : timesteps, 입력 시퀀스의 길이. 시점의 수 => 문장의 길이

input_dim : 입력의 크기. 입력의 차원 => 단어 벡터의 차원

 

 

tensorflow의 SimpleRNN을 사용한다.

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import SimpleRNN
model = Sequential()
model.add(SimpleRNN(3, input_shape=(2,10)))  # 3*3 + 3*10 + 3 = 42
# model.add(SimpleRNN(3, input_length=2, input_dim=10))와 동일함.
model.summary()

model = Sequential()
model.add(SimpleRNN(3, batch_input_shape=(8,2,10)))     # 8은 batch_size. 위에는 설정 안해줘서 None
model.summary()

model = Sequential()
model.add(SimpleRNN(3, batch_input_shape=(8,2,10), return_sequences=True))  # return_sequence=True 면 3D 텐서를 리턴, 아니면 2D 리턴
model.summary()

 

 

< 파이썬으로 RNN 구현하기 >

 

입력 시퀀스의 길이를 10, 입력의 크기를 4, 은닉상태의 크기를 8로 설정하고,

임의로 (10,4)의 2D텐서를 입력으로 하고, 초기 은닉상태는 영벡터로 초기화했다.

import numpy as np

timesteps = 10      # 입력 시퀀스의 길이. 시점의 수 > 문장의 길이
input_dim = 4       # 입력의 크기  > 단어 벡터의 차원
hidden_units = 8    # 은닉 상태의 크기 > 메모리 셀의 용량

# 입력에 해당되는 2D 텐서
inputs = np.random.random((timesteps, input_dim))

# 초기 은닉 상태는 0(벡터)로 초기화
hidden_state_t = np.zeros((hidden_units,))

 

그리고 계산에 이용할 가중치들을 생성해준다.

# 가중치
Wx = np.random.random((hidden_units, input_dim))  # (8,4) 크기의 2D 텐서 생성. 입력에 대한 가중치
Wh = np.random.random((hidden_units, hidden_units))  # (8,8) 크기의 2D 텐서 생성. 은닉 상태에 대한 가중치
b = np.random.random((hidden_units,))   # (8,) 크기의 1D 텐서 생성. 편향(bias)

 

이제 모든 시점의 은닉상태를 계산할 수 있다.

total_hidden_states = []

for input_t in inputs:      # 10번(timesteps) 반복. totol_hidden_states 길이가 10이 될 것.

    # Wx * Xt + Wh * Ht-1 + b(bias)
    output_t = np.tanh(np.dot(Wx, input_t)+np.dot(Wh, hidden_state_t) + b)

    total_hidden_states.append(list(output_t))

    hidden_state_t = output_t  # 이번 출력이 다음 셀로 가게 됨


total_hidden_states = np.stack(total_hidden_states, axis=0) # 배열을 깔끔하게 보여줌
total_hidden_states     # 모든 시점의 은닉 상태

 

 

< 깊은 순환 신경망 >

RNN은 다수의 은닉층을 가질 수 있다.

아래 사진은 은닉층이 2개인 깊은 순환 신경망이다.

model = Sequential()
model.add(SimpleRNN(hidden_units, input_length=10, input_dim=5, return_sequences=True)) # return_sequences=True로 인해 모든 시점에 대해서 은닉 상태의 값을 다음 은닉층으로 보내줌
model.add(SimpleRNN(hidden_units, return_sequences=True))

 

 

< 양방향 순환 신경망 >

- 시점 t에서의 출력값을 예측할 때 '이전 시점'과 '이후 시점'의 입력 모두 예측에 기여할 수 있다는 아이디어

- 문장에 구멍을 뚫어 놨을 경우, 앞 뒤를 봐야 단어를 채울 수 있다.

- 하나의 출력값을 예측하기 위해 기본적으로 두개의 메모리 셀을 사용

- 첫번째 메모리 셀은 앞 시점의 은닉상태를 전달받아 현재의 은닉상태 계산

- 두번째 메모리 셀은 뒤 시점의 은닉상태를 전달받아 현재의 은닉상태 계산 >> 입력 시퀀스를 반대방향으로 읽는 것.

from tensorflow.keras.layers import Bidirectional

timesteps = 10
input_dim = 5

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

 

# 양방향 RNN도 다수의 은닉층을 가질 수 있음
model = Sequential()
model.add(Bidirectional(SimpleRNN(hidden_units, return_sequences=True), input_shape=(timesteps, input_dim)))
model.add(Bidirectional(SimpleRNN(hidden_units, return_sequences=True)))
model.add(Bidirectional(SimpleRNN(hidden_units, return_sequences=True)))
model.add(Bidirectional(SimpleRNN(hidden_units, return_sequences=True)))
728x90
Comments