One neuron draws a line. Stack them, and you can draw anything.
A layer is a matrix multiply, a bias, and a squashing curve. Chain layers and raw inputs become features no single line could see. This is the forward pass — the half of training that never learns.
A single neuron can only slice the plane with a straight line.
XOR puts [0,1] and [1,0] on one side, [0,0] and [1,1] on the other — and no single line can separate them. Minsky and Papert proved that limit in 1969. The fix is not a smarter neuron; it is a stack of them, where the first layer builds new features and the next layer decides with those features.
stack neurons → new features → curves02 / W·x + b, THEN ACTIVATE
Every neuron: weighted sum, plus bias, through a nonlinearity.
A layer holds a weight matrix W with one row per neuron and one column per input — shape (neurons now, neurons before) — plus one bias per neuron. The linear step z = W·x + b moves and stretches the space; the activation a = σ(z) bends it. Both halves appear in every layer of every deep model.
W is (now × before) · a = σ(W·x + b)03 / THE FORWARD PASS CHAINS LAYERS
Layer k's output is layer k+1's input — four lines of logic.
Data goes in, flows through every layer, comes out. Nothing is learned or changed here: no loss, no gradients, just multiply–add–activate on repeat. The intermediate vectors are the hidden state — for text that can be 768 numbers per token; the last layer reads that state out as a decision.
x → a¹ → a² → … → y, pure computation
MENTAL MODEL IN ONE SENTENCE
A network is a composition of functions: x → a¹ → a² → … → y. Each layer rewrites its input into a new set of coordinates, and the whole job of the hidden layers is to build coordinates in which the output layer’s one straight decision is enough.
By the end you will be able to run a forward pass by hand through a 2-2-1 and a 2-3-1 network; check every weight shape before running anything; explain why two linear layers collapse into one matrix and why the activation is the only reason depth pays; count an architecture’s parameters; state the universal approximation theorem without overclaiming; and narrate exactly how a hidden layer makes XOR solvable.
01
A LINE IS NOT ENOUGH
One neuron draws a line. XOR needs more.
The perceptron from Lesson 03.01 is a line drawer — that is its entire power. In 1969 Minsky and Papert showed XOR is not “hard” for it; it is impossible. The escape route is not a smarter neuron, but a stack of ordinary ones.
A single neuron computes one weighted sum and passes it through a threshold. Geometrically, that is a straight line: everything on one side is class 1, everything on the other side is class 0. For a dataset where a line can do the job — the OR gate, a spam filter with a good keyword — that is enough. XOR is not such a dataset.
Minsky and Papert’s 1969 result was precise: a single-layer network cannot learn XOR, no matter how long you train or how you tune its weights. No line separates the classes. The result landed at the worst possible time, funding drained away, and neural networks went quiet for more than a decade.
The fix, obvious in hindsight, is to stop insisting on one line. Stack neurons into layers: let the first layer carve the input space into new features, and let the second layer combine those features into a decision that no single line could make. That stack is the multi-layer network — the object under every production deep learning model — and the forward pass is the piece you build first.
The XOR truth table. Four examples, two classes — and the classes alternate around the square.
x₁
x₂
y
0
0
0
0
1
1
1
0
1
1
1
0
XOR asks for a boundary that is not a straight line: [0,1] and [1,0] must land on one side, [0,0] and [1,1] on the other. Whichever line you try, two corners of the same class end up on opposite sides.
Quick check
XOR has exactly four examples and the perceptron from Lesson 03.01 has three parameters. Why can't it solve XOR, even with perfect training?
02
INPUT, HIDDEN, OUTPUT
Three kinds of layers, one working middle.
A multi-layer network arranges neurons in columns: the input holds the raw data, the hidden layers do the work, and the output layer answers the question. Only the hidden and output layers compute — and the middle ones are where the learning lives.
The input layer is not really a layer. It holds your raw data — pixels, sensor readings, words — one node per feature. No weights, no biases, no computation. Two features means two input nodes.
Hidden layers are where work happens. Each neuron takes every output from the previous layer, multiplies each by its own weight, adds a bias, and pushes the sum through an activation function. The results form a vector called the hidden state. “Hidden” because those values never appear in your training data — the network invented them.
The output layer gives the final answer. For binary classification it is one neuron with a sigmoid: a number in (0,1) that reads as a probability. For multi-class problems it is one neuron per class. Everything before it exists to make this last, simple decision possible.
The activation used throughout this lesson is the sigmoid. It squashes any real number into (0,1): large positives approach 1, large negatives approach 0, and zero maps to exactly 0.5. Unlike the perceptron’s hard step, the curve is smooth and differentiable everywhere — its derivative is σ(z)·(1−σ(z)) — which is what makes gradient-based learning possible in Lesson 03.03.
σ(z) = 1 / (1 + e^(−z)) "the S-curve"
σ(0) = 0.5 the undecided middle
σ(10) = 0.999955 large positive → ≈ 1
σ(−10) = 0.000045 large negative → ≈ 0
σ′(z) = σ(z)·(1 − σ(z)), never zero — so gradients can flow
The 2-3-1 network: two inputs, three hidden neurons, one output. Every connection carries a weight; every neuron except the inputs carries a bias. The shapes printed above the edges are the whole bookkeeping problem of deep learning, and Chapter 04 makes them mechanical.
The hidden state is the point of the whole exercise. For text models it expands: a single token enters as a handful of numbers and travels as a 768-number vector (BERT-base) or a 4096-number vector (Llama-2-7B), with each layer rewriting that vector in light of its context. For images it compresses: millions of pixels funnel down to a few hundred numbers that summarize the picture. Either direction, the hidden state is a representation the network built for itself, and the next layer reads it instead of the raw input.
The forward pass, live in a 2-2-1 network
Move the inputs, switch the weights, and watch the numbers climb the network: pre-activations z, activations a, and one output. Nothing here learns — this is pure computation.
input x = [0.00, 1.00]
hidden layer (2 neurons)
z¹ = [10.00, 10.00]
h = [1.0000, 1.0000]
output layer (1 neuron)
z² = [10.00] (z² = 20·h₁ + 20·h₂ − 30)
y = σ(z²) = 1.0000 → class 1
shapes: W1 (2×2) @ x (2,) + b1 (2,) → (2,)
W2 (1×2) @ h (2,) + b2 (1,) → (1,)
With the XOR weights at full scale, σ acts like a step: h₁ ≈ OR, h₂ ≈ NAND, and the output is their AND — which is exactly XOR. Slide the weight scale down and watch the sharp corners melt: the same architecture stops separating the classes because sigmoid is no longer saturating.
03
THE FORWARD PASS
Multiply, add, activate. Then do it again.
The forward pass pushes data through the network, layer by layer, until it reaches the output. Nothing is learned or changed along the way — it is pure computation, and it is the foundation everything else in this phase stands on.
At every layer, three operations happen in sequence. First the linear transformation z = W·x + b: each neuron takes a weighted sum of the previous layer’s outputs and shifts it by its bias. Then the activation a = σ(z) squashes each number through the sigmoid curve. Then the output vector becomes the next layer’s input.
z = W · x + b "weighted vote, plus a per-neuron offset"
a = σ(z) "squash every number into (0, 1)"
output of layer k = input of layer k + 1
In plain English: W holds one row of weights per neuron, so W·x just says “every neuron listens to every input, with its own volume knob per input.” The bias then sets how easy that neuron is to switch on: a large negative bias means the neuron stays quiet even when its inputs are positive. And σ keeps every value in a bounded range so the next layer receives a consistent, comparable signal.
That is the entire forward pass. No learning happens here — the weights are whatever they are, and the pass just computes. Training (backpropagation, Lesson 03.03) is a separate loop that runs a forward pass, measures the error, and only then nudges the weights.
The entire forward pass, from the source lessonpython
import math
def sigmoid(z):
z = max(-500.0, min(500.0, z)) # clamp: math.exp(1000) overflowsreturn1.0 / (1.0 + math.exp(-z))
class Layer:
def __init__(self, n_inputs, n_neurons, weights, biases):
self.weights = weights # (n_neurons, n_inputs)
self.biases = biases # (n_neurons,)def forward(self, inputs):
self.last_input = inputs
self.last_output = []
for neuron_idx in range(len(self.weights)):
row = self.weights[neuron_idx]
z = sum(w * x for w, x in zip(row, inputs))
z += self.biases[neuron_idx]
self.last_output.append(sigmoid(z))
return self.last_output
class Network:
def __init__(self, layers):
self.layers = layers
def forward(self, inputs):
current = inputs
for layer in self.layers: # k's output feeds k+1
current = layer.forward(current)
return current
Layer holds one weight matrix and one bias vector; Network chains the calls. That is four lines of logic and the reason PyTorch's nn.Sequential can be so small.
Worked check: a full 2-3-1 forward pass, number by number
The XOR network later in this lesson is the famous example; here is a second pass, end to end, so the arithmetic is visible before any of it becomes familiar. Weights and biases are ordinary small numbers — no saturation, no tricks.
Follow one number all the way: h₂ came from z¹₂ = 0.230, which came from x₂ = 0.8 carrying its weight 0.1, plus x₁ = 0.5 carrying 0.7, minus the bias 0.2. Then h₂ went into the output neuron with weight −0.6: it was the only hidden neuron voting against the positive class, and without it z² would have been 0.796 (y = 0.689 instead of 0.613). Every weight matters a little; some matter a lot.
A forward pass you can read line by line
Pick one of the four XOR inputs, then step through the arithmetic of the hand-tuned 2-2-1 network. This is the table a debugger prints.
x (2,) · raw input
0.0000001.000000
→
z¹ (2,) · W¹x + b¹
10.00000010.000000
σ
h (2,) · hidden state
0.9999550.999955
→
z² (1,) · W²h + b²
9.998184
σ
y (1,) · output
0.999955
Each hidden neuron computes its weighted sum plus bias:
z¹₁ = 20·0 + 20·1 + (-10) = 10.000000
z¹₂ = -20·0 + -20·1 + (30) = 10.000000
Big weights (±20) make σ saturate, so each neuron acts like a hard threshold.
σ(10) = 0.999955 because e^(−10) is 0.0000454 — the curve is already flat out here. Large weights push every neuron into the flat region, which is what turns a smooth sigmoid into the step function XOR needs.
Quick check
You run a forward pass on one training example. Which of these does the network change?
04
SHAPES & THE SHAPE RULE
Every layer is a shape contract. Break it and you learn instantly.
Tracking dimensions is the single most important debugging skill in deep learning. The rule fits in one line, and half of all beginner errors — including the silent ones — come from breaking it.
Every matmul has a contract: the number of columns on the left must equal the number of entries on the right. A layer’s weight matrix W is shaped (neurons in this layer, neurons in the previous layer) — rows match the current layer, columns match the previous one — so W·x lines up by construction. The bias has one entry per neuron, so it matches the result’s shape exactly. If the shapes do not line up, you have a bug.
There is no magic beyond that. The activation is element-wise, so it never changes a shape. The output of one layer is a vector whose length equals that layer’s neuron count, and it arrives at the next layer as the “previous layer” whose length the columns must match. Walk the 2-3-1 network from Chapter 02:
The 2-3-1 network, one operation at a time. No step changes shape unexpectedly: the linear step goes (2,) → (3,), and the output linear goes (3,) → (1,).
Step
Operation
Dimensions
Result shape
Input
x
—
(2,)
Hidden linear
W¹·x + b¹
W¹: (3, 2), b¹: (3,)
(3,)
Hidden activation
σ(z¹)
—
(3,)
Output linear
W²·h + b²
W²: (1, 3), b²: (1,)
(1,)
Output activation
σ(z²)
—
(1,)
Worked check: the inner dimensions, with numbers
z¹ = W¹ · x (3, 2) · (2,) → (3,) inner dims: 2 = 2 ✓
z² = W² · h (1, 3) · (3,) → (1,) inner dims: 3 = 3 ✓
the same product with a transposed W²:
W²ᵀ · h (3, 1) · (3,) → ✗ columns 1 ≠ entries 3
the framework raises a shape error — which is the good case.
If W² had been square (3,3), the product would run and the
network would compute a completely different function in silence.
Two numbers decide whether every layer works: the current layer’s neuron count (rows) and the previous layer’s output length (columns). The bias matches rows. Everything else follows.
Shape checker: walk the dimensions
Build an architecture, then break it on purpose. Shape errors are the most common bug in deep learning — this board makes the inner dimensions visible before the framework prints a stack trace.
PyTorch writes nn.Linear(in, out) but stores the weight as (out, in) — the same (now × before) rule. The 2-3-1 network from the source has W1 (3×2) and W2 (1×3); swap either and the chain breaks or silently lies.
Quick check
A hidden layer has 5 neurons and receives the 3-number output of the previous layer. What is the shape of its weight matrix, and what shape comes out?
05
WHY ACTIVATIONS MATTER
Without the bend, depth is a lie.
Two matrix multiplies in a row are just one matrix multiply with extra steps. The activation function between them is the only thing that stops a hundred-layer network from collapsing into a single linear map — and the only reason stacked layers can draw curves.
A dense layer without its activation applies an affine map — a linear transformation plus a shift. Compose two of them and you do not get a richer kind of function — you get one affine map that happens to be computed in two steps. The algebra says it plainly: W²·(W¹·x + b¹) + b² = (W²W¹)·x + (W²b¹ + b²). Any stack of purely linear layers, however deep, is equivalent to one layer with a combined matrix.
two layers z = W²·σ(W¹·x + b¹) + b²
remove σ z = W²·(W¹·x + b¹) + b²
= (W²·W¹)·x + (W²·b¹ + b²)
= W_combined · x + b_combined ← one layer, not two
The sigmoid between the layers breaks the factorization. σ bends each coordinate independently, so the second layer’s matrix multiplies a warped version of the input rather than the input itself. That is why Chapter 07’s XOR network works: the hidden layer moves the four points into a new coordinate system where they can be separated by a line, and the output layer draws that line.
Worked check: collapse two layers into one matrix — with numbers
Take a two-layer stack with W¹ = [[2, 0], [1, −1]] and b¹ = [1, 2], W² = [[1, 1]] and b² = [0.5], and a probe input x = [3, 4].
two layers, no activation
z¹ = W¹·x + b¹ = [2·3 + 0·4 + 1, 1·3 + (−1)·4 + 2] = [7, 1]
z² = W²·z¹ + b² = 1·7 + 1·1 + 0.5 = 8.5
collapsed into one matrix
W_combined = W²·W¹ = [3, −1]
b_combined = W²·b¹ + b² = (1·1 + 1·2) + 0.5 = 3.5
z = 3·3 + (−1)·4 + 3.5 = 8.5 ✓ identical
same weights, sigmoid inserted between the layers
h = [σ(7), σ(1)] = [0.999089, 0.731059]
z² = 0.999089 + 0.731059 + 0.5 = 2.230148
y = σ(2.230148) = 0.9029 ≠ 8.5 — a different function
With no activation the two-layer network and the single matrix agree to the last digit: 8.5 both ways. Add σ and the same weights produce 0.9029 for the same input — different outputs, so the two functions are genuinely different. The difference is also structural: the activated version is bounded inside (0,1) for every input, while the linear version grows without bound. The nonlinearity is not decoration. It is the difference between a deep network and an expensive identity.
Two linear layers are one linear layer
The grid is the space of possible inputs, warped by each layer in turn. With no activation between layers, the dashed single matrix W₂W₁ traces the exact same curves as the two-step network. Switch the nonlinearity on and watch the shortcut fail.
layer 1 weights W₁ (drag to reshape)
W₁ = [[1.20, 0.40], [-0.30, 0.90]]
W₂ = [[0.80, 0.60], [−0.60, 0.80]] (fixed)
composed W₂·W₁ = [[0.78, 0.86], [-0.96, 0.48]]
composed bias = [0.10, -0.20]
probe x = [0.80, 0.40]
two layers → [1.0680, -0.7760]
one matrix → [1.0680, -0.7760]
difference → 0.000000 = 0 · the deeper stack adds nothing (yet)
Two matrix multiplies in a row collapse into one: depth without an activation is just a longer way to write a single linear map.
The algebra: W₂(W₁x) = (W₂W₁)x. The numeric check above is the whole proof — and it is also the trap: stacking layers is only worth it because the activation happens between them.
Quick check
You build a 5-layer network but forget to put an activation after each dense layer. What function is your model actually computing?
06
HOW MANY NEURONS?
Enough neurons can trace any curve. “Enough” is doing heavy lifting.
In 1989 George Cybenko proved that a single hidden layer, given enough neurons, can approximate any continuous function to any accuracy. It is the theoretical license for everything since — and it is easy to read as a promise it never made.
The intuition is the one Chapter 05 set up. Each hidden neuron adds one bend to the function; a neuron with a steep sigmoid is a step, and a step with a negative output weight carves a bump. Place enough bumps and you can trace any smooth curve. More neurons, more bumps, better approximation — up to any accuracy you name, for any continuous function on a bounded region.
What the theorem does not say is that one hidden layer is always best. It is a statement about representation: there exists a set of weights that does the job. Practice cares about two more questions — will training find those weights, and will they generalize to new data? Deeper networks answer both better: a stack of layers reuses features, so it reaches the same accuracy with far fewer total parameters than the shallow-wide network the theorem needs. That is why deep learning works.
Enough neurons can trace any curve
Each faint line is one hidden sigmoid neuron with its output weight; the bold line is their sum. Add neurons and watch the staircase melt into the target — the universal approximation theorem, drawn.
target smooth hill
hidden units 4
fitted weights 4 output weights + 1 bias
rmse 0.0146
units rmse trend
1 0.2818
2 0.1049
4 0.0146
8 0.0130
16 0.0032
24 0.0018
At 1 unit the output is a single smooth step: it can only
say "low then high". Every added unit sharpens the staircase.
This is a teaching sketch — hidden positions are fixed and only
the output weights are fitted by least squares. A real network
learns both halves (Lesson 03.03).
The theorem is about representation, not magic: enough neurons can approximate any continuous function, but “enough” can be enormous, and it says nothing about learning those weights from finite data.
Worked check: what “enough neurons” looks like in numbers
The lab above fits a network output to a target curve with fixed neuron positions and least-squares output weights — a teaching sketch, not a training procedure, but a real measurement of approximation error.
smooth hill target, measured in the lab
neurons rmse
1 0.2818 one step: "low, then high" — no hill
2 0.1049
4 0.0146
8 0.0130
16 0.0032
24 0.0018 ~25 fitted numbers trace the curve
the same architecture names from the source lesson, counted
2-2-1 XOR network (2·2+2) + (2·1+1) = 9
2-8-1 circle classifier (2·8+8) + (8·1+1) = 33
784-256-128-10 MNIST 200,960 + 32,896 + 1,290 = 235,146
approximating one 1-D curve is cheap; approximating the
function that maps a million pixels to a label is not — and
"enough" is where width stops being efficient and depth wins.
The last line is the honest reading of the theorem. A single wide layercan represent the pixel-to-label function; the parameter count to do it grows so fast that a stacked network with many fewer numbers — each layer building on the last — is the only practical way to get there.
07
XOR BY HAND
Nine numbers that draw a curve.
The 2-2-1 network from the source solves XOR with 6 weights and 3 biases — chosen by a human, not learned. Walking its forward pass is the clearest proof that a hidden layer can turn an impossible line problem into an easy one.
The architecture: two inputs, two hidden neurons, one output. The hidden weights are deliberately huge — ±20 — because large inputs push sigmoid into its flat regions, where it behaves like a hard step. The first hidden neuron then acts like OR (fires when x₁ + x₂ is past 0.5) and the second like NAND (stays on unless both inputs are 1). The output neuron computes their AND: it fires only when OR and NAND are both on — exactly the two cases where the inputs differ. AND(OR, NAND) is XOR.
These specific numbers were hand-tuned to make each hidden neuron compute a named logic gate. Training will not be told to do that — in Lesson 03.03 backpropagation finds its own weights, and it is free to invent features no human named. What matters here is that the forward pass works, and that it is a complete, checkable computation:
Worked table: the hand-tuned 2-2-1 on all four inputs
Read the [0,1] row against the [1,1] row. For [0,1] both hidden neurons are saturated on, h = (0.999955, 0.999955), and the output z² = 9.998 lands far above the 0.5 threshold. For [1,1] the second hidden neuron has flipped to 0.000045, so z² = −9.999 and the output collapses to 0. The only thing separating those rows is which hidden neuron carries the signal — a distinction no single line in the original (x₁, x₂) plane can make. Nine numbers, one curved boundary.
XOR in hidden space: where a line becomes enough
Drag the morph slider and watch the four XOR points move from the raw input plane into the hidden layer’s coordinates. Two of them land on top of each other, and a single straight line finishes the job.
input hidden (h₁, h₂) y expected
[0, 0] (0.00005, 1.00000) 0.00005 0 ✓
[0, 1] (0.99995, 0.99995) 0.99995 1 ✓
[1, 0] (0.99995, 0.99995) 0.99995 1 ✓
[1, 1] (1.00000, 0.00005) 0.00005 0 ✓
separating line in hidden space: h₁ + h₂ = 1.5
from z² = 20g·h₁ + 20g·h₂ − 30g = 0 (divide by 20g → same line at any g > 0)
[0, 1] and [1, 0] land on the SAME hidden point:
the hidden layer folded two inputs into one feature, and the
output neuron only has to separate that point from the rest.
This is the whole argument for depth: the hidden layer does not draw the curved boundary itself — it re-coordinates the data so the output layer can draw a straight one.
The same network is also the honest version of “running the model”: change an input and everything downstream recomputes; run it twice on the same input and you get the same output, because nothing is mutated. Frameworks packaged this exact computation. In PyTorch, the whole two-layer network is four lines:
The same forward pass in PyTorchpython
import torch
import torch.nn as nn
model = nn.Sequential(
nn.Linear(2, 8), # weight (8, 2), bias (8,)
nn.Sigmoid(),
nn.Linear(8, 1), # weight (1, 8), bias (1,)
nn.Sigmoid(),
)
xor = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])
print(model(xor)) # forward pass on all four rows at once
nn.Linear(2, 8) is our Layer(n_inputs=2, n_neurons=8) and stores a (8, 2) weight matrix; nn.Sigmoid() is our sigmoid; nn.Sequential is our Network. PyTorch adds GPUs, batches and automatic gradients — not different mathematics.
08
CHECK YOURSELF
Five questions. Then the terms worth keeping.
Answer before you look. The weight-shape question and the forward-pass question are the two that separate a memorized definition from a working instinct.
0 / 5 answered · 0 correct
01What is the purpose of a hidden layer in a multi-layer network?
02What does the forward pass do in a neural network?
03For a layer with 3 neurons receiving input from 2 neurons, what is the shape of the weight matrix?
04What does the Universal Approximation Theorem guarantee?
05Why does the sigmoid activation function make learning possible, unlike the step function used in perceptrons?
Key terms, demystified
Click a card to swap the lazy description for what it actually means.
Exercises from the lesson
Four problems with exact numbers — a deeper XOR stack, parameter counting, a width sweep on the circle classifier, and a leaky-step replacement for sigmoid. Try first; a worked answer is one click away. (The source lesson also ships a reusable network-architect prompt at outputs/prompt-network-architect.md — use it when deciding depth, width and activations for a real problem.)
Build a 2-4-2-1 network — two hidden layers — and run the forward pass on the XOR inputs with random weights, printing the hidden outputs at each layer. Watch how the representation changes from the raw pair to the second hidden layer.Show one worked answer
With weights W1 = [[0.5, −0.5], [1, 0], [−1, 1], [0, −1]], b1 = [0, 0, 0, 0], W2 = [[1, 1, −1, −1], [0.5, −0.5, 0.5, −0.5]], b2 = [0, 0], W3 = [[1, −1]], b3 = [0], the pass for input [0, 1] is: z1 = [−0.5, 0, 1, −1] → a1 = [0.378, 0.500, 0.731, 0.269]; z2 = [0.378 + 0.500 − 0.731 − 0.269, 0.189 − 0.250 + 0.366 − 0.134] = [−0.122, 0.170] → a2 = [0.469, 0.542]; z3 = 0.469 − 0.542 = −0.073 → y = 0.482, rounded to class 0 — wrong (expected 1). Input [1, 1]: z1 = [0, 1, 0, −1] → a1 = [0.500, 0.731, 0.500, 0.269]; z2 = [0.462, 0.000] → a2 = [0.614, 0.500]; z3 = 0.114 → y = 0.528, rounded to class 1 — also wrong. That is the point of the exercise: a bigger architecture still needs training; random numbers have no reason to encode XOR. What you should watch is the representation, not the accuracy — by a2 the two inputs are already different points, and after Lesson 03.03 teaches these weights, the same 4-layer chain separates them.
Implement count_parameters on your Network class: for each layer, add (neurons × inputs) + neurons. Test it on 784-256-128-10, the classic MNIST architecture. How many parameters does it have?Show one worked answer
Layer 1: 784 × 256 + 256 = 200,960. Layer 2: 256 × 128 + 128 = 32,896. Layer 3: 128 × 10 + 10 = 1,290. Total: 200,960 + 32,896 + 1,290 = 235,146 trainable numbers. For scale: the lesson's 2-2-1 XOR network has 9, the 2-8-1 circle classifier has 33, and a deeper MNIST variant 784-512-256-128-10 has 401,920 + 131,328 + 32,896 + 1,290 = 567,434. The first layer alone is 85% of the shallow network's parameters — which is why deep networks push the work into later layers instead of widening the first one.
Change the circle classifier's hidden layer from 8 neurons to 2, then to 32. Run the forward pass with random weights each time. Does the number of hidden neurons change the output range, the distribution of outputs, or the parameter count? Why?Show one worked answer
Parameter counts: 2 hidden neurons → layer 1 (2×2 + 2) = 6, layer 2 (2×1 + 1) = 3, total 9; 8 neurons → 24 + 9 = 33; 32 neurons → 96 + 33 = 129 (in general 4N + 1). The output range never changes: sigmoid always lands in (0, 1), whatever N is. What changes is the distribution. The output pre-activation is z₂ = Σ wᵢhᵢ + b over N random terms, so its spread grows roughly with √N while the mean drifts with Σwᵢ; more random features therefore push more outputs toward the saturated ends 0 and 1. That widening does not mean better classification — the features are still random, so accuracy stays near the majority-class baseline. Width changes capacity, not knowledge; knowledge is what training (Lesson 03.03) adds.
Replace sigmoid with a 'leaky step': return 0.01·z when z < 0, else 1.0. Run the same hand-tuned 2-2-1 XOR weights. Does it still classify all four inputs? Why is the smooth sigmoid still preferred?Show one worked answer
It still classifies all four. [0,0]: z1 = [−10, 30] → [−0.1, 1.0]; z2 = 20·(−0.1) + 20·1 − 30 = −12 → −0.12 → class 0. [0,1]: z1 = [10, 10] → [1, 1]; z2 = 20 + 20 − 30 = 10 → class 1. [1,0] is identical by symmetry → class 1. [1,1]: z1 = [30, −10] → [1, −0.1]; z2 = −12 → class 0. With weights of ±20 the nonlinearity only has to be approximately a step, so the exact shape barely matters at this scale. But training requires a slope: the leaky step is flat (derivative 0) for every z ≥ 0, so once a neuron is on, no gradient can tell it how to move, and the kink at 0 is not differentiable. Sigmoid's derivative σ(1−σ) is positive everywhere, so every neuron keeps receiving guidance — that is why smooth wins even when a hard step would work by hand.
Terms this lesson borrows from later lessons (or outside)
You do not need to master these here. Each one gets a proper treatment in its own lesson; the one-line meaning is enough to keep reading. Orange dotted underlines in the prose point back to this list.
dot product — Multiply two equal-length vectors element by element and sum: [2, 3]·[4, 5] = 2·4 + 3·5 = 23. One neuron's weighted sum is exactly one dot product between its weight row and its input vector. (Phase 1, Lessons 01–02)
matrix–vector product — W @ x stacks one dot product per row of W: a (3, 2) matrix turns a 2-number vector into a 3-number vector. That is the linear half of every layer. (Phase 1, Lesson 02)
logistic regression — A one-neuron classifier: dot product, add bias, pass through sigmoid, threshold at 0.5. A dense layer is logistic regression whose features are another layer's outputs — which is why a 2-8-1 network is a logistic model of eight learned features. (Phase 2, Lesson 03)
gradient descent — The loop that nudges every weight downhill on the loss surface. This lesson builds the forward half of training; Lesson 03.03 builds the backward half that produces those nudges. (Phase 1, Lesson 08; Phase 2, Lesson 02)
overfitting — Fitting the quirks of the training rows instead of the pattern. Every extra parameter is a new chance to do that, which is why Exercises 2 and 3 count parameters instead of trusting 'more neurons, better model'. (Phase 2, Lesson 10)
KEEP GOING
A picture is a start. Practice is the rest.
This lesson is a port of an open course. Everything here traces back to it — and the next step is running the code yourself.
Lesson text adapted from AI Engineering from Scratch (Phase 03, Lesson 02) and the Math Foundations Notebook reference build. The six labs (forward-pass playground, hand-forward stepper, shape checker, composition lab, universal-approximation bump lab, XOR hidden-space view), the full 2-2-1 XOR table with activations to six decimals, the second 2-3-1 worked pass, the W₂W₁ collapse check, the parameter counts for the classic architectures, the width-sweep and leaky-step exercise traces, and the factory quality-gate scenario are original to this page. Every number shown is computed live by the labs or verified by hand in the prose.