I'm trying to train an LSTM network in Tensorflow.
But this gives me an error:
ValueError: Layer "model_10" expects 2 input(s), but it received 1 input tensors. Inputs received: [<tf.Tensor 'IteratorGetNext:0' shape=(None, 6, 21) dtype=float32>]
And yes I know that my model (create_lstm_encoder_decoder) needs two inputs!
The train dataframe has 22 columns, first column as Label and the rest (21 columns) as features.
With a total window size (Windowing) 8, and a batch size of 128 I can generate a sequence of BatchDatase Then I use the function below to split each window to include 7 previous features and two future labels (since I want to be able to predict two steps in the future)
I would really appreciate any help and ideas.
def make_dataset(data, total_window_size, BATCH_SIZE, SHIFT):
data = np.array(data, dtype=np.float32)
ds = tf.keras.utils.timeseries_dataset_from_array(
data=data,
targets=None,
sequence_length=total_window_size,
sequence_stride=SHIFT,
shuffle=False,
batch_size= BATCH_SIZE)
return ds
and then
train_df = make_dataset(train_df_org, total_window_size=8, BATCH_SIZE=128, SHIFT=2)
split function(actually is a class but I wanted to make it reproducible here)
def split_windows_map(features):
input_start = 1
shift = 2
input_width = 6
total_window_size = input_width + shift
label_width = 2
label_start = total_window_size-label_width
column_indices = {'Demand': 0,
'Temp': 1,
'solar': 2,
'wind': 3,
'humid': 4,
'quarter': 5,
'Holidays': 6,
'weekend': 7,
'sin_hour': 8,
'cos_hour': 9,
'sin_dow': 10,
'cos_dow': 11,
'sin_dom': 12,
'cos_dom': 13,
'sin_doy': 14,
'cos_doy': 15,
'sin_month': 16,
'cos_month': 17,
'sin_woy': 18,
'cos_woy': 19,
'sin_year': 20,
'cos_year': 21}
label_columns = ['Demand']
inputs = features[:, slice(0, input_width), input_start:]
labels = features[:, slice(label_start, None), :]
column_indices = column_indices
if label_columns is not None:
labels = tf.stack(
[labels[:, :, column_indices[name]] for name in 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 = tf.convert_to_tensor(inputs)
inputs.set_shape([None, input_width, None])
labels.set_shape([None, label_width, None])
return inputs, labels
And then map it
trained_window = train_df.map(split_windows_map)
what it gives me is pretty much okay. for example:
for example_inputs, example_out in trained_window.take(1):
inputs_seq = example_inputs
labels_out = example_out
print(inputs_seq.shape), print(labels_out.shape)
(128, 6, 21) >> #Batch, timestep, Features
(128, 2, 1) >> # Batch, timestep, Labels (two step in the future, eachstep predicts one value)
so far is great and it's what I want. the LSTM model looks like this:
import tensorflow as tf
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, LSTM, Dense
def create_lstm_encoder_decoder(input_shape, output_shape, lstm_units=64):
"""
Create an LSTM encoder-decoder model for time series data.
Parameters:
input_shape (tuple): Shape of the input data (batch_size, timesteps, features).
output_shape (tuple): Shape of the output data (batch_size, output_timesteps, output_features).
lstm_units (int): Number of units in the LSTM layer (default is 64).
Returns:
model (tensorflow.keras.models.Model): The LSTM encoder-decoder model.
"""
# Input layer for the encoder
encoder_input = Input(shape=input_shape[1:]) # Excluding batch_size from input shape
# LSTM encoder
encoder_lstm = LSTM(lstm_units, return_state=True)
_, state_h, state_c = encoder_lstm(encoder_input)
# Input layer for the decoder (with the last output as initial state)
decoder_input = Input(shape=output_shape[1:]) # Excluding batch_size from output shape
decoder_lstm = LSTM(lstm_units, return_sequences=True, return_state=True)
decoder_output, _, _ = decoder_lstm(decoder_input, initial_state=[state_h, state_c])
# Output layer
output = Dense(output_shape[2]) # Output shape does not contain batch_size
decoder_output = output(decoder_output)
# Model combining encoder and decoder
model = Model([encoder_input, decoder_input], decoder_output)
return model
# Example usage with the specified shapes
input_shape = (128, 6, 21)
output_shape = (128, 2, 1)
model = create_lstm_encoder_decoder(input_shape, output_shape)
# Printing the summary of the model
model.summary()
model.compile(optimizer='adam', loss='mse')
model.fit(trained_window, epochs=10)
Yes I know that my model (create_lstm_encoder_decoder) needs two inputs, one tuple of encoder-decoder input and one decoder output. but I don't know how to extract them or feed them (based on the created batch and sequences) to the model.fit.