Modules / Deep Learning / Network Architecture

Calculating Parameters in CNNs

Explore how the size and number of filters, input channels, and biases dictate the total number of trainable parameters in a Convolutional layer.

A Single Filter (3D)

A filter is not just a 2D square! It extends through all input channels.

KxK
C_in
Parameters in ONE Filter:
3 × 3 × 3 = 27 weights
+ 1 bias term

Overview

Explore how the size and number of filters, input channels, and biases dictate the total number of trainable parameters in a Convolutional layer.

In this guide
  1. The formula
  2. Filters are three-dimensional
  3. Weight sharing, and the comparison that makes the point
  4. Counting weights, layer by layer
  5. A full worked case
  6. Params are not the whole cost
  7. Interactive Exploration Guide
  8. What trips people up
  9. In one line
  10. Checking it in code
  11. Rules of thumb
  12. Count each weight in a real design
  13. Questions people ask
  14. Recap in one screen

Calculating Parameters in CNN: A Practical Guide

A convolutional layer's parameter count depends on the filter size, the input channels and the number of filters - and not at all on the size of the image. That independence is the whole reason CNNs are practical.

The formula

For a convolutional layer with kernel size k×k, Cin input channels and F filters:

params = (k × k × Cin × F) + F

Each filter is a small 3-D volume of size k×k×Cin. And there are F of them. The trailing + F is one bias per filter.

The part worth pausing on is what is absent: the height and width of the input never appear. A layer applied to a 32×32 pic and the same layer applied to a 4096×4096 pic have just the same count of params. This is since the same filter slides across each spatial position — param sharing — so the count of learned weights depends just on the filter's shape, not the pic's. A fully connected layer with the same input and output would have H × W × C_in × H_out × W_out × C_out params. It for still a modest 32×32 pic is millions. The convolution formula gives a few thousand. That gap is the reason CNNs can process high-resolution pics at all. The param count also tells you how many training cases you need: a layer with 100,000 params trained on 1,000 pics is almost certainly overfitting, while the same layer on 100,000 pics is fine. This page lets you build a network layer by layer, shows the per-layer and cumulative param counts. And checks them to the equivalent fully connected layer.

Filters are three-dimensional

A “3×3 filter” on an RGB input is not 9 weights, it is 3×3×3 = 27. A filter always spans each input channel, since it looks for a pattern across all of them at once — an edge detector on colour pics must consider red, green and blue together.

Work one through. First conv layer, 3×3 kernel, RGB input, 64 filters:

(3 × 3 × 3 × 64) + 64 = 1728 + 64 = 1792

Second layer, 3×3 kernel, taking those 64 channels, giving 128:

(3 × 3 × 64 × 128) + 128 = 73728 + 128 = 73,856

Forty times more, from the same kernel size — since Cin and F both grew. The product of those two dominates. It is why deep layers with many channels hold most of a CNN’s weights.

Weight sharing, and the comparison that makes the point

A fully connected layer on a 224×224×3 pic with 64 outputs would need 224 × 224 × 3 × 64 ≈ 9.6 million params. The convolutional layer above does a comparable job with 1,792.

The saving comes from weight sharing: the same filter slides across each position rather than each position having its own weights. That encodes a real assumption — a vertical edge is a vertical edge wherever it appears — and it buys two things at once. Far fewer params, and translation equivariance, since a feature is detected the same way no matter where it sits.

Counting weights, layer by layer

Knowing where a network's params live tells you what will overfit, what will be slow. And where a design is wasteful. Three formulas cover almost all.

Convolution:

(kh × kw × Cin + 1) × Cout

Dense:

(inputs + 1) × outputs

Batch normalisation:

2 × C  (a scale and a shift per channel; the running statistics are not trained)

Pooling, ReLU, dropout and flattening have zero params — they compute. But they learn nothing.

The detail that catches everyone: a convolution filter spans all input channels. A 3×3 filter applied to a 256-channel map holds 3×3×256 = 2,304 weights.

A full worked case

A small classifier on 32×32×3 pics:

LayerOutput shapeParameters
Input32×32×30
Conv 3×3, 3232×32×32(3×3×3+1)×32 = 896
BatchNorm32×32×3264
MaxPool 2×216×16×320
Conv 3×3, 6416×16×64(3×3×32+1)×64 = 18,496
BatchNorm16×16×64128
MaxPool 2×28×8×640
Conv 3×3, 1288×8×128(3×3×64+1)×128 = 73,856
Flatten81920
Dense 256256(8192+1)×256 = 2,097,408
Dense 1010(256+1)×10 = 2,570

Total: 2,193,418 — and 96% of it is in one layer, the dense layer after the flatten.

That single observation drove a real architectural change. Replace the flatten with global average pooling and the 8×8×128 tensor turns 128 vals. So the dense layer needs (128+1)×256 = 33,024 params instead of 2.1 million. The network drops to about 127,000 params, trains faster, overfits less. And often scores the same or better.

Params are not the whole cost

Two other counts matter, and they behave differently.

Steps (FLOPs) depend on how many times each filter is applied:

FLOPs ≈ 2 × kh × kw × Cin × Cout × Hout × Wout

The first convolution above has 896 params and about 1.8 million multiply-adds, since it is applied at 1,024 positions. Early layers are param-light and compute-heavy. Late layers are the reverse.

Activation memory is what often limits batch size in training, since each intermediate feature map must be kept for the backward pass. A 224×224×64 map is 3.2 million floats — 12.8MB at 32-bit precision, per pic, for one layer. Multiply by batch size and by the count of layers and it dwarfs the weights.

That is why a net with 25 million params (about 100MB) can still exhaust a 16GB GPU: the weights are not the problem, the activations are.

Interactive Exploration Guide

  1. Grow the kernel. Raise 3x3 from 3 to 7 and watch the count. It grows with the square of the kernel size. So 7×7 costs more than five times a 3×3 — which is why modern networks stack small kernels instead.
  2. Grow the channels. Raise Input Channels and then Count of Filters. Each scales the count linearly, and together they scale it multiplicatively.
  3. Toggle the bias. Switch the bias checkbox and note the change is just F — a rounding error next to the weights. It is why layers followed by batch normalisation often drop it fully.
  4. Confirm the pic size is irrelevant. Nothing in the math means input height or width. That is the property that makes a CNN usable on large pics at all.

What trips people up

  • Forgetting the depth dimension. Counting a 3×3 filter as 9 weights instead of 9 × Cin is the most common error. And it understates the layer by a large factor.
  • Confusing params with activations. Params are fixed and independent of pic size. Activation memory scales with height × width × channels × batch. Out-of-memory errors in training are almost always activations, not weights.
  • With large kernels. Two stacked 3×3 layers cover the same receptive field as one 5×5 with fewer params and an extra non-linearity. VGG made this the standard.
  • Keeping the bias before batch norm. The normalisation subtracts the mean and cancels it just. So those params do nothing.

In one line

A convolutional layer holds (k × k × Cin × F) + F params, with filters spanning each input channel and the pic dimensions appearing nowhere. Weight sharing is what buys the enormous reduction against a fully connected layer, along with translation equivariance. Cost grows with the square of the kernel and the product of input and output channels — which is why small kernels and staged channel growth are the standard design.

Checking it in code

import torch
from torchvision.models import resnet18

model = resnet18()
total = sum(p.numel() for p in model.parameters())
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"{total:,} parameters, {trainable:,} trainable")

for name, module in model.named_children():
    n = sum(p.numel() for p in module.parameters())
    if n:
        print(f"{name:<12} {n:>12,}")

Two things worth checking with this. The trainable count should match your intent — if you froze a backbone for transfer learning and it still reports 11 million trainable params, the freezing did not take. And the per-module breakdown shows at once whether one layer dominates. It is nearly always fixable.

Storage follows right: 4 bytes per param in 32-bit precision, 2 in half precision, 1 in int8. A 25-million-param net is 100MB, 50MB or 25MB depending on precision. It is the arithmetic behind each quantisation decision.

Rules of thumb

  • Flatten-then-dense is where params explode. Global average pooling is the standard fix.
  • Doubling the channels roughly quadruples that layer's params, since both C_in and C_out appear in the formula.
  • Early layers cost compute. Late layers cost params. Optimise the right one for your constraint.
  • More params is not more capacity in any useful sense if they sit in a badly placed dense layer.
  • Batch normalisation is nearly free in params and considerably improves trainability.
  • 1×1 convolutions are the cheap way to change channel count, which is why bottleneck blocks use them either side of the costly 3×3.

Count each weight in a real design

The formula is one line per layer type. Applying it to a whole network shows that almost all the params sit somewhere people rarely look. And almost all the compute sits somewhere else fully.

example_01.pyNumPy
Output

Now apply those formulas to a full VGG-style network and see where the params really sit.

example_02.pyNumPy
Output

The table reveals the key insight: where params sit versus where compute sits.

example_03.pyNumPy
Output

Global average pooling solves that bottleneck. BatchNorm and bias removal also affect the count.

example_04.pyNumPy
Output

Questions people ask

Why does my net have more params than I calculated? Biases, batch normalisation. And any auxiliary heads. Also check whether an embedding or a large final classifier is included.

Do frozen layers count as params? They count in the total and not in the trainable count. And they still consume memory and compute in the forward pass.

How many params do I need? It depends on the data, not on a target. A few hundred thousand is plenty for CIFAR-scale problems. ImageNet-scale nets run to tens of millions.

Does more params mean better accuracy? Just with enough data. On a small dataset a large net overfits. And transfer learning from a pretrained one beats training a big net from scratch.

What limits my batch size? Activation memory, almost always, not the weights. Gradient checkpointing trades compute for memory when this binds.

How do I reduce params without losing much accuracy? Global average pooling instead of flatten, depthwise separable convolutions, fewer channels. And quantisation after training.

Recap in one screen

  • Conv: (k×k×C_in + 1) × C_out. Dense: (inputs + 1) × outputs. BatchNorm: 2 per channel.
  • Pooling, activations and dropout have no params.
  • Each filter spans each input channel — that is the term people forget.
  • The dense layer after a flatten often holds most of a naive network's weights. Global average pooling removes it.
  • Params are not the just cost: early layers dominate compute. And activation memory dominates GPU usage.

Recall check

0 of 4

Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.

  1. What is meant by “Flatten-then-dense is where params explode” here?

  2. What is meant by “Doubling the channels roughly quadruples that layer's params,” here?

  3. What is meant by “Early layers cost compute. Late layers cost params” here?

  4. What is meant by “More params is not more capacity in any useful sense” here?

Cheat sheet

Calculating Parameters in CNN

Count a CNN's trainable parameters layer by layer and see why image size never appears in the formula — only the filter shape does.

COMPUTER VISION · vizlearn.in/computer_vision/calculating_parameters_in_cnn.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.