Salta ai contenuti

Filtri, convoluzione, smoothing, edge detection

La convoluzione come unica operazione che governa lo smoothing, lo sharpening e l’edge detection; i filtri come scelta di quali frequenze tenere; e perché lo stesso conto che sfoca un’immagine, una volta reso apprendibile, è il cuore delle reti convoluzionali e ricompare nella convoluzione causale di Mamba.

Sfochi una foto, e l’hai convoluta con un kernel gaussiano. Estrai i bordi di un volto per un filtro fotografico, e hai convoluto con un kernel di Sobel. Calcoli la media mobile della latenza di un servizio per vederne il trend, e hai convoluto con un kernel uniforme. Le tre cose sembrano operazioni diverse, fatte con strumenti diversi per scopi diversi. Sono la stessa identica operazione, con kernel diversi.

Quell’operazione è la convoluzione, e nel mondo dei segnali è centrale al punto che si può dire senza esagerare: ogni filtro, ogni riverbero, ogni smoothing, ogni rilevatore di pattern calcola, sotto il cofano, una convoluzione. Il capitolo che apre questa Parte, Segnali continui, discreti, sistemi lineari, l’ha già enunciata e ne ha mostrato un esempio a mano; il capitolo sul campionamento l’ha usata due volte, per il filtro anti-aliasing e per la ricostruzione sinc. Questo è il capitolo che le dà il trattamento completo che gli altri due hanno solo promesso.

C’è una ragione precisa per cui chi lavora con l’AI dovrebbe padroneggiare questa operazione, e non è erudizione. La convoluzione è il cuore delle reti convoluzionali, le CNN che hanno dominato la computer vision per un decennio.

Ma il legame va maneggiato con cura: nel signal processing classico il kernel è progettato a mano per uno scopo noto, mentre nelle CNN i kernel sono appresi dai dati. La stessa macchina, con una differenza che cambia tutto. E la convoluzione ricompare, in forma causale e lunga, dentro architetture moderne come Mamba. Capire la convoluzione come operazione dei sistemi lineari demistifica in un colpo i filtri classici, i primi layer di una rete vision e l’equivalenza ricorrente-convoluzionale dei modelli a spazio di stato — e, soprattutto, permette di distinguere quando c’è un’identità matematica, quando una discendenza storica e quando solo un’analogia comoda.

Il filtraggio nasce molto prima dei computer, ed era fatto di rame e ceramica. Un filtro era un circuito: resistenze, condensatori, bobine combinati in modo da lasciar passare certe frequenze e attenuarne altre. L’equalizzatore di un impianto stereo, il crossover che manda i bassi al woofer e gli acuti al tweeter, la manopola che sintonizza una radio su una stazione e non sulle altre: tutto questo era filtraggio analogico, tensioni vere su fili veri, ben prima che esistesse un solo bit.

Il quadro teorico che unifica tutti questi marchingegni sotto un’unica operazione è la teoria dei sistemi lineari e tempo-invarianti (gli LTI, Linear Time-Invariant: sistemi che rispettano la sovrapposizione e si comportano uguale in ogni istante), maturata nell’ingegneria delle telecomunicazioni a metà del Novecento.

Il risultato cardine di quella teoria, già visto nel capitolo introduttivo, è doppio. Primo: un sistema LTI è interamente descritto da una sola funzione, la sua risposta all’impulso — come reagisce a un singolo colpo secco. Secondo: la sua uscita per qualunque ingresso è la convoluzione dell’ingresso con quella risposta. Un solo numero misurato (la risposta a un impulso) e un’unica operazione (la convoluzione) bastano a prevedere il comportamento del sistema su ogni segnale possibile.

Lo spostamento dal rame al software arriva con i computer, e ha una data simbolica. Nel 1965 James Cooley e John Tukey (matematici americani) pubblicano “An Algorithm for the Machine Calculation of Complex Fourier Series” (Mathematics of Computation), introducendo la Fast Fourier Transform: un modo di calcolare la trasformata di Fourier in tempo proporzionale a NlogNN \log N invece che a N2N^2.

Sembra un dettaglio tecnico, ma è ciò che rende il filtraggio numerico praticabile, anche in tempo reale, e fa nascere il DSP, l’elaborazione numerica dei segnali. Da lì in poi il filtro è codice: una funzione che prende un vettore di campioni e ne restituisce un altro, invece di un circuito da saldare.

In parallelo, dagli anni Settanta, l’elaborazione dell’immagine sviluppa il suo repertorio di filtri convoluzionali progettati a mano: il kernel gaussiano per sfocare, il kernel di Sobel (dal nome di Irwin Sobel, ingegnere che lo propose alla fine degli anni Sessanta) per i bordi, il Laplaciano per i contorni fini.

Sono filtri costruiti da un umano che sa cosa vuole rilevare: si decide a priori la forma del kernel in base all’effetto desiderato. Questo è esattamente il sostrato tecnico da cui, decenni dopo, le reti convoluzionali ereditano l’operazione — cambiando una cosa sola, ma decisiva: chi sceglie i pesi del kernel.

Nella mappa di questa Parte, il capitolo siede dopo il campionamento e prima di Fourier (fourier-intuizione, in preparazione, questa Parte) nell’ordine, anche se logicamente i due si sostengono a vicenda: i filtri si capiscono meglio in frequenza, e la frequenza è l’oggetto di Fourier. Anticiperemo quel legame con il teorema di convoluzione, marcando con onestà che la sua dimostrazione vive nel capitolo successivo.

La convoluzione si può guardare da due angoli che illuminano pezzi diversi. Il primo è meccanico e concreto: una media mobile pesata che scorre. Il secondo è strutturale: la risposta di un sistema lineare a un ingresso qualunque. Tenerli entrambi evita di ridurre la convoluzione a un trucco di calcolo o, all’opposto, a un’astrazione senza presa.

Immagina di voler ammorbidire una curva frastagliata — la latenza di un servizio misurata ogni minuto, piena di picchi casuali. L’idea più naturale: sostituisci ogni punto con la media dei suoi vicini. Il punto di oggi diventa la media di ieri, oggi e domani.

I picchi isolati si abbassano, perché vengono diluiti con i vicini più calmi; l’andamento di fondo, che cambia lentamente, sopravvive quasi intatto. Hai ottenuto una curva più liscia senza buttare via la tendenza che ti interessa.

Questa è già una convoluzione. Hai una finestra di pesi — qui tre pesi uguali a 1/31/3 — che fai scorrere lungo il segnale. A ogni posizione, moltiplichi i pesi per i campioni che ci stanno sotto e sommi. Il risultato è il nuovo valore in quella posizione. Sposti la finestra di un passo, ripeti.

Cambia i pesi e cambi l’effetto, pur con la stessa macchina. Se i pesi sono una gaussiana (alti al centro, bassi ai lati), pesi di più i vicini stretti e ottieni uno smoothing morbido: il blur.

Se invece i pesi sono [1,0,1][-1, 0, 1], non stai più mediando: stai calcolando una differenza tra il vicino a destra e quello a sinistra. Dove il segnale è piatto la differenza è zero; dove cambia di colpo — un bordo — la differenza è grande. Lo stesso scorri-moltiplica-somma, pesi diversi, e da smoothing diventa edge detection.

Questa è la prima cosa da portare via: la convoluzione è una sola operazione, e il kernel decide cosa fa. Sfocare e trovare i bordi non sono due algoritmi: sono lo stesso algoritmo con due finestre di pesi diverse.

Secondo angolo: la risposta di un sistema a un colpo solo

Sezione intitolata “Secondo angolo: la risposta di un sistema a un colpo solo”

Il secondo angolo viene dal capitolo introduttivo e dà alla convoluzione il suo significato profondo, non solo procedurale. Un sistema LTI — un filtro, un amplificatore, una stanza che riverbera — è completamente descritto da come reagisce a un singolo impulso: un colpo secco, infinitamente stretto. Quella reazione si chiama risposta all’impulso, e la indichiamo con hh.

Perché un colpo solo basta a descrivere tutto? Perché qualunque segnale si può vedere come una sequenza di colpi: un campione qui, uno lì, ciascuno con la propria altezza. Per la linearità del sistema, la risposta alla somma di colpi è la somma delle risposte ai singoli colpi. Per la tempo-invarianza, la risposta a un colpo ritardato è la risposta al colpo originale, ritardata uguale.

Quindi: prendi ogni campione dell’ingresso, sostituiscilo con una copia di hh scalata da quel campione e centrata dove stava il campione, e somma tutte queste copie sovrapposte. La somma è l’uscita. È il movimento della sovrapposizione, applicato fino in fondo: un sistema lineare e tempo-invariante è completamente determinato da come reagisce a un singolo colpo.

Quella somma di copie scalate e traslate di hh è, parola per parola, la convoluzione. Ecco perché filtrare con un kernel hh ed “essere un sistema LTI con risposta all’impulso hh” sono la stessa cosa. Il kernel del primo angolo (la finestra di pesi che scorre) e la risposta all’impulso di questo angolo sono lo stesso oggetto, visto da due lati. Progettare un filtro significa scegliere quella hh.

I due angoli si saldano: la finestra di pesi che scivola è la risposta all’impulso ribaltata che scorre, e il “moltiplica e somma” è la sovrapposizione delle risposte ai singoli colpi. Uno è la procedura, l’altro è il perché la procedura calcola proprio ciò che il sistema fa.

Terzo angolo: misurare quanto il segnale somiglia al kernel

Sezione intitolata “Terzo angolo: misurare quanto il segnale somiglia al kernel”

C’è un terzo modo di leggere la convoluzione, e fa da ponte diretto verso le reti neurali. A ogni posizione, l’operazione “moltiplica punto per punto e somma” è esattamente un prodotto scalare tra il kernel e il pezzo di segnale che ci sta sotto. E un prodotto scalare misura quanto due cose si somigliano: è grande quando i due vettori puntano nella stessa direzione, piccolo o negativo quando divergono.

Letta così, la convoluzione fa scorrere un pattern (il kernel) lungo il segnale e, a ogni posizione, risponde con un numero che dice quanto il segnale localmente assomiglia a quel pattern. Dove il pezzo di segnale ha la stessa forma del kernel, la risposta si accende; dove ha forma diversa, resta spenta.

Nel DSP questa idea ha un nome, matched filter: il filtro la cui risposta all’impulso ha la forma del segnale che vuoi rilevare risponde al massimo proprio quando quel segnale passa. È il principio dietro la rilevazione di un’eco radar o di una sequenza nota in un canale rumoroso: costruisci il kernel a immagine di ciò che cerchi, e la convoluzione ti dice dove e quanto forte compare.

Questo angolo spiega perché un kernel di edge detection “trova i bordi”: il kernel [1,0,1][-1, 0, 1] ha la forma di una transizione, e si accende dove il segnale fa una transizione. È anche il modo più diretto per capire cosa fa un kernel appreso in una CNN: ogni kernel è un piccolo pattern, e la mappa di uscita dice dove nell’immagine quel pattern compare.

I tre angoli sono lo stesso oggetto visto da tre lati — media mobile pesata, risposta di un sistema LTI, rilevatore di pattern — e ciascuno illumina un uso diverso. Il primo serve a intuire lo smoothing, il secondo a capire perché un filtro è un sistema, il terzo a leggere cosa fa un filtro come ricerca di una forma. Tienili tutti e tre: ciascuno torna utile in un contesto diverso del resto del capitolo.

La convoluzione a tempo discreto di un ingresso xx con una risposta all’impulso hh è

y[n]=k=x[k]h[nk]y[n] = \sum_{k=-\infty}^{\infty} x[k]\, h[n-k]

Leggiamola con calma, perché ogni pezzo conta. Per calcolare l’uscita all’istante nn: scorri tutti gli indici kk dell’ingresso; per ciascuno moltiplica il campione x[k]x[k] per la risposta all’impulso valutata in h[nk]h[n-k]; somma tutti questi prodotti.

Il termine h[nk]h[n-k] è il cuore dell’operazione, e contiene due movimenti. Il segno meno davanti a kk ribalta la risposta all’impulso, la specchia rispetto all’origine. L’nn la trasla nella posizione corrente, la fa scivolare dove stiamo calcolando l’uscita.

Questi due movimenti — ribalta e trasla — sono ciò che rende l’operazione una convoluzione e non una banale moltiplicazione punto per punto. La procedura completa, nota come flip-and-slide, ha quattro mosse: ribalta hh, fallo scorrere fino alla posizione nn, moltiplica punto per punto con l’ingresso dove i due si sovrappongono, somma i prodotti. Ripeti per ogni nn.

La versione a tempo continuo sostituisce la somma con un integrale, ma la struttura è identica. Dove nel discreto sommiamo su un indice intero, nel continuo integriamo su una variabile reale:

y(t)=(xh)(t)=x(τ)h(tτ)dτy(t) = (x * h)(t) = \int_{-\infty}^{\infty} x(\tau)\, h(t-\tau)\, d\tau

L’asterisco * è il simbolo standard della convoluzione (da non confondere con la moltiplicazione). In parole povere, l’uscita ora è una media pesata dell’ingresso, dove i pesi sono dati dalla forma di hh.

Numeri minuscoli tolgono ogni mistero. Prendi un ingresso di due soli campioni e una risposta all’impulso corta:

x=[2,  3],h=[1,  1]x = [\,2,\; 3\,], \qquad h = [\,1,\; 1\,]

La convoluzione produce un risultato lungo quanto la somma delle lunghezze meno uno: qui 2+21=32 + 2 - 1 = 3 valori. Li calcoliamo uno per uno, applicando la formula:

y[0]=x[0]h[0]=21=2y[0] = x[0]\,h[0] = 2 \cdot 1 = 2 y[1]=x[0]h[1]+x[1]h[0]=21+31=5y[1] = x[0]\,h[1] + x[1]\,h[0] = 2 \cdot 1 + 3 \cdot 1 = 5 y[2]=x[1]h[1]=31=3y[2] = x[1]\,h[1] = 3 \cdot 1 = 3

Il risultato è y=[2,  5,  3]y = [\,2,\; 5,\; 3\,]. Guarda cosa è successo: con h=[1,1]h = [1, 1] il sistema somma ogni campione con il precedente, e infatti il valore centrale 55 è la somma dei due ingressi nel punto dove si sovrappongono.

Cambia hh in [1,1][1, -1] e otterresti y=[2,1,3]y = [2, 1, -3]: lo stesso meccanismo, ora calcola differenze invece di somme. Il kernel decide, sempre.

Questa regola sulla lunghezza ha un nome implementativo. La modalità che restituisce tutti gli N+M1N + M - 1 campioni si chiama full. Spesso si vuole un’uscita lunga come l’ingresso (modalità same, si taglia ai bordi) oppure solo le posizioni di pieno sovrapposizione (modalità valid, lunghezza NM+1N - M + 1). Sono convenzioni su come trattare i bordi, dove il kernel sporge oltre il segnale; la matematica sotto è sempre la stessa.

La convoluzione è commutativa: xh=hxx * h = h * x. Conta più di quanto sembri: significa che non c’è differenza formale tra “il segnale scorre sotto il kernel fermo” e “il kernel scorre sopra il segnale fermo”. È la stessa operazione vista da due posti.

È associativa: (xh1)h2=x(h1h2)(x * h_1) * h_2 = x * (h_1 * h_2). Filtrare in cascata con due filtri equivale a filtrare una volta sola con il filtro combinato h1h2h_1 * h_2. È il motivo per cui un blur seguito da un altro blur è ancora un blur (più forte), e per cui si possono pre-combinare più filtri in uno per risparmiare calcolo.

È distributiva sulla somma: x(h1+h2)=xh1+xh2x * (h_1 + h_2) = x*h_1 + x*h_2. Discende direttamente dalla linearità del sistema, ed è il motivo per cui un filtro che sia la somma di due filtri si può applicare a pezzi e poi sommare.

La convoluzione in due dimensioni: kernel su immagini

Sezione intitolata “La convoluzione in due dimensioni: kernel su immagini”

Tutto quello che abbiamo visto in una dimensione si estende a due senza cambiare nulla di concettuale. Un’immagine in scala di grigi è un segnale I[x,y]I[x, y]: una griglia di valori. Un kernel 2D è una piccola matrice di pesi — tipicamente 3×33 \times 3 o 5×55 \times 5 — che si fa scorrere su tutta la griglia. A ogni posizione, si moltiplicano i pesi del kernel per i pixel sottostanti e si sommano in un singolo valore di uscita. Lo stesso scorri-moltiplica-somma del caso 1D, su una griglia invece che su una riga.

Tre kernel classici dell’image processing mostrano l’intero spettro degli effetti. Il kernel gaussiano (pesi che decrescono dal centro verso i bordi, normalizzati a somma 11) è un passa-basso: produce il blur. Il kernel di Sobel è una versione 2D del kernel di differenza: ne esistono due, uno per i bordi verticali e uno per gli orizzontali. Quello verticale ha la forma

[101202101]\begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \end{bmatrix}

Leggiamolo: la colonna di destra ha pesi positivi, quella di sinistra negativi, quella centrale zero. Dove l’immagine è uniforme, positivi e negativi si annullano e l’uscita è zero; dove c’è una transizione orizzontale di luminosità — un bordo verticale — i due lati non si bilanciano e l’uscita è grande. È un passa-alto orientato: misura quanto velocemente cambia l’intensità in direzione orizzontale. Il Laplaciano (pesi 1-1 tutt’intorno e +8+8 al centro, o varianti) misura invece la curvatura, e risponde ai contorni fini in ogni direzione.

C’è una proprietà che rende il blur gaussiano economico, e si appoggia sull’associatività vista sopra: il kernel gaussiano 2D è separabile, cioè si può scrivere come la convoluzione di due kernel 1D — uno orizzontale e uno verticale.

Invece di un kernel 5×55 \times 5 (venticinque moltiplicazioni per pixel) si applicano due kernel da cinque pesi in sequenza (dieci moltiplicazioni per pixel). Per kernel grandi il risparmio è sostanziale, ed è il motivo per cui i blur gaussiani delle librerie grafiche sono veloci. La stessa convoluzione, scomposta in due passaggi più economici grazie all’associatività: (Igx)gy=I(gxgy)(I * g_x) * g_y = I * (g_x * g_y), e gxgyg_x * g_y è proprio il gaussiano 2D.

Fin qui abbiamo guardato la convoluzione nel tempo. Ma c’è un secondo punto di vista, già anticipato nel capitolo introduttivo, che rende i filtri trasparenti: il dominio della frequenza. Ogni segnale si può descrivere non con la sua evoluzione nel tempo, ma con la ricetta delle frequenze che lo compongono. Un sistema LTI, in questo dominio, è descritto dalla sua risposta in frequenza H(f)H(f): un numero per ogni frequenza, che dice di quanto quella frequenza viene amplificata o attenuata attraversando il sistema.

Filtrare significa esattamente scegliere la forma di H(f)H(f). Decidere quanto tenere di ogni frequenza è progettare un filtro, e la forma di H(f)H(f) determina interamente cosa il filtro fa al segnale. Da qui i nomi delle quattro classi di filtri, ciascuna definita dalla forma della sua risposta in frequenza:

  • Passa-basso (low-pass): H(f)H(f) vale circa 11 per le frequenze basse e cala verso 00 per quelle alte. Lascia passare l’andamento lento, taglia le variazioni rapide. Effetto nel tempo: smussa, sfoca, fa smoothing. Esempi di kernel: la media mobile uniforme, il gaussiano. È il filtro anti-aliasing del capitolo sul campionamento.
  • Passa-alto (high-pass): l’opposto. Vale 00 in basso e 11 in alto. Taglia il lento, lascia il rapido. Effetto nel tempo: esalta i bordi e i dettagli, rimuove la componente continua. Esempi: i kernel di differenza, Sobel, Laplaciano. È la famiglia dell’edge detection.
  • Passa-banda (band-pass): lascia passare solo una finestra di frequenze intermedie, taglia sotto e sopra. È il principio della sintonia di una radio: isolare la banda di una stazione e zittire il resto. I filtri di Gabor — gaussiana modulata da una sinusoide — sono passa-banda orientati e localizzati nello spazio.
  • Elimina-banda (band-stop o notch): l’opposto del passa-banda, toglie una finestra stretta e lascia passare tutto il resto. Il caso tipico è il filtro notch a 50 o 60 Hz che rimuove il ronzio della rete elettrica da una registrazione audio o da un tracciato ECG, senza toccare il resto del segnale.

L’idea unificante è una sola: un filtro è una scelta di quali frequenze tenere e quali buttare, e il nome del filtro descrive la forma della sua risposta in frequenza.

C’è un fatto che lega i due domini e spiega perché tutto il campo ama lavorare in frequenza. Si chiama teorema di convoluzione, ed enuncia che la convoluzione nel tempo corrisponde alla moltiplicazione nel dominio della frequenza:

xh        XHx * h \;\;\longleftrightarrow\;\; X \cdot H

dove XX e HH sono le trasformate di Fourier di xx e hh, e il punto è una moltiplicazione frequenza per frequenza. Vale anche il duale: moltiplicare nel tempo corrisponde a convolvere in frequenza.

In parole povere: invece di far scorrere hh lungo il segnale e sommare prodotti — un’operazione che costa dell’ordine di NMN \cdot M moltiplicazioni — porti entrambi nel dominio della frequenza, li moltiplichi punto per punto (dell’ordine di NN operazioni), e torni indietro.

Con la FFT i due passaggi avanti e indietro costano NlogNN \log N ciascuno, e il totale resta NlogNN \log N: per kernel lunghi è enormemente meno di NMN \cdot M. È esattamente il motivo per cui la FFT di Cooley e Tukey fu dirompente: rese il filtraggio via frequenza abbastanza veloce da usarlo in pratica, e oggi è il modo standard di applicare filtri lunghi a segnali lunghi.

Questo è un teorema, non un’analogia: una relazione formalmente provabile, valida sotto ipotesi precise sulla trasformata. La sua dimostrazione richiede la trasformata di Fourier e vive nel capitolo successivo, fourier-intuizione (in preparazione, questa Parte). Qui lo enunciamo e lo usiamo come strumento, marcando esplicitamente che è il prossimo capitolo a renderlo rigoroso.

Il teorema spiega anche perché i nomi dei filtri sono così puliti. Un passa-basso ideale, in frequenza, è semplicemente H(f)H(f) che vale 11 sotto una soglia e 00 sopra: una scalinata netta. Lo stesso filtro, nel tempo, è una funzione sinc, un kernel oscillante e infinitamente lungo (l’abbiamo incontrato come filtro di ricostruzione nel capitolo sul campionamento). In frequenza: banale. Nel tempo: laborioso. Stessa identica operazione, due descrizioni di difficoltà opposta.

Un cenno a una distinzione che ricorre appena si implementano filtri. I filtri digitali si dividono in due famiglie a seconda di quanto dura la loro risposta all’impulso.

Un filtro FIR (Finite Impulse Response, risposta all’impulso finita) ha una hh di durata finita: l’uscita è una somma finita di campioni passati dell’ingresso, pesati. È esattamente una convoluzione con un kernel finito — il caso che abbiamo trattato finora.

I FIR sono sempre stabili (la somma di un numero finito di pesi è finita), possono avere fase lineare (non distorcono la forma del segnale), ma per tagli ripidi richiedono molti pesi e quindi più calcolo. I kernel delle CNN sono FIR per costruzione: finestre finite di pesi, senza alcun feedback.

Un filtro IIR (Infinite Impulse Response, risposta all’impulso infinita) è invece ricorsivo: l’uscita dipende non solo dall’ingresso ma anche da uscite passate, in uno schema come y[n]=kakx[nk]kbky[nk]y[n] = \sum_k a_k\, x[n-k] - \sum_k b_k\, y[n-k]. Quel secondo termine, che richiama le uscite precedenti, è il feedback.

Questo feedback rende la risposta all’impulso infinitamente lunga, e con pochi coefficienti ottiene tagli molto ripidi (è l’equivalente digitale dei filtri analogici RC e RLC). Il prezzo: un IIR mal progettato può essere instabile e divergere, e introduce distorsione di fase. La differenza pratica da ricordare: il FIR è una convoluzione pura e sempre stabile; l’IIR ha memoria ricorsiva — uno stato, nel senso della teoria dei sistemi — e va progettato con attenzione alla stabilità.

Esempio 1 — numerico: blur contro bordi, stesso meccanismo

Sezione intitolata “Esempio 1 — numerico: blur contro bordi, stesso meccanismo”

Prendi una riga di pixel con un bordo netto: una zona scura che diventa chiara di colpo.

x=[10,  10,  10,  200,  200,  200]x = [\,10,\; 10,\; 10,\; 200,\; 200,\; 200\,]

Convolviamola prima con un kernel di smoothing hblur=[13,13,13]h_{\text{blur}} = [\tfrac{1}{3}, \tfrac{1}{3}, \tfrac{1}{3}] (media mobile), in modalità “valid”:

y[0]=13(10+10+10)=10,y[1]=13(10+10+200)=73.3,y[2]=13(10+200+200)=136.7,y[3]=13(200+200+200)=200y[0] = \tfrac{1}{3}(10+10+10) = 10, \quad y[1] = \tfrac{1}{3}(10+10+200) = 73.3, \quad y[2] = \tfrac{1}{3}(10+200+200) = 136.7, \quad y[3] = \tfrac{1}{3}(200+200+200) = 200

Il bordo netto si è ammorbidito: dove prima c’era un salto da 1010 a 200200, ora c’è una rampa che sale gradualmente attraverso 73.373.3 e 136.7136.7. Questo è il blur.

Ora la stessa riga con un kernel di differenza hbordo=[1,0,1]h_{\text{bordo}} = [-1, 0, 1]:

y[0]=10+10=0,y[1]=10+200=190,y[2]=10+200=190,y[3]=200+200=0y[0] = -10 + 10 = 0, \quad y[1] = -10 + 200 = 190, \quad y[2] = -10 + 200 = 190, \quad y[3] = -200 + 200 = 0

Il risultato è [0,190,190,0][0, 190, 190, 0]: zero dove l’immagine è piatta (a sinistra e a destra), grande in corrispondenza del bordo. Questo è l’edge detection. Stessa operazione, stessa riga di input, due kernel: uno sfuma il bordo, l’altro lo isola. È la dimostrazione numerica che il kernel è tutto.

Esempio 2 — in codice: smoothing, bordi e blur gaussiano

Sezione intitolata “Esempio 2 — in codice: smoothing, bordi e blur gaussiano”
import numpy as np
segnale = np.array([10, 10, 10, 200, 200, 200], dtype=float)
# Passa-basso: media mobile -> smussa il bordo
smoothing = np.convolve(segnale, [1/3, 1/3, 1/3], mode="valid")
print(smoothing) # [ 10. 73.3 136.7 200. ] bordo ammorbidito
# Passa-alto: differenza -> isola il bordo
bordi = np.convolve(segnale, [-1, 0, 1], mode="valid")
print(bordi) # [ 0. 190. 190. 0. ] picco sul bordo
# Blur gaussiano 1D: pesi da una gaussiana, normalizzati a somma 1
g = np.array([1, 4, 6, 4, 1], dtype=float)
g = g / g.sum()
blur = np.convolve(segnale, g, mode="same")
print(blur) # smoothing morbido: il centro pesa, i bordi quasi no

Tre filtri, una sola funzione (np.convolve). Il kernel uniforme media in modo piatto; il gaussiano [1,4,6,4,1] pesa di più il centro, producendo uno smoothing più naturale (è il blur standard in image processing); il kernel di differenza non media affatto, misura quanto velocemente cambia il segnale.

In due dimensioni — su un’immagine vera invece che su una riga — vale lo stesso. Il gaussiano si applica come kernel quadrato e produce la sfocatura che vedi in ogni programma di fotoritocco; il Sobel, una versione 2D del kernel di differenza, produce la mappa dei contorni. Cambia la dimensione della griglia, non l’operazione.

Esempio 3 — scenario reale: smoothing e anomalie sulla stessa metrica

Sezione intitolata “Esempio 3 — scenario reale: smoothing e anomalie sulla stessa metrica”

Loggi la latenza di un endpoint ogni minuto. La curva è frastagliata: un trend lento giorno/notte sotto, sovrapposto a picchi casuali da contesa di risorse e garbage collection.

Se vuoi vedere il trend, convolvi con un kernel passa-basso — una media mobile su una finestra di, diciamo, sessanta minuti. I picchi rapidi vengono diluiti, l’andamento lento emerge. È lo smoothing che applichi prima di mettere una metrica su una dashboard per leggere la tendenza senza farti distrarre dal rumore.

Se invece vuoi rilevare le anomalie, ti interessa esattamente ciò che il passa-basso scarta: gli scostamenti improvvisi. Convolvi con un kernel passa-alto, o sottrai dal segnale la sua versione smussata (il segnale meno il suo passa-basso è un passa-alto). I picchi che prima sparivano ora risaltano. Lo stesso segnale, due obiettivi opposti, due filtri complementari. È la prova operativa che filtrare non è “ripulire in assoluto”, ma scegliere cosa tenere in funzione della domanda.

Esempio 4 — su immagine: il Sobel su una macchia di pixel

Sezione intitolata “Esempio 4 — su immagine: il Sobel su una macchia di pixel”

Estendiamo l’edge detection a due dimensioni con un blocco 3×33 \times 3 di pixel che contiene un bordo verticale: tre colonne, scura a sinistra e chiara a destra.

I=[101020010102001010200]I = \begin{bmatrix} 10 & 10 & 200 \\ 10 & 10 & 200 \\ 10 & 10 & 200 \end{bmatrix}

Applichiamo il Sobel verticale (quello introdotto sopra) centrandolo sul pixel di mezzo. Si moltiplica ogni peso del kernel per il pixel corrispondente e si somma. La colonna sinistra del kernel (1,2,1-1, -2, -1) cade sui pixel scuri (1010), la destra (+1,+2,+1+1, +2, +1) sui chiari (200200), la centrale conta zero:

(110)+(210)+(110)+(1200)+(2200)+(1200)=40+800=760(-1\cdot 10) + (-2\cdot 10) + (-1\cdot 10) + (1\cdot 200) + (2\cdot 200) + (1\cdot 200) = -40 + 800 = 760

Il risultato 760760 è grande e positivo: il filtro segnala forte la presenza di un bordo verticale in quel punto, e il segno dice da che parte va la transizione (scuro verso chiaro, da sinistra a destra). Su un’area uniforme — tutti i pixel uguali — i contributi positivi e negativi si annullerebbero e l’uscita sarebbe zero. Far scorrere questo conto su ogni pixel di un’immagine produce la mappa dei contorni: zero nelle zone piatte, picchi sui bordi. È esattamente lo stesso meccanismo del kernel 1D [1,0,1][-1, 0, 1] dell’esempio 1, esteso alla griglia.

Esempio 5 — di sistema: i primi layer di una rete vision

Sezione intitolata “Esempio 5 — di sistema: i primi layer di una rete vision”

Quando dai un’immagine a un modello di computer vision, i suoi primi strati convoluzionali applicano decine di kernel, ciascuno una piccola finestra di pesi che scorre sull’immagine. La differenza rispetto agli esempi precedenti è che questi pesi non li hai scelti tu: sono stati appresi durante il training. Eppure, quando li visualizzi (lo vedremo nel ponte), assomigliano in modo sorprendente ai filtri classici — rilevatori di bordi orientati, pattern di texture. La macchina è la stessa di questo capitolo; chi sceglie i pesi è cambiato.

Smoothing di serie temporali nell’osservabilità. Latenza, throughput, costo-per-token loggati nel tempo sono segnali a tempo discreto. La media mobile per il trend, la sottrazione del trend per le anomalie, l’estrazione di stagionalità: sono tutte convoluzioni con kernel diversi.

Conoscere la convoluzione rende ovvi due fatti che altrimenti sorprendono. Aggregare su finestre troppo larghe nasconde i micro-burst, perché un kernel largo è un passa-basso aggressivo che cancella le variazioni rapide. E lo smoothing introduce sempre un ritardo, perché un kernel causale “guarda indietro”: il valore smussato di oggi incorpora i giorni passati, quindi il trend mostrato è in ritardo sul trend vero.

Pre-processing di immagini per modelli vision. Un blur gaussiano prima di rimpicciolire un’immagine è il filtro anti-aliasing del capitolo precedente, applicato con un kernel di questo capitolo. Lo sharpening (un passa-alto aggiunto all’originale) e l’edge detection sono feature classiche ancora utili a valle di certe pipeline.

Denoising audio prima di uno speech model. Un passa-banda che isola la banda della voce umana (grosso modo 300-3400 Hz per il parlato telefonico) e un notch che toglie il ronzio di rete a 50 Hz sono convoluzioni che migliorano l’SNR dell’input prima che il modello lo veda.

Filtrare nel posto giusto della pipeline è spesso più economico che chiedere al modello di essere robusto al rumore: un filtro fisso costa pochissimo e toglie un problema noto, mentre rendere un modello robusto a un disturbo richiede dati, training e capacità. Il trade-off, però, va valutato: un filtro troppo aggressivo a monte può togliere informazione che al modello sarebbe servita.

Leggere i primi layer di una CNN o di un VLM. Sapere che i primi strati sono banchi di filtri appresi simili a rilevatori di bordi e texture toglie il mistero dal “cosa vede la rete”: vede esattamente ciò che vedrebbe una pipeline classica di edge/texture detection, solo con kernel scoperti dai dati invece che progettati.

Convoluzione causale dentro architetture moderne. Lo strato Conv1d causale dentro un blocco Mamba, o le convoluzioni dilatate di un modello audio come WaveNet, sono convoluzioni di questo capitolo lungo l’asse del tempo, con kernel appresi e il vincolo di causalità (solo presente e passato).

Il ponte verso l’AI: convoluzione, CNN e modelli a stato

Sezione intitolata “Il ponte verso l’AI: convoluzione, CNN e modelli a stato”

Questa è la sezione dove la convoluzione smette di essere un’operazione da corso di DSP e diventa il cuore di alcune delle architetture più importanti del deep learning. I legami sono di classi diverse — alcuni sono identità matematiche, uno è una filiazione storica, uno è un’analogia supportata da evidenza, uno è un’equivalenza tecnica — e confonderli porta a intuizioni che si rompono ai dettagli. Li enumeriamo con cura, marcando ogni volta la classe.

Stessa operazione, kernel appreso: la filiazione delle CNN

Sezione intitolata “Stessa operazione, kernel appreso: la filiazione delle CNN”

Il primo legame è una filiazione documentata. L’operazione di convoluzione nelle CNN (Convolutional Neural Networks, le reti convoluzionali che hanno dominato la computer vision dagli anni 2012 in poi) è la stessa operazione matematica dei sistemi LTI: un kernel che scorre sull’input, moltiplica e somma.

La struttura è identica a quella di questo capitolo. Quando un layer convoluzionale fa passare un kernel 3×33 \times 3 su una mappa di feature, sta facendo esattamente la convoluzione 2D dell’esempio sul Sobel, su scala più grande e ripetuta su molti kernel.

Il paper canonico è “Gradient-Based Learning Applied to Document Recognition” di Yann LeCun, Léon Bottou, Yoshua Bengio e Patrick Haffner (Proceedings of the IEEE, 86(11):2278-2324, 1998), che introduce LeNet-5 per il riconoscimento di cifre manoscritte.

Le CNN ereditano la macchina convoluzionale dall’elaborazione dell’immagine classica — che usava da decenni filtri convoluzionali per smoothing, sharpening, edge detection. Il legame è una filiazione, non una semplice somiglianza: c’è una linea storica diretta dai filtri progettati ai layer convoluzionali, con gli stessi kernel 3×33 \times 3 che scorrono sull’immagine.

Ma qui sta la differenza fondamentale, da marcare con precisione perché è ciò che separa un filtro da un layer di rete. Nel DSP classico il kernel è progettato a mano per uno scopo noto: Sobel per i bordi, gaussiano per il blur. Nelle CNN i kernel sono appresi dai dati durante il training, via backpropagation.

Non decidi a priori cosa il filtro debba rilevare; lasci che emerga dall’ottimizzazione su un compito. Come scrivono gli autori del 1998, la rete viene alimentata con immagini minimamente processate e si affida all’apprendimento per estrarre da sé le features giuste, senza feature engineering manuale.

Questa è la rottura concettuale: dal filtro progettato al filtro appreso. La filiazione riguarda l’operazione — lo scorri-moltiplica-somma è identico; il kernel appreso è la novità che la trasforma in deep learning. Confondere i due livelli porta a dire che “le CNN sono solo filtri”, perdendo proprio ciò che le rende capaci di imparare.

Cross-correlazione, non convoluzione: una differenza tecnica che non conta (perché il kernel è appreso)

Sezione intitolata “Cross-correlazione, non convoluzione: una differenza tecnica che non conta (perché il kernel è appreso)”

Il secondo punto è tecnico e quasi sempre frainteso. La “convoluzione” delle CNN è, in senso stretto, una cross-correlazione, non una convoluzione. La differenza è proprio il ribaltamento del kernel: la convoluzione vera ribalta hh (il k-k nella formula, il “flip”), la cross-correlazione lo fa scorrere così com’è, senza ribaltarlo.

Le librerie di deep learning (PyTorch, TensorFlow) implementano la cross-correlazione ma la chiamano convoluzione. Perché questa licenza è innocua? Perché il kernel è appreso.

Se la rete avesse bisogno del kernel ribaltato, lo imparerebbe ribaltato: i pesi assorbono il flip senza alcun costo. Il ribaltamento non aggiunge nulla quando i pesi sono liberi di assumere qualunque valore, come notano Ian Goodfellow, Yoshua Bengio e Aaron Courville nel loro testo “Deep Learning” (MIT Press, 2016, capitolo 9). Implementare la cross-correlazione è anche più semplice ed evita la confusione di indici del flip — un vantaggio pratico, dato che il risultato finale non cambia.

Vale la pena tenere distinte tre affermazioni di classi diverse che qui si accavallano. Primo, identità di operazione: il meccanismo scorri-moltiplica-somma è lo stesso. Secondo, differenza tecnica: la CNN usa cross-correlazione (niente flip), il DSP convoluzione (con flip). Terzo, irrilevanza pratica di quella differenza per le CNN: dovuta al fatto che i kernel sono appresi.

Per un kernel fisso e progettato — come il Sobel — il flip conterebbe, perché cambia il risultato in modo prevedibile (lo specchia). Per un kernel appreso no, perché l’ottimizzazione è libera di scegliere i pesi nella forma che le serve. Non confondere “stessa operazione” con “identica pixel per pixel”: sono la stessa famiglia, con un ribaltamento di differenza che l’apprendimento rende ininfluente.

I primi layer apprendono filtri tipo bordo e Gabor: analogia con evidenza

Sezione intitolata “I primi layer apprendono filtri tipo bordo e Gabor: analogia con evidenza”

Il terzo legame è un fatto empirico ben documentato, ed è il più affascinante. Dopo il training su immagini reali, i kernel del primo layer convoluzionale di una rete profonda tendono ad assomigliare a rilevatori di bordi e a filtri di Gabor (gaussiana modulata da una sinusoide: rilevatori di bordi e texture orientati). Nessuno li ha progettati così: emergono dall’ottimizzazione.

L’evidenza è visiva. Il lavoro di Matthew Zeiler e Rob Fergus, “Visualizing and Understanding Convolutional Networks” (ECCV 2014), introduce una tecnica (la deconvnet) per proiettare i filtri appresi nello spazio dei pixel e guardarli. Le visualizzazioni dei pesi del primo layer di reti come AlexNet mostrano un mix di rilevatori di bordi orientati, pattern tipo Gabor e qualche pattern ad alta frequenza.

C’è anche una prova più forte di una semplice somiglianza a occhio. Si può sostituire il primo strato di filtri appresi con filtri di Gabor fissi, progettati a mano, e mantenere buona parte dell’accuratezza di classificazione su ImageNet. È il segno che il primo layer, lasciato libero di imparare, converge di fatto verso qualcosa di molto vicino a Gabor: non un’imitazione casuale, ma il punto in cui l’ottimizzazione e l’ingegneria classica arrivano alla stessa soluzione.

La classe va marcata con cura: questa è un’analogia supportata da evidenza, non una filiazione. Nessuno ha costruito le CNN perché imparassero filtri di Gabor; la somiglianza tra i kernel appresi e i filtri classici (Sobel, Gabor) è una convergenza osservata, non una discendenza progettata. È un’analogia robusta, misurata, ma resta un’analogia: i kernel appresi del primo layer assomigliano a Sobel e Gabor, non derivano da essi. Il fatto che l’ottimizzazione, lasciata libera, riscopra strumenti che gli ingegneri avevano progettato a mano decenni prima è uno dei risultati più eleganti del campo — ma proprio per questo va raccontato come convergenza, non come eredità.

Il pooling come downsampling: identità di fenomeno con il campionamento

Sezione intitolata “Il pooling come downsampling: identità di fenomeno con il campionamento”

Il quarto legame riporta dritto al capitolo precedente. Il pooling (max-pooling, average-pooling) e le convoluzioni a passo (strided convolution) riducono la risoluzione delle mappe di feature di una rete: sono operazioni di downsampling. E ogni downsampling è un campionamento, soggetto al teorema di Nyquist come qualunque altro.

Questo significa che il pooling senza un filtro passa-basso a monte può causare aliasing, esattamente come sotto-campionare un’immagine senza sfocarla prima.

È il punto del lavoro di Richard Zhang, “Making Convolutional Networks Shift-Invariant Again” (ICML 2019), già discusso nel capitolo sul campionamento: le operazioni di downsampling standard nelle CNN ignorano il teorema del campionamento, e la cura è il BlurPool — un blur passa-basso (un kernel di questo capitolo) inserito prima del subsampling.

È un’identità di fenomeno: l’aliasing dentro una rete è lo stesso aliasing del segnale fisico, su un asse spaziale, con la stessa cura (filtrare prima di sottocampionare). Non un’analogia poetica, ma il teorema di Nyquist che si applica a una mappa di feature appresa come si applicherebbe a un’immagine.

Convoluzione e modelli a spazio di stato: l’identità LTI ritrovata

Sezione intitolata “Convoluzione e modelli a spazio di stato: l’identità LTI ritrovata”

Il quinto legame è il più sottile, e collega la convoluzione ad architetture di sequenza recenti. I modelli a spazio di stato (SSM, State Space Models) per sequenze — S4 (Albert Gu, Karan Goel, Christopher Ré, “Efficiently Modeling Long Sequences with Structured State Spaces”, ICLR 2022) e Mamba (Albert Gu, Tri Dao, “Mamba: Linear-Time Sequence Modeling with Selective State Spaces”, 2023) — hanno una proprietà chiave: la stessa dinamica si può calcolare in due forme equivalenti. Una forma ricorrente, in cui uno stato evolve passo per passo (efficiente per generare un token alla volta in inference); e una forma convoluzionale, in cui l’uscita è una convoluzione dell’input con un kernel lungo determinato dai parametri del modello (parallelizzabile, comoda per il training).

Perché queste due forme sono equivalenti? Per l’identità che attraversa tutta questa Parte. Un sistema con uno stato che evolve linearmente nel tempo è un sistema LTI, e la sua relazione ingresso-uscita è una convoluzione con la sua risposta all’impulso. È esattamente il concetto di stato della teoria dei sistemi (Parte IX, Stato, transizione, traiettoria) saldato al concetto di convoluzione di questo capitolo.

Quindi “S4 è esprimibile come convoluzione lunga” non è un’analogia poetica: è l’identità LTI = convoluzione applicata a un modello a stato lineare. Il kernel della convoluzione è semplicemente la risposta all’impulso del sistema a stato. La classe del legame è filiazione tecnica ed equivalenza matematica, non somiglianza: le due forme calcolano, bit per bit, la stessa funzione.

La convoluzione qui è causale: usa solo presente e passato, mai il futuro (la causalità del capitolo introduttivo), perché un modello che predice il prossimo token non può guardare avanti. L’implementazione di Mamba include infatti uno strato Conv1d causale dentro il blocco.

C’è però un caveat onesto, ed è una delle ragioni del design di Mamba. Mamba è selettivo, cioè i suoi parametri dipendono dall’input invece di essere fissi. Questa dipendenza rompe la tempo-invarianza — il sistema non si comporta più uguale in ogni istante — e quindi la pura forma convoluzionale a kernel fisso non vale più per Mamba come valeva per S4. È proprio la selettività che lo rende più espressivo, al prezzo di non essere più un LTI esatto: un buon promemoria che l’identità LTI = convoluzione vale dove c’è tempo-invarianza, e cessa di valere appena la si rompe.

Il sesto legame è un’identità di operazione diretta. La convoluzione 1D — un kernel che scorre lungo l’asse temporale di una sequenza — è diffusa nei modelli audio e di sequenza.

WaveNet (van den Oord et al., DeepMind, 2016) genera audio campione per campione con convoluzioni causali dilatate: il kernel “salta” campioni a intervalli crescenti per coprire un contesto temporale ampio con pochi parametri, invece di usare un kernel enorme e contiguo. Lo stesso strato Conv1d compare come blocco di mescolamento locale dentro architetture moderne, incluso il Conv1d causale di Mamba.

È la stessa convoluzione di questo capitolo: asse temporale, kernel appreso, vincolo causale. Nessuna astrazione nuova, solo l’operazione di base applicata alle sequenze invece che alle immagini.

La morale per chi costruisce sistemi AI è che la convoluzione non vive solo nei vecchi corsi di ingegneria. È la stessa macchina che sfoca un’immagine, che i primi layer di una rete vision riscoprono dai dati, che esprime la forma parallelizzabile di un modello a stato, e che mescola localmente le sequenze in un modello audio.

Riconoscerla sotto i suoi travestimenti è metà del lavoro. L’altra metà è sapere, ogni volta, di che classe è il legame: identità matematica (la convoluzione è l’operazione LTI di base), filiazione (le CNN ereditano la macchina dell’image processing), analogia con evidenza (i kernel appresi che assomigliano a Gabor), equivalenza (la doppia forma ricorrente-convoluzionale di S4). È questa disciplina sulle classi a separare una comprensione meccanica da una superstiziosa.

I concetti di questo capitolo sono solidi, ma le intuizioni scivolano in errori ricorrenti. Vale la pena disinnescarli uno per uno.

Convoluzione non è cross-correlazione (ma per le CNN la differenza svanisce). La convoluzione ribalta il kernel, la cross-correlazione no. È una distinzione reale: per un kernel fisso e progettato — un Sobel applicato a mano — usare l’una o l’altra dà risultati diversi, specchiati l’uno rispetto all’altro.

Per le CNN la differenza è invece ininfluente, perché i kernel sono appresi e i pesi assorbono il flip. L’errore qui è di due tipi opposti: credere che convoluzione e cross-correlazione siano sempre identiche (falso per i kernel fissi) o credere che la differenza conti per le CNN (falso, perché il kernel è appreso). La verità sta nel mezzo e dipende da una sola domanda: chi sceglie i pesi, un umano o l’ottimizzazione.

Un filtro non “pulisce in assoluto”, seleziona. Un passa-basso che toglie il rumore ad alta frequenza cancella anche i dettagli utili che vivono in quella banda. Filtrare è scegliere cosa tenere, non rendere il segnale “migliore” in senso assoluto.

Lo stesso filtro che ti serve per vedere il trend ti nasconde le anomalie, e viceversa: il giudizio su cosa sia “rumore” dipende dalla domanda, non dal segnale. E c’è un limite duro: se segnale utile e rumore condividono la stessa banda di frequenze, nessun filtro lineare li separa. Il guadagno in pulizia si paga sempre in fedeltà.

Convoluzione non è sinonimo di blur. Il blur è solo il caso del kernel passa-basso. Lo stesso meccanismo, con un kernel di differenza, fa l’opposto: esalta i bordi invece di sfumarli. Chi associa “convoluzione” a “sfocatura” ha visto un solo kernel e l’ha scambiato per l’operazione. È il kernel a decidere se l’effetto è smoothing, sharpening, edge detection o estrazione di una banda.

Il kernel appreso non “capisce” i bordi. Quando il primo layer di una CNN apprende filtri tipo Gabor, non è perché la rete abbia un concetto di “bordo”. È perché quei filtri minimizzano la loss sul compito, e su immagini naturali i bordi sono statisticamente informativi: rilevarli aiuta a classificare, quindi l’ottimizzazione li scopre.

La somiglianza con i filtri classici è una convergenza dell’ottimizzazione, un’analogia con evidenza, non una comprensione intenzionale né una filiazione progettata. Attribuire intenzione al kernel — “ha imparato a vedere i contorni perché sa che contano” — è antropomorfismo: i pesi sono semplicemente i valori che riducono l’errore.

Il teorema di convoluzione è un teorema, non una comodità. L’affermazione “convoluzione nel tempo = moltiplicazione in frequenza” è una relazione provabile, valida sotto ipotesi precise sulla trasformata di Fourier. Non è un’analogia né una regola empirica. Va usata sapendo che la sua giustificazione vive nel capitolo su Fourier, e che ha condizioni di validità (segnali per cui la trasformata esiste).

FIR e IIR non sono intercambiabili. Un FIR è una convoluzione finita e sempre stabile; un IIR ha feedback, può ottenere tagli ripidi con pochi coefficienti ma può anche divergere se progettato male, e distorce la fase. Trattarli come la stessa cosa porta a errori di progetto concreti: un filtro che oscilla, un ritardo di fase che sfasa il segnale, un’instabilità che esplode su un ingresso innocuo.

Il pooling è un campionamento, e il campionamento ha le sue regole. Ridurre la risoluzione di una feature map con max-pooling o strided convolution è un downsampling, soggetto al teorema di Nyquist come qualunque altro campionamento.

Senza un blur a monte, il pooling introduce aliasing, che qui si manifesta come perdita di shift-invariance: spostare l’input di un pixel può cambiare l’output in modo sproporzionato (Zhang 2019). Chi vede il pooling come “ridurre i dati e basta” perde una correzione architetturale reale — il BlurPool — che applica il filtro passa-basso di questo capitolo prima di sottocampionare.

“S4 è una convoluzione” è matematica, “Mamba è una convoluzione” è impreciso. L’equivalenza ricorrente-convoluzionale vale per i sistemi a stato lineari e tempo-invarianti, come S4. Mamba aggiunge la selettività: i parametri dipendono dall’input, il che rompe la tempo-invarianza e fa decadere la forma convoluzionale a kernel fisso. Dire “Mamba è solo una convoluzione lunga” sbaglia proprio sul punto che lo rende espressivo. L’identità LTI = convoluzione è esatta dove c’è tempo-invarianza, e Mamba è stato progettato apposta per romperla.

La convoluzione è lineare; le reti no. Un layer convoluzionale, nella sua parte di convoluzione, è un’operazione lineare — un sistema LTI. È la non-linearità che la rete aggiunge dopo (le funzioni di attivazione) a darle la capacità di apprendere relazioni complesse. Trattare una CNN come “una pila di filtri lineari” perde esattamente ciò che la rende potente: senza le non-linearità tra i layer convoluzionali, per l’associatività della convoluzione l’intera pila collasserebbe in un singolo filtro lineare equivalente.

I bordi sono un caso speciale, non un dettaglio. Quando il kernel scorre fino al margine del segnale, sporge oltre i dati: non c’è niente da moltiplicare per i pesi che restano fuori. Le librerie risolvono in modi diversi — riempire di zeri (zero-padding), riflettere il segnale, ripeterne il bordo, o semplicemente accorciare l’uscita (modalità “valid”). La scelta non è neutra: lo zero-padding di un’immagine può creare un bordo scuro artificiale che un filtro di edge detection scambia per un contorno vero. Sapere quale convenzione usa la tua pipeline evita di inseguire artefatti che esistono solo ai margini.

  • Segnali continui, discreti, sistemi lineari — il capitolo che introduce gli LTI, la risposta all’impulso e la convoluzione: qui ne abbiamo dato il trattamento completo, la meccanica flip-and-slide e i filtri.
  • Campionamento, aliasing, teorema di Nyquist — il filtro anti-aliasing e quello di ricostruzione sono i passa-basso di questo capitolo; il pooling delle CNN è un downsampling soggetto allo stesso aliasing.
  • fourier-intuizione (in preparazione, questa Parte) — dimostra il teorema di convoluzione (tempo = prodotto in frequenza) e dà senso pieno alla descrizione dei filtri come scelta di H(f)H(f).
  • rumore-snr (in preparazione, questa Parte) — il filtraggio del rumore è l’applicazione diretta dei filtri di questo capitolo, con il limite che segnale e rumore in banda comune non si separano.
  • spettrogrammi (in preparazione, questa Parte) — il front-end tempo-frequenza dei modelli speech parte da filtri e finestrature costruiti su queste basi.
  • Prodotto scalare come proiezione e somiglianza (Parte IV) — la convoluzione a ogni posizione è un prodotto scalare tra kernel e segnale: il terzo angolo dell’intuizione (il matched filter, “quanto si somigliano”) nasce da lì.
  • Stato, transizione, traiettoria (Parte IX) — il concetto di stato che, quando l’evoluzione è lineare, rende un sistema un LTI e quindi una convoluzione: il ponte verso S4 e Mamba.
  • cnn-base (Parte XVIII, in preparazione) — la convoluzione dentro le reti neurali, con kernel appresi invece che progettati: la filiazione diretta da questo capitolo.
  • ssm-mamba (Parte XXII, in preparazione) — i modelli a spazio di stato e la loro forma convoluzionale, con la selettività di Mamba che rompe la tempo-invarianza.
  • IVF, product quantization (Parte VIII) — un altro punto in cui un’operazione del signal processing (qui la quantizzazione) ricompare nei sistemi AI: utile per allenare l’occhio alle classi di affermazioni.
  • Alan V. Oppenheim, Alan S. Willsky, S. Hamid Nawab — Signals and Systems (2nd ed., Prentice Hall, 1996). Il capitolo 2 costruisce la convoluzione dei sistemi LTI da linearità, tempo-invarianza e proprietà di setaccio dell’impulso. La fonte canonica per convoluzione, risposta all’impulso, FIR/IIR e filtri.
  • Yann LeCun, Léon Bottou, Yoshua Bengio, Patrick Haffner — Gradient-Based Learning Applied to Document Recognition (Proceedings of the IEEE, 86(11):2278-2324, 1998). Il paper che introduce LeNet-5 e il kernel appreso: la filiazione dall’image processing classico alle CNN.
  • Matthew D. Zeiler, Rob Fergus — Visualizing and Understanding Convolutional Networks (ECCV 2014, arXiv:1311.2901). Le visualizzazioni dei filtri appresi che mostrano i rilevatori di bordi e i pattern tipo Gabor nel primo layer: l’evidenza per l’analogia kernel appresi / filtri classici.
  • Ian Goodfellow, Yoshua Bengio, Aaron Courville — Deep Learning (MIT Press, 2016), capitolo 9. Spiega perché le CNN implementano una cross-correlazione pur chiamandola convoluzione, e perché il flip è irrilevante con i kernel appresi.
  • Albert Gu, Tri Dao — Mamba: Linear-Time Sequence Modeling with Selective State Spaces (2023, arXiv:2312.00752). Il modello a stato selettivo con il Conv1d causale nel blocco e la selettività che rompe la tempo-invarianza: il riferimento per il legame convoluzione / SSM.

← Torna all’indice della Parte XII