i have this code for time series forecasting using cnn bidirectional lstm:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import LSTM, Dense, Flatten, TimeDistributed, Conv1D, MaxPooling1D, AveragePooling1D, Dropout, Bidirectional, ELU
from sklearn.metrics import mean_squared_error, mean_absolute_error
from sklearn.preprocessing import MinMaxScaler
import tensorflow as tf
import random as rn
import os
from keras import backend as K

# Set the random seed for reproducibility
seed_value = 42
os.environ['PYTHONHASHSEED'] = str(seed_value)
np.random.seed(seed_value)
rn.seed(seed_value)
#tf.random.set_seed(seed_value)
K.clear_session()

def parse_date(date_string):
    return pd.to_datetime(date_string, format='%d/%m/%Y')

df = pd.read_csv('daily2023.csv', parse_dates=['Date'], date_parser=parse_date, index_col='Date')
passenger_count = df['passenger count'].values
df.head(), df.tail()

def split_sequence(sequence, n_steps):
    X, y = list(), list()
    for i in range(len(sequence)):
        end_ix = i + n_steps
        if end_ix > len(sequence) - 1:
            break
        seq_x, seq_y = sequence[i:end_ix], sequence[end_ix]
        X.append(seq_x)
        y.append(seq_y)
    return np.array(X), np.array(y)

np.shape(df)

def root_mean_squared_error(y_true, y_pred):
    return np.sqrt(mean_squared_error(y_true, y_pred))

def mean_absolute_percentage_error(y_true, y_pred):
    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

# Set the random seed for reproducibility
seed_value = 42
np.random.seed(seed_value)
rn.seed(seed_value)
tf.random.set_seed(seed_value)
K.clear_session()

# Assuming passenger_count is already loaded as a NumPy array and has no zero values
train_size = int(len(passenger_count) * 0.6)
val_size = int(len(passenger_count) * 0.2)
test_size = len(passenger_count) - train_size - val_size

# Split the data without shuffling
train_data = passenger_count[:train_size]
val_data = passenger_count[train_size:train_size+val_size]
test_data = passenger_count[train_size+val_size:]

# Reshape the data once before scaling
train_data = train_data.reshape(-1, 1)
val_data = val_data.reshape(-1, 1)
test_data = test_data.reshape(-1, 1)

# Scale the data
scaler = MinMaxScaler(feature_range=(0, 1))
scaler.fit(train_data)  # Fit only on training data

scaled_train_data = scaler.transform(train_data)
scaled_val_data = scaler.transform(val_data)
scaled_test_data = scaler.transform(test_data)

# Prepare the input and output sequences
n_steps = 35
X_train, y_train = split_sequence(scaled_train_data, n_steps)
X_test, y_test = split_sequence(scaled_test_data, n_steps)

# Reshape the input sequences for the model; no need to reshape each time
n_features = 1
n_seq = 1
X_train = X_train.reshape(X_train.shape[0], n_seq, n_steps, n_features)
X_test = X_test.reshape(X_test.shape[0], n_seq, n_steps, n_features)

# Prepare the validation sequences
X_val, y_val = split_sequence(scaled_val_data, n_steps)
X_val = X_val.reshape(X_val.shape[0], n_seq, n_steps, n_features)

initializer=tf.keras.initializers.GlorotNormal(seed=42)
initializer2=tf.keras.initializers.Orthogonal(seed=42)

def create_model():
  model = Sequential()
  model.add(TimeDistributed(Conv1D(filters=8, kernel_size=3, activation='relu', kernel_initializer=initializer), input_shape=(None, n_steps, n_features))) # Changed filters=16 to filters=8, and kernel_size=3 to kernel_size=5
  model.add(TimeDistributed(Dropout(0.2)))
  model.add(TimeDistributed(Flatten()))
  model.add(Bidirectional(LSTM(20, activation=ELU(),kernel_initializer=initializer,recurrent_initializer=initializer2)))
  model.add(Dense(1,kernel_initializer=initializer))
  model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.001), loss='mse')
  return model

model = create_model()
model.summary()


history = model.fit(X_train, y_train, epochs=150, verbose=1, validation_data=(X_val, y_val))
# Plotting the training and validation loss
plt.plot(history.history['loss'], label='Training loss')
plt.plot(history.history['val_loss'], label='Validation loss')
plt.title('Training vs Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

# Evaluate the model and make predictions on the training dataset
y_pred = model.predict(X_train)
y_pred_inverse = scaler.inverse_transform(y_pred)
y_true_inverse = scaler.inverse_transform(y_train)

# Assign the predicted values for the training set to y_train_pred_inverse
y_train_pred_inverse = y_pred_inverse

# Calculate the evaluation metrics
mse = mean_squared_error(y_true_inverse, y_pred_inverse)
mae = mean_absolute_error(y_true_inverse, y_pred_inverse)
rmse = np.sqrt(mse)  # Assuming you have a function to calculate RMSE or you can use np.sqrt(mse)
mape = np.mean(np.abs((y_true_inverse - y_pred_inverse) / y_true_inverse)) * 100  # Assuming you have a function to calculate MAPE or you can use this formula

# Print the evaluation metrics
print(f"Mean Squared Error: {mse}")
print(f"Mean Absolute Error: {mae}")
print(f"Root Mean Squared Error: {rmse}")
print(f"Mean Absolute Percentage Error: {mape}")

# Plot the forecasting
plt.plot(y_true_inverse, label='True values', color='blue')
plt.plot(y_pred_inverse, label='Forecast', color='orange')
plt.legend()
plt.title("Forecast vs True values using CNN LSTM")
plt.show()

# Evaluate the model and make predictions on the test dataset
y_pred = model.predict(X_test)
y_pred_inverse = scaler.inverse_transform(y_pred)
y_true_inverse = scaler.inverse_transform(y_test)

# Assign the predicted values for the test set to y_test_pred_inverse
y_test_pred_inverse = y_pred_inverse

# Calculate the evaluation metrics
mse = mean_squared_error(y_true_inverse, y_pred_inverse)
mae = mean_absolute_error(y_true_inverse, y_pred_inverse)
rmse = np.sqrt(mse)  # Assuming you have a function to calculate RMSE or you can use np.sqrt(mse)
mape = np.mean(np.abs((y_true_inverse - y_pred_inverse) / y_true_inverse)) * 100  # Assuming you have a function to calculate MAPE or you can use this formula

# Print the evaluation metrics
print(f"Mean Squared Error: {mse}")
print(f"Mean Absolute Error: {mae}")
print(f"Root Mean Squared Error: {rmse}")
print(f"Mean Absolute Percentage Error: {mape}")

# Plot the forecasting
plt.plot(y_true_inverse, label='True values', color='blue')
plt.plot(y_pred_inverse, label='Forecast', color='orange')
plt.legend()
plt.title("Forecast vs True values using CNN LSTM")
plt.show()



how do i implement these suggestions?

Data
try to create  rolling windows with slight shifts, that should produce  more intervals you can train upon

Model
From the top of my tongue, you could try add more layers though  you need to be careful to avoid overfitting
Implement dropout in both convolutional and LSTM layers  then tune the dropout rate  until you've reached something you think can work 
Use a learning rate scheduler or  a learning  method like Adam