A Simple PyTorch MLP model
Python Jupyter notebook code
The following code downloads historical the Google stock prices (GOOG) using yfinance package, splits training/test samples, and then, converts them into torch.Tensor type.
import pandas as pd import matplotlib.pyplot as plt import torch import torch.nn as nn import yfinance as yf # download data = yf.download('GOOG', start='2010-01-01', end ='2023-06-01') print(data) # Access the date values from the index dates = data.index print(dates) # split traning/test and set lags nlag = 20 ei_train = 2500 y_raw = data.iloc[nlag:,4:5]; y = y_raw.to_numpy() X_raw = data.iloc[:-nlag,4:5]; X = X_raw.to_numpy() date = dates[nlag:] X_train=X[:ei_train,:]; X_test=X[ei_train:,:] y_train=y[:ei_train,:]; y_test=y[ei_train:,:] # convert torch.Tensor X_train = torch.Tensor(X_train) X_test = torch.Tensor(X_test) y_train = torch.Tensor(y_train) y_test = torch.Tensor(y_test) | cs |
[*********************100%***********************] 1 of 1 completed Open High Low Close Adj Close \ Date 2010-01-04 15.615220 15.678981 15.547723 15.610239 15.610239 2010-01-05 15.620949 15.637387 15.480475 15.541497 15.541497 2010-01-06 15.588072 15.588072 15.102393 15.149715 15.149715 2010-01-07 15.178109 15.193053 14.760922 14.797037 14.797037 2010-01-08 14.744733 15.024933 14.672753 14.994298 14.994298 ... ... ... ... ... ... 2023-05-24 121.879997 122.750000 120.750000 121.639999 121.639999 2023-05-25 125.209999 125.980003 122.900002 124.349998 124.349998 2023-05-26 124.065002 126.000000 123.290001 125.430000 125.430000 2023-05-30 126.290001 126.379997 122.889999 124.639999 124.639999 2023-05-31 123.699997 124.900002 123.099998 123.370003 123.370003 [3375 rows x 6 columns] DatetimeIndex(['2010-01-04', '2010-01-05', '2010-01-06', '2010-01-07', '2010-01-08', '2010-01-11', '2010-01-12', '2010-01-13', '2010-01-14', '2010-01-15', ... '2023-05-17', '2023-05-18', '2023-05-19', '2023-05-22', '2023-05-23', '2023-05-24', '2023-05-25', '2023-05-26', '2023-05-30', '2023-05-31'], dtype='datetime64[ns]', name='Date', length=3375, freq=None) | cs |
A MLP model can be implemented in a class by inheriting nn.Module. __init__() defines layers and forward() makes links between these layers. I think that PyTorch treats a layer and its output type separately. We can use the torchsummary package to display a model summary.
# Define MLP model for univariate time series forecasting class Dense1(nn.Module): def __init__(self, input_size, h_size1, h_size2, h_size3, output_size): super(Dense1, self).__init__() # Define the Dense layers self.dense1 = nn.Linear(input_size, h_size1) self.dense2 = nn.Linear(h_size1,h_size2) self.dense3 = nn.Linear(h_size2,h_size3) # Define the activation function self.relu = nn.ReLU() # Define the output layer self.output = nn.Linear(h_size3, output_size) def forward(self, x): # Dense layer 1 with ReLU out = self.dense1(x); out = self.relu(out) # Dense layer 2 with ReLU out = self.dense2(out); out = self.relu(out) # Dense layer 2 with ReLU out = self.dense3(out); out = self.relu(out) # final linear output out = self.output(out) return out num_epochs = 5000 learning_rate = 0.001 # Set the input size, hidden sizes, and output size input_size = 1 h_size1 = 64 h_size2 = 32 h_size3 = 16 output_size = 1 # Create an instance of the DenseLayer model = Dense1(input_size, h_size1, h_size2, h_size3, output_size) criterion = torch.nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate) from torchsummary import summary # Display model summary summary(model, input_size=(input_size,)) | cs |
---------------------------------------------------------------- Layer (type) Output Shape Param # ================================================================ Linear-1 [-1, 64] 128 ReLU-2 [-1, 64] 0 Linear-3 [-1, 32] 2,080 ReLU-4 [-1, 32] 0 Linear-5 [-1, 16] 528 ReLU-6 [-1, 16] 0 Linear-7 [-1, 1] 17 ================================================================ Total params: 2,753 Trainable params: 2,753 Non-trainable params: 0 ---------------------------------------------------------------- Input size (MB): 0.00 Forward/backward pass size (MB): 0.00 Params size (MB): 0.01 Estimated Total Size (MB): 0.01 ---------------------------------------------------------------- | cs |
This is the main part of learning parameters with data. This is slightly different from the Keras model. In PyTorch, parameter estimation is done by iterating by num_epochs, within which forward and backward passes are carried out sequentially: prediction, calculation of prediction errors, calculation of loss gradient, and updating.
for epoch in range(num_epochs): # Forward pass: # Perform the forward pass of the model # to obtain the predicted outputs outputs = model.forward(X_train) # Zero the gradients in the optimizer # before backward pass optimizer.zero_grad() # Calculate the loss between the true labels # and the predicted outputs loss = criterion(outputs, y_train) # Backward pass: # Compute gradients of the loss # with respect to model parameters loss.backward() # Update the model parameters using the gradients # and the optimizer's update rule optimizer.step() # Print the loss value every 100 epochs if epoch % 100 == 0: print("Epoch: %d, loss: %1.5f" % (epoch, loss.item())) | cs |
Epoch: 0, loss: 1362.96155 Epoch: 100, loss: 7.13212 Epoch: 200, loss: 3.94204 ... Epoch: 4700, loss: 3.93202 Epoch: 4800, loss: 3.93175 Epoch: 4900, loss: 3.93146 | cs |
After parameter estimation, we can draw forecast output as follows.
# Estimated and Forecasted prices X_all = torch.Tensor(X) # apply the estimated model to full dataset train_predict = model(X_all) predicted = train_predict.detach().numpy() # Create a DataFrame from the numpy array y_pred = pd.DataFrame(data=predicted) # Set the dates as the index of the DataFrame y_pred.index = pd.DatetimeIndex(date) axv = date[ei_train] # Figure plt.figure(figsize=(8,3)) plt.axvline(x=axv, c='r', linestyle='--') plt.plot(y_raw , label='Actual', color='deeppink', linewidth=1) plt.plot(y_pred, label='Predicted', color='deepskyblue',linewidth=1) #plt.title(str(int(nlag)) + '-day-ahead forecasting') plt.title(str(int(nlag/20)) + '-month-ahead forecasting') plt.legend() plt.show() | cs |
For clear presentation, I do not apply various deep learning technique such as feature scaling, multiple lagged variables or hyper parameter optimization. But these parts are similar to those of Keras model. Next time, LSTM model will be considered since it can handle time steps.
No comments:
Post a Comment