🗺️ What we'll cover
A neural network is a pile of multiplications, additions, and one elegant calculus trick. This class builds the whole thing from scratch, in one sitting, with sliders you can drag and switches you can flip at every step.
x²
and watch the tangent swing. Chain speed × grade on an ATV.
y = w·x + b
, weights vs bias, five data points.
loss.backward()
chain-rule for us.
🎛️ How to drive this class
Every tab has at least one INTERACTIVE panel. The story text is for reading. The panels are for doing . Read one paragraph, then go play with the widget above or below it, then come back. That's the whole recipe.
- Sliders — drag to change a value. The formulas, plots, and numbers update live.
- Buttons — a Step button does one gradient step; a Run button trains continuously; a Reset button zeroes everything.
- Switches — click bit-inputs on / off, choose a GPU, or toggle inference vs training.
- Canvases — live plots redraw on every interaction; nothing is pre-rendered.
Nothing sends anything anywhere — everything runs in your browser. Refresh the page at any time to start over.
🎯 Two ideas you need before you touch a neural network
A neural network is just a pile of multiplications and additions that we adjust to make its outputs less wrong. To do the adjusting, you need exactly two tools from calculus:
- Derivatives — how much does an output change when you nudge an input?
- The chain rule — how do you chain those nudges together across a pipeline of operations?
Everything in this deck — forward pass, loss, backprop, PyTorch's
loss.backward()
— is these two ideas applied relentlessly. So let's spend five minutes on them first.
📐 Derivatives — the slope at a point
A derivative answers one question: if I move the input by a tiny amount, how much does the output move? That ratio — output change over input change, in the limit — is the slope of the function at that point.
At x = 3, the slope is 2·3 = 6. That means: nudging x up by 0.001 makes x² go up by roughly 0.006. Not exact, but very close — and the smaller the nudge, the better the approximation. (3.001)² − 3² = 9.006001 − 9 = 0.006001. The 0.000001 extra is what vanishes in the limit.
Derivative playground — drag x, watch the tangent
Blue curve = f(x) = x². Orange line = the tangent at the current x. At x = 0 the slope is flat; push x further out and the tangent steepens quadratically. That's what df/dx = 2x says in one sentence.
Power rule
For any x raised to a power n:
x² → 2x, x³ → 3x², x⁴ → 4x³
Constants vanish
Constants don't change when you nudge x — so their derivative is zero.
This is why
y_true
drops out of loss gradients — it's constant with respect to the weights.
🔗 The chain rule — nudges flow through pipelines
Real functions aren't single terms. They're pipelines: you transform x to get an intermediate value, then transform that to get another, then finally get the output. The chain rule says: to get the end-to-end derivative, multiply the derivatives of each step along the way.
In words: how x affects y = (how g affects y) × (how x affects g). Each arrow in the pipeline contributes one factor.
Example: y = (3x + 1)²
Split into two stages:
-
Inner:
u = 3x + 1→ du/dx = 3 -
Outer:
y = u²→ dy/du = 2u
Chain them: dy/dx = 2u · 3 = 6(3x + 1) . One function, two nudges, multiplied.
🏍️ The chain rule, ATV version — Monteverde
You're on an ATV descending from a ridge in Monteverde. You want to know: how fast is my altitude dropping per minute? Two things feed into that:
-
Speed
: how much distance you cover per unit time —
dx/dt = 30 km/h -
Grade
: how much altitude you lose per unit distance —
dh/dx = −32 m/km
The km units cancel. You drop 960 meters per hour — faster if you speed up, faster if the grade steepens. Neither factor alone tells you the answer. The chain rule chains them.
ATV chain rule — twist the throttle, change the grade
Two nudges, multiplied. Double the speed → twice the altitude-rate. Double the grade → twice the altitude-rate. Exactly the structure backprop uses to chain gradients through a pipeline of operations.
🍂 The chain rule of composting
Another version — same math. You're composting. Three things speed up decomposition, and they multiply :
4 × 3 × 2 = 24×
| Factor | Value | Meaning |
|---|---|---|
| shred | 4× | surface area |
| turn | 3× | oxygen |
| heat | 2× | temperature |
| total | 24× | final multiplier |
Now the backward pass — which factor matters most right now?
∂speedup/∂turn = shred × heat = 4 × 2 = 8
∂speedup/∂heat = shred × turn = 4 × 3 = 12
Heat has the biggest gradient → improving heat gives you the most bang for your buck. That's exactly how a neural network decides which weight to adjust most: compute each parameter's gradient, update most where the gradient is largest.
Composting chain rule — turn the knobs, see which one dominates
Backward pass — gradient per factor
Heat wins — improving it gives the most speedup per unit effort. Raise heat or drop it and watch which gradient overtakes.
🧠 The first neuron — McCulloch & Pitts, 1943
Before there were CNNs, transformers, or GPUs, there was a paper in the Bulletin of Mathematical Biophysics , Volume 5, 1943. Warren McCulloch (a neurophysiologist) and Walter Pitts (an 18-year-old homeless mathematical prodigy) proposed the first mathematical model of a neuron.
Their claim was audacious: cognition could be explained as computation performed by interconnected binary threshold units. That model is the root of everything in modern deep learning.
The McCulloch–Pitts neuron
- Inputs arrive as binary signals (0 or 1).
- Each input has a weight — "how much do I trust this signal?"
- Sum the weighted inputs.
- Compare to a threshold. Above it → fire (output 1). Below it → silent (output 0).
Build your own McCulloch–Pitts neuron
Flip the inputs, tune the weights, slide the threshold. The neuron fires whenever the weighted sum clears the bar. Try this: make an AND gate (threshold = 3, weights = 1), then change it to OR (threshold = 1), then NAND (negate a weight), XOR (you can't — one of the original papers' most famous limits).
Try these presets
🍜 Neural network alphabet soup
Before we build one from scratch, here's what's on the menu. Every "X-NN" you've heard of is a different way to wire neurons together for a different shape of data.
🖼️ CNN
🔁 RNN / LSTM
⚡ Transformer
🕸️ GNN
| |
(D)———(E)
US10740433B2
. A
residual connection
—
output = x + f(x)
, from He et al. 2015 (
Deep Residual Learning
) — is what lets attention layers stack deep. Interpretability researchers call the
accumulated sum across all those skip connections the
residual stream
.
KV cache
is a decode-time optimization: store past keys and values so next-token generation reuses
them instead of recomputing.
📈 Learning curve
A few honest warnings before we start coding:
- Transformers are not intuitive. Neither was the first time you saw a for-loop.
- A neural network can be implemented in a few lines of code — even a transformer . The math is harder than the code.
- A single line change inside a research codebase often represents a full published paper worth of thought. Read slowly.
- Patience is key. The concepts compound. What feels impossible at slide 30 is obvious by slide 80.
🧮 The simplest neural network
Strip a neural network to its bones and you get one line of math:
That's it. A weight w , an input x , a bias b , and an output y . A real neural network stacks millions or billions of these and pipes them through nonlinearities — but the fundamental unit is this single line. Understand it, and you understand what every weight in GPT-4 is doing.
Weights interpret evidence. They decide how much an input should push the output up or down. A big weight means "this signal matters a lot"; a near-zero weight means "ignore it."
Bias sets the default. It's the output when x = 0 — the prior belief before any evidence comes in. It lets the network shift its whole prediction up or down without changing how it weighs inputs.
🎛️ Why bias matters — real examples
Bias sounds mundane until you see where it hides in every modern network:
🧬 AlphaFold (protein folding)
"Attention with a bias." Bias terms in the attention layers encode structural priors about how amino acids pair up before any data is looked at.
💳 Fraud detection
Most transactions aren't fraud. A negative bias biases the model toward "not fraud" so it doesn't cry wolf on every charge.
🖼️ CNN filters — trigger sensitivity
Each convolutional filter has a bias that controls its trigger sensitivity. Consider a filter that detects vertical edges:
- Negative bias → only fires on strong, obvious edges
- Zero bias → fires on moderate edges
- Positive bias → fires on subtle gradients too
🎯 A concrete example
Let's pick specific numbers. Suppose the true relationship we want to model is:
The weight is 3, the bias is 1. If we feed it inputs 1 through 5, it should produce:
y = [ 4, 7, 10, 13, 16 ]
A story to hang this on: an object started 1 m from the origin and is moving at 3 m/s. y = 3·x + 1 is its position after x seconds. The network only sees the pairs — and has to rediscover the 3 and the 1.
Fit the line by hand — drag w and b
The five blue dots are the training data. The orange line is
your
current
y = w·x + b
. Try to line it up with the dots — the loss number below tells you how close.
The whole loss landscape is a parabolic bowl in (w, b) space — one unique minimum. Gradient descent's job is to roll down to the bottom of that bowl. You're doing it by hand right now.
Now here's the setup for learning: we have the inputs x and the true outputs y, but we don't know w or b. The job of the neural network is to figure them out from examples alone.
Initialize w and b to something — anything.
A common choice: both zero.
w = 0.0 ; b = 0.0
Make a prediction for every input.
Call it
y_pred = w·x + b
. At the start, all predictions are 0 — garbage.
Measure how wrong we are. Compute a loss: a single number that summarizes "how badly did this fail?"
Use the loss to adjust w and b so next time we're less wrong. Repeat until the loss is small.
💻 Forward pass — in real Python
Let's put real numbers through real code. The entire forward pass — from raw inputs to a single loss number — is a handful of numpy calls.
# Initial state w = 0.0 b = 0.0 X = np.array([1, 2, 3, 4, 5]) y = np.array([4, 7, 10, 13, 16]) # true values
Five training examples. We know what the right answer looks like. Now the forward pass:
# Forward pass with w=0, b=0 y_pred = w * X + b # y_pred = 0 * [1, 2, 3, 4, 5] + 0 # y_pred = [0, 0, 0, 0, 0]
Every prediction is zero. Predictably bad — we haven't trained anything yet. But the
structure
is there: five inputs, five predictions, all coming out of the same one-line formula
w·X + b
.
📉 Measuring how wrong we are — step by step
We need a single number that captures the total badness. Three stages:
# Error (prediction - truth) error = y_pred - y # error = [0-4, 0-7, 0-10, 0-13, 0-16] # error = [-4, -7, -10, -13, -16]
# Square it (makes everything positive, penalizes big errors more) squared_error = error ** 2 # squared_error = [16, 49, 100, 169, 256]
# Mean (average of all squared errors) loss = np.mean(squared_error) # loss = (16 + 49 + 100 + 169 + 256) / 5 # loss = 590 / 5 # loss = 118.0
loss = np.mean((y_pred - y) ** 2)
. The number itself doesn't matter yet — what matters is that we can
change w and b and watch this number go down
. That's what makes it a useful compass.
Per-point loss breakdown — drag w, watch every squared error squirm
Each bar is one training example's
squared_error
. Their mean is the MSE loss on the right. At
w = 0
, the big-x examples dominate — a squared error of 256 for x = 5. As you climb toward
w = 3
, all the bars collapse.
🎚️ From loss number to loss signal
We have loss = 118. But which direction should we push w? Which way for b? The loss alone doesn't say — it just reports the current damage.
To make a decision, we need to know:
if I nudge w a tiny bit, how does the loss change?
That's the derivative
∂L/∂w
. Same for the bias:
∂L/∂b
.
∂L/∂b = "nudge b a hair → how much does the loss move?"
These two numbers — a pair of gradients — are the entire steering system of the neural network. We're going to derive them next, using the chain rule you met in Tab 1.
🔗 Why we need the chain rule here
We want
∂(squared_error) / ∂w
. But
w doesn't appear in squared_error directly
. Trace the pipeline:
w affects y_pred, which affects error, which affects squared_error. So we chain the nudges, one stage at a time:
∂(squared_error) / ∂(error)
× ∂(error) / ∂(y_pred)
× ∂(y_pred) / ∂w
Three nudges, multiplied together. Exactly the same pattern as dh/dt = dh/dx · dx/dt from the ATV example — just with more stages.
🧮 Deriving each stage
How does w affect y_pred?
How does y_pred affect error?
y_true is a constant — its derivative is zero. Only y_pred moves.
How does error affect squared_error?
Power rule. The 2 comes from differentiating a square; the factor of error is what's left.
Now chain them:
🔬 Sanity-check by hand
Let's verify for the first training point, where x = 1, y_true = 4, y_pred = 0, error = −4. The chain-rule formula says:
Does that match what we'd get by literally nudging w? Let's check. Nudge w by 0.001 and recompute the squared error for the same point:
y_pred = 0.001 * 1 + 0 = 0.001 error = 0.001 - 4 = -3.999 squared_error = (-3.999)² = 15.992 # went from 16 to 15.992 → change of -0.008 # Δ(squared_error) / Δw = -0.008 / 0.001 = -8
Same answer — −8 . The chain rule gets it in one shot without needing to poke around with nudges.
Numerical vs chain-rule gradient — side by side
Pick a training point, pick a current w , pick a nudge size. Watch the two methods — crude numerical (recompute with and without the nudge) vs chain rule (closed-form 2·error·x) — agree to more decimal places as the nudge shrinks.
Drag Δw toward 0.0001 — agreement gets perfect. That's what a derivative is: the numerical answer in the limit.
🔗 The bias gradient — same pattern
For b, the chain is the same except for the final stage:
∂(y_pred)/∂b = 1
instead of
x
.
So for the first training point: 2 · (−4) = −8 . Nudging b up decreases the error for that example — just like nudging w, because at x=1 they happen to have the same effect.
📋 The gradient table — all five points
MSE averages over the whole dataset, so the final gradient is the mean of each point's gradient. Compute for every training example, then average:
| x | y_true | y_pred | error | 2·error·x (∂L/∂w) | 2·error (∂L/∂b) |
|---|---|---|---|---|---|
| 1 | 4 | 0 | −4 | −8 | −8 |
| 2 | 7 | 0 | −7 | −28 | −14 |
| 3 | 10 | 0 | −10 | −60 | −20 |
| 4 | 13 | 0 | −13 | −104 | −26 |
| 5 | 16 | 0 | −16 | −160 | −32 |
| mean = | −72 | −20 | |||
∂L/∂b = −20
Both negative → both should increase. The magnitude tells you which one to push harder: w's gradient is ~3.6× larger, so w moves proportionally more. That's the steering signal — and it came straight out of the chain rule.
⬇️ Using gradients to adjust weights
We have ∂L/∂w = −72 and ∂L/∂b = −20 . Two rules decide the direction:
- If the gradient is positive → increasing the parameter increases loss → decrease it.
- If the gradient is negative → increasing the parameter decreases loss → increase it.
Both of our gradients are negative. So both parameters should go up. But by how much ?
📐 The update rule
For every parameter, one step of gradient descent is:
Plug in:
# Starting point w = 0.0, b = 0.0 lr = 0.01 # Gradients (computed via chain rule) dw = -72 db = -20 # Update w_new = 0 - 0.01 * (-72) = 0 + 0.72 = 0.72 b_new = 0 - 0.01 * (-20) = 0 + 0.20 = 0.20
After one training step, our model went from
y = 0·x + 0
to
y = 0.72·x + 0.20
. Still wrong (target is 3·x + 1), but closer. Each step nudges it a little closer.
🔁 Gradient Descent — step-by-step breakdown
The full recipe of one training step — exactly what PyTorch's
optimizer.step()
hides under a friendly name:
y_pred = 0.00 × X + 0.00 = [0.0, 0.0, 0.0, 0.0, 0.0]
error = y_pred − y = [-4, -7, -10, -13, -16]
∂L/∂w = mean(2 × error × X) = -72.0000 ∂L/∂b = mean(2 × error) = -20.0000
w = 0.0000 − 0.0100 × -72.0000 = 0.7200 b = 0.0000 − 0.0100 × -20.0000 = 0.2000
118.0000 → 68.7664 (↓ 49.2336)
📉 Loss history — 10 epochs
An epoch = one full pass over the training data. Do step 1–5 above, ten times. Watch what happens.
| Epoch | w (target 3) | b (target 1) | Loss |
|---|---|---|---|
| 1 | 0.7200 | 0.2000 | 68.7664 |
| 2 | 1.2207 | 0.3392 | 40.1220 |
| 3 | 1.6891 | 0.4696 | 23.3558 |
| 4 | 2.0093 | 0.5588 | 13.6124 |
| 5 | 2.2538 | 0.6271 | 7.9344 |
| 6 | 2.4403 | 0.6793 | 4.6256 |
| 7 | 2.5827 | 0.7193 | 2.6973 |
| 8 | 2.6913 | 0.7500 | 1.5736 |
| 9 | 2.7742 | 0.7735 | 0.9188 |
| 10 | 2.8375 | 0.7916 | 0.5371 |
Train live — step by step, or run 100 epochs at once
The model starts at
w = 0, b = 0
. Click
Step
to apply one gradient update;
Run
to animate the whole trajectory;
Reset
to start over. Crank the learning rate past ~0.05 and watch what
"overshoot"
actually looks like.
The canvas shows the loss-vs-epoch curve. Low learning rates creep; high learning rates zig-zag and can blow up entirely. Somewhere around 0.03 is fastest without oscillation for this problem — every problem has its own sweet spot.
🚀 Beyond vanilla SGD — Adam & AdamW
What we just implemented is SGD (stochastic gradient descent). It works, but it has a weakness: it only uses the current gradient and treats every parameter the same. Real networks are trained with smarter optimizers:
🧲 Momentum
Keep a running mean of recent gradients. Accelerate along consistent directions, dampen wobbles. Like the ATV — once you're moving down the hill, you keep moving.
📊 Adaptive rates (variance)
Track each parameter's gradient variance . Noisy parameters get smaller steps; steady ones get bigger steps. Every weight gets its own custom learning rate.
💻 The whole thing in numpy — 25 lines
Everything we derived — forward pass, loss, gradients via chain rule, update — in one file:
#!/usr/bin/python3 import numpy as np # Single linear neuron: y = w·x + b # Training data: y = 3x + 1 X = np.array([1, 2, 3, 4, 5], dtype=np.float32) y = np.array([4, 7, 10, 13, 16], dtype=np.float32) # Initialize parameters w = 0.0 b = 0.0 lr = 0.01 # Training loop for epoch in range(100): # Forward pass y_pred = w * X + b # Loss (MSE) loss = np.mean((y_pred - y) ** 2) # Gradients (by hand) dw = np.mean(2 * (y_pred - y) * X) db = np.mean(2 * (y_pred - y)) # Update w -= lr * dw b -= lr * db if epoch % 20 == 0: print(f"epoch {epoch}: loss={loss:.4f}, w={w:.4f}, b={b:.4f}") print(f"\nLearned: y = {w:.2f}x + {b:.2f}") print(f"Target: y = 3.00x + 1.00")
After 100 epochs this script prints
Learned: y = 3.00x + 1.00
. No magic, no black box — the whole thing is ~25 lines of arithmetic.
🔥 Same thing in PyTorch — let the framework chain-rule for us
Once you have one neuron working, you want to scale.
PyTorch
(originally led by Meta) is the deep-learning library that makes that scaling tolerable. Its
core trick: you write the forward pass, it remembers the chain, and when you call
loss.backward()
it runs
automatic differentiation
— applies the chain rule for you across the entire graph.
#!/usr/bin/python3 import torch # Same data X = torch.tensor([1, 2, 3, 4, 5], dtype=torch.float32) y = torch.tensor([4, 7, 10, 13, 16], dtype=torch.float32) # requires_grad=True tells PyTorch to track gradients w = torch.tensor(0.0, requires_grad=True) b = torch.tensor(0.0, requires_grad=True) lr = 0.01 for epoch in range(100): # Forward pass y_pred = w * X + b loss = torch.mean((y_pred - y) ** 2) # Backward pass — PyTorch runs the chain rule for us loss.backward() # Update (no_grad: don't track this as part of the graph) with torch.no_grad(): w -= lr * w.grad b -= lr * b.grad # Zero the gradients (they accumulate by default) w.grad.zero_() b.grad.zero_()
Notice what disappeared: the hand-derived
dw = 2·error·X
line. PyTorch's autograd walks the chain for us. That's the entire reason you can train a
175-billion-parameter transformer without going insane — no human is computing ∂L/∂w₁₂₃,₄₅₆,₇₈₉
by hand.
nn.Linear()
wraps
w·x + b
,
nn.MSELoss()
wraps our loss,
torch.optim.SGD()
wraps the update rule. Same math, more leverage. Install with
sudo apt-get install python3-torch
.
🧩 Terminology sync: "Backpropagation"
Everything we've been doing manually has a name:
- Forward pass — compute the prediction from the inputs.
- Backward pass (backpropagation) — compute the gradient of the loss with respect to every parameter, by applying the chain rule from the loss back to the inputs.
- Dynamic programming — the backward pass reuses intermediate results efficiently instead of recomputing them. Roots in Richard Bellman's work at RAND in the 1950s, originally for aerospace and engineering.
How "backprop" became the default training algorithm
loss.backward()
, every gradient shows up.
The episode the textbooks skip — Werbos & Minsky
Werbos got the math first, but the field didn't pick it up for another twelve years. The reason is closer to a soap opera than to a research narrative. Werbos walked the algorithm in to Marvin Minsky — whose 1969 Perceptrons book had argued that multi-layer learning was a dead end and helped trigger the first AI winter:
"The real history has never been written. It's like a soap opera you wouldn't believe. So one episode of the soap opera, I needed support to do a thesis. And I had taken independent studies with Marvin Minsky. I knew his way of thinking, and I walked in and said, 'Marvin, you've got this great book, but the thing is, the problem can be solved. Here's how to solve it. Why don't we become co-authors so that you don't be embarrassed when it comes out? I'm willing to share, I'm not trying to own all this. Here's how you solve the problem that you described in your book.'"Minsky's answer, in Werbos's recollection: "if I do this, the modelers will all kill me, and I have to deal with my reputation." So the field waited until 1986 for Rumelhart, Hinton & Williams to publish the same idea on a bigger stage.
On where the math actually came from, Werbos is unusually direct. He read Freud as a teenager — long before he ever read von Neumann — and decided the shape of the missing algorithm was the one Freud had described informally: the mind allocates and re-allocates "psychic energy" ( cathexis ) to optimize outcomes (the pleasure principle ). Translating that picture into a quantifiable framework — a backwards flow of partial derivatives that assigns blame for the loss back to every weight — is the path that produced the chain rule for ordered derivatives. As Werbos puts it in the same interview:
"The most important part of my PhD thesis, some people say, is I translated backpropagation. First, it was Freud, then it was an algorithm, and then it was mathematics. So I translated it into something I called the chain rule for ordered derivatives… So I translated Freud into math, von Neumann translated Fourier into math."That's a one-line summary of where the backwards in backpropagation comes from. Not from optimization theory. From psychoanalysis, re-derived as calculus.
Sources used in this section: Mind Matters #137 transcript · Werbos AD2004 · Backpropagation and Freud's psychic energy · Werbos on noosphere species theory .
🕸️ Scaling & the computation DAG
When you have one neuron, you can draw the chain on a napkin. When you have millions, you need a Direct Acyclic Graph (DAG) . Every operation is a node; every dependency is an edge. PyTorch builds this graph as your forward pass runs, then walks it backward to compute gradients.
This is a tiny 2-input, 2-hidden-unit, 1-output toy network. A modern transformer's DAG has billions of nodes — but it's the same structure: multiply, sum, activate, repeat. Every node's gradient is computed by looking at its outgoing edges and applying the chain rule.
📐 Scale-up: LeNet-5 (1998) — the first real CNN
Yann LeCun 's LeNet-5 (1998) was the first broadly successful convolutional neural network, trained on the MNIST handwritten-digit dataset. It applied a modified version of backpropagation to a multi-layer convnet and actually worked at a useful scale.
🧮 The memory math — why params become a wall
Parameter count is the easy number. The hard number is memory — how much RAM you need just to hold the model in GPU.
Why is training so much worse? Adam keeps a running mean and variance per parameter (Tab 6). That's 2× the weights, doubled again for FP32 optimizer state, plus activations for the backward pass, plus gradient buffers. Rule of thumb: ~2 GB per 1B parameters at FP16 for inference, ~16 GB per 1B parameters for training.
🕰️ 1998 – 2015 · No memory wall
For the first 17 years of deep learning, models stayed within one consumer GPU's reach. A single card trained what you needed.
| Model | Year | Params | Inference (FP16) | Training (Adam) | GPU Required |
|---|---|---|---|---|---|
| 🎞️ Classic CNNs (1998 – 2015) | |||||
| LeNet-5 | 1998 | 60K | 120 KB | 960 KB | CPU OK |
| AlexNet | 2012 | 60M | 120 MB | 960 MB | GTX 580 |
| VGG-16 | 2014 | 138M | 276 MB | 2.2 GB | GTX 980 |
| ResNet-50 | 2015 | 25M | 50 MB | 400 MB | GTX 980 |
AlexNet (2012) is the shot heard round the world — it won ImageNet by a huge margin and convinced the field that GPUs + deep nets were the future. ResNet-50 (2015) proved deeper networks could work with residual connections. Both fit in a gaming GPU.
🤖 2017 – 2019 · Early Transformers — mild signs
Then came the 2017 paper "Attention Is All You Need." Parameters start climbing fast; training memory starts eating real cards.
| Model | Year | Params | Inference (FP16) | Training (Adam) | GPU Required |
|---|---|---|---|---|---|
| 🤖 Early Transformers (2017 – 2019) | |||||
| Transformer (original) | 2017 | 65M | 130 MB | 1 GB | GTX 1080 |
| BERT-Base | 2018 | 110M | 220 MB | 1.8 GB | GTX 1080 Ti |
| BERT-Large | 2018 | 340M | 680 MB | 5.4 GB | V100 16GB |
| GPT-2 Small | 2019 | 117M | 234 MB | 1.9 GB | RTX 2080 |
| GPT-2 XL | 2019 | 1.5B | 3 GB | 24 GB | RTX 3090 |
BERT-Large needs a V100 for training. GPT-2 XL needs the biggest consumer card you can buy. Still one-GPU territory — but only just.
🚀 2020 – 2022 · GPT-3 era — the wall arrives
GPT-3 at 175 billion parameters is the moment single-GPU training dies. You can't hold the weights of GPT-3 on a single GPU, let alone the Adam state.
| Model | Year | Params | Inference (FP16) | Training (Adam) | GPU Required |
|---|---|---|---|---|---|
| 🚀 GPT-3 Era (2020 – 2022) | |||||
| GPT-3 Small | 2020 | 125M | 250 MB | 2 GB | RTX 3080 |
| GPT-3 Medium | 2020 | 2.7B | 5.4 GB | 43 GB | A100 40GB |
| GPT-3 XL | 2020 | 6.7B | 13.4 GB | 107 GB | 2× A100 80GB |
| GPT-3 (175B) | 2020 | 175B | 350 GB | 2.8 TB | 1000+ V100s |
🌟 2023 – 2025 · Modern LLMs — strong wall
Llama 2 democratized the 7B – 70B range. Frontier models (GPT-4, Llama-3 405B) pushed well into territory where fleets of H100s are the only option.
| Model | Year | Params | Inference (FP16) | Training (Adam) | GPU Required |
|---|---|---|---|---|---|
| 🌟 Modern LLMs (2023 – 2025) | |||||
| Llama-2 7B | 2023 | 7B | 14 GB | 112 GB | RTX 4090 |
| Llama-2 13B | 2023 | 13B | 26 GB | 208 GB | A100 40GB |
| Llama-2 70B | 2023 | 70B | 140 GB | 1.1 TB | 2× A100 80GB |
| Mistral 7B | 2023 | 7B | 14 GB | 112 GB | RTX 4090 |
| Mixtral 8×7B (MoE) | 2023 | 47B | 94 GB | 752 GB | 2× A100 80GB |
| GPT-4* (est.) | 2023 | ~1.8T | ~3.6 TB | ~29 TB | 10,000+ A100s |
| Llama-3 405B | 2024 | 405B | 810 GB | 6.5 TB | 16,000 H100s |
🛸 2025+ · Frontier & beyond — insane signs
Rumored and theoretical frontier sizes. The numbers start to look unhinged because they are.
| Model | Year | Params | Inference (FP16) | Training (Adam) | GPU Required |
|---|---|---|---|---|---|
| 🛸 Frontier & Beyond (2025+) | |||||
| Llama-4 (rumored) | 2025 | ~2T? | ~4 TB | ~32 TB | 50,000+ H100s? |
| 10T model (theoretical) | 2026? | 10T | 20 TB | 160 TB | 100,000+ GPUs |
• needs memory on a chip,
• needs to be moved across a network during training,
• needs electricity to run at inference time.
The industry's response is multi-front: smaller models that punch above their weight (distillation), smarter architectures (MoE — mixture of experts — only activates a subset per token), and better quantization (4-bit and lower). But the underlying math is the same single neuron you saw in Tab 3, applied a trillion times , trained via the chain rule, scaled across a datacenter.
🏁 Where this leaves us
Start to finish: a single weight, a single bias, one derivative rule, and the chain rule. That's the whole toolkit. Everything that makes a modern neural network "hard" comes from scaling that toolkit — not from new math.
-
The forward pass
is
w·x + b, stacked and nonlinearly composed. - The backward pass is the chain rule, run automatically by PyTorch's autograd engine across a DAG.
- The optimizer (SGD, Adam) turns gradients into parameter updates — the same new = old − lr · grad you saw in Tab 6.
- The GPU memory wall is the physical limit on how many parameters and how much optimizer state you can fit per accelerator.
🧮 Memory Wall Explorer — pick any model, any GPU
Slide through parameter counts from a laptop-sized MLP to the theoretical 10T model. Choose a precision. Choose a GPU. See whether it fits — and if not, how many you need.
Will this model fit?
A 7B model in FP16 training with Adam needs ~112 GB — that's one-and-a-change H100s, or one B200 with room to spare. Now try LLaMA-3 405B.