From perceptron to MLP; universal approximation
Stacking dot products and nonlinearities until anything becomes learnable
Every network you will meet — convolutional nets (5.1 Convolution: the operation and its math), the feed-forward block inside a transformer (7.4 Inside the block: residuals, LayerNorm, FFN and embeddings), the value network in an RL agent (4.11 Reinforcement learning essentials) — is a stack of affine maps and simple nonlinearities. Understanding exactly what a multilayer perceptron computes, why a single layer cannot solve XOR, and what the universal approximation theorem does and does not promise gives you the mental model that the rest of deep learning refines rather than replaces.
You'll be able to
- Write the perceptron, its learning rule and the condition under which it converges
- Show by explicit construction how one hidden layer solves XOR and why that is representation learning
- Write the forward pass of an L-layer MLP in both single-example and batched matrix form and count its parameters
- State the universal approximation theorem precisely and list three things it does not guarantee
- Explain the geometric picture of a ReLU network as a piecewise-linear function
Key ideas
- A perceptron is a thresholded dot product; its learning rule converges only when the data are linearly separable.
- XOR is not linearly separable; one hidden layer re-represents the inputs so that a linear rule works — this is representation learning.
- An L-layer MLP computes z⁽ˡ⁾ = W⁽ˡ⁾h⁽ˡ⁻¹⁾ + b⁽ˡ⁾, h⁽ˡ⁾ = φ(z⁽ˡ⁾); in batched form each layer is one matrix multiply X Wᵀ + b.
Show 4 more key ideas
- Parameter count is Σ (n_{ℓ−1}+1)·n_ℓ; the first layer usually dominates.
- Without a nonlinearity, any stack of layers collapses to one affine map.
- The universal approximation theorem guarantees existence of a one-hidden-layer approximator, not a reasonable width, learnability by SGD, or generalization.
- A ReLU network is a piecewise-linear function; depth multiplies the number of linear regions far faster than width.
Suggested path through this lesson
A neuron is a thresholded dot product
In 1958 Frank Rosenblatt's perceptron took an input vector , formed the dot product with a weight vector, added a bias, and fired if the result was positive:
You already know what this computes (1.1 Vectors, dot products and norms): is a template, and scores how well the input matches it. Geometrically, is the normal vector of a hyperplane that splits the input space in two. The perceptron learning rule nudges the template toward misclassified positives and away from misclassified negatives: for each example with label ,
The perceptron convergence theorem guarantees that if the data are linearly separable, this rule makes finitely many mistakes and stops. Logistic regression (3.3 Logistic regression and softmax classification) is the same model with the hard threshold replaced by a sigmoid, trained by gradient descent; the perceptron is where the word neuron and the idea of learning weights from errors enter the story.
XOR: the wall a single layer hits
Consider the exclusive-or function on two binary inputs:
| XOR | ||
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
The two positive points sit on one diagonal and the two negatives on the other: no single line separates them, so no perceptron (and no logistic regression on raw inputs) can represent XOR. Minsky and Papert's 1969 book made this precise and helped freeze neural-network research for a decade. The fix is a hidden layer. Take two hidden units with ReLU activations :
| input | |||
|---|---|---|---|
| (0,0) | 0 | 0 | 0 |
| (0,1) | 1 | 0 | 1 |
| (1,0) | 1 | 0 | 1 |
| (1,1) | 2 | 1 | 0 |
Look at what happened in the hidden space: the two positive inputs both map to , while the negatives map to and . In those new coordinates the classes are linearly separable, and the output unit is an ordinary perceptron. The hidden layer did not "solve" XOR by being cleverer; it re-represented the data so that a linear rule works. That is representation learning in miniature, and it is the entire idea behind deep learning.
The multilayer perceptron, written out
An MLP with layers applies an affine map followed by an element-wise nonlinearity , times. With :
where and . The last layer usually skips and feeds (the logits) into a softmax for classification or uses it directly for regression. is called the pre-activation and the activation; you will differentiate with respect to both in 4.4 Backpropagation, fully derived.
For a mini-batch of examples stacked as rows of (the PyTorch convention), the same computation is one matrix product per layer:
which is exactly what nn.Linear(n_in, n_out) does: it stores as an matrix and computes with broadcasting (2.2 NumPy and vectorized thinking). Batching is why GPUs love neural networks: one big matmul instead of small ones (4.12 Compute, hardware and scale basics).
Parameter count. Layer has weights and biases, so
For an MNIST classifier : , , , total . The first layer holds 85% of the weights — a pattern you will see again when counting transformer parameters (7.4 Inside the block: residuals, LayerNorm, FFN and embeddings).
Why the nonlinearity is not optional. Compose two affine maps and you get another affine map:
Without , a 100-layer network is a single linear model with extra steps and still cannot do XOR. The nonlinearity is where the expressive power comes from; which one to choose is the subject of 4.2 Activation functions.
The universal approximation theorem — and what it does not say
Theorem (Cybenko 1989; Hornik 1991). Let be a continuous, non-polynomial activation and compact. For every continuous and every there exist a width and parameters such that the one-hidden-layer network satisfies .
Intuition. In one dimension, the difference of two shifted ReLUs, , is a ramp that rises from to and then stays flat. Sums of ramps make any piecewise-linear function, and piecewise-linear functions approximate any continuous function on an interval as finely as you like. Each hidden unit contributes one "kink".
The theorem is reassuring but routinely over-interpreted. It does not say:
- that the width is reasonable — for some functions the required grows exponentially with the input dimension ;
- that gradient descent will find those weights — existence of a solution is not learnability from finite data with SGD;
- anything about generalization — a network that fits the training set perfectly may fail on new inputs (3.5 Evaluating models: metrics, validation and the bias–variance trade-off, 4.7 Regularization in deep nets);
- that depth is pointless — deep ReLU networks can represent certain compositional functions with exponentially fewer units than any shallow network (the number of linear regions a ReLU net can carve grows exponentially with depth but only polynomially with width).
Depth, width and what layers do
Each layer re-represents its input, so a deep network builds a hierarchy of features: in images, edges become textures become parts become objects (5.3 Architectures: LeNet → AlexNet → VGG → Inception → ResNet → EfficientNet → ConvNeXt); in language, characters become morphemes become syntax become meaning (7.6 Decoder-only: GPT and autoregressive generation). Depth is composition, and composition is cheap to express and hard to match with width. The catch is that very deep plain MLPs are hard to optimize — gradients shrink or explode as they pass through many layers (4.2 Activation functions), so careful initialization (4.6 Initialization and normalization) and residual connections (5.3 Architectures: LeNet → AlexNet → VGG → Inception → ResNet → EfficientNet → ConvNeXt, 7.4 Inside the block: residuals, LayerNorm, FFN and embeddings) were needed before depth became practical. Today's MLPs are mostly two-layer blocks living inside larger architectures: the feed-forward sub-layer of a transformer is literally applied to each token independently.
The geometry of a ReLU network
Because ReLU is linear on each side of zero, a ReLU network is a piecewise-linear function: the input space is cut into polyhedral regions, and inside each region the network is a single affine map. Decision boundaries are therefore made of flat facets, and more units or layers mean more (and smaller) facets, which is why the nn-playground demo below shows jagged boundaries for small networks and smooth-looking ones for larger networks. The same picture explains why networks can be confidently wrong far from the data: outside the training region the function keeps extrapolating linearly.
In code
import torch, torch.nn as nn
model = nn.Sequential(
nn.Flatten(),
nn.Linear(784, 256), nn.ReLU(),
nn.Linear(256, 128), nn.ReLU(),
nn.Linear(128, 10), # logits; the loss applies softmax
)
print(sum(p.numel() for p in model.parameters())) # 235146
x = torch.randn(32, 1, 28, 28) # a batch of 32 images
print(model(x).shape) # torch.Size([32, 10])
Where this shows up later
- The nonlinearities that make depth work and the vanishing-gradient problem — 4.2 Activation functions; the losses attached to the logits — 4.3 Loss functions catalog.
- Computing gradients through this exact stack — 4.4 Backpropagation, fully derived; keeping activations well-scaled through many layers — 4.6 Initialization and normalization.
- A convolution is an MLP layer with shared, local weights — 5.1 Convolution: the operation and its math; the transformer's feed-forward block is a two-layer MLP per token — 7.4 Inside the block: residuals, LayerNorm, FFN and embeddings.
- Logistic regression is the zero-hidden-layer special case — 3.3 Logistic regression and softmax classification; a Q-network is an MLP from states to action values — 4.11 Reinforcement learning essentials.
Common pitfalls (4)
- Believing the universal approximation theorem means 'one hidden layer is all you need' in practice — depth is exponentially more efficient for many functions.
- Forgetting that nn.Linear stores W as (out_features, in_features) and computes x Wᵀ + b; shape bugs follow.
- Putting a softmax at the end of the model and then using nn.CrossEntropyLoss (which applies softmax itself) — pass logits.
- Confusing the number of layers with the number of weight matrices: a '3-layer MLP' usually means three Linear layers (two hidden).
Recap: all 7 key points
- A perceptron is a thresholded dot product; its learning rule converges only when the data are linearly separable.
- XOR is not linearly separable; one hidden layer re-represents the inputs so that a linear rule works — this is representation learning.
- An L-layer MLP computes z⁽ˡ⁾ = W⁽ˡ⁾h⁽ˡ⁻¹⁾ + b⁽ˡ⁾, h⁽ˡ⁾ = φ(z⁽ˡ⁾); in batched form each layer is one matrix multiply X Wᵀ + b.
- Parameter count is Σ (n_{ℓ−1}+1)·n_ℓ; the first layer usually dominates.
- Without a nonlinearity, any stack of layers collapses to one affine map.
- The universal approximation theorem guarantees existence of a one-hidden-layer approximator, not a reasonable width, learnability by SGD, or generalization.
- A ReLU network is a piecewise-linear function; depth multiplies the number of linear regions far faster than width.
Watch
The layer-by-layer picture of an MLP on MNIST; watch before reading.
Read
Try it live
Interactive demo
runs in your browserExercises
- By hand: XOR with your own hidden units
Find a different pair of hidden units and output weights that computes XOR exactly (try sigmoid-free constructions with thresholds, or ReLUs with other offsets). Tabulate for the four inputs. Expected: your hidden representation makes the positives and negatives linearly separable.
- NumPy: forward pass and parameter count
Implement
forward(x, params)for an MLP with arbitrary layer sizes using only@, broadcasting andnp.maximum. Verify on a batch of 5 random inputs that the output shape is (5, n_out), and that your hand-computed parameter count matchessum(W.size + b.size). Expected for 784-256-128-10: 235,146. - Experiment: regions of a ReLU network
In the nn-playground demo (or TensorFlow Playground) train on the spiral dataset with 1 hidden layer of 4, 8 and 32 units, then with 3 layers of 8. Sketch how the decision boundary changes. Expected: more units and more depth → more linear facets; depth gets a smooth spiral with far fewer total units than width does.
- PyTorch: fit XOR
Train a 2-2-1 network with tanh hidden units on the four XOR points for 2,000 steps with SGD (lr 0.1). Run it 10 times with different seeds. Expected: most runs reach ~0 loss, a few get stuck in a local minimum — your first taste of why initialization matters (4.6 Initialization and normalization).
Quiz
Flashcards
These cards are now in your spaced-repetition queue. Review all due cards →