01

02 ยท useful win

Build backpropagation from scalar values

Make a tiny reverse-mode autodiff engine so gradients stop feeling like hidden framework magic.

Represent a computation as a directed acyclic graph.
02

The invariant chain

forward values becomes a testable update

forward values
local derivatives
reverse topological order
gradient accumulation
parameter update
03

Why it works

A gradient answers a local counterfactual

For a scalar output, each parameter gradient measures the first-order change in that output for a tiny change in the parameter. Backpropagation reuses local derivatives so the same question can be answered for every upstream value efficiently.

1A gradient answers a local counterfactual
2The graph is the memory of the forward pass
3reverse topological order becomes observable
04

Implementation compass

Accumulation is not optional

class Value:
    def __init__(self, data, children=()):
        self.data, self.grad = data, 0.0
        self._prev = set(children)
        self._backward = lambda: None

# for out = a * b
out._backward = lambda: (
    setattr(a, "grad", a.grad + b.data * out.grad),
    setattr(b, "grad", b.grad + a.data * out.grad),
)
ShapeWrite every semantic axis beside the tensor.
ReferenceCompare one output against the smallest trusted version.
Scale gateOverfit one controlled batch before a real run.
05

Build gate

Represent a computation as a directed acyclic graph.

Implement +, *, tanh, exp, pow, and a backward() topological traversal.
Check each derivative against a finite-difference estimate.
Add Neuron, Layer, and MLP modules with a parameters() method.
Stop and inspect

Overwriting gradients instead of accumulating

Updating parameters before every gradient is complete

BUILD โ†’ TEST โ†’ EXPLAIN