Search code examples
pythontensorflowkerasdeep-learningtime-series

Why my LSTM Model forecasts almost straight line on validation set?


I trained a BI-LSTM model on stock prices. For this model, I did 2 approaches of backtesting :

  1. Applying the predict function for the whole validation set and then compare predictions to real data
  2. Predict the whole validation set based on the prediction of each day and then using it to predict the next day and so on.

With the 1) method, results look like pretty good whith a RMSE near of 0.25 which can tell me that the model has good performance on test set, as follows:

enter image description here

The code used:

 pas = 20
 train_len=5586
 test_data = df_scaled[train_len - pas: ]
    print ('len(test_data):', len(test_data))

    # Create the data sets x_test and y_test
    x_test = []
    y_test = df[train_len:, :]
    for i in range(pas, len(test_data)):
        x_test.append(test_data[i-pas:i, 0])
    # Convert the data to a numpy array
    x_test = np.array(x_test)

    # Reshape the data
    x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1 ))

    # Get the models predicted price values
    fichier_modele = f"{symbols}.h5"
    model = load_model(fichier_modele)
    predictions = model.predict(x_test)
    scaler2=dictio_scalers[symbols]

    predictions = scaler2.inverse_transform(predictions)

But using the 2) method, the model predicts almost a straight line, enter image description here

Code used:

Pred_Array_Global=df[int(train_len)-pas:int(train_len)]

 # Get the models predicted price values
fichier_modele = f"{symbols}.h5"
model = load_model(fichier_modele)
scaler2=dictio_scalers[symbols]
Pred_Array_Global=scaler2.fit_transform(Pred_Array_Global)

for i in range(0,len(test['Close'])):
    Pred_Array_Global=np.array(Pred_Array_Global)
    Pred_Array=Pred_Array_Global[i:i+pas]
    # Convert the data to a numpy array
    Pred_Array = np.array(Pred_Array)

    
    # Reshape the data
    Pred_Array_Input = np.reshape(Pred_Array,(1,pas, 1 ))
    predictions = model.predict(Pred_Array_Input,verbose=0)

    Pred_Array_Global=np.append(Pred_Array_Global,predictions)
    

Pred_Array_Global=Pred_Array_Global.reshape(-1,1)
Pred_Array_Global = scaler2.inverse_transform(Pred_Array_Global)

As the model performs really well with the whole test data, if I want to make predictions from each day to each day, I was expecting a slight drop in performance but not a straight line!

Did I Make a mistake in my code?

NB: Here is the code I use to build the model (epochs=2000, batch_size=256):

model = Sequential()
model.add(Bidirectional(LSTM(units=128, input_shape=(20, 1))))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,verbose=0)
fichier_modele = f"{symbols}.h5"
model.save(fichier_modele)

Solution

  • Your two approaches are two different problems. It depends on how long the future you want to predict.

    With your training code, it was designed for the model to learn to predict just one step future. You then feed the future ground truth data as input to the model so the values which was fed into model in the validation phase look likely to the data which was trained that's why it gives a good performance.

    With the your second approach, that's long-term forecasting problem which you want the model to predict N-step future base on K-step in the past which is clearly harder compare to the first one and this is not what you trained your model to learn. But you still can do it with LSTM, take a look at recursive forecasting.