0

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.

Soprano
  • 17
  • 3

0 Answers0