TensorFlow fit using dataset from generator with multiple outputs: Cannot properly define shapes?

Viewed 1744

I am attempting to convert a project to a single network with multiple outputs using a generator but I cannot seem to work out how to get the multiple outputs to function properly when a generator is being used. Here is a minimally verifiable hunk of code:

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models

def generate_sample():
    x = list("123456789")
    y = list("2345")
    while 1:
        yield np.array(x).astype(np.float32),[np.array(y).astype(np.float32),np.array(y).astype(np.float32)]

dataset = tf.data.Dataset.from_generator(generate_sample,
            output_signature=(
                 tf.TensorSpec(shape=(9,), dtype=tf.float32),
                 tf.TensorSpec(shape=(2,4), dtype=tf.float32)

            ))

dataset = dataset.batch(batch_size=32)

inputs = keras.Input(shape=(next(generate_sample())[0].shape))
x = layers.Dense(512, activation = "relu")(inputs)
x_outputs = layers.Dense(4, activation="relu", name="output")(x)
y_outputs = layers.Dense(4, activation="relu", name="output2")(x)

model = keras.Model(inputs=inputs, outputs=[x_outputs,y_outputs])
model.compile(loss="mse", optimizer = "adam", metrics=['accuracy'])
history = model.fit(dataset, epochs=1, steps_per_epoch=10, validation_data=dataset, validation_steps=5)

This results in a very long error, the final portion of which is:

InvalidArgumentError: Incompatible shapes: [32,2,4] vs. [32,4]
[[node mean_squared_error/SquaredDifference (defined at :1) ]] [Op:__inference_train_function_8957]

Function call stack: train_function

I have tried this using output_shape, output_signature, etc. with every way I can imagine reshaping the data. No matter what, I continue to run into shape problems.

Am I missing something obvious here or is there something wrong in fit using a generator as a source for a dataset? I have no problem doing this when I'm loading the data from memory, for example.

1 Answers

The output of the model is not one Tensor of shape (2,4), but two Tensors of shape (4).

You should change your generator function to reflect that:

def generate_sample():
    x = list("123456789")
    y = list("2345")
    while 1:
        yield np.array(x).astype(np.float32),(np.array(y).astype(np.float32),np.array(y).astype(np.float32))

As well as your output signature:

dataset = tf.data.Dataset.from_generator(generate_sample,
            output_signature=(
                 tf.TensorSpec(shape=(9,), dtype=tf.float32),
                 (tf.TensorSpec(shape=(4,), dtype=tf.float32),
                 tf.TensorSpec(shape=(4,), dtype=tf.float32)),
            ))

Note that the output of the generator is a nested tuple.

Related