Chapter 8 · Part 3
Hand-designed vs learned
Chapter 7 left us wanting a better representation — a description of an image that survives shifts and lighting. For decades, the answer was to design one by hand. Smart researchers sat down and wrote out the numbers: the Sobel weights for edges, oriented histograms for HOG, scale-space tricks for SIFT.
It worked, up to a point. But every hand-designed feature carries a hidden assumption: that a human guessed correctly about what's worth measuring. What if the best way to tell a cat from a dog involves a pattern no person would ever think to write down?
Scroll to watch the two philosophies side by side.
On the left: a hand-designed kernel. A human chose all nine numbers, once, by reasoning about edges.
Same machinery, different source of numbers
Here's the quiet punchline: a learned filter is still just a kernel. It slides over the image and does the exact convolution from Chapter 5. The math is identical. The only thing that changes is where the nine (or forty-nine) numbers come from:
- Hand-designed: a person reasons about the problem and writes the weights down. Fixed forever. Interpretable, but limited by human imagination.
- Learned: the weights start random and are nudged, over thousands of tiny steps, toward whatever values make the predictions better. Discovered from examples, not designed.
Why learned features win
Remarkably, when you let a network learn its own first-layer filters, they often rediscover edge and blob detectors that look a lot like Sobel and Gabor — the very things humans designed. That's reassuring: the hand-designed features weren't wrong, they were a sensible starting guess.
But the learned filters don't stop there. Deeper layers build patterns we'd never write by hand — curved contours, textures, eventually whole object parts — stacked so that each layer's features are combinations of the last. No human designs that hierarchy; it falls out of the data.
# hand-designed: you write the numbers
sobel_x = np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
# learned: you start from noise and let optimisation fill them in
conv = Conv2D(filters=8, kernel_size=7) # 8 kernels, all random at first
# ... after training on many images ...
learned = conv.get_weights() # now they detect edges, bars, blobsThe doorway to neural networks
This is the hinge the whole course turns on. Once you accept that the numbers in a filter can be learned rather than designed, you've accepted the core premise of deep learning — and you need a machine that can learn numbers from examples.
That machine is built from a tiny, repeatable unit: weights times inputs, plus a bias, run through a simple function. Part 4 starts there, with a single neuron, and stacks it up until we have a network that can see.