Independence across axes

Convolutional layer parameters operate independently along each axis.
Formally, the choice of kernel size, stride, or padding along axis affects only the output size of axis , and does not interact with axis .

For example, in a 2D image: modifying the stride or padding along the horizontal axis changes the width of the output, but leaves the height unchanged.

Here, the term axis follows the same convention as in NumPy (and most deep learning libraries): axis 0 corresponds to rows (height), axis 1 to columns (width), and so on.

Dimostrazione

Note

Nel prosieguo, a meno di riferimenti espliciti, si assume che lo stride sia unitario: Stride


1. Quantità in gioco

SimboloSignificatoNota
dimensione del local receptive field (finestra nel caso )iper‑parametro
numero di valori nulli (zero padding) aggiunti per latoiper‑parametro
estensione dell’input lungo una qualunque dimensione (qui si sceglie la larghezza)dato del layer precedente
estensione dell’output lungo la stessa dimensioneincognita da calcolare

Il ragionamento per si replica mutatis mutandis per l’altezza e per qualsiasi altra dimensione spaziale (e.g. profondità nei dati 3‑D).


2. Estensione dovuta allo zero padding

Il padding inserisce valori nulli su ciascun lato della dimensione considerata. Se si considera la larghezza (width), ad esempio, questi vengono aggiunti ai bordi sinistro e destro dell’input.

La dimensione totale su cui il local receptive field potrà scorrere, ossia la dimensione effettiva (), è data dalla dimensione originale più i valori aggiunti su entrambi i lati.

In pratica, l’input viene “incorniciato” da zeri, passando da una struttura [dati] a una [zeri, dati, zeri] lungo quella dimensione.


3. Calcolo delle Posizioni del LRF (Stride = 1)

Per determinare la dimensione dell’output (), bisogna contare in quante posizioni distinte il local receptive field (LRF), di dimensione , può scorrere lungo la dimensione effettiva .

  • Il primo LRF si allinea con l’inizio della dimensione effettiva. Il suo indice di partenza è quindi 0.

  • L’ultimo LRF deve essere contenuto interamente nella dimensione effettiva. Un LRF di ampiezza che parte dall’indice occupa il range di indici . Per garantire che l’LRF non “sfori” i limiti, il suo ultimo elemento () non può superare l’ultimo indice della dimensione effettiva ():

    dove è la massima posizione di partenza del LRF consentita.

Important

La posizione finale valida per l’inizio del LRF è quindi .

Conteggio Totale

L’estensione dell’output lungo la dimensione in esame () è uguale al numero totale di posizioni che l’LRF può assumere. Poiché gli indici di partenza vanno da a , il conteggio è: Sostituendo i valori trovati, si ottiene:


4. Formula finale

Stante la formula ricavata al passo precedente:

poiché :

allora:

Applicando lo stesso ragionamento alla dimensione verticale:

e, in un dominio 3‑D, analogamente per la profondità.

Caso generale

La relazione

\text{dimensione_out} = \text{dimensione_in} - K + 2P + 1


Formula generale per la dimensione dell’output (Stride )

Quando lo stride è maggiore di 1, la finestra (LRF) salta di posizioni invece di scorrere di 1. In questo caso, il numero di posizioni valide è dato da:

Info

La formula tiene conto del fatto che, partendo da indice 0 e saltando di , l’ultima posizione utile è quella più grande per cui il filtro non esce dal dominio paddato.

Viene quindi calcolato quante volte il filtro “entra” nell’input con salto , fino all’ultima posizione valida:

e da qui il conteggio delle posizioni è .

Applicando la stessa formula alla dimensione verticale o ad altre dimensioni spaziali:

e in un dominio 3D si procede allo stesso modo per la profondità.


Padding che preserva la dimensione ()

Imponendo che la dimensione spaziale dell’output identica a quella dell’input () nella formula (con ): si ottiene: Semplificando si arriva alla relazione che deve soddisfare il padding:

Tipo di KernelConcetto ChiaveFormula per il Padding (P)Esempi Pratici
DispariPermette un padding esatto e simmetrico, mantenendo le dimensioni dell’output identiche a quelle dell’input (con stride 1).- Se
- Se
Pari / GeneraleFornisce un valore di padding “ragionevole” quando un kernel pari è inevitabile. La soluzione non è perfettamente centrata. (Equivalente a )- Per
- Per

Il Caso Standard: Kernel di Dimensione Dispari

La suddetta formula evidenzia un concetto fondamentale.

Poiché il padding deve essere un numero intero, una soluzione esatta e simmetrica è possibile solo quando il numeratore è pari, e cioè quando la dimensione del kernel è dispari. Questa è la ragione principale per cui nella pratica si usano quasi esclusivamente kernel di dimensione dispari (, etc.). In questo scenario, la formula è semplice e diretta.

Esempi:

  • Se , il padding necessario è .
  • Se , il padding necessario è .

I Kernel Pari Non Preservano Esattamente la Dimensione

Allorché si usi un kernel di dimensione pari con stride , è matematicamente impossibile preservare la dimensione esatta dell’input con un padding simmetrico. La formula con ceiling fornisce un valore di padding, ma l’output si ridurrà comunque.

Esempio con :

  1. Calcolo del Padding: .
  2. Dimensione di Output Risultante: Usando la formula generale , si ottiene:

Come si vede, la dimensione di output si riduce di 1 pixel. Questo avviene perché un kernel pari non ha un pixel centrale, rendendo impossibile una sovrapposizione perfettamente simmetrica.

PyTorch mapping & quick checks

Symbol ↔ PyTorch args

Math symbolMeaningPyTorch (Conv2d/MaxPool2d/AvgPool2d)
kernel sizekernel_size
(symmetric) padding per sidepadding (int/tuple) or 'same'¹
stridestride
dilationdilation
effective kernel = derived (no direct arg)

¹ Asymmetric padding in PyTorch: use torch.nn.ZeroPad2d((left, right, top, bottom)) or torch.nn.functional.pad(...) before the conv.


Output size (Conv/Pool) — PyTorch-exact

For 1D/2D/3D conv and pooling, PyTorch uses:

Equivalently, with effective kernel :

Quick sanity checks (run in a PyTorch REPL)

import torch, torch.nn as nn
x = torch.zeros(1, 3, 32, 32)               # N=1,C=3,H=W=32
 
# 3x3, stride=1, padding=1  → out=32
m = nn.Conv2d(3, 8, kernel_size=3, stride=1, padding=1)
print(m(x).shape)  # torch.Size([1, 8, 32, 32])
 
# 5x5, stride=2, padding=2  → out=floor((32+4-5)/2)+1 = 16
m = nn.Conv2d(3, 8, kernel_size=5, stride=2, padding=2)
print(m(x).shape)  # torch.Size([1, 8, 16, 16])
 
# Dilation doubles the effective kernel: K_eff = 2*(3-1)+1 = 5
m = nn.Conv2d(3, 8, kernel_size=3, stride=1, padding=2, dilation=2)
print(m(x).shape)  # torch.Size([1, 8, 32, 32])  since (32+4-5)/1+1 = 32

"same" padding in PyTorch

  • nn.Conv{1,2,3}d(..., padding='same') picks (possibly asymmetric) padding so that
  • With stride and odd (any ), this reduces to symmetric padding
  • With even or , PyTorch uses asymmetric padding internally to satisfy the ceil rule.

Example

x = torch.zeros(1, 3, 32, 32)
# stride=2, 'same' → out = ceil(32/2) = 16
m = nn.Conv2d(3, 16, kernel_size=3, stride=2, padding='same')
print(m(x).shape)  # torch.Size([1, 16, 16, 16])

Transposed conv (a.k.a. deconv) — PyTorch-exact

For nn.ConvTranspose{1,2,3}d:

Example

x = torch.zeros(1, 8, 16, 16)
# K=3,S=2,P=1,output_padding=1 → out=(16-1)*2 - 2 + 2 + 1 + 1 = 32
m = nn.ConvTranspose2d(8, 3, kernel_size=3, stride=2, padding=1, output_padding=1)
print(m(x).shape)  # torch.Size([1, 3, 32, 32])

How dilation maps to your RF derivation

Plug into your formulas

In your receptive-field derivations, replace every kernel size with the effective kernel

for layers that use dilation .
All RF recurrences and closed forms remain valid with .


Asymmetric padding (p_l vs q_l) in PyTorch

Your notes distinguish left/right padding (, ). PyTorch’s Conv2d(..., padding=…) is symmetric; if you need asymmetric padding to match your exactly:

import torch.nn.functional as F
 
def conv2d_asym(x, weight, bias=None, stride=1, dilation=1, pleft=0, pright=0, ptop=0, pbot=0):
    x = F.pad(x, (pleft, pright, ptop, pbot))   # (left, right, top, bottom)
    return F.conv2d(x, weight, bias=bias, stride=stride, padding=0, dilation=dilation)