This is the worked-examples deep dive for Convolutional neural networks — convolution & pooling . The parent gave you the formulas; here we stress-test them against every case class — every sign of the output, every degenerate input, the limiting behaviour of stride and padding, a real aerospace word problem, and an exam twist.
Before we start, one reminder of the two formulas everything below leans on. If either symbol is unfamiliar, re-read the parent — but we re-explain each as it appears.
Definition One symbol we will need repeatedly:
F
Throughout, F = the number of filters in a convolution layer (also called the number of output channels). One filter produces one output feature map; stacking F filters produces F maps. Whenever you see F below, read it as "how many different little stamps this layer slides over the image."
Recall Three parent-page facts we lean on (so you don't need the parent open)
The parent listed common mistakes; we cite three by name. Restated plainly:
Pooling has zero learnable parameters — max/average is a fixed function, not trained.
Stride is not just a speed knob — a larger s directly shrinks the output via the size formula.
Conv parameters are independent of image size — they depend only on F ( k 2 C + 1 ) , never on W in .
Every problem this topic can hand you falls into one of these cells . The examples below are chosen so that together they touch every row.
#
Case class
What makes it tricky
Covered by
A
Padding preserves size (p chosen so W o u t = W in )
the "same" convolution — is the arithmetic exact?
Ex 1
B
Non-divisible / floor kicks in
( W in − k + 2 p ) not a multiple of s → rounding down loses a position
Ex 2
C
Negative output value
a kernel producing S < 0 — signs matter, no clipping
Ex 3
D
Degenerate: 1 × 1 kernel, stride 1
is convolution still "doing" anything?
Ex 4
E
Limiting stride: s = k (no overlap) & s > 1 shrink
how far can stride push before output hits 1?
Ex 5
F
Multi-channel filter (sum over depth)
parameter count and the extra sum
Ex 6
G
Pooling: max vs average, with a shift to prove invariance
does the max really not move?
Ex 7
H
Real aerospace word problem (crack-detector sizing)
translate words → numbers → layer stack
Ex 8
I
Exam twist: solve for an unknown (p or s ) from a target size
invert the formula
Ex 9
J
Zero/empty degenerate: kernel bigger than input
when is W o u t ≤ 0 (invalid)?
Ex 10
Worked example "Same" convolution
Input W in = 32 , kernel k = 5 , stride s = 1 . Choose p so the output is also 32 . Then confirm.
Forecast: guess the padding before reading. Bigger kernel → need more padding?
Set up the equation. We want W o u t = W in = 32 . Plug into the formula with s = 1 :
32 = 1 32 − 5 + 2 p + 1.
Why this step? "Same" convolution is defined by the requirement W o u t = W in , so we impose it and solve for the only unknown, p .
Solve for p . Subtract the + 1 : 31 = 27 + 2 p ⇒ 2 p = 4 ⇒ p = 2 .
Why this step? Plain algebra — isolate p . The rule of thumb p = ( k − 1 ) /2 gives p = ( 5 − 1 ) /2 = 2 , matching.
Verify: W o u t = ⌊( 32 − 5 + 2 ⋅ 2 ) /1 ⌋ + 1 = ⌊ 31 ⌋ + 1 = 32. ✓ Units: pixels in, pixels out, same count. Padding preserves spatial size exactly when p = ( k − 1 ) /2 and s = 1 .
Worked example Stride that does not divide evenly
Input W in = 7 , kernel k = 3 , padding p = 0 , stride s = 2 . Find W o u t and list the exact kernel start positions.
Forecast: ( 7 − 3 ) /2 = 2 … is the answer 2, or 3? Guess.
Compute the numerator. W in − k + 2 p = 7 − 3 + 0 = 4 .
Why this step? This is the last valid start index — the furthest left the kernel's left edge can go and still fit. Positions run 0 , 1 , … , 4 .
Divide by stride and floor. ⌊ 4/2 ⌋ = 2 , then + 1 = 3 .
Why this step? With s = 2 the kernel only lands on start indices 0 , 2 , 4 — every second position. That's 3 landings. The + 1 counts position 0 .
List the starts to check the floor. Starts = { 0 , 2 , 4 } . A start at 6 would need the window to occupy columns 6 , 7 , 8 — but the last column is index 6 , so 6 overflows. Confirmed: 3 positions.
Why this step? When the numerator is not a multiple of s (e.g. change W in to 8: numerator 5, ⌊ 5/2 ⌋ = 2 , still 3), the floor silently drops the leftover — this is exactly cell B's trap.
Verify: ⌊( 7 − 3 + 0 ) /2 ⌋ + 1 = 2 + 1 = 3. ✓
Worked example Negative activation (no clipping yet)
Take the diagonal-edge kernel from the parent and a fresh patch:
I = [ 0 9 5 0 ] , K = [ 1 0 0 − 1 ] , b = 0.
Kernel 2 × 2 , so a single output value S ( 0 , 0 ) . Compute it.
Forecast: will the answer be positive, zero, or negative?
Overlay and multiply. S ( 0 , 0 ) = I ( 0 , 0 ) ⋅ 1 + I ( 0 , 1 ) ⋅ 0 + I ( 1 , 0 ) ⋅ 0 + I ( 1 , 1 ) ⋅ ( − 1 ) . With I ( 0 , 0 ) = 0 , I ( 1 , 1 ) = 0 , this gives S = 0 ⋅ 1 + 0 ⋅ ( − 1 ) = 0 .
Why this step? We follow the sum ∑ m ∑ n I K ; only the ( 0 , 0 ) and ( 1 , 1 ) kernel entries are nonzero.
Now flip the patch's diagonal to I ′ = [ 9 0 0 5 ] : S ′ = 9 ⋅ 1 + 5 ⋅ ( − 1 ) = 9 − 5 = 4 (positive). And I ′′ = [ 2 0 0 8 ] : S ′′ = 2 − 8 = − 6 (negative ).
Why this step? Convolution output is a signed number. A negative S means "the top-left is dimmer than the bottom-right along the diagonal." Before any activation (e.g. ReLU), negatives are real and meaningful — do not clip prematurely.
Verify: S ′′ = 1 ⋅ 2 + ( − 1 ) ⋅ 8 = − 6. ✓ Sign correct: bottom-right (8 ) larger than top-left (2 ), and the kernel subtracts bottom-right, so output goes negative.
1 × 1 convolution do anything?
Input W in = 6 , kernel k = 1 , p = 0 , s = 1 , single channel, kernel value K = [ 3 ] , bias b = 1 . What is W o u t and what does the layer compute per pixel?
Forecast: is a 1 × 1 conv just an identity, or something useful?
Output size. W o u t = ⌊( 6 − 1 + 0 ) /1 ⌋ + 1 = 5 + 1 = 6 . Size unchanged.
Why this step? With k = 1 , the window is a single cell that fits everywhere; no shrinking.
What it computes. S ( i , j ) = I ( i , j ) ⋅ 3 + 1 for every pixel.
Why this step? The sum ∑ m , n has only one term. So it's a per-pixel affine map — a scale (× 3 ) plus shift (+ 1 ), applied identically everywhere.
The real point (multi-channel). A 1 × 1 kernel is not trivial when there are C channels: it becomes a learned mix across channels at each pixel, F ( 1 ⋅ 1 ⋅ C + 1 ) parameters (recall F = number of filters) — used in aerospace pipelines to compress a stack of physics fields into fewer channels cheaply.
Why this step? Shows the degenerate spatial case is still doing depthwise work.
Verify: for a pixel with I = 4 : S = 4 ⋅ 3 + 1 = 13. ✓ Size 6 ✓.
Worked example How much can stride shrink?
Input W in = 8 , kernel k = 2 , p = 0 . Compute W o u t for s = 1 , 2 , 4 , 8 .
Forecast: at which stride does the output collapse to 1 ?
s = 1 : ⌊( 8 − 2 ) /1 ⌋ + 1 = 6 + 1 = 7 .
s = 2 : ⌊ 6/2 ⌋ + 1 = 3 + 1 = 4 . Non-overlapping windows begin — with k = 2 , s = 2 each window touches new pixels.
s = 4 : ⌊ 6/4 ⌋ + 1 = 1 + 1 = 2 .
s = 8 : ⌊ 6/8 ⌋ + 1 = 0 + 1 = 1 . Just one window — the kernel lands only at position 0 .
Why these steps? Increasing s directly shrinks output (stride is not just a speed knob — see the recall box above). The limit is W o u t = 1 : once s > W in − k , the kernel can only sit at index 0 , and no bigger stride changes that.
Verify: the four answers are 7 , 4 , 2 , 1. ✓ Monotonically non-increasing in s ✓, floored at 1 ✓.
Worked example Summing over depth + parameter count
A single 2 × 2 filter over C = 2 channels, bias b = 0 . Input patch (channel 0 then channel 1) and kernel slices:
I 0 = [ 1 3 2 4 ] , I 1 = [ 0 1 1 0 ] , K 0 = [ 1 0 0 1 ] , K 1 = [ 2 0 0 2 ] .
Compute the single output value, then the parameter count for F = 8 such filters (recall F = number of filters).
Forecast: one number comes out even though there are two channels — why one?
Convolve channel 0. ∑ I 0 ⊙ K 0 = 1 ⋅ 1 + 2 ⋅ 0 + 3 ⋅ 0 + 4 ⋅ 1 = 1 + 4 = 5 .
Why this step? Each channel is cross-correlated with its own kernel slice.
Convolve channel 1. ∑ I 1 ⊙ K 1 = 0 ⋅ 2 + 1 ⋅ 0 + 1 ⋅ 0 + 0 ⋅ 2 = 0 .
Sum across channels + bias. S = 5 + 0 + b = 5 .
Why this step? A filter outputs one feature per position; the channel results are added , collapsing depth C into a single scalar. That is why RGB doesn't give 3 outputs per filter.
Parameter count. F ( k 2 C + 1 ) = 8 ( 2 2 ⋅ 2 + 1 ) = 8 ( 8 + 1 ) = 72 .
Why this step? Each filter has k 2 C weights plus 1 bias; independent of image size (see the recall box).
Verify: output = 5 ✓; params = 72 ✓.
Worked example Max-pool vs average-pool, then shift the feature
S = 1 5 0 1 3 6 2 1 2 1 9 3 4 2 1 8 , 2 × 2 , s = 2.
Compute both pools. Then shift the "6" within its window and re-max-pool to test invariance.
Forecast: which pooling reacts to the shift, max or average?
Figure walkthrough (also readable without the image): the figure shows two copies of the top-left 2 × 2 window. On the left the value 6 sits in the bottom-right cell of that window; on the right the 6 has moved up one row (we swapped it with the 3 ). In both copies the highlighted accent-red cell is the window's maximum , and in both it reads 6 — the maximum's value is identical even though its position moved. That is the visual proof of invariance.
Max-pool the four windows. Top-left { 1 , 3 , 5 , 6 } → 6 ; top-right { 2 , 4 , 1 , 2 } → 4 ; bottom-left { 0 , 2 , 1 , 1 } → 2 ; bottom-right { 9 , 1 , 3 , 8 } → 9 . So P ma x = [ 6 2 4 9 ] .
Why this step? Non-overlapping windows because s = k = 2 ; max keeps the strongest "feature present?" signal.
Average-pool. Top-left ( 1 + 3 + 5 + 6 ) /4 = 3.75 ; top-right ( 2 + 4 + 1 + 2 ) /4 = 2.25 ; bottom-left ( 0 + 2 + 1 + 1 ) /4 = 1 ; bottom-right ( 9 + 1 + 3 + 8 ) /4 = 5.25 . P a v g = [ 3.75 1 2.25 5.25 ] .
Shift inside a window (invariance test). Move the top-left window's max from cell ( 1 , 1 ) = 6 up to cell ( 0 , 1 ) (swap the 3 and 6 ). New window { 1 , 6 , 5 , 3 } → max still 6 . This matches the accent-red cell in the figure: the maximum did not change value even though its position changed.
Why this step? This is the whole point of pooling — local translation invariance . A wobble of one pixel leaves the max unchanged, so the network stops caring about exact position.
Contrast with average. The average of { 1 , 6 , 5 , 3 } is still 15/4 = 3.75 — unchanged too, because we only permuted the same four numbers. But if the shift brings a new number into the window (e.g. from a neighbouring window), the max often survives while the average changes. That's why max is the standard invariance tool.
Verify: P ma x = [ 6 2 4 9 ] , P a v g = [ 3.75 1 2.25 5.25 ] , shifted-window max = 6 . ✓
Worked example Sizing a composite-panel crack detector
An inspection camera gives 256 × 256 single-channel panel images (Image classification for aerospace inspection ). Your pipeline is:
Conv (k = 5 , p = 2 , s = 1 , F = 16 ) → MaxPool (2 × 2 , s = 2 ) → Conv (k = 3 , p = 1 , s = 1 , F = 32 ) → MaxPool (2 × 2 , s = 2 ). Here F is again the number of filters (output channels) of each conv.
Find the spatial size after each stage and the parameters of each conv layer.
Forecast: guess the final spatial size — bigger or smaller than 64 ?
Conv 1 size. ⌊( 256 − 5 + 2 ⋅ 2 ) /1 ⌋ + 1 = ⌊ 255 ⌋ + 1 = 256 . Why? p = ( k − 1 ) /2 = 2 is "same" padding → size preserved. Output 256 × 256 × 16 .
Pool 1. ⌊( 256 − 2 + 0 ) /2 ⌋ + 1 = 127 + 1 = 128 . Halves each side → 128 × 128 × 16 .
Conv 2. ⌊( 128 − 3 + 2 ⋅ 1 ) /1 ⌋ + 1 = 127 + 1 = 128 . Again "same" (p = ( 3 − 1 ) /2 = 1 ). Output 128 × 128 × 32 .
Pool 2. ⌊( 128 − 2 ) /2 ⌋ + 1 = 63 + 1 = 64 . → 64 × 64 × 32 .
Parameters. Conv 1: F ( k 2 C + 1 ) = 16 ( 5 2 ⋅ 1 + 1 ) = 16 ⋅ 26 = 416 . Conv 2: 32 ( 3 2 ⋅ 16 + 1 ) = 32 ( 144 + 1 ) = 32 ⋅ 145 = 4640 . Pools: 0 each (pooling has zero learnable parameters — see the recall box).
Why this step? This is the practical payoff — a full crack-detector front-end needs only 416 + 4640 = 5056 weights, independent of the 256 × 256 image size (conv parameters don't scale with image size). A fully-connected first layer would need ∼ 25 6 2 × 25 6 2 = 4.3 × 1 0 9 .
Verify: sizes 256 → 128 → 128 → 64 ✓; params 416 and 4640 ✓.
Worked example Find the padding for a target output
You must map W in = 28 to W o u t = 14 using k = 3 , s = 2 . What integer p works?
Forecast: with s = 2 we roughly halve 28 to 14 — but does the arithmetic need padding, or does the floor already do it?
Invert the formula. Start from W o u t = ⌊( W in − k + 2 p ) / s ⌋ + 1 . Drop the floor first (pretend the division is exact): 14 − 1 = ( 28 − 3 + 2 p ) /2 ⇒ 13 ⋅ 2 = 25 + 2 p ⇒ 26 = 25 + 2 p ⇒ p = 0.5 .
Why this step? Solving for the unknown is just algebra — but p must be an integer (you cannot pad half a pixel), so 0.5 is impossible exactly. The fraction is a warning that we must now bring the floor back and test the neighbouring integers p = 0 and p = 1 .
Test p = 0 . ⌊( 28 − 3 + 0 ) /2 ⌋ + 1 = ⌊ 12.5 ⌋ + 1 = 12 + 1 = 13 . Too small by one.
Why this step? With the floor restored, p = 0 undershoots the target, so it is rejected.
Test p = 1 . ⌊( 28 − 3 + 2 ) /2 ⌋ + 1 = ⌊ 13.5 ⌋ + 1 = 13 + 1 = 14 . ✓ p = 1 is the answer.
Why this step? The floor absorbs the leftover half (13.5 → 13 ), so the integer p = 1 lands exactly on the target even though the "exact" solve gave a fraction. Conclusion: when inverting the size formula, never trust the fractional solve — always re-check integer candidates against the floored formula.
Verify: ⌊( 28 − 3 + 2 ⋅ 1 ) /2 ⌋ + 1 = ⌊ 13.5 ⌋ + 1 = 14. ✓ Target hit with p = 1 .
Worked example When is the output non-existent?
Input W in = 3 , kernel k = 5 , p = 0 , s = 1 . Is a valid convolution possible? If not, find the smallest padding that rescues it.
Forecast: what does the formula give, and can an output size be zero or negative?
Plug in. W o u t = ⌊( 3 − 5 + 0 ) /1 ⌋ + 1 = ⌊ − 2 ⌋ + 1 = − 2 + 1 = − 1 .
Why this step? A 5 × 5 kernel cannot fit inside a 3 × 3 image — the numerator W in − k = − 2 goes negative , and the formula returns a non-positive number.
Interpret the non-positive result. W o u t ≤ 0 means no valid kernel position exists ; the layer is undefined, and real libraries raise a shape error here. This is the degenerate boundary of the whole topic.
Why this step? It tells you the precondition every earlier example silently satisfied: convolution needs at least one place for the kernel to sit.
Find the rescue padding. We need the numerator non-negative: W in − k + 2 p ≥ 0 ⇒ 3 − 5 + 2 p ≥ 0 ⇒ 2 p ≥ 2 ⇒ p ≥ 1 . Take the smallest, p = 1 : W o u t = ⌊( 3 − 5 + 2 ) /1 ⌋ + 1 = 0 + 1 = 1 — one valid output.
Why this step? Padding grows the effective width W in + 2 p until the kernel fits. The general precondition is W in + 2 p ≥ k .
Verify: unpadded gives − 1 (invalid) ✓; with p = 1 gives 1 (valid) ✓.
Recall The scenario checklist
Before trusting any conv/pool answer, which four things do you sanity-check? ::: Sign of the output (can be negative pre-activation), the floor when numerator isn't divisible by stride, that W in + 2 p ≥ k (else invalid), and that pooling has zero parameters.
"Same" padding rule for stride 1 ::: p = ( k − 1 ) /2 , which makes W o u t = W in .
When does stride force W o u t = 1 ? ::: When s > W in − k (with p = 0 ): the kernel lands only at position 0.
What does F stand for? ::: The number of filters in a conv layer, i.e. the number of output channels/feature maps it produces.
Parent topic — the formulas worked here.
Padding and stride — Examples 1, 2, 5, 9, 10 are all its edge cases.
Feature maps and receptive fields — every W o u t computed here is a feature-map dimension.
Translation equivariance vs invariance — Example 7's shift test is the invariance demo.
Image classification for aerospace inspection — Example 8 sizes a real detector.
Fully-connected neural networks — the 4.3 × 1 0 9 comparison in Example 8.
Backpropagation — trains the shared weights we counted throughout.