Counting a CNN
COMP90086 Computer Vision · CNN Workshop Exercise

48,770

Four questions about one small CNN. By the end, every number on these slides can be reproduced from the network diagram alone — including the outputs when all weights are 0, or all 1.

i · countii · zerosiii · onesiv · diet
00The exercise

One network, four questions

RGB image 26 × 26 × 3 values 0–255 Convolutional layer 5×5 · valid · stride 1 20 filters · ReLU → ? A Convolutional layer 3×3 · valid · stride 1 40 filters · ReLU → ? B Max pooling 2×2 · valid · stride 2 → ? C flatten FC 10 units D
iTotal number of parameters — show your work. iiAll parameters initialised to 0 — what does layer B output? iiiAll weights 1, biases 0 — what does layer B output look like? ivReduce parameters without reducing filter count or effective kernel size.
PART ZERO
Three tools

What one filter computes · why filters have depth · how sizes shrink

pre·01What one filter computes

Slide, multiply, sum

  • The kernel is a small grid of weights that slides over the input.
  • At each stop: multiply element-by-element, add everything up, add the bias.
  • That one sum is one cell of the output map.
  • ReLU then clamps negatives to 0, element-wise.

Why "all 1s" is here

A kernel of all ones just sums its patch — an unnormalised box filter. Hold that thought for part iii.

input 6×6
kernel 3×3 (all 1s)
output 4×4
pre·02How big is the output?

Count where the kernel fits

First valid start: 0. Last: W−F. Step by the stride:

  • valid padding means P = 0 — the map shrinks by F−1.
  • Max pooling obeys the same formula (F = pool size).
  • Sanity check: 3-wide kernel on a 3-wide input fits exactly once → (3−3)+1 = 1. The “+1” is not optional.

This network, precomputed

A= 22
B= 20
C= 10

Same formula for height — everything here is square.

Stride 2 pooling, drawn

2×2 windows land at columns 0, 2, 4, 6 — each row of 20 becomes 10, and channels are untouched: 40 in, 40 out.

pre·03Why filters have depth

A filter spans the full input depth

The exercise states it directly: “each kernel has the same number of channels as the input.” A “5×5” filter on RGB is really 5×5×3 = 75 weights, and its dot product with a patch gives one number.

input 26×26×3 one 5×5 patch · all 3 channels filter = 5×5×3 = 75 weights same depth as its input — always Σ+b one number slide everywhere → one 22×22 map × 20 20 filters → output 22×22×20
pre·04What counts as a parameter

Three layer types, three rules

convolution

F·F weights per slice · through Cin channels · +1 bias · × N filters. Independent of image size — the filter is shared across positions.

max pooling · flatten · ReLU

0

Taking a max, reshaping, clamping at zero — none of it is learned. Zero parameters, every time.

fully connected

A weight for every input–unit pair, plus one bias per unit. Nin is the flattened length.

That is the whole toolkit. Everything in part i is these two formulas plus the size formula.

trapThe two classic wrong answers
A FILTER IS NEVER FLAT · A LAYER IS NEVER BIAS-FREE

Layer A, three ways

5·5·20 = 500 ✗ forgot the input depth 5·5·3·20 = 1500 ✗ forgot the 20 biases (5·5·3+1)·20 = 1520 ✓

Both wrong answers survive a quick glance because they look like “kernel × filters”. The check that catches them: one filter must match its input in depth, and every filter carries a bias.

The habit

Before counting any conv layer, ask:

“What is Cin here?” — for layer B it is 20, the number of filters in A. The RGB 3 is long gone.

Same discipline at the flatten: it flattens the pooled shape (10×10×40), not the conv output before pooling.

PART ONE · QUESTION i
Count it

Two ledgers through the network: the shape flowing out, and the parameters added

i · ALayer A · conv 5×5 · 20 filters

Shape ledger

in 26×26×3

22

out 22×22×20 — one 22×22 map per filter.

ReLU changes values, never shapes or parameter counts.

Parameter ledger

(F·F·Cin + 1) × N



= 1,520

75 weights and 1 bias per filter, twenty filters. Running total: 1,520.

i · BLayer B · conv 3×3 · 40 filters

Shape ledger

in 22×22×20

20

out 20×20×40.

the trap, live

Cin = 20 — layer A’s filter count. Each 3×3 filter is a 3×3×20 brick: 180 weights, not 9.

Parameter ledger

(F·F·Cin + 1) × N



= 7,240

Running total: 1,520 + 7,240 = 8,760.

i · CLayer C · max pool 2×2 stride 2 · then flatten

Shape ledger

in 20×20×40

10

out 10×10×40 — channels untouched.

flatten

One long vector for the FC layer. Flatten the pooled shape — 20×20×40 here would silently quadruple layer D.

Parameter ledger

learned weights in pooling

max(window) has nothing to learn
= 0

Flatten adds 0 too. Running total: still 8,760.

i · DLayer D · fully connected · 10 units

Parameter ledger

Nin·Nout + Nout


= 40,010

Every one of the 4,000 flattened values connects to every one of the 10 units — no sharing, unlike a conv filter. That is why this little layer dwarfs everything.

Verified against model.summary()

Layer Output shape Param # conv2d (A) (22, 22, 20) 1520 conv2d_1 (B) (20, 20, 40) 7240 max_pool (C) (10, 10, 40) 0 flatten (4000,) 0 dense (D) (10,) 40010 ───────────────────────────────────────── Total params 48,770

The habit that catches every miscount: print model.summary() and reconcile it line by line with your hand count.

i · ✓Answer · part i

48,770 parameters

Aconv 5×5, 20 f22×22×201,520
Bconv 3×3, 40 f20×20×407,240
Cpool + flatten10×10×40 → 4,0000
Dfully connected1040,010
total48,770
share of parameters
A · 3.1% B · 14.8% C · 0 D · 82.0%

Where the parameters concentrate

The layers that see hold 18% of the parameters. The little classifier head holds 82% — because it shares nothing.

File that away: it is the whole motivation for part iv, and for architectures that replace flatten+FC with pooling.

PART TWO · QUESTION ii
All zeros

Initialise every weight and bias to 0 — run an image through

iiThe chain of zeros

Follow one cell of layer A

  • True for every cell of every map: A = 22×22×20 of zeros. The image is erased at the first multiply.
  • Layer B convolves zeros with zeros: zeros again — and ReLU keeps them.

answer · part ii

Layer B outputs 20×20×40, every value exactly 0 — whatever the input image was.

Why nobody initialises this way

symmetry never breaks

All 20 filters are identical, so they receive identical gradients — they can never become different detectors. Random init exists to break this tie.

no gradient signal

Weight gradients scale with the activations flowing in — which are all 0. The conv layers cannot even start updating.

PART THREE · QUESTION iii
All ones

Weights 1, biases 0 — what does layer B look like?

iii · aWhat an all-ones filter does

Weighted sum → plain sum

  • Every weight is 1, so each filter just adds up its patch — an unnormalised box / averaging filter that also sums the channels together.
  • Sums of 0–255 values are never negative → ReLU never fires.
  • All 20 filters of A are identical → all 20 maps are the same map. Same for B’s 40.

value ranges

A cellΣ over 5×5×3 ≤ 255·75 = 19,125 B cell20 × (3×3 sum of A) ≤ 3,442,500

box ∘ box = pyramid

Cascading the 5×5 and 3×3 box filters is one 7×7 filter whose weights taper from the centre — a gentler, wider blur (the separable-Gaussian story from the filtering week, run in reverse):

So layer B’s map is the input, channel-summed, blurred with this 7×7 pyramid, ×20.

iii · bRun it — live, in this slide

Forty copies of a blur

INPUT
input 26×26×3
layer A · 22×22×20 · all 20 identical
layer B · 20×20×40 · all 40 identical

answer · part iii

Layer B outputs 20×20×40: a stack of 40 identical, blurry, brightness-summed copies of the input — both conv layers act as (unnormalised) averaging filters. Values are large positive sums; ReLU is a no-op. (Maps above are shown normalised for display.)

PART FOUR · QUESTION iv
Fewer parameters

Same number of filters · same effective kernel size — where can parameters go?

iv · 1Official move 1 · separable convolution

Factor the kernel spatially

spatially separable · 5×5 → 5×1 ∘ 1×5

Constrain each kernel slice to a rank-1 outer product — exactly how Gaussian and Sobel kernels factor. 10 numbers per slice instead of 25.

A: 20·3·10 + 20 = 620 (was 1,520) B: 40·20·6 + 40 = 4,840 (was 7,240)

Cost: only rank-1 kernels are expressible — a real constraint, usually a mild one.

Factor the kernel by channel

depthwise separable · the MobileNet pattern

One F×F filter per channel (space only), then 1×1 filters to mix channels. Receptive field and filter count unchanged.

A: (5·5·3+3)+(3·20+20) = 158 9.6× fewer B: (3·3·20+20)+(20·40+40) = 1,040 7.0× fewer

Layer B’s 7,200 weights become 180 + 800 = 980 — same 3×3 receptive field, same 40 maps out.

iv · 2Official move 2 · stack 3×3s in place of the 5×5

Two 3×3 see 5×5

  • Each cell after two 3×3 convs reaches 3+2 = 5 input cells each way — same effective kernel.
  • Output size even matches: 26 → 24 → 22.
  • The VGG argument, for C channels in and out: . Plus a free extra ReLU.

caveat for layer A

Here Cin is only 3, so the 5×5 is cheap (1,520) while a stack pays for channel mixing twice. It only wins if the middle conv stays narrow.

replace A with 3×3(m) → 3×3(20)

m = 3 28·3 + (9·3+1)·20 = 644 ✓ saves m = 7 28·7 + (9·7+1)·20 = 1,476 ✓ saves m = 8 28·8 + (9·8+1)·20 = 1,684 ✗ costs m = 20 28·20 + (9·20+1)·20 = 4,180 ✗ 2.7× worse

Break-even at m ≤ 7. The claim “stacked is smaller” is an architecture-dependent fact, not a law — check it with the counting rules you now own.

(The interactive lab page has this as a slider.)

iv · ✓Answer · part iv

answer · part iv

  • Replace the conv layers with separable convolutions (spatial 5×5 → 5×1∘1×5, or depthwise + 1×1).
  • Replace the 5×5 layer with stacked 3×3 convolutions (narrow middle).

Both keep 20 / 40 filters and the 5×5 / 3×3 effective kernels — the constraint is satisfied.

worth raising in the workshop

The constraint never mentioned layer D — where 82% of the parameters live. Swap flatten for global average pooling (mean of each 10×10 map → 40 values): D becomes 40·10+10 = 410, total 9,170. Filters and kernels untouched.

parameters, before → after each move (network total)
original48,770
spatially separable convs45,470
depthwise separable convs41,208
+ global average pooling head≈ 1,600

The conv moves shave the 18%; touching the head removes the mountain. Constraint-shaped answers and best answers are not always the same thing.

99Recap

The exercise on one slide

i · count

1,520 + 7,240 + 0 + 40,010 = 48,770. Shapes: 26→22→20→10, flatten 4,000.

ii · zeros

20×20×40 of exact zeros — 0·x kills the image, +0 and ReLU(0) keep it dead.

iii · ones

40 identical blurry copies of the (channel-summed) input — all-ones filters are unnormalised averaging filters; ReLU is a no-op.

iv · diet

Separable convolutions · stacked 3×3s — filters and effective kernels intact.

keep these two formulas


Pool / flatten / ReLU: 0. And always ask: “what is Cin here?”

refCompanion & sources

Companion

  • CNN Parameter Lab — the interactive page version of this walkthrough: conv playground, size calculator, drawable all-ones demo, stacked-conv slider.

Go deeper

Keys

→ / spaceadvance fragments & slides Sspeaker notes view Oslide overview ?print-pdfappend to the URL, then print to PDF

Exercise © COMP90086 Computer Vision (University of Melbourne) workshop materials. Deck follows the Workshop 2 slide system; built with reveal.js (MIT). All demo computation runs in-slide and is verified against a NumPy reference.