Skip to main content...
ML → Deep Learning via PyTorch — the Garment Classifier
35 min

Day 22: Building micrograd: the autograd engine from scratch

micrograd is a ~100-line autograd engine. Building it once makes "backprop" stop being a magic word and become code you understand.

Why build an autograd engine by hand

PyTorch computes gradients for you automatically, which is a gift — and a trap, if you never see how. Karpathy's micrograd is a tiny (~100-line) engine that does exactly what PyTorch's autograd does, small enough to hold in your head. Building it is the single most demystifying exercise in this stage: after it, 'the model backpropagates the loss' is something you've *implemented*, not memorized.

The Value: a number that remembers where it came from

The core trick: wrap every number in a Value object that records not just its data, but the operation and the operands that produced it. This builds a computation graph as your math runs. Each Value also stores a grad (its derivative of the final output) and a local _backward function that knows how to propagate gradient to its inputs using the chain rule.

The heart of micrograd — a Value that tracks its own computation graph
class Value:
    def __init__(self, data, _children=(), _op=""):
        self.data = data
        self.grad = 0.0                # dOutput/dSelf, starts at 0
        self._backward = lambda: None  # how to push grad to children
        self._prev = set(_children)    # the operands that made this Value
        self._op = _op

    def __add__(self, other):
        out = Value(self.data + other.data, (self, other), "+")
        def _backward():
            # d(a+b)/da = 1, d(a+b)/db = 1 — gradient flows through unchanged
            self.grad += out.grad
            other.grad += out.grad
        out._backward = _backward
        return out

    def __mul__(self, other):
        out = Value(self.data * other.data, (self, other), "*")
        def _backward():
            # d(a*b)/da = b, d(a*b)/db = a — the chain rule, locally
            self.grad += other.data * out.grad
            other.grad += self.data * out.grad
        out._backward = _backward
        return out

The += is not a typo

Gradients *accumulate* with += because a Value can feed into multiple downstream operations, and the chain rule says their contributions add. This is also why PyTorch makes you call optimizer.zero_grad() each step — otherwise gradients from the previous step keep accumulating. You'll understand that ritual because you built the reason for it.

Key terms

Autograd (automatic differentiation)
Automatically computing exact derivatives by recording operations and applying the chain rule mechanically.
Computation graph
A DAG of the operations that produced a value, built as the forward computation runs, and traversed backward to compute gradients.
micrograd
Karpathy's ~100-line educational autograd engine implementing scalar reverse-mode automatic differentiation.

In micrograd, why does each Value accumulate gradient with `self.grad += ...` rather than overwriting with `=`?

We use cookies

We use cookies to enhance your browsing experience, serve personalized content, and analyze our traffic. By clicking "Accept All", you consent to our use of cookies. Learn more

    Day 22: Building micrograd: the autograd engine from scratch | RBTechIconX