ML Systems Lab Open interactive version →
Foundational 31 min read neural networksuniversal approximationdepthperceptron

Neural Network Fundamentals

Hidden layers, universal approximation, depth vs width, XOR

Take two on/off inputs, x₁ and x₂, and try to learn XOR: output 1 when *exactly one* input is on, and 0 otherwise. Plot the four cases on a grid and try to separate the 1s from the 0s with a single straight line. You cannot — the 1s sit on one diagonal, the 0s on the other. This is not a data problem or a tuning problem; it is a hard limit. A single linear model can only draw *one* straight boundary, and XOR needs the space bent. And here is the thing: *every* problem a neural network solves is, deep down, this same problem — the input cannot be split as-is, so the model has to reshape it first.


One hidden layer is the fix

Slip a layer of two neurons between the inputs and the output, pass each through a non-linear squash, and suddenly the network can draw curved, bent, folded boundaries. For XOR: one hidden neuron learns to fire whenever *either* input is on — an OR gate, active on three of the four cases — and the other fires only when *both* are on — an AND gate, active on just one case. Neither neuron alone can fire only on the "exactly one on" cases: that pattern is XOR itself, and no single linear-plus-squash unit can separate it (push the weights high enough to fire on (0,1) and (1,0) and you necessarily also fire on (1,1)). It's the *combination* — OR minus AND, i.e. OR-and-not-AND — that fires only on "exactly one on." The hidden layer has *transformed* the input into a new space where a straight line finally works — and that is what every hidden layer in every network is doing: reshaping the representation until the decision becomes easy. Mechanically, each layer computes a = sigma(Wx + b), where W is shape output-units by input-units -- so a layer with 512 inputs and 256 outputs has a 256x512 weight matrix (131,072 weights) plus one bias per output unit (256), 131,328 parameters total -- that shape convention and parameter count is what every layer in this course means by "the forward pass."


How wide, how deep?

The universal approximation theorem says something reassuring: a network with a *single* hidden layer, given enough neurons, can approximate *any* continuous function as closely as you like. So why go deep at all? Because "enough neurons" in one layer can be astronomically many — sometimes exponential in the number of inputs — while a *second* layer can represent the same function with far fewer neurons. That is the real case for depth: not "deeper is magically more accurate," but "depth lets you represent complex functions far more *efficiently*, with fewer parameters." For structured inputs like images this efficiency shows up as hierarchy: each layer can compose the previous layer's features into something more complex — edges combine into textures, textures into object parts, parts into whole objects — and a single very wide layer that maps pixels straight to output units has no way to reuse a detected edge across multiple higher-level features the way stacked layers do. Hierarchical composition and parameter-efficiency are the same underlying argument for depth, just visible in different domains.

But — and this matters — the theorem only says a good solution *exists* at depth. It says nothing about whether gradient descent will *find* it. A careless 10-layer network can have its early layers starved of gradient (the vanishing-gradient problem) and simply not learn. That is why so much of deep learning — better activations, normalisation, residual connections — exists purely to make depth *trainable*. Depth buys efficiency; the rest of the toolkit buys the ability to actually use it.


How does the network actually learn these weights?

Everything above is the *forward pass* — matrix multiplies and squashes, turning an input into a prediction from weights that are already fixed. Training is a loop of four steps, repeated thousands of times: forward pass (compute a prediction from the current weights, exactly as above), loss (a single number scoring how wrong that prediction was — mean squared error for a real-valued target, cross-entropy for a class label), backward pass (work out how much each individual weight contributed to that error), and update (nudge every weight a small step in the direction that reduces the loss, then repeat from the top). This module has only covered the first step. The next module, Backpropagation, is entirely about the third — the one that looked hopeless (a network can have a hundred million weights, each seemingly needing its own gradient computation) until a single trick made it cheap. For now, the one thing worth fixing in your head before moving on: the *loss function has to match what the output represents* — get that pairing wrong and the gradients you compute in the next module point nowhere useful.

Key points

Takeaway

Depth buys representational efficiency, not accuracy for free — every layer must receive gradient signal or it contributes nothing, which is why the entire architecture of modern deep learning is an answer to the question of how to make depth trainable.

Recap

Check your understanding

Q1. A fully connected layer with 512 inputs and 256 outputs has how many parameters? What is the forward pass computation?

Q2. Universal approximation theorem says a neural network can approximate any continuous function. Why doesn't this guarantee good generalisation?

Q3. Two hidden layers with 64 units each vs one hidden layer with 4096 units, roughly matched in parameter count — which TWO statements about image recognition are correct?

Try it interactively

ML Systems Lab is a free interview-prep platform for ML engineers — work through the full interactive module, quizzes, and drills.

Open ML Systems Lab →