C.W.K.
Stream
Lesson 05 of 07 · published

Mixing Functional and Subclass

~10 min · subclass

Level 0Keras Apprentice
0 XP0/97 lessons0/20 achievements
0/120 XP to next level120 XP to go0% complete

The best-of-both-worlds pattern

This is the move the whole track has been building toward: subclass a custom layer, then compose it with the Functional API. The layer holds whatever Python logic you need on the inside; from the outside, it's a callable that takes a tensor and returns a tensor — indistinguishable from Dense or Conv2D. So you call it inside a Functional graph exactly like a built-in (see the Code block).

Why the seam works — and why it's free

The reason this composes cleanly is the layer contract. Every Keras layer, built-in or custom, exposes the same interface: layer(tensor) -> tensor. The Functional API doesn't care what happens inside a layer — it only wires the tensor that comes out into the next call. So your ResidualBlock, with its skip connection and Python-level logic, slots into the graph and the surrounding Functional structure stays fully introspectable: model.summary() still draws the skeleton, and only the custom block's internals are opaque. You localize the introspection cost from Lesson 1 to exactly the blocks that earned it.

The reverse direction works too: a subclassed Model can build a Functional sub-model in its __init__() and call it from call(). In practice the common shape is a pretrained Functional backbone (ResNet, a vision transformer) wrapped by a thin subclassed head that does the custom routing or loss bookkeeping.

Code

A subclassed ResidualBlock used inside a Functional model·python
# Custom layer
class ResidualBlock(keras.layers.Layer):
    def __init__(self, filters, **kwargs):
        super().__init__(**kwargs)
        self.dense1 = layers.Dense(filters, activation="relu")
        self.dense2 = layers.Dense(filters)
        self.add_layer = layers.Add()
        self.activation = layers.Activation("relu")

    def call(self, inputs):
        x = self.dense1(inputs)
        x = self.dense2(x)
        x = self.add_layer([x, inputs])
        return self.activation(x)

# Use custom layer in Functional API
inputs = keras.Input(shape=(64,))
x = layers.Dense(64, activation="relu")(inputs)
x = ResidualBlock(64)(x)  # Custom layer used like any built-in
x = ResidualBlock(64)(x)
outputs = layers.Dense(10, activation="softmax")(x)
model = keras.Model(inputs, outputs)

External links

Exercise

Build a hybrid: a Functional model whose layers include one Subclassed layer (e.g. a custom MultiHeadAttention). Verify model.summary() shows both clearly.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.