Aria AAs
Aria AAs

Reputation: 66

Trying to represent the Long Short-Term Memory (LSTM) model in PyTorch to improve understanding

I am currently engaged in the implementation of Long Short-Term Memory (LSTM) models using Python and PyTorch for the purpose of predicting some time series data, specifically through the utilization of a simple sine wave as a test case. This particular problem is classified as many-to-one, wherein multiple past values are employed to forecast a present value.

Does this representation accurately reflect the model in the following code?

enter image description here

The code:

from matplotlib import pyplot
import numpy
import torch


# Define the model class
class LSTM(torch.nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, output_size, dropout):
        super().__init__()
        self.num_layers = num_layers
        self.hidden_size = hidden_size
        self.lstm = torch.nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, dropout=dropout)
        self.linear = torch.nn.Linear(hidden_size, output_size)

    def forward(self, x):
        h0 = torch.randn(self.num_layers, x.size(0), self.hidden_size)
        c0 = torch.randn(self.num_layers, x.size(0), self.hidden_size)
        out, (ht, ct) = self.lstm(x, (h0, c0))
        return self.linear(out[:, -1, :])


# Define hyper-parameters
SEED = 0
SEQ_LENGTH = 5
EPOCHS = 500
HIDDEN_SIZE = 5
NUM_LAYERS = 3
NUM_FEATURES = 1
DROPOUT = 0.2
TRAIN_DATA_SIZE = 0.8
LEARNING_RATE = 0.001

# Set seed
torch.manual_seed(SEED)

# Generate data (sine wave)
x = numpy.linspace(0, 50, 1000)
fx = numpy.sin(x).reshape(-1, 1)

# Convert data to sequences
# (X_t-5, X_t-4, X_t-3, X_t-2, X_t-1) => (Y_t)
sequences = []
targets = []
for i in range(len(fx) - SEQ_LENGTH):
    sequences.append(fx[i:i+SEQ_LENGTH])
    targets.append(fx[i+SEQ_LENGTH])

# Convert data to tensor
# python.list => numpy.ndarray => torch.Tensor
X = torch.tensor(numpy.array(sequences), dtype=torch.float32)
y = torch.tensor(numpy.array(targets), dtype=torch.float32)

# Split data
train_size = int(TRAIN_DATA_SIZE * len(X))
X_train, X_test = X[:train_size], X[train_size:]
y_train, y_test = y[:train_size], y[train_size:]

# Make datasets and dataloaders (full-batch)
train_dataset = torch.utils.data.TensorDataset(X_train, y_train)
test_dataset = torch.utils.data.TensorDataset(X_test, y_test)
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=len(y_train), shuffle=True)
test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=len(y_test), shuffle=False)

# Create the model, loss-function, and optimizer
model = LSTM(NUM_FEATURES, HIDDEN_SIZE, NUM_LAYERS, NUM_FEATURES, DROPOUT)
loss_function = torch.nn.L1Loss()
optimizer = torch.optim.Adam(model.parameters(), lr=LEARNING_RATE)

# Evaluate the model before training
model.eval()
with torch.inference_mode():
    for input, target in test_dataloader:
        prediction_before_training = model(input)

# Define lists to keep data of training process
epochs_list = []
train_loss_list = []
test_loss_list = []

# Train the model
for epoch in range(EPOCHS):
    epochs_list.append(epoch + 1)
    model.train()
    for input, target in train_dataloader:
        prediction_during_training = model(input)
    loss = loss_function(prediction_during_training, target)
    train_loss_list.append(loss.detach())
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    model.eval()
    with torch.inference_mode():
        for input, target in test_dataloader:
            prediction_during_training = model(input)
        loss = loss_function(prediction_during_training, target)
        test_loss_list.append(loss.detach())

# Evaluate the model after training
model.eval()
with torch.inference_mode():
    for input, target in test_dataloader:
        prediction_after_training = model(input)

# Visualize
figure = pyplot.figure(figsize=(16, 9))
axes = figure.subplots(1, 2)
axes[0].grid(True)
axes[0].set_xlabel("Epoch")
axes[0].set_ylabel("Loss")
axes[0].plot(epochs_list, train_loss_list, label="Training")
axes[0].plot(epochs_list, test_loss_list, label="Testing")
axes[0].legend()
axes[1].grid(True)
axes[1].set_xlabel("x")
axes[1].set_ylabel("F(x) = sin(x)")
axes[1].plot(target, label="Actual values")
axes[1].plot(prediction_before_training, label="Predictions before training")
axes[1].plot(prediction_after_training, label="Predictions after training")
axes[1].legend()
figure.tight_layout()
pyplot.show()

The output graph should be like this:

enter image description here

Thanks for your answers.

Upvotes: 0

Views: 20

Answers (0)

Related Questions