Why in Keras subclassing API, the call method is never called and as an alternative the input is passed by calling the object of this class?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In Keras subclassing, you usually execute a model with model(inputs) rather than calling model.call(inputs) directly. That can make it look as if call is somehow being skipped, but it is not. Keras routes execution through __call__, which then invokes your call method while also adding framework behavior such as shape handling, mask propagation, and graph tracing.
What Actually Happens When You Write model(x)
The user-facing syntax is:
Internally, Keras runs the model’s __call__ method. That wrapper is responsible for more than just dispatching to your code. It also handles things such as:
- Building layers lazily on first use.
- Managing
trainingandmaskarguments. - Keras history tracking for symbolic graphs.
- Dtype policy and casting.
- Integration with tracing and SavedModel export.
Your custom call method is still executed, but it is executed through that managed path.
Minimal Example
Here is the standard subclassing pattern.
Even though user code calls model(x), your call implementation is what computes the output.
Why Keras Discourages Direct call(...)
You can technically write:
but that bypasses part of the framework contract. In simple eager experiments it may appear to work, yet subtle issues show up later with:
- Mixed precision.
- Nested models.
- Masked inputs.
- Distribution strategies.
- Symbolic graph construction.
Keras wants model(x) to be the public entry point because that keeps all of its lifecycle and bookkeeping consistent.
Proving That call Is Executed
If the behavior still feels abstract, add a print inside call.
You will see inside call in the output. The method is not missing; it is simply reached through __call__.
The Role of training and Other Special Arguments
The wrapper path matters even more when you use layers such as dropout or batch normalization.
That training value is propagated through the managed call path. Writing code in the normal model(x, training=...) style keeps it aligned with Keras expectations.
First Call Also Builds the Model
Subclassed models often create weights lazily because input shape is not always known in __init__.
That first object call is the normal moment when variables are created. If you bypass the intended call path too aggressively, debugging build-time behavior becomes harder.
Best Practice for Subclassed Models
The standard pattern is:
- Define layers in
__init__. - Put forward-pass logic in
call. - Execute with
model(x), notmodel.call(x).
That division keeps the code compatible with fit, predict, evaluate, tracing, and export.
Common Pitfalls
- Assuming
callis not executed because user code writesmodel(x). Fix by remembering__call__delegates tocall. - Invoking
model.call(...)directly as the main API. Fix by usingmodel(...)so Keras wrapper behavior stays active. - Forgetting to include
training=Falsein the customcallsignature when the model uses training-sensitive layers. Fix by adding the parameter explicitly. - Creating new layers inside
callinstead of__init__. Fix by constructing layers once in__init__so variables are not recreated on every pass. - Mixing ad hoc manual invocation style with
fitandpredictexpectations. Fix by following one consistent subclassing pattern everywhere.
Summary
- In Keras subclassing,
model(x)is the correct public way to run the model. - '
callis still executed, but it is reached through__call__.' - The wrapper adds important framework behavior beyond raw forward computation.
- Direct
call(...)can bypass masking, tracing, and lifecycle logic. - Keep layers in
__init__, forward logic incall, and execution throughmodel(...).

