본문 바로가기

AI/PyTorch

PyTorch #순환 신경망(RNN)

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

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

 

1. 순환 신경망(RNN)의 특징

- RNN은 은닉층의 노드에서 활성화 함수를 통해 나온 결과값을 출력층 방향으로도 보내 다시 은닉층 노드의 다음 계산의 입력으로 보냄

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

- 은닉층의 셀은 각각의 시점(time step)에서 바로 이전 시점의 셀에서 나온 값을 자신의 입력으로 사용

- 은닉 상태(hidden state)는 셀이 출력층 방향 또는 다음 시점의 자신에게 보내는 값

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

 

하나의 입력 여러개 출력 예) 하나의 이미지 입력에 대해 사진의 제목을 출력하는 이미지 캡셔닝 등
여러개 입력 하나의 출력 예) 문장의 긍부정 판별(감성 분류), 스펨 매일 판별 등
여러개 입력 여러개 출력 예) 입력문장으로부터 대답 문장 출력, 챗봇, 번역, 개체명 인식, 품사 태깅 등

 


2. RNN 구현

 

# 2D 텐서를 통한 예시
import numpy as np

timesteps = 10 # 시점의 수. NLP에서는 보통 문장의 길이가 된다.
input_size = 4 # 입력의 차원. NLP에서는 보통 단어 벡터의 차원이 된다.
hidden_size = 8 # 은닉 상태의 크기. 메모리 셀의 용량이다.

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

hidden_state_t = np.zeros((hidden_size,)) # 초기 은닉 상태는 0(벡터)로 초기화
# 초기 은닉상태 출력
print(hidden_state_t) # 8의 크기를 가지는 은닉 상태. 현재는 초기 은닉 상태로 모든 차원이 0의 값을 가짐.

 

# 가중치 및 편향 정의
Wx = np.random.random((hidden_size, input_size))  # (8, 4)크기의 2D 텐서 생성. 입력에 대한 가중치.
Wh = np.random.random((hidden_size, hidden_size)) # (8, 8)크기의 2D 텐서 생성. 은닉 상태에 대한 가중치.
b = np.random.random((hidden_size,)) # (8,)크기의 1D 텐서 생성. 이 값은 편향(bias).
# 가중치와 편향 크기 출력
print(np.shape(Wx)) # (은닉 상태의 크기 x 입력의 차원)
print(np.shape(Wh)) # (은닉 상태의 크기 x 은닉 상태의 크기)
print(np.shape(b))  # (은닉 상태의 크기)

 

# RNN 층 동작
total_hidden_states = []

# 메모리 셀 동작
for input_t in inputs: # 각 시점에 따라서 입력값이 입력됨.
  output_t = np.tanh(np.dot(Wx,input_t) + np.dot(Wh,hidden_state_t) + b) # Wx * Xt + Wh * Ht-1 + b(bias)
  total_hidden_states.append(list(output_t)) # 각 시점의 은닉 상태의 값을 계속해서 축적
  print(np.shape(total_hidden_states)) # 각 시점 t별 메모리 셀의 출력의 크기는 (timestep, output_dim)
  hidden_state_t = output_t

total_hidden_states = np.stack(total_hidden_states, axis = 0) 
# 출력 시 값을 깔끔하게 해준다.

print(total_hidden_states) # (timesteps, output_dim)의 크기. 이 경우 (10, 8)의 크기를 가지는 메모리 셀의 2D 텐서를 출력.

 

 


3. 파이토치의 nn.RNN()

 

# 도구 임포트
import torch
import torch.nn as nn
# 입력과 은닉 상태 크기 정의
input_size = 5 # 입력의 크기
hidden_size = 8 # 은닉 상태의 크기
# 입력 텐서 정의 / 배치 크기 1, 10번의 시점동안 5차원의 입력 벡터가 들어가도록 텐서 정의
# (batch_size, time_steps, input_size)
inputs = torch.Tensor(1, 10, 5)
# nn.RNN()을 사용해 RNN 셀 생성. 인자로 입력 크기, 은닉 상태의 크기 정의 및 batch_fist = True를 통해 입력 텐서의 첫번째 차원이 배치 크기임을 정의
cell = nn.RNN(input_size, hidden_size, batch_first=True)
# 입력 텐서를 RNN 층에 입력하여 출력 확인
outputs, _status = cell(inputs)
# RNN 셀은 두 개의 입력을 리턴하는데 첫번째 리턴값은 모든 시점(timesteps)의 은닉상태들이며, 두번째 리턴값은 마지막 시점(timesteps)의 은닉상태

# 첫번째 리턴값 출력
print(outputs.shape) # 모든 time-step의 hidden_state, 10번의 시점동안 8차원의 은닉상태가 출력되었음

 

# 두번째 리턴값 출력
print(_status.shape) # 최종 time-step의 hidden_state

 

 


4. 깊은 순환 신경망(Deep Recurrent Nueral Network, DRNN)

- RNN 층에 은닉층을 N개 더 추가

- 파이토치로 DRNN을 구현할 때는 nn.RNN()의 인자인 num_layers에 값을 전달해 층을 쌓는다.

 

# 층이 2개인 깊은 순환 신경망
# (batch_size, time_steps, input_size)
inputs = torch.Tensor(1, 10, 5)

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

outputs, _status = cell(inputs)

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

 

# 두번째 리턴값 출력
print(_status.shape) # (층의 개수, 배치 크기, 은닉 상태의 크기)

 

 


5. 양방향 순환 신경망(Bidirectional Recurrent Neural Network, BRNN)

- 양방향 순환 신경망은 과거 시점의 데이터와 향후 시점의 데이터를 힌트로 사용하기 위해 고안

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

- BRNN은 하나의 출력값을 예측하기 위해 두 개의 메모리 셀을 사용(Forward States, Backword States)

- BRNN을 구현할 때는 nn.RNN()의 인자인 bidirectional의 값을 True로 전달

 

# 층이 2개인 깊은 순환먕이면서 양방향인 경우 임의의 입력에 대해 출력의 변화 확인
# (batch_size, time_steps, input_size)
inputs = torch.Tensor(1, 10, 5)

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), 은닉상태의 크기 값이 두배가 됨, 이는 양방향의 은닉 상태들의 값이 연결되었기 때문

 

print(_status.shape) # (층의 개수 x 2, 배치 크기, 은닉 상태의 크기), 정방향 기준으로는 마지막 시점에 해당되면서, 역방향 기준에서는 첫번째 시점에 해당되는 시점의 출력값을 층의 개수만큼 쌓아올린 값

 

 

 


장단기 메모리(Long Short-Term Memory, LSTM)

- 가장 기본적 형태의 RNN을 바닐라 RNN이라고 부름

- 바닐라 RNN의 한계를 극복하기 위한 변형 중 하나

 

1. 바닐라 RNN의 한계

- 바닐라 RNN은 출력 겨로가가 이전의 계산 겨로가에 의존, time step이 길어질 수록 앞의 정보가 뒤로 충분히 전달 되지 않음

- 이때문에 중요한 정보가 시점의 앞에 있을 때 충분한 기억력을 갖지 못하므로 답의 정확도가 떨어짐

 

2. LSTM

- LSTM은 은닉층의 메모리 셀에 입력 게이트, 망각 게이트, 출력 게이트를 추가해 불필요한 기억을 지우고, 기억해야 할 것을 정함

- LSTM은 RNN과 비교할 때 시퀀스의 입력을 처리하는데 탁월한 성능을 보임

 

3. 파이토치의 nn.LSTM()

# 도구 임포트
import torch
import torch.nn as nn

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

# 입력 텐서 정의 / 배치 크기 1, 10번의 시점동안 5차원의 입력 벡터가 들어가도록 텐서 정의
# (batch_size, time_steps, input_size)
inputs = torch.Tensor(1, 10, 5)

# nn.LSTM()을 사용해 LSTM 셀 생성. 인자로 입력 크기, 은닉 상태의 크기 정의 및 batch_fist = True를 통해 입력 텐서의 첫번째 차원이 배치 크기임을 정의
cell = nn.LSTM(input_size, hidden_size, batch_first=True)

# 첫번째 리턴값 출력
print(outputs.shape) # 모든 time-step의 hidden_state, 10번의 시점동안 8차원의 은닉상태가 출력되었음

# 두번째 리턴값 출력
print(_status.shape) # 최종 time-step의 hidden_state

 

 

 

 


참고:

https://wikidocs.net/book/2788

 

PyTorch로 시작하는 딥 러닝 입문

이 책은 딥 러닝 프레임워크 PyTorch를 사용하여 딥 러닝에 입문하는 것을 목표로 합니다. 이 책은 2019년에 작성된 책으로 비영리적 목적으로 작성되어 출판 ...

wikidocs.net

 

반응형

'AI > PyTorch' 카테고리의 다른 글

PyTorch #다대일 RNN  (0) 2022.04.07
PyTorch #다대다 RNN  (0) 2022.04.06
PyTorch #원-핫 인코딩 #워드 임베딩  (0) 2022.04.05
PyTorch #자연어 데이터 전처리  (0) 2022.04.04
PyTorch #합성곱 신경망(CNN)  (0) 2022.04.01