Help to understand why the Pytorch RNN model is not trained on a simple formalized ( Sin function) dataset. I get predictions far from the original. (More like an exponent than a sine) I am using dataset by slicing single element ..( 5 elements in sequence and the sixth is target)
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
x_data = np.arange(2000)
class Dataset:
def __init__(self,data, seq_length=5):
self.seq_length = seq_length
self.data = np.sin(x_data*2*np.pi/360)
self.X = np.array([])
self.Y = np.array([])
for i in range(len(self.data) - self.seq_length - 1):
self.X = np.append(self.X,self.data[i:i+self.seq_length])
self.Y = np.append(self.Y,self.data[i+self.seq_length])
self.x = torch.from_numpy(self.X.reshape(int(self.X.shape[0]/self.seq_length), self.seq_length,1)).float()
self.y = torch.from_numpy(self.Y.reshape(-1,1)).float()
def __len__(self):
return self.x.shape[0]
class VanillaRnn(nn.Module):
def __init__(self, input_size, hidden_size, seq_length=5, n_layers=1,batch_size=4):
super().__init__()
self.n_layers = n_layers
self.input_size = input_size
self.hidden_size = hidden_size
self.seq_length = seq_length
self.batch_size = batch_size
self.rnn = nn.RNN(self.input_size,self.hidden_size, self.n_layers, batch_first=True,)
self.fc = nn.Linear(self.hidden_size,1)
def reset_hidden_state(self):
self.hidden = torch.zeros(self.n_layers, self.batch_size, self.hidden_size)
def forward(self,x):
out, self.hidden = self.rnn(x,self.hidden)
out = self.fc(out[:,-1,:]) # out[:,-1,:] is size of 4x51
return out
INPUT_SIZE = 1
HIDDEN_SIZE = 51
BATCH_SIZE = 4
NUM_EPOCHS = 41
seq_length = 5
sinset = Dataset(x_data)
X = DataLoader(sinset.x[:-2], batch_size=BATCH_SIZE) # just cut off the last two elements to get
Y = DataLoader(sinset.y[:-2], batch_size=BATCH_SIZE) # a convenient number for breaking into batches
model = VanillaRnn(INPUT_SIZE,HIDDEN_SIZE)
def train_loop(model, xdata, ydata):
loss_fn = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
for epoch in range(NUM_EPOCHS):
for xi, yi in zip(xdata, ydata):
model.reset_hidden_state()
optimizer.zero_grad()
y_pred = model(xi)
loss = loss_fn(y_pred, yi)
loss.backward()
optimizer.step()
if epoch%5 == 0:
print(f'LOSS: {loss.item()}')
return model.eval()
train_loop(model,X,Y)
with torch.no_grad():
test_seq = sinset.x[:1]
preds = []
for _ in range(len(sinset.x)):
model.hidden = torch.zeros(1, 1, 51)
y_test_pred = model(test_seq)
pred = torch.flatten(y_test_pred).item()
preds.append(pred)
new_seq = test_seq.numpy().flatten()
new_seq = np.append(new_seq, [pred])
new_seq = new_seq[1:]
test_seq = torch.as_tensor(new_seq).view(1, seq_length, 1).float()
plt.plot(preds)
P.S What tensor to use as input in nn.Linear better (out or hidden) ?