RNN 복습
- 순환 신경망이기 때문에 sequential 데이터에 대해 잘 동작함
- 이전 시간 단계의 정보를 현재 시간 단계로 전달해, 시퀀스 데이터의 패턴을 학습할 수 있음
- 모든 시점의 가중치가 동시에 update가 된다. (처음부터 끝까지 같은 가중치를 갖지 않도록 해줌)
- 다만 주의해야 할 점은 과거의 데이터의 경우에는 유실될 위험이 있다는 것이다.
LSTM
- 입력 게이트와 출력 게이트, 망각 게이트를 사용하여 정보를 조절함 (즉 얼마나 셀 상태를 반영할지를 조절할 수 있다는 것임)
GRU
- 셀 상태 대신 은닉 상태만을 사용하여 구조를 단순화함
- 리셋 게이트와 업데이트 게이트가 존재하는데 리셋 게이트는 새로운 정보와 이전 정보를 결합하는데 사용, 업데이트 게이트는 얼마나 새로운 정보를 받아들일지를 결정
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
# Sine 파형 데이터 생성
def create_sine_wave_data(seq_length, num_samples):
X = []
y = []
for _ in range(num_samples):
start = np.random.rand()
# 한 주기 만큼 x 값 간격 생성 (Dot 생성)
x = np.linspace(start, start + 2 * np.pi, seq_length)
# 사인 함수 생성
# 학습용 사인 함수 x
X.append(np.sin(x))
# 비교할 사인 함수가 들어갈 y
y.append(np.sin(x + 0.1))
return np.array(X), np.array(y)
seq_length = 50
num_samples = 1000
X, y = create_sine_wave_data(seq_length, num_samples)
# 데이터셋을 PyTorch 텐서로 변환
X = torch.tensor(X, dtype=torch.float32).unsqueeze(-1)
y = torch.tensor(y, dtype=torch.float32).unsqueeze(-1)
모델 정의
class SimpleRNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(SimpleRNN, self).__init__()
self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(1, x.size(0), hidden_size) # 초기 은닉 상태
out, _ = self.rnn(x, h0)
out = self.fc(out) # 마지막 시간 단계의 출력
return out
input_size = 1
hidden_size = 32 # 은닉 사이즈를 지정해주어야 함
output_size = 1
model = SimpleRNN(input_size, hidden_size, output_size)
모델 학습
# 손실 함수와 최적화 알고리즘 정의
criterion = nn.MSELoss()
# lr은 학습률을 지정
optimizer = optim.Adam(model.parameters(), lr=0.01)
# 모델 학습
num_epochs = 100
for epoch in range(num_epochs):
outputs = model(X)
# 기울기 초기화
optimizer.zero_grad()
# 기존 사인함수와 비교
loss = criterion(outputs, y)
# 손실에 대한 기울기를 계산 (역전파를 이용하여)
loss.backward()
# 계산된 기울기를 사용하여 모델의 가중치를 업데이트
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
print('Finished Training')
모델 평가
# 모델 평가
model.eval()
# 평가 단계에서는 기울기를 계산할 필요가 없으므로 비활성화
with torch.no_grad():
# 텐서의 계산 그래프에서 분리하여, 메모리 절약을 위해 Numpy 배열로 변형
predicted = model(X).detach().numpy()
# 시각화
plt.figure(figsize=(10, 5))
# 1차원 배열로 변환해 시각화
plt.plot(y.numpy().flatten(), label='True')
plt.plot(predicted.flatten(), label='Predicted')
plt.legend()
plt.show()
LSTM
class SimpleLSTM(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(SimpleLSTM, self).__init__()
self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, output_size)
def forward(self, x):
h0 = torch.zeros(1, x.size(0), hidden_size) # 초기 은닉 상태 (초기 값은 은닉상태가 없기 때문에 정의함)
# 초기 셀 상태 c0를 생성합니다. LSTM은 은닉 상태 외에도 셀 상태를 기억하여 장기 의존성 문제를 완화할 수 있습니다.
c0 = torch.zeros(1, x.size(0), hidden_size) # 초기 셀 상태
# LSTM에 입력 x와 초기 상태(h0, c0)를 전달하여 출력을 계산합니다. RNN에서는 h0만 사용하고 c0는 사용하지 않습니다.
out, _ = self.lstm(x, (h0, c0))
out = self.fc(out) # 전체 시퀀스에 대해 출력을 생성
return out
# 파라미터 값들이 RNN과 동일함
model = SimpleLSTM(input_size, hidden_size, output_size)
Dataset에 대해
raw data를 쉽게 클래스로 만들도록 도와주는 도구
구성요소
1. init : 데이터의 위치나 파일명과 같은 초기화 작업을 위해 동작
2. len : Dataset의 길이를 반환하는 데 사용
3. getitem :
데이터 셋의 idx 번째 데이터를 반환하는데 사용
일반적으로 특정 인덱스의 raw data를 가져와서 전처리하고 데이터 증강하는 부분이 여기에서 진행됨
*모든 데이터를 메모리에 로드하지 않고 사용한다는 점에서 효율적임
DataLoader에 대해
모델 학습을 위해서 데이터를 미니 배치 단위로 제공해주는 역할을 함
보통 batch_size나 collate_fn 정도를 주로 사용
구성요소
1. batch_size : 한 배치당 들어있는 데이터의 개수를 의미
2. shuffle : 데이터를 섞을 건지 여부, 매 에폭마다 데이터를 새로 섞는다.
3. collate_fn :