TensorFlow
Keras
subclass model
model.summary()
deep learning debugging

model.summary can't print output shape while using subclass model

Master System Design with Codemia

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

Introduction

model.summary() is most informative when Keras knows the model has been built and can trace the layer structure. With subclassed models, that information is often unavailable until the model sees input data or is explicitly built, which is why output shapes can appear missing or the summary call can fail.

Why Subclassed Models Behave Differently

Functional and Sequential models describe their graph structure up front. A subclassed model is more imperative: you define Python code in call, and Keras only sees the concrete path once the model is invoked.

TensorFlow’s Keras documentation makes two related points:

  • subclassed layers and models typically build lazily on first call
  • 'summary() raises an error if the model has not been built yet'

That is the root cause of the missing output-shape problem.

Define Layers in __init__, Not in call

Before talking about summary(), make sure the model itself is structured correctly. Sublayers should usually be created in __init__, not inside call.

python
1import tensorflow as tf
2
3
4class MyModel(tf.keras.Model):
5    def __init__(self):
6        super().__init__()
7        self.dense1 = tf.keras.layers.Dense(16, activation="relu")
8        self.dense2 = tf.keras.layers.Dense(4)
9
10    def call(self, inputs):
11        x = self.dense1(inputs)
12        return self.dense2(x)

This allows Keras to track the sublayers properly. If you create layers inside call, summary output becomes much less reliable and you risk creating new weights on each call.

Build the Model Before Calling summary()

The simplest fix is to call the model once with sample input.

python
1import tensorflow as tf
2
3
4class MyModel(tf.keras.Model):
5    def __init__(self):
6        super().__init__()
7        self.dense1 = tf.keras.layers.Dense(16, activation="relu")
8        self.dense2 = tf.keras.layers.Dense(4)
9
10    def call(self, inputs):
11        x = self.dense1(inputs)
12        return self.dense2(x)
13
14
15model = MyModel()
16dummy = tf.ones((1, 8))
17_ = model(dummy)
18model.summary()

Once the model has been called, its weights exist and Keras has enough information to print a useful summary.

Explicit build() Can Also Help

If the input shape is known, you can build the model explicitly.

python
1import tensorflow as tf
2
3
4class MyModel(tf.keras.Model):
5    def __init__(self):
6        super().__init__()
7        self.dense1 = tf.keras.layers.Dense(16, activation="relu")
8        self.dense2 = tf.keras.layers.Dense(4)
9
10    def call(self, inputs):
11        x = self.dense1(inputs)
12        return self.dense2(x)
13
14
15model = MyModel()
16model.build((None, 8))
17model.summary()

This can work well for straightforward models. Still, actually calling the model is often clearer because it verifies that the forward pass runs with realistic input.

Why Output Shapes May Still Be Less Detailed

Even after building, subclassed models are not always as transparent as Functional models. Because the forward pass is arbitrary Python code, Keras may not infer every intermediate detail as cleanly as it can with a graph assembled from keras.Input tensors.

If you need rich structural inspection, named tensors, or clean visualization tooling, the Functional API is often a better fit:

python
1inputs = tf.keras.Input(shape=(8,))
2x = tf.keras.layers.Dense(16, activation="relu")(inputs)
3outputs = tf.keras.layers.Dense(4)(x)
4model = tf.keras.Model(inputs, outputs)
5model.summary()

That is not a criticism of subclassing. It is simply a tradeoff: flexibility versus inspectability.

A Good Debugging Sequence

When summary() is not showing what you expect for a subclassed model, check in this order:

  1. are layers created in __init__
  2. has the model been called or built
  3. does the input shape match what the model expects
  4. do you actually need subclassing, or would Functional API fit better

That sequence resolves most confusion quickly.

Common Pitfalls

The biggest mistake is calling summary() on a subclassed model before it has been built. Keras does not yet know enough about the model.

Another mistake is creating layers inside call. That makes layer tracking and summary output much less predictable and can create repeated weights incorrectly.

Developers also expect subclassed models to expose the same degree of static graph detail as Functional models. That expectation is too strong because subclassing intentionally allows dynamic Python control flow.

Finally, building with the wrong shape can make summary output misleading or cause the first real batch to fail later. Use a realistic input shape when possible.

Summary

  • Subclassed Keras models usually need to be called or built before model.summary() can show useful shape information.
  • Define sublayers in __init__, not inside call.
  • A sample forward pass is often the simplest way to prepare the model for summary().
  • The Functional API remains better when you want maximum graph visibility and easier inspection.
  • Missing output shapes are usually a model-build issue, not a broken summary() method.

Course illustration
Course illustration

All Rights Reserved.