Compose a multilayer perceptron
A multilayer perceptron, or MLP, is neurons arranged in layers. A hidden layer holds several neurons that all read the same inputs, each with its own weights and bias, and each gives one number. An output neuron then takes a weighted sum of those numbers. One layer feeding the next is all there is to it. With enough hidden neurons, this shape can fit almost any curve.
Learn it
Words to know
- hidden layer
- A layer of neurons between the input and the output. Its values are not seen from outside.
- forward pass
- Running input through the model, layer by layer, to get its output.
- ReLU
- The function
max(0, x). It keeps positive numbers and turns everything else into 0.
How it works
Wholds one row of weights per hidden neuron. For each row, take the dot product with the inputxand add that neuron's bias.- Pass each result through ReLU. These are the hidden values, one per hidden neuron.
- Output: the dot product of the hidden values and
out_weights, plusout_bias.
Worked example
Input x = [1, -2] W = [[1, 0], [0, 1]] bias = [0, 0] out_weights = [2, 3] out_bias = 1 Output 3
| What | Calculation | Value |
|---|---|---|
| Hidden neuron 1 | ReLU(1×1 + 0×(-2) + 0) | 1 |
| Hidden neuron 2 | ReLU(0×1 + 1×(-2) + 0) | ReLU(-2) = 0 |
| Output | 2×1 + 3×0 + 1 | 3 |
The second hidden neuron got -2, and ReLU turned that into 0. Its output weight of 3 then has nothing to multiply.
Why it matters
Every transformer block in a GPT ends with a small MLP like this one. The digit classifier in chapter 4 is one layer of it.
Your turn
Run the forward pass of a small network for one input: a hidden layer with ReLU, then a single output neuron.
x- the input, a list of numbers
W- the hidden weights: one row per hidden neuron, each row as long as
x bias- one bias per hidden neuron
out_weights- one weight per hidden neuron, for the output
out_bias- the bias of the output
- Returns
- One number: the hidden values dotted with
out_weights, plusout_bias.
Example 1
Input x = [1, -2] W = [[1, 0], [0, 1]] bias = [0, 0] out_weights = [2, 3] out_bias = 1 Output 3
The hidden values are 1 and 0. The output is 2 × 1 + 3 × 0 + 1 = 3.
Example 2
Input x = [0] W = [[1]] bias = [0] out_weights = [2] out_bias = 0 Output 0
One hidden neuron with input 0 gives a hidden value of 0, and the output is 2 × 0 + 0 = 0.
Example 3
Input x = [2] W = [[1]] bias = [1] out_weights = [-1] out_bias = 0.5 Output -2.5
The hidden value is ReLU(2 + 1) = 3. The output is -1 × 3 + 0.5 = -2.5. It can be negative, because the output has no ReLU.
Example 4
Input x = [1, 2] W = [[1, 1], [-1, 1]] bias = [-1, 0.5] out_weights = [2, -1] out_bias = 0.5 Output 3
The hidden values are ReLU(3 - 1) = 2 and ReLU(1 + 0.5) = 1.5. The output is 4 - 1.5 + 0.5 = 3.
Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1: Where to start
Two stages. First build the list of hidden values, one per row of
W. Then combine that list into one number.Hint 2: The key step
Each hidden value is the linear model from chapter 1, followed by
max(0, ...): dot the row withx, add that neuron's bias, apply ReLU.Hint 3: The outline
For each
rowandbfromzip(W, bias): add upweight * valueoverzip(row, x), addb, and appendmax(0, total)tohidden. Then add uph * weightoverzip(hidden, out_weights)and addout_bias.
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
Step by step
- One hidden value per row of W: weighted sum, bias, ReLU. Every hidden neuron reads the same input
xbut has its own row of weights and its own bias, so each can react to something different. - The output neuron: a weighted sum of the hidden values. The output has no ReLU here, so it can be any number, positive or negative.
The same numbered steps are the comments in the solution.
Python
def solve(x, W, bias, out_weights, out_bias):
# 1. One hidden value per row of W: weighted sum, bias, ReLU
hidden = []
for row, b in zip(W, bias):
total = b
for weight, value in zip(row, x):
total += weight * value
hidden.append(max(0, total))
# 2. The output neuron: a weighted sum of the hidden values
output = out_bias
for h, weight in zip(hidden, out_weights):
output += h * weight
return outputWatch out
- Apply ReLU to each hidden value, not to the final output. This exercise leaves the output as a plain weighted sum.
- Each hidden neuron has its own bias. Pair the rows of
Wwithbias, one to one.
Check yourself
What does each row of the hidden weight table stand for?
One hidden neuron: the weights it puts on each input.
Why is there an activation between the two layers?
Without it the two weighted sums would combine into a single weighted sum, and the hidden layer would add nothing.