오늘은 Pytorch를 통해 RNN을 알아보겠습니다.
https://www.youtube.com/watch?v=bPRfnlG6dtU&t=2674s
RNN의 기본구조를 모르시면 위 링크를 보시는걸 추천드립니다.
Pytorch document에 RNN을 확인하겠습니다.
https://pytorch.org/docs/stable/nn.html
1. RNN (default)
RNN의 입력은 [sequence, batch_size, input_size] 으로 이루어집니다.
import torch
import torch.nn as nn
input = torch.randn(4, 7, 5)
print(input.size())
# 결과
# torch.Size([4, 7, 5])
sequence = 4차원,
batch_size = 7차원,
input_size = 5차원 인 임의의 input 데이터를 생성했습니다.
2. nn.RNN
RNN의 기본 인자 값으로 input_size=5, hidden_size=4, num_layer=3 값을 받습니다.
rnn_layer = nn.RNN(input_size=5, hidden_size=4, num_layers=3)
print(rnn_layer)
# 결과
# RNN(5, 4, num_layers=3, batch_first=True)
input_size는 Input의 input_size의 값을 받으므로, 5로 적어주시면 됩니다.
hidden_size는 nn.RNN을 걸치면 나오는 Output으로 볼 수 있으며, 위 그림의 주황색 박스입니다.
hidden_size = 4 이므로 output 또한 4차원으로 만들어집니다.
num_layer는 층으로 보시면 편할 것 같습니다. num_layer = 3 이므로 3개의 층이 생성됩니다.
(output, hidden) = rnn_layer(input)
print("Output size : {}".format(output.size()))
print("Hidden size : {}".format(hidden.size()))
# 결과
# Output size : torch.Size([4, 7, 4])
# Hidden size : torch.Size([3, 7, 4])
RNN을 검색해보셨다면 위 그림은 정말 많이 보셨을거라고 생각합니다.
처음에 RNN을 공부할 때 위 그림이 무슨 말인고 하고 별로 신경쓰지 않았지만, 상당히 중요한 그림입니다.
nn.RNN의 함수를 사용하면 위 코딩처럼 output, hidden의 값을 뱉어냅니다.
2개의 값을 뱉어낸 이유는 그림을 쉽게 이해할 수 있습니다.
A 박스에 input X0의 값이 들어가면, output은 h0 의 값을 반환하고 hidden은 다음 Sequnece의 A박스에 값이 들어가므로 output과 hidden의 값을 반환합니다.
Output size : torch.Size[4, 7, 4])
Hidden size : torch.Size[3, 7, 4])
값의 size를 찍어보면 이상한 형태로 사이즈가 반환됩니다.
output : [sequence, batch_size, hidden_size]
hidden : [num_layer, batch_size, hidden_size]
값의 반환은 위처럼 규칙을 따라 모양이 변형됩니다.
batch_size = 7
sequence = 4
input_size = 5
hidden_size =4
num_layer = 3
위에서 사용하는 인자들을 보면서 하나씩 봐보면 값이 일치합니다.
조금 더 자세히 보도록 하겠습니다.
output[-1]이란.
output : [sequence, batch_size, hidden_size] 에서 Sequence의 가장 끝을 의미합니다. (보라색 상자)
hidden[-1]이란.
hidden : [num_layer, batch_size, hidden_size] 에서 num_layer의 가장 끝을 의미합니다. (회색 상자)
결국 output[-1]과 hidden[-1]이 hT(k)를 지칭하므로, 둘은 같은 값을 의미합니다 한 번 찍어보겠습니다.
print(output[-1])
print(hidden[-1])
# 결과
tensor([[ 0.8153, -0.1394, 0.3829, 0.0173],
[ 0.8094, 0.2289, 0.4830, -0.2243],
[ 0.7936, -0.0426, 0.3890, -0.0643],
[ 0.7714, 0.3094, 0.4685, -0.2558],
[ 0.8282, 0.1141, 0.4310, -0.1885],
[ 0.8027, -0.0607, 0.3745, -0.0249],
[ 0.8292, -0.1473, 0.4938, 0.0935]], grad_fn=<SelectBackward>)
tensor([[ 0.8153, -0.1394, 0.3829, 0.0173],
[ 0.8094, 0.2289, 0.4830, -0.2243],
[ 0.7936, -0.0426, 0.3890, -0.0643],
[ 0.7714, 0.3094, 0.4685, -0.2558],
[ 0.8282, 0.1141, 0.4310, -0.1885],
[ 0.8027, -0.0607, 0.3745, -0.0249],
[ 0.8292, -0.1473, 0.4938, 0.0935]], grad_fn=<SelectBackward>)
실제로도 들어있는 값들이 같음을 알 수 있습니다.
2. batch_first=True ( default는 False이다. )
pytorch는 모델에 데이터를 넣을 때는 batch_size를 가장 먼저 앞에 나옵니다.
하지만 RNN이나 LSTM 같은 경우는 batch_size가 아닌 sequence가 가장 먼저 나옵니다.
input : [sequence, batch_size, input_size]
model에서 나오는 output 또한 sequence가 가장 먼저 나옵니다.
output : [sequence, batch_size, hidden_size]
이렇게 sequence가 가장 앞에서 사용되면 가끔 데이터 차원이 헷갈립니다.
그럴 때 사용하는 것이 batch_first=True 입니다. default는 False입니다.
batch_first를 True로 설정하면 batch_size가 제일 먼자 앞으로 이동합니다.
input : [batch_size, sequence, input_size]
output : [batch_size, sequence, hidden_size]
hidden은 그대로입니다.
사용하는 방법은 간단합니다.
import torch
import torch.nn as nn
input = torch.randn(4, 7, 5)
print(input.size())
rnn_layer = nn.RNN(input_size=5, hidden_size=4, num_layers=3, batch_first=True)
print(rnn_layer)
# 결과
# RNN(5, 4, num_layers=3, batch_first=True)
batch_first를 True하게 되어 batch_size가 가장 앞으로 가게 됩니다.
그렇다면 인자들에 전달된 값 또한 변합니다.
batch_size = 4
sequence = 7
input_size = 5
hidden_size =4
num_layer = 3
으로 변경됩니다.
print("Output size : {}".format(output.size()))
print("Hidden size : {}".format(hidden.size()))
#output : [batch_size, sequence, hidden_size]
#hidden : [num_layer, batch_size, hidden_size]
# Output size : torch.Size([4, 7, 4])
# Hidden size : torch.Size([3, 4, 4])
모양이 달라졌지만 사이즈 이외에는 크게 바뀌는 것은 없습니다.
indexing 하는 방법을 sequnece, num_layer를 똑같이 적용시켜주면 됩니다.
print(output[:, -1, :])
print()
print(hidden[-1])
#결과
tensor([[-0.2105, 0.4423, 0.8115, -0.2838],
[-0.4891, 0.1518, 0.8839, -0.3675],
[-0.5495, 0.3221, 0.8500, -0.4782],
[-0.5822, 0.3100, 0.7938, -0.4242]], grad_fn=<SliceBackward>)
tensor([[-0.2105, 0.4423, 0.8115, -0.2838],
[-0.4891, 0.1518, 0.8839, -0.3675],
[-0.5495, 0.3221, 0.8500, -0.4782],
[-0.5822, 0.3100, 0.7938, -0.4242]], grad_fn=<SelectBackward>)
'Python > Deep Learning' 카테고리의 다른 글
[딥러닝] Depthwise Separable Covolution with Pytorch( feat. Convolution parameters VS Depthwise Separable Covolution parameters ) (0) | 2020.08.01 |
---|---|
[딥러닝] BRNNs(Bidirectional Recurrent Neural Networks) with Pytorch (0) | 2020.05.01 |
[딥러닝] 선형회귀 (Linear Regression) : Pytorch 구현 (2) | 2020.04.14 |
[딥러닝] 선형 회귀(Linear Regression) (1) | 2020.04.09 |
[딥러닝] 파이토치 기본 step3::구조 1탄 (0) | 2020.02.06 |