A finite impulse response filter, an image kernel and a CNN layer all form local weighted sums. Their indexing conventions—and the ways we compute them—matter.
The sliding sum
Linear convolution combines input x and kernel h as y[n] = Σₖ x[n−k]h[k]. The n−k reverses the kernel relative to the input before it slides. Boundary choices determine whether the output is full, same-sized or valid-only; they are part of the operation, not presentation detail.
Interactive experiment
One output, multiply by multiply
Which input values contribute to one sample of a three-tap smoothing filter?
Blue is the input and dashed amber is the full output. The moving window and filled blue points show the samples under the kernel; the large amber point is the selected output. The fixed kernel is [0.25, 0.5, 0.25].
Convolution versus cross-correlation
Cross-correlation uses x[n+k]h[k] and does not reverse the kernel. Most deep-learning APIs implement cross-correlation while naming the layer “convolution”. For learned weights this naming rarely harms optimisation—the network can learn the reversed pattern—but it matters when porting a known filter or comparing values across libraries.
From FIR to feature map
An FIR filter applies one kernel along time. A two-dimensional image filter applies weights across a spatial neighbourhood. A CNN layer adds input and output channels: each output location reduces a small spatial patch across every input channel, then usually adds a bias. Stride samples this output lattice; padding decides what the operator assumes beyond the boundary.
The frequency-domain identity
The DFT of a circular convolution is the pointwise product of DFTs. Linear convolution can use that identity after zero-padding enough to prevent wrap-around. Direct work scales roughly with output length times kernel length; FFT-based work adds transforms and pointwise products. Which is faster depends on sizes, batching, cache behaviour, implementation and hardware. No universal crossover is claimed here.
Where the analogy breaks
A classical filter is normally designed for a specified frequency response and remains fixed. A CNN kernel is fitted jointly with nonlinear layers, channel mixing and a loss. Inspecting its spectrum can be informative, but it does not reduce the network to an ordinary linear time-invariant system.
Implementation checklist
- Write down reversal, padding, stride and dilation conventions.
- Test impulse and boundary cases.
- Zero-pad before using an FFT for linear convolution.
- Measure the intended shape and hardware before selecting an algorithm.
Read one output before sliding
At output index 3 in the experiment, the products are 0.25 × x[3] + 0.5 × x[2] + 0.25 × x[1], giving 0.25 + 1 + 0.25 = 1.5. Move to index 0: only the first input overlaps, and samples outside the input are treated as zero. The boundary is why a full convolution of eight samples with three taps has ten outputs.
Why this kernel smooths
The weights sum to one, so a constant signal stays constant away from zero-padded edges. Alternating positive and negative values cancel because the middle weight balances its neighbours. In frequency terms this kernel suppresses rapid variation. Because its taps are symmetric, it also introduces a one-sample delay under the causal indexing used here.
Symmetry hides reversal. Try an asymmetric mental example: input [1, 2, 3] and kernel [1, −1]. Full convolution is [1, 1, 1, −3]. Valid cross-correlation is [−1, −1]; valid convolution is [1, 1]. Comparing the valid regions removes output-length differences and exposes the sign change caused by reversal.
Padding is a statement about the world
Zero padding assumes the unobserved input is zero. Reflection assumes the signal turns back at the edge. Circular padding joins the last sample to the first. Each can be reasonable in a different setting, and each creates a different boundary response. “Same” describes output size; it does not fully specify those assumptions or the alignment for an even-length kernel.
When an FFT helps
To multiply spectra for a linear convolution of lengths M and K, use a transform length of at least M + K − 1. Otherwise the tail wraps into the beginning. For long streams, overlap-add and overlap-save process blocks so transform work and latency stay bounded. For a short kernel, direct multiply–accumulate often has less setup and traffic; benchmark the shapes you actually use.
Further reading
PyTorch's Conv1d reference specifies the cross-correlation convention and output shapes. The aliasing essay explains why stride is a sampling decision in addition to a speed decision.