How to predict time series values with keras, and using predictions as inputs

Viewed 45

I have built a LSTM model that works well on my test and validation set in Keras; however, when I try to use it to predict values where my two target variables are NaN, the model is unable to predict. Now, I am worried that the modeling process will be all for nothing. I will put my code here, and I have mostly referred to the guide on the tensorflow website. This is my first tensorflow model, so I apologize if this is simple but I can't seem to predict any values and I don't really know how to go about formatting it to make it predictable similar to how it was easy to do for the validation and then use those predictions for input to compute farther back because I only have 3 years of train data, but 40 years that need to be backcasted.

I believe the problem is that right now I have data in the form (batch size, inputs) and I need it in the form (batch size, time steps looking back, inputs), but I can't figure out the way to make this possible

Creating data:

df.rename(columns = {'Unnamed: 0':'date'}, inplace = True)
true_test = df[pd.isnull(df['Return'])]
df=df[pd.isnull(df['Return'])==False]

Window Generator Class:

class WindowGenerator():
def __init__(self, input_width, label_width, shift,
           train_df=train_df, val_df=val_df, test_df=test_df,
           label_columns=None):
# Store the raw data.
self.train_df = train_df
self.val_df = val_df
self.test_df = test_df

# Work out the label column indices.
self.label_columns = label_columns
if label_columns is not None:
  self.label_columns_indices = {name: i for i, name in
                                enumerate(label_columns)}
self.column_indices = {name: i for i, name in
                       enumerate(train_df.columns)}

# Work out the window parameters.
self.input_width = input_width
self.label_width = label_width
self.shift = shift

self.total_window_size = input_width + shift

self.input_slice = slice(0, input_width)
self.input_indices = np.arange(self.total_window_size)[self.input_slice]

self.label_start = self.total_window_size - self.label_width
self.labels_slice = slice(self.label_start, None)
self.label_indices = np.arange(self.total_window_size)[self.labels_slice]

def __repr__(self):
return '\n'.join([
    f'Total window size: {self.total_window_size}',
    f'Input indices: {self.input_indices}',
    f'Label indices: {self.label_indices}',
    f'Label column name(s): {self.label_columns}'])

 def split_window(self, features):
    inputs = features[:, self.input_slice, :]
    labels = features[:, self.labels_slice, :]
    if self.label_columns is not None:
       labels = tf.stack(
    [labels[:, :, self.column_indices[name]] for name in self.label_columns],
    axis=-1)

  # Slicing doesn't preserve static shape information, so set the shapes
  # manually. This way the `tf.data.Datasets` are easier to inspect.
  inputs.set_shape([None, self.input_width, None])
  labels.set_shape([None, self.label_width, None])

   return inputs, labels

def make_dataset(self, data):
  data = np.array(data, dtype=np.float32)
  ds = tf.keras.utils.timeseries_dataset_from_array(
      data=data,
      targets=None,
      sequence_length=self.total_window_size,
      sequence_stride=1,
      shuffle=True,
      batch_size=32,)

  ds = ds.map(self.split_window)

  return ds

 WindowGenerator.make_dataset = make_dataset

def plot(self, model=None, plot_col=['Return','Supply'], max_subplots=3):
   if isinstance(plot_col, list):
      self.plot(model = model, plot_col = 'Return')
      self.plot(model = model, plot_col = 'Supply')
      return None
    inputs, labels = self.example
    plt.figure(figsize=(12, 8), dpi=300)
    plot_col_index = self.column_indices[plot_col]
    max_n = min(max_subplots, len(inputs))
    for n in range(max_n):
       print("somthing plz \n\n\n\n")
       plt.subplot(max_n, 1, n+1)
       plt.ylabel(f'{plot_col} [normed]')
       plt.plot(self.input_indices, inputs[n, :, plot_col_index],
         label='Inputs', marker='.', zorder=-10)

   if self.label_columns:
     label_col_index = self.label_columns_indices.get(plot_col, None)
   else:
     label_col_index = plot_col_index
   if label_col_index is None:
      continue

   plt.scatter(self.label_indices, labels[n, :, label_col_index],
            edgecolors='k', label='Labels', c='#2ca02c', s=64)
   if model is not None:
      if plot_col == 'Return':
           plt.scatter(self.label_indices, predictions[n, :, 0],
              marker='X', edgecolors='k', label='Predictions',
              c='#ff7f0e', s=64)
   elif plot_col == 'Supply':
     plt.scatter(self.label_indices, predictions[n, :, 1],
              marker='X', edgecolors='k', label='Predictions',
              c='#ff7f0e', s=64)
   else:
     plt.scatter(self.label_indices, predictions[n, :, label_col_index],
              marker='X', edgecolors='k', label='Predictions',
              c='#ff7f0e', s=64)
   if n == 0:
      plt.legend()

   plt.xlabel('Time [h]')

WindowGenerator.plot = plot

Compile and Fit Function:

def compile_and_fit(model, window, patience=2):
early_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss',
                                                patience=patience,
                                                mode='min')

model.compile(loss=tf.keras.losses.MeanAbsoluteError(),
            optimizer=tf.keras.optimizers.Adam(),
            metrics=[tf.keras.metrics.MeanAbsoluteError(), coeff_determination])

history = model.fit(window.train, epochs=MAX_EPOCHS,
                  validation_data=window.val,
                  callbacks=[early_stopping])
return history

Fitting Model:

wide_window = WindowGenerator(
input_width=24, label_width=24, shift=1,
label_columns=['Return', 'Supply'])

## RNN: LSTM 
n_steps = 24
n_features = 10 
lstm_model = tf.keras.models.Sequential([
    # Shape [batch, time, features] => [batch, time, lstm_units]
tf.keras.layers.LSTM(32, return_sequences = True, input_shape=(n_steps, n_features)),
tf.keras.layers.LSTM(16, return_sequences = True),
tf.keras.layers.LSTM(4, return_sequences = True),
# Shape => [batch, time, features]
tf.keras.layers.Dense(units=2)
 ])
val_performance['LSTM_SR'] = lstm_model.evaluate(wide_window.val)
performance['LSTM_SR'] = lstm_model.evaluate(wide_window.test, verbose=0)

Trying to test:

## Tried no expansion, axis = 1, and axis = 0, this one seems the closest
true_test2 = np.expand_dims(true_test, axis=1)
lstm_model.predict(true_test2, verbose = 2)

Error from above call:

ValueError                                Traceback (most recent call last)
path in <cell line: 
 5>()
 ----> 545 lstm_model.predict(true_test2, verbose = 2)

 File ~/lib/python3.9/site- 
 packages/keras/utils/traceback_utils.py:67, in filter_traceback. 
 <locals>.error_handler(*args, **kwargs)
     65 except Exception as e:  # pylint: disable=broad-except
     66   filtered_tb = _process_traceback_frames(e.__traceback__)
 ---> 67   raise e.with_traceback(filtered_tb) from None
    68 finally:
    69   del filtered_tb

File ~/lib/python3.9/site- 
packages/keras/engine/input_spec.py:264, in assert_input_compatibility(input_spec, 
inputs, layer_name)
   262 if spec_dim is not None and dim is not None:
   263   if spec_dim != dim:
 --> 264     raise ValueError(f'Input {input_index} of layer "{layer_name}" is '
   265                      'incompatible with the layer: '
   266                      f'expected shape={spec.shape}, '
   267                      f'found shape={display_shape(x.shape)}')

ValueError: Input 0 of layer "sequential_21" is incompatible with the layer: expected 
shape=(None, 24, 10), found shape=(32, 1, 10)

Error with Just true_test:

ValueError: Input 0 of layer "sequential_23" is incompatible with 
the layer: expected shape=(None, 24, 10), found shape=(32, 10)
1 Answers

Try removing input_shape() from 2nd and 3rd layers of your model. input_shape() must be used only in the first layer of your model.

lstm_model = tf.keras.models.Sequential([
    # Shape [batch, time, features] => [batch, time, lstm_units]
tf.keras.layers.LSTM(32, return_sequences = True, input_shape=(n_steps, n_features)),
tf.keras.layers.LSTM(16, return_sequences = True),
tf.keras.layers.LSTM(4),
# Shape => [batch, time, features]
tf.keras.layers.Dense(units=2)
 ])
Related