advanced · ~25 min
Keras Functional API, Deeper
Beyond a single stack of layers: multi-input/output models, shared layers, and skip connections you can't build with Sequential.
The Keras basics module introduced the Functional API as "what you reach for when Sequential's one-input-one-output stack isn't enough." This module is about what that actually buys you.
The core idea is simple: instead of Sequential([...]) building an implicit chain, you call
layers directly as functions on tensors, and wire the graph yourself.
inputs = keras.Input(shape=(2,))
x = layers.Dense(16, activation="relu")(inputs)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
That's identical to a two-layer Sequential — but because you're holding onto the actual
tensors (inputs, x, outputs) instead of just appending to a list, you can do things a
straight stack can't express at all:
- Multiple inputs or outputs — a model that takes both an image and some tabular metadata, or one that predicts a class and a numeric score from the same shared trunk.
- Shared layers — apply the same layer instance to two different inputs (e.g. encoding two sentences with one shared embedding for a similarity model), so they're forced to learn the same representation.
- Non-linear topologies — a layer's output feeding into more than one place, or two branches
merging back together. This is what a skip connection is:
layers.Add()([x, block(x)])instead of justblock(x).
🔍 Deep dive: Why skip connections make deep networks trainable
Stack enough plain layers and gradients flowing backward through all of them tend to shrink
(or occasionally blow up) multiplicatively — the classic vanishing gradient problem.
A skip connection gives the gradient a second path — straight through the Add(), with
derivative 1 — so even a very deep stack has at least one route back to early layers that
doesn't get squashed. This is the core idea behind ResNet, and it's a big part of why networks
with hundreds of layers became trainable at all. The playground below builds an 8-block deep
network two ways — with and without skip connections around each block — and trains both, live,
on the same hard dataset.
Production note
layers.Add() requires its inputs to be the same shape (it's an elementwise sum) — that's why
residual blocks keep the same number of units throughout. layers.Concatenate() is the merge to
reach for when shapes differ or you want the model to see both signals side by side instead of
summed.
Beginner tip
If the "without skip connections" model in the playground looks like it's barely learning at all while the "with skip connections" one solves the task cleanly, that's not a rigged demo — 8 plain layers deep is genuinely a hard optimization problem for a small MLP, which is exactly the failure mode skip connections exist to fix.
Playground
8 layers deep, no skip connections
8 layers deep, with skip connections
- no skip
- with skip