본문 바로가기
전공/딥러닝

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

by mhiiii 2024. 12. 10.
728x90

RNN

입력과 출력을 시퀀스 단위로 처리하는 시퀀스 모델

 

  • 피드 포워드 신경망과 달리, 결과값을 출력층 방향으로 보내면서도 다시 은닉층 노드의 다음 계산의 입력으로 보냄 

은닉층의 메모리 셀(은닉층에서 활성화 함수를 통해 결과를 내보내는 역할)은 각각의 시점(time step)에서 바로 이전 시점에서의 은닉층의 메모리 셀에서 나온 값을 자신의 입력으로 사용하는 재귀적 활동을 함

현재 시점 t에서의 메모리 셀이 갖고있는 값은 과거의 메모리 셀들의 값에 영향을 받은 것임을 의미

 

은닉 상태(hidden state)

메모리 셀이 출력층 방향으로 또는 다음 시점 t+1의 자신에게 보내는 값을 은닉 상태(hidden state)라고 함 

 

회색과 초록색으로 표현한 각 네모들은 기본적으로 벡터 단위를 가정

 

RNN은 입력과 출력의 길이를 다르게 설계 할 수 있으므로 다양한 용도로 사용 가능 

 

입력 벡터의 차원이 4, 은닉 상태의 크기가 2, 출력층의 출력 벡터의 차원이 2인 RNN이 시점이 2일 때의 모습

1. 일 대 다 (one-to-many)

하나의 이미지 입력에 대해서 사진의 제목을 출력하는 이미지 캡셔닝(Image Captioning) 작업에 주로 사용

 

2. 대 다 일 (many-to-one)

 

입력 문서가 긍정적인지 부정적인지를 판별하는 감성 분류(sentiment classification),

또는 메일이 정상 메일인지 스팸 메일인지 판별하는 스팸 메일 분류(spam detection)에 사용할 수 있음

 

3. 다 대 다 (many-to-many)

입력 문장으로 부터 대답 문장을 출력하는 챗봇과 입력 문장으로부터 번역된 문장을 출력하는 번역기,

개체명 인식이나 품사 태깅과 같은 작업에 주로 사용

 

RNN의 수식

현재 시점 t

  • 은닉층
    $h_t = tanh(W_xx_t + W_hh_{t-1}+b) $

  • 출력층
    $y_t = f(W_yh_t + b) $, $f$는 비선형 활성화 함수 

 

벡터와 행렬 연산

배치 크기가 1이고,  $d$와  $D_h$  두 값 모두를 4로 가정

 

 

각각의 가중치 $W_x, W_h, W_y$의 값은 모든 시점에서 값을 동일하게 공유

만약, 은닉층이 2개 이상일 경우에는 은닉층 2개의 가중치는 서로 다름 

 

은닉층에서 tanh를 사용하는 이유는

  • 출력값이 [−1,1]로 제한되어 은닉 상태 값이 안정적으로 유지
  • 0 중심화 특성 덕분에 가중치 업데이트가 효율적
  • 양수와 음수 정보를 모두 표현할 수 있어, 시계열 데이터 학습에 적합
  • Sigmoid에 비해 기울기 소멸 문제가 덜 발생

 

출력층은 상황에 따라 활성화 함수를 다르게 사용

  • 이진 분류 : 시그모이드
  • 다중 분류 : 소프트맥스 

 

구현 코드

# 아래의 코드는 의사 코드(pseudocode)로 실제 동작하는 코드가 아님. 

hidden_state_t = 0 # 초기 은닉 상태를 0(벡터)로 초기화
for input_t in input_length: # 각 시점마다 입력을 받는다.
    output_t = tanh(input_t, hidden_state_t) # 각 시점에 대해서 입력과 은닉 상태를 가지고 연산
    hidden_state_t = output_t # 계산 결과는 현재 시점의 은닉 상태가 된다.

 

파이토치에서는 nn.RNN()을 통해서 구현 가능

input_size = 5 # 입력의 크기
hidden_size = 8 # 은닉 상태의 크기

# (batch_size, time_steps, input_size)
inputs = torch.Tensor(1, 10, 5)

cell = nn.RNN(input_size, hidden_size, batch_first=True)

outputs, _status = cell(inputs)

 

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

은닉층이 2개로 늘어난 모습

 

깊은 순환 신경망을 파이토치로 구현할 때는 nn.RNN()의 인자인 num_layers에 값을 전달하여 층을 쌓음 

cell = nn.RNN(input_size = 5, hidden_size = 8, num_layers = 2, batch_first=True)

print(outputs.shape) # 모든 time-step의 hidden_state

#torch.Size([1, 10, 8])

print(_status.shape) # (층의 개수, 배치 크기, 은닉 상태의 크기)

#torch.Size([2, 1, 8])

 

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

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

 

 

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

  • 첫번째 메모리 셀은 앞에서 배운 것처럼 앞 시점의 은닉 상태(Forward States)를 전달받아 현재의 은닉 상태를 계산
  • 두번째 메모리 셀앞 시점의 은닉 상태가 아니라 뒤 시점의 은닉 상태(Backward States)를 전달 받아 현재의 은닉 상태를 계산

 

깊은 순환 신경망 + 양방향 RNN 

cell = nn.RNN(input_size = 5, hidden_size = 8, num_layers = 2, batch_first=True, bidirectional = True)

outputs, _status = cell(inputs)

print(outputs.shape) # (배치 크기, 시퀀스 길이, 은닉 상태의 크기 x 2)

#torch.Size([1, 10, 16])

print(_status.shape) # (층의 개수 x 2, 배치 크기, 은닉 상태의 크기)

#torch.Size([4, 1, 8])

 

RNN의 한계 

 

RNN은 출력 결과가 이전의 계산 결과에 의존한다는 것이 특징

 

  • 장기 의존성 문제(the problem of Long-Term Dependencies)

바닐라 RNN은 비교적 짧은 시퀀스(sequence)에 대해서만 효과를 보이는 단점 존재 

바닐라 RNN의 시점(time step)이 길어질 수록 앞의 정보가 뒤로 충분히 전달되지 못하는 현상이 발생

 

 

 

References

https://wikidocs.net/60690

 

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

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

wikidocs.net

 

728x90