๐Ÿ“š Study Notes / Home / Neural Nets / Session 3
Session 03 ยท Perceptron to MLP

From Perceptron to Multi-Layer Perceptron

Welcome back! Last time we asked why deep learning works. Today we build the actual machine โ€” starting from a single tiny artificial neuron and stacking it up into a real network. We assume you've studied none of this before. Every topic begins with a tiny "explain like I'm 5" story, then we go deeper with the real math and a little code. Take it slow โ€” by the end you'll know exactly what a neural network is.

โฑ 20 min read๐Ÿ“– 4 topics

1 The perceptron โ€” a single artificial neuron


Explain like I'm 5

Imagine a tiny doorman deciding whether to let you into a party. He has a checklist: "Are you on the guest list?", "Did you bring a gift?", "Are you wearing shoes?" Some questions matter a lot to him, some barely matter. He adds up the answers โ€” giving more weight to the ones he cares about โ€” and if the total is high enough, he opens the door. That little yes/no doorman is exactly what a perceptron is.

A perceptron is the simplest possible artificial neuron โ€” and the building block of every neural network. It was invented by Frank Rosenblatt in 1958, inspired by how a real brain cell works. Let's build it up piece by piece, because once you understand this one tiny unit, the whole rest of the course is just "lots of these, stacked together."

The biological analogy

A real brain cell (a neuron) receives little electrical signals through branches called dendrites. If the combined signal is strong enough, the neuron "fires" and sends its own signal down its axon to the next neuron. If the signal is too weak, it stays quiet. The artificial perceptron copies this idea exactly: take in several inputs, combine them, and either "fire" (output 1) or stay quiet (output 0).

The parts of a perceptron

PartSymbolWhat it does
Inputsxโ‚, xโ‚‚, โ€ฆ, xโ‚™The numbers coming in (like the doorman's questions).
Weightswโ‚, wโ‚‚, โ€ฆ, wโ‚™How much each input matters. A big weight means "this input is important."
BiasbA built-in nudge โ€” how eager the neuron is to fire even before seeing any input.
Weighted sumzAll inputs multiplied by their weights and added up, plus the bias.
Activationstep()The final decision: fire (1) or stay quiet (0).

The formula

First the neuron computes the weighted sum โ€” multiply each input by its weight, add them all up, then add the bias:

# Weighted sum (also called the "pre-activation", z)
z = (w₁·x₁) + (w₂·x₂) + … + (wₙ·xₙ) + b

# In compact form, where ∑ means "add up all of them":
z = ∑(wᵢ · xᵢ) + b

Then it passes z through a step activation function to make the final yes/no decision:

# Step function: fire if the sum clears the threshold (here, 0)
output = 1   if z >= 0
output = 0   if z <  0
Why a bias?

The bias b shifts the threshold. With a big positive bias, the neuron fires easily (an eager doorman). With a big negative bias, it's very hard to make it fire (a strict doorman). Without a bias, the neuron would be forced to fire exactly when the weighted inputs hit zero โ€” which is rarely what we want. The bias gives it freedom to set its own threshold.

Worked example: a perceptron that acts like AND

Let's build a perceptron that outputs 1 only when both inputs are 1 (the logical AND). We'll use weights w₁ = 1, w₂ = 1, and bias b = -1.5. Now feed it every combination:

x₁x₂z = x₁+x₂ − 1.5step(z)
000 + 0 − 1.5 = −1.50
010 + 1 − 1.5 = −0.50
101 + 0 − 1.5 = −0.50
111 + 1 − 1.5 =  0.51

It fires (outputs 1) only on the last row, exactly when both inputs are 1. We just built a logic gate out of one neuron, purely by choosing the right weights and bias!

The same thing in code

def perceptron(inputs, weights, bias):
    # weighted sum: multiply each input by its weight, add them, add bias
    z = bias
    for x, w in zip(inputs, weights):
        z = z + x * w
    # step activation: fire if the sum reaches the threshold
    return 1 if z >= 0 else 0

# Our AND neuron from above
print(perceptron([1, 1], [1, 1], -1.5))   # -> 1
print(perceptron([1, 0], [1, 1], -1.5))   # -> 0
Key takeaway

A perceptron does just three things: weight its inputs, sum them (plus a bias), and fire if the total clears a threshold. "Learning" later will just mean automatically finding good weights and biases โ€” that's the whole game.

Recap A perceptron is a tiny artificial neuron: inputs × weights, summed with a bias to get z, then a step function turns z into a 1 or 0. Choose the weights and bias well and a single neuron can act like a logic gate (we built AND).

2 Activation functions โ€” adding the spark


Explain like I'm 5

Imagine a light dimmer switch. A plain on/off switch can only do two things โ€” fully on or fully off. A dimmer can do anything in between: dim, medium, bright. An activation function is the dimmer switch of a neuron. It decides how the neuron turns its inner sum into an output โ€” and choosing a smart dimmer is what lets a network learn curvy, complicated patterns instead of just straight lines.

In Topic 1 we used the simplest activation: the hard step function. But the step has a problem โ€” it's flat everywhere and then jumps suddenly, which makes it impossible to train with the smooth math we'll meet in Session 4. So in practice we use smoother activation functions. They do two jobs: shape the output into a useful range, and โ€” crucially โ€” add non-linearity.

Why non-linearity is essential

This is the single most important idea in this topic, so let's be careful. A linear operation is just "multiply and add" โ€” it can only draw straight lines (or flat planes). Here's the catch: if you stack many neurons that only multiply and add, the whole stack collapses back into one big multiply-and-add. A pile of straight lines is still just a straight line.

The big idea

Without a non-linear activation between layers, a 100-layer network is mathematically identical to a single layer โ€” useless. The non-linearity is what lets stacked neurons bend and fold the space, so the network can learn curves, corners, and complex patterns. No activation = no deep learning.

The common activation functions

Let's meet the cast. Each takes the weighted sum z and reshapes it.

Sigmoid

The sigmoid squashes any number into the range 0 to 1, smoothly. Big positive numbers โ†’ near 1; big negative โ†’ near 0; zero โ†’ exactly 0.5. Great for representing a probability.

sigmoid(z) = 1 / (1 + e^(−z))

z:  −6   −2    0    2    6
σ:  0.00 0.12 0.50 0.88 1.00   # a smooth S-shaped curve

Tanh

The tanh (hyperbolic tangent) is sigmoid's cousin, but it squashes into the range −1 to +1 and is centred at 0. Being zero-centred often makes training a little easier than sigmoid.

tanh(z) = (e^z − e^(−z)) / (e^z + e^(−z))

z:    −3    0    3
tanh: −0.99 0.00 0.99   # S-shaped, but spanning −1 to +1

ReLU

The ReLU (Rectified Linear Unit) is the workhorse of modern deep learning. It's brutally simple: if the input is positive, pass it through unchanged; if it's negative, output 0. Fast to compute and it dodges a big problem we'll meet in a moment.

ReLU(z) = max(0, z)

z:    −3  −1   0   2   5
ReLU:  0   0   0   2   5   # a flat floor, then a straight ramp up

Leaky ReLU

Plain ReLU has one weakness: if a neuron's input is always negative, it outputs 0 forever and stops learning (a "dead neuron"). Leaky ReLU fixes this by letting a tiny slope through on the negative side instead of a hard zero.

LeakyReLU(z) = z        if z > 0
LeakyReLU(z) = 0.01 * z if z <= 0

z:    −3     −1     0   2
out:  −0.03  −0.01  0   2   # a gentle slope instead of dead-flat zero

Softmax

The others handle one neuron at a time. Softmax is different: it takes a whole row of output scores and turns them into a set of probabilities that add up to 1. It's used at the very end of a classifier to answer "which class is this?" (You saw softmax in the GenAI course turning model scores into probabilities โ€” same function, same job.)

softmax(zᵢ) = e^(zᵢ) / ∑ e^(zⱼ)   # divide each by the total

scores [2.0, 1.0, 0.1]  →  softmax  →  [0.66, 0.24, 0.10]
                                          # adds up to 1.00 = 100%

Pros and cons at a glance

FunctionOutput rangeProsCons
Step0 or 1Simplest; pure decision.Not smooth โ†’ can't train with gradients.
Sigmoid0 to 1Smooth; reads like a probability.Saturates at the ends โ†’ vanishing gradients; not zero-centred.
Tanh−1 to 1Smooth and zero-centred.Still saturates โ†’ vanishing gradients.
ReLU0 to ∞Fast; avoids vanishing gradient for positive inputs; today's default."Dead neurons" if stuck negative.
Leaky ReLU−∞ to ∞Fixes dead neurons with a small negative slope.Extra tiny knob (the leak slope) to choose.
Softmax0 to 1 (sums to 1)Turns scores into class probabilities.Only for the output layer of a classifier.
The vanishing-gradient hint

Notice that sigmoid and tanh go almost flat at their extremes. When the curve is flat, its slope is nearly zero. In Session 4 (Backpropagation) we'll learn that networks improve by following slopes โ€” so a near-zero slope means an early layer barely gets a learning signal. In a deep network these tiny slopes multiply together and shrink to almost nothing โ€” the vanishing-gradient problem. This is the main reason ReLU largely replaced sigmoid/tanh in deep hidden layers. Hold that thought for next session.

Worked example: same z, different activations

Suppose a neuron computes a weighted sum of z = −2. What comes out depends entirely on its activation function:

  • Step โ†’ 0 (since −2 < 0, it stays quiet)
  • Sigmoid โ†’ 0.12 (a small probability)
  • Tanh โ†’ −0.96 (strongly negative)
  • ReLU โ†’ 0 (negatives become zero)
  • Leaky ReLU โ†’ −0.02 (a tiny leak gets through)

Same input, five different "personalities." Choosing the activation is a real design decision.

Recap Activation functions reshape a neuron's weighted sum and, crucially, add non-linearity โ€” without it, stacked layers collapse into one. Sigmoid/tanh are smooth S-curves that can saturate (hinting at vanishing gradients); ReLU and Leaky ReLU are the fast modern defaults for hidden layers; softmax turns final scores into class probabilities.

3 Multi-Layer Perceptrons (MLP)


Explain like I'm 5

One doorman (a perceptron) can only make a simple decision. But imagine a whole office: the front-desk people each notice one small thing, pass notes to a middle team, who combine those notes and pass them to a boss who makes the final call. Each person is simple, but as a team passing messages forward they can solve hard problems. That team of neurons, organised in rows, is a Multi-Layer Perceptron.

A Multi-Layer Perceptron (MLP) is what you get when you stop using one neuron and instead organise many of them into layers. This is, finally, a real neural network. There are three kinds of layer:

๐Ÿ“ฅ
Input layer
The raw numbers you feed in
โ†’
๐Ÿง 
Hidden layer(s)
Neurons that find patterns
โ†’
๐Ÿ“ค
Output layer
The final answer
  • The input layer isn't really neurons โ€” it's just your data (one slot per feature, e.g. the brightness of each pixel).
  • One or more hidden layers sit in the middle. They're called "hidden" because you never see their values directly โ€” they're the network's internal scratch work. This is where patterns get built up.
  • The output layer produces the final result (one neuron for yes/no, or several with softmax for "which class").

Fully-connected layers

In a standard MLP, every neuron in one layer connects to every neuron in the next. That's called a fully-connected (or dense) layer. Each connection has its own weight, and each neuron has its own bias. A layer with 3 inputs and 4 neurons therefore has 3 × 4 = 12 weights plus 4 biases to learn.

"Deep" just means more hidden layers

That's the whole secret behind the word deep in "deep learning" โ€” a network with many hidden layers stacked up is a deep network. Each layer learns slightly more abstract features than the one before (edges โ†’ shapes โ†’ objects, for an image).

The forward pass with matrix math

Running data through the network from input to output is called the forward pass. We could compute each neuron one at a time like in Topic 1, but it's far cleaner to do a whole layer at once with a matrix. For one layer:

# x = inputs (a row of numbers)
# W = weight matrix (one column per neuron in this layer)
# b = bias vector (one per neuron)
# f = the activation function

z = x · W + b          # matrix multiply, then add biases  (the weighted sums)
a = f(z)              # apply activation elementwise        (the layer's output)

The output a of one layer becomes the input x of the next. Repeat through every layer and the final a is your answer. That's the entire forward pass.

Worked forward pass: 2 inputs โ†’ 2 hidden โ†’ 1 output

Tiny network. Inputs x = [1, 0]. Hidden layer has 2 neurons using ReLU; output layer has 1 neuron using sigmoid. Watch the numbers flow:

# ---- Given weights & biases ----
x  = [1, 0]                 # the input

# Hidden layer: 2 inputs -> 2 neurons
W1 = [[ 0.5, -0.4],         # weights from x1 to (h1, h2)
      [ 0.8,  0.2]]         # weights from x2 to (h1, h2)
b1 = [0.1, -0.1]

# Output layer: 2 inputs -> 1 neuron
W2 = [[1.0],
      [0.6]]
b2 = [0.2]

# ---- Step 1: hidden weighted sums  z1 = x·W1 + b1 ----
h_z1 = 1*0.5 + 0*0.8 + 0.1  =  0.6     # neuron h1
h_z2 = 1*(-0.4) + 0*0.2 - 0.1 = -0.5   # neuron h2

# ---- Step 2: hidden activation (ReLU) ----
h1 = ReLU(0.6)  = 0.6
h2 = ReLU(-0.5) = 0.0                   # negative -> clamped to 0
h  = [0.6, 0.0]

# ---- Step 3: output weighted sum  z2 = h·W2 + b2 ----
o_z = 0.6*1.0 + 0.0*0.6 + 0.2  =  0.8

# ---- Step 4: output activation (sigmoid) ----
output = sigmoid(0.8) = 0.69            # final answer ~ 69%

Every number above came purely from multiplying, adding, and applying an activation โ€” exactly the perceptron from Topic 1, just done many times and chained layer to layer.

The same forward pass in code

import numpy as np

def relu(z):    return np.maximum(0, z)
def sigmoid(z): return 1 / (1 + np.exp(-z))

x  = np.array([1.0, 0.0])
W1 = np.array([[0.5, -0.4], [0.8, 0.2]])
b1 = np.array([0.1, -0.1])
W2 = np.array([[1.0], [0.6]])
b2 = np.array([0.2])

h = relu(x @ W1 + b1)        # hidden layer  -> [0.6, 0.0]
y = sigmoid(h @ W2 + b2)     # output layer  -> [0.69]
print(y)                     # -> [0.69...]
Key takeaway

An MLP is just neurons arranged in layers, fully connected, run front-to-back. The forward pass is the same move repeated: multiply by weights, add bias, apply activation, then hand the result to the next layer. Matrices let us do a whole layer in one line.

Recap A Multi-Layer Perceptron stacks neurons into input, hidden, and output layers, fully connected. The forward pass pushes data through with a = f(x·W + b) at each layer, feeding one layer's output into the next. More hidden layers = "deeper" = more abstract patterns.

4 The XOR problem โ€” why we need hidden layers


Explain like I'm 5

Imagine four toys on the floor: two red ones in opposite corners, two blue ones in the other two corners. Now try to separate the reds from the blues by laying down a single straight piece of string. You can't โ€” no matter how you angle it, a red and a blue end up on the same side! You'd need to bend the string. That bend is exactly what a hidden layer gives a neural network.

The XOR problem ("exclusive OR") is the most famous puzzle in neural network history. XOR outputs 1 when the two inputs are different, and 0 when they're the same:

x₁x₂XOR output
000 (same)
011 (different)
101 (different)
110 (same)

Why a single perceptron CANNOT solve XOR

Recall from Topic 1 that a perceptron fires when w₁x₁ + w₂x₂ + b >= 0. That equation draws a single straight line through the input space, and the perceptron says "1 on this side, 0 on that side." So a perceptron can only solve problems that are linearly separable โ€” ones you can split with one straight line.

Now plot the four XOR points on a grid and mark which should output 1:

x2
 1 |  ●(0,1)=1        ○(1,1)=0
   |
   |
 0 |  ○(0,0)=0        ●(1,0)=1
   +-------------------------- x1
        0                 1

   ● = should output 1     ○ = should output 0

The two "1" points sit in opposite corners (bottom-right and top-left). The two "0" points sit in the other opposite corners. There is no single straight line that puts both โ—'s on one side and both โ—‹'s on the other. Try it โ€” every line you draw gets at least one point wrong. XOR is not linearly separable, so one perceptron is mathematically incapable of solving it.

The moment that nearly killed neural networks

In 1969, Minsky and Papert's book Perceptrons proved exactly this limitation. The field lost confidence and funding dried up for years โ€” the first "AI winter." The fix was known in principle (add a hidden layer) but a good way to train such networks didn't catch on until backpropagation became popular in the 1980s โ€” which is precisely our next session.

Why a 2-layer MLP CAN solve XOR

The trick: use a hidden layer to first transform the problem into one that is linearly separable. Each hidden neuron draws its own line; the output neuron then combines those lines to carve out a bent boundary. A classic solution uses two hidden neurons that compute simpler gates, then combines them:

โ‘ 
Hidden h₁
acts like OR (is either input on?)
โ†’
โ‘ก
Hidden h₂
acts like AND (are both on?)
โ†’
โ‘ข
Output
"OR but NOT AND" = XOR

The insight in plain English: XOR means "at least one input is on, but not both." That's exactly OR minus AND โ€” and each of those is a straight-line (linearly separable) problem a single neuron can do. The hidden layer computes OR and AND; the output layer subtracts.

Worked example: an MLP that solves XOR

Two hidden neurons (h₁ = OR, h₂ = AND) using a step activation, then an output neuron that fires for "OR is on AND AND is off." Concrete weights:

# Hidden neuron h1 (OR):   fires if x1 + x2 - 0.5  >= 0
# Hidden neuron h2 (AND):  fires if x1 + x2 - 1.5  >= 0
# Output (XOR):            fires if  h1 - h2 - 0.5 >= 0
#                          ( = "OR is on, but AND is not" )

Run all four inputs through it:

x₁x₂h₁ (OR)h₂ (AND)h₁ − h₂ − 0.5OutputXOR?
0000−0.50โœ“
0110 0.51โœ“
1010 0.51โœ“
1111−0.50โœ“

All four rows correct! What one perceptron couldn't do, two layers handle with ease โ€” because the hidden layer reshaped the problem into a linearly separable one.

Key takeaway

XOR is the textbook proof that hidden layers add real power. A single perceptron only draws one straight line, so it fails on patterns that aren't linearly separable. Stacking layers lets the network bend the boundary โ€” and that's why every useful neural network has hidden layers.

Recap XOR (output 1 when inputs differ) is not linearly separable, so one perceptron can never solve it โ€” the historic limitation Minsky & Papert proved. A 2-layer MLP solves it by having hidden neurons compute OR and AND, then combining them ("OR but not AND"). Hidden layers are what give neural networks their power.

โ˜… Putting it all together


You just built a neural network from scratch โ€” from one neuron all the way to a network that beats the famous XOR puzzle. Here's the one-paragraph story tying all four topics together:

A perceptron is a single artificial neuron: it takes inputs, multiplies each by a weight, adds them up with a bias to get the weighted sum, and fires through an activation function. Plain step activations can't be trained smoothly and can't bend space, so we use non-linear activations (sigmoid, tanh, ReLU, Leaky ReLU, softmax) โ€” without them, stacked layers collapse into one. Stacking neurons into input, hidden, and output layers gives a Multi-Layer Perceptron, run via the forward pass a = f(x·W + b) layer after layer. And the XOR problem shows exactly why we bother: one perceptron only draws a straight line and fails on non-linearly-separable data, but a hidden layer reshapes the problem so the network can solve it. Next session โ€” backpropagation โ€” we'll finally learn how the network finds all those weights and biases on its own.

Quick self-check

What are the three computations a perceptron performs?

It (1) multiplies each input by its weight, (2) sums them and adds the bias to get the weighted sum z, and (3) passes z through an activation function to produce the output.

Why do we need a non-linear activation function between layers?

Because stacking purely linear (multiply-and-add) layers collapses into a single linear layer. The non-linearity lets the network bend space and learn curves and complex patterns โ€” it's what makes depth meaningful.

What does the bias do in a neuron?

It shifts the firing threshold. A positive bias makes the neuron fire more easily; a negative bias makes it harder to fire. Without it, the threshold is stuck at zero.

Why can't a single perceptron solve XOR?

A perceptron can only separate data with one straight line (linearly separable problems). XOR's two "1" points sit in opposite corners, so no single line can split the 1s from the 0s.

How does a 2-layer MLP manage to solve XOR?

The hidden layer computes simpler linearly-separable functions (e.g. OR and AND), and the output layer combines them ("OR but not AND"). The hidden layer reshapes the problem into one that's linearly separable.

Why is ReLU often preferred over sigmoid in hidden layers?

Sigmoid saturates (goes flat) at its extremes, giving near-zero slopes that cause the vanishing-gradient problem in deep networks. ReLU stays linear for positive inputs, keeping gradients healthy, and it's faster to compute.

๐Ÿ“š References & Further Reading


Class material

Papers, docs & deep dives