Size a convolution, fire an edge detector, then rectify and pool in the sandbox, and predict — before you read it off the feature-map panels — the conv and pooled map sizes, the Sobel-x response at a vertical edge versus a flat region, how many cells ReLU zeroes, and what max-pool returns from a block.
A convolutional layer slides one small fixed kernel over the image and, at each position, sums the elementwise products with the pixels under it — a 2D cross-correlation. That produces a smaller feature map whose size is H_out = floor((H - k + 2p)/s) + 1. ReLU then zeroes every negative response, and max-pool shrinks the map by keeping the largest value in each little block. The kernels here are fixed textbook operators, not learned — the identity kernel even returns the image unchanged — so every number is exact.
Open the sandbox. Leave the input on the vertical edge pattern at 16×16 with noise off, the kernel on Sobel-x, padding valid and stride 1. Turn pooling on. The last two steps swap in tiny hand-built maps you can check against the ReLU and max-pool panels.
Pattern -> vertical edge Size -> 16 Noise -> 0 Kernel -> Sobel-x
Padding -> valid Stride -> 1 Pooling -> on
The pipeline panel shows the input, then conv (H_out = floor((H - k + 2p)/s) + 1), then ReLU, then max-pool — each an array of real numbers, with its width and height printed above it.
A valid 3×3 convolution (no padding, stride 1) on a 16×16 image loses one pixel off each of the four edges. Using H_out = floor((16 - 3 + 0)/1) + 1, predict the width of the conv map, then read it above the panel.
H_out = floor(13/1) + 1 = 14. The map is 14×14 — two smaller than the input in each dimension, exactly the border a 3×3 valid window cannot reach.
Now 2×2 max-pooling with stride 2 tiles the 14×14 map into non-overlapping 2-by-2 blocks and keeps one value per block. Predict the pooled width from floor((14 - 2)/2) + 1, then read it.
floor(12/2) + 1 = 7. Pooling halves each dimension, so the 14×14 map becomes 7×7 — a quarter as many cells, the down-sampling that lets deeper layers see more of the image at once.
The Sobel-x kernel measures the horizontal gradient. On the vertical-edge image (dark left, bright right, the step at column 8), a conv cell that straddles the step sums to 4×(bright - dark) = 4×(1 - 0). Predict the response at the edge cell (row 5, column 6), then read it off the conv panel.
The response is 4 — a strong, positive spike right at the edge. The kernel weights sum to 0, so it responds only to a change in brightness, not to brightness itself. That is what makes it an edge detector.
Now read a cell far from the edge, in the flat dark region (row 5, column 2), where every pixel under the kernel is the same. Predict the Sobel-x response there before you read it.
The response is exactly 0. With no gradient under the window, the positive and negative kernel weights cancel. An edge detector that is loud at edges and silent on flat regions is doing precisely its job — this is the pairing that makes the previous step meaningful.
A Sobel map has negative cells too (a bright-to-dark edge). ReLU(x) = max(0, x) clips every negative to 0 and leaves the rest alone. Take the little map [-3, 0, 2.5, -0.1] and predict how many of its cells ReLU sets to 0.
ReLU([-3, 0, 2.5, -0.1]) = [0, 0, 2.5, 0]: the two negative cells (-3 and -0.1) become 0, so 2 cells are zeroed, while the positive 2.5 survives untouched. This non-linearity is what lets a stack of layers learn more than one big linear map.
Finally, pool the 2×2 block [[1, 7], [3, 2]] with a 2×2 window. Predict the single value max-pool returns — and note it is not the mean, 3.25.
max-pool returns 7, the largest value in the block — not the mean 3.25. Keeping the maximum makes the feature map report whether a feature appeared anywhere in each block, and gives a little tolerance to exactly where it sat.
Everything above is waiting in the sandbox. Switch kernels to see Sobel-y fire on horizontal edges and the Laplacian on any edge, change the pattern and padding to watch the map sizes track the formula, and stack a second conv layer to see the map shrink again.
- Sized a valid 3×3 conv: 16 → 14
- Halved it with 2×2 max-pool: 14 → 7
- Read Sobel-x = 4 at a vertical edge and 0 where it is flat — a real edge detector
- Watched ReLU zero the 2 negative cells of [-3, 0, 2.5, -0.1]
- Saw max-pool return 7, the block maximum — not the mean 3.25
- Every value you predicted is the demo's own convolution, ReLU and pooling arithmetic on fixed kernels, not a picture