LSTM은 RNN 모델이 장기 기억력이 낮다는(?) 문제를 해결한 방법 (cell state를 통해)
(아래 그림처럼 RNN은 시간이 지날 수록 Gradient vanishing 현상이 나타남)
RNN에서는 없었던 'cell state'가 추가된다 (장기 기억력을 올려주는 역할)
torch의 nn.lstm 모델은 보통 input size, hidden size, num layers 를 인풋으로 받음
# LSTM Hyperparameter
# RNN과 매우 비슷함
# 너무 많은 num layers 와 hidden size는 overfitting 을 유발
input_size = x_seq.size(2) # 변수의 개수(데이터의 개수 X,The number of expected features in the input x)
num_layers = 2
hidden_size = 8
class LSTM(nn.Module):
def __init__(self, input_size, hidden_size, sequence_length, num_layers, device):
super(LSTM, self).__init__()
self.device = device
self.hidden_size = hidden_size
self.num_layers = num_layers
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size*sequence_length, 1) # length 마다 hidden size!
def forward(self, x): # <- cell state 추가, x.size()[0] = 변수 개수
h0 = torch.zeros(self.num_layers, x.size()[0], self.hidden_size).to(self.device)
c0 = torch.zeros(self.num_layers, x.size()[0], self.hidden_size).to(self.device)
out, _ = self.lstm(x, (h0, c0)) # output, (hn, cn)
out = out.reshape(out.shape[0], -1)
out = self.fc(out)
return out
# make LSTM 모델
model = LSTM(input_size=input_size,
hidden_size=hidden_size,
sequence_length=sequence_length,
num_layers=num_layers,
device=device)
model = model.to(device)
criterion = nn.MSELoss()
lr = 1e-3
num_epochs = 201
optimizer = optim.Adam(model.parameters(), lr=lr)
loss_graph = []
n = len(train_loader)
for epoch in range(num_epochs): # epoch
running_loss = 0.0
for data in train_loader: # batch
seq, target = data # 배치 데이터
out = model(seq)
loss = criterion(out, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
running_loss += loss.item()
loss_graph.append(running_loss/n)
if epoch % 100 == 0:
print('[epoch: %d] loss: %.4f' %(epoch, running_loss/n))
# 시각화
plt.figure(figsize=(20,10))
plt.plot(loss_graph)
plt.show()
def plotting(train_loader, test_loader, actual):
with torch.no_grad():
train_pred = []
test_pred = []
for data in train_loader:
seq, target = data # 배치 데이터
#print(seq.size())
out = model(seq)
train_pred += out.cpu().numpy().tolist()
for data in test_loader:
seq, target = data # 배치 데이터
#print(seq.size())
out = model(seq)
test_pred += out.cpu().numpy().tolist()
total = train_pred+test_pred
plt.figure(figsize=(20,10))
plt.plot(np.ones(100)*len(train_pred),np.linspace(0,1,100),'--', linewidth=0.6)
plt.plot(actual,'--')
plt.plot(total,'b', linewidth=0.6)
plt.legend(['train boundary','actual','prediction'])
plt.show()
plotting(train_loader, test_loader, df['Close'][sequence_length:].values)
개인적으로 LSTM은 실제 프로젝트나 분석에서 사용할 일이 많다고 느낌. 등장한지는 엄청 오래된 모델인데 RNN 보다는 조금 모델 구조가 복잡함. torch 공식 documentation을 보고 한 줄씩 뜯어보면 도움이 될 것으로 예상함. (parameter, input, output 구조 위주)
4. torch.nn.lstm의 output 구조
위의 코드에서 out은 결국 document 기준 ouput만 을 받는 것인데, output은 결국 다시 (L,D*H) 형태의 tensor임