Pytorch Rnn Can't learn sin function dataset

Viewed 33

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) ?

0 Answers
Related