import numpy as np
import pandas as pd
import torch
import torch.nn as nn

# Deep LSTM Neural Network Model
class DeepLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, layers_count, output_size, dropout_value):
        super(DeepLSTM, self).__init__()
        self.hidden_size = hidden_size
        self.layers_count = layers_count
        # Creating a deeper LSTM layer
        self.lstm_layers = nn.LSTM(input_size, hidden_size, layers_count, batch_first=True, dropout=dropout_value)
        # Adding additional fully connected layers
        self.fc1 = nn.Linear(hidden_size, hidden_size)
        self.fc2 = nn.Linear(hidden_size, output_size)
        self.relu = nn.ReLU()

    def forward(self, input_data):
        initial_hidden = torch.zeros(self.layers_count, input_data.size(0), self.hidden_size).requires_grad_()
        initial_cell = torch.zeros(self.layers_count, input_data.size(0), self.hidden_size).requires_grad_()
        lstm_out, _ = self.lstm_layers(input_data, (initial_hidden.detach(), initial_cell.detach()))
        final_out = lstm_out[:, -1, :]
        final_out = self.fc1(final_out)
        final_out = self.relu(final_out)
        return self.fc2(final_out)