์ค๋์ 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' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์ค๋์ 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>)