Keras
TensorFlow 2
tf.data.Dataset.from_generator
multiple inputs model
machine learning

Multiple inputs of keras model with tf.data.Dataset.from_generator in Tensorflow 2

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Feeding a multi-input Keras model from tf.data.Dataset.from_generator works well when the dataset structure exactly matches the model input structure. Most failures come from mismatched nesting, shapes, or dtypes rather than from the model itself. The safest workflow is to name the inputs, define an explicit output_signature, and inspect one batch before training.

Build the Model with Named Inputs

Named inputs make the data contract much clearer than relying on positional tuples.

python
1import tensorflow as tf
2
3tokens_in = tf.keras.Input(shape=(20,), dtype=tf.int32, name="tokens")
4meta_in = tf.keras.Input(shape=(5,), dtype=tf.float32, name="meta")
5
6x_tokens = tf.keras.layers.Embedding(input_dim=2000, output_dim=32)(tokens_in)
7x_tokens = tf.keras.layers.GlobalAveragePooling1D()(x_tokens)
8
9x_meta = tf.keras.layers.Dense(16, activation="relu")(meta_in)
10
11x = tf.keras.layers.Concatenate()([x_tokens, x_meta])
12out = tf.keras.layers.Dense(1, activation="sigmoid")(x)
13
14model = tf.keras.Model(inputs={"tokens": tokens_in, "meta": meta_in}, outputs=out)
15model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])

Now the input structure is explicit: the model expects a dictionary with keys tokens and meta.

Make the Generator Yield the Same Structure

The generator must yield one sample at a time in the exact structure the model expects.

python
1import numpy as np
2
3def sample_generator(num_samples=512, seed=11):
4    rng = np.random.default_rng(seed)
5
6    for _ in range(num_samples):
7        tokens = rng.integers(0, 2000, size=(20,), dtype=np.int32)
8        meta = rng.random(5, dtype=np.float32)
9        label = np.float32((tokens.mean() > 1000) or (meta.mean() > 0.55))
10
11        yield {"tokens": tokens, "meta": meta}, label

If the model expects a dictionary and the generator yields a tuple, or vice versa, training usually fails immediately with a structure mismatch.

Define output_signature Precisely

from_generator needs a clear tensor specification so TensorFlow knows what the generator will produce.

python
1output_signature = (
2    {
3        "tokens": tf.TensorSpec(shape=(20,), dtype=tf.int32),
4        "meta": tf.TensorSpec(shape=(5,), dtype=tf.float32),
5    },
6    tf.TensorSpec(shape=(), dtype=tf.float32),
7)
8
9train_ds = tf.data.Dataset.from_generator(sample_generator, output_signature=output_signature)
10train_ds = train_ds.shuffle(512).batch(32).prefetch(tf.data.AUTOTUNE)

If the signature does not match the real generator output, the error is often reported on first iteration or first fit call.

Inspect One Batch Before Training

This step catches most input-pipeline mistakes early.

python
1for x_batch, y_batch in train_ds.take(1):
2    print(x_batch["tokens"].shape, x_batch["tokens"].dtype)
3    print(x_batch["meta"].shape, x_batch["meta"].dtype)
4    print(y_batch.shape, y_batch.dtype)

If these shapes and dtypes are not exactly what the model expects, fix the pipeline before wasting time inside a training loop.

Train the Model Normally Once the Contract Matches

After the structure is correct, training is ordinary Keras code.

python
history = model.fit(train_ds, epochs=3, verbose=2)
print(history.history.keys())

The main lesson is that multi-input training is not special at the fit call. It is special in the data structure contract between the model and the dataset.

Three-Value Generators Also Work for Sample Weights

If you need sample weights, the generator can yield three values: inputs, label, and weight. In that case, the output_signature must include the third tensor as well.

This is a common place where people update the generator but forget to update the signature, then start debugging the wrong part of the stack.

from_generator Is Flexible but Not Always Fastest

from_generator is useful when data must come from Python logic, external iterators, or unusual sampling rules. But it runs Python code, which can become a throughput bottleneck.

If training speed matters, keep the generator light and move expensive transforms into TensorFlow graph operations or precomputed files when possible.

Common Pitfalls

  • Yielding a tuple structure when the model expects a dictionary of named inputs.
  • Using the wrong dtype, especially int64 where embedding inputs expect int32.
  • Forgetting to update output_signature after changing the generator output.
  • Debugging the model architecture when the actual issue is the dataset structure.
  • Using heavy Python logic inside the generator and then blaming TensorFlow for slow input throughput.

Summary

  • Multi-input Keras models work with from_generator when the dataset structure matches the model inputs exactly.
  • Named input dictionaries reduce ambiguity.
  • 'output_signature must describe the real shapes and dtypes precisely.'
  • Validate one batch before training.
  • Keep generator logic deterministic and lightweight so debugging and performance stay manageable.

Course illustration
Course illustration

All Rights Reserved.