Introduzione

La convoluzione è un’operazione matematica che rende il prodotto parte integrante di 2 funzioni (segnali), con uno dei segnali capovolto. Ad esempio, sotto si convolgono 2 segnali f(t) e g(t).

Quindi la prima cosa da fare è capovolgere il segnale g in orizzontale (180 gradi), e poi far scorrere il g a testa in giù su f, moltiplicando e accumulando tutti i suoi valori.

L’ordine in cui i segnali sono convolti non ha alcuna importanza per il risultato finale, quindi conv(a,b)==conv(b,a)

In questo caso si consideri che il segnale blu f(τ) è il nostro segnale di ingresso e g(t) il nostro kernel, il termine kernel si usa quando si usano le convoluzioni per filtrare i segnali.

Dimensione del segnale di uscita 1D

Nel caso della convoluzione 1D, la dimensione di uscita viene calcolata in questo modo:

outputSize=(InputSize-KernelSize)+1

Applicazione di convoluzioni

Le persone usano la convoluzione sull’elaborazione del segnale per i seguenti casi d’uso:

Filtraggio di segnali (audio 1D, elaborazione di immagini 2D)

Controllare quanto un segnale è correlato ad un altro

Trovare schemi nei segnali

Un semplice esempio in matlab e pitone (intorpidito)

Di seguito sono riportati due segnali x = (0,1,2,3,4) con w = (1,-1,2).


Fare a mano

Per capire meglio il concetto di convoluzione, prendiamo a mano l’esempio precedente. Fondamentalmente andiamo a convolgere 2 segnali (x,w). La prima cosa è di capovolgere W orizzontalmente (O girare a sinistra di 180 gradi)

Dopo di che dobbiamo far scorrere il W capovolto sull’ingresso X

Si noti che nei passi 3,4,5 la finestra invertita è completamente all’interno del segnale d’ingresso. Questi risultati sono chiamati convoluzioni “valide”. I casi in cui la finestra invertita non è completamente all’interno della finestra di ingresso(X), possiamo considerarli come zero, oppure possiamo calcolare ciò che può essere calcolato, per esempio nel passo 1 moltiplichiamo 1 per zero, e il resto viene semplicemente ignorato.

Imbottitura di ingresso

Per mantenere la dimensione del risultato della convoluzione uguale a quella dell’ingresso, e per evitare un effetto chiamato convoluzione circolare, imbottiamo il segnale con degli zeri.

Dove si mettono gli zeri dipende da quello che si vuole fare, cioè: sul caso 1D si possono concatenare su ogni estremità, ma su un caso 2D normalmente si mettono tutti intorno al segnale originale.

Su matlab si può usare il comando ‘padarray’ per imbottigliare l’ingresso:

>> x

x(:,:,1) =

1 1 0 2 0

2 2 2 2 1

0 0 0 2 1

2 2 2 2 1

2 0 2 2 1

x(:,:,2) =

2 1 0 0 0

0 2 0 1 0

1 0 1 2 0

1 2 0 2 1

1 2 1 2 2

x(:,:,3) =

2 1 1 2 2

1 1 1 0 0

2 0 1 0 2

0 2 0 2 1

0 0 2 1 0

>> padarray(x,[1 1])

ans(:,:,1) =

0 0 0 0 0 0 0

0 1 1 0 2 0 0

0 2 2 2 2 1 0

0 0 0 0 2 1 0

0 2 2 2 2 1 0

0 2 0 2 2 1 0

0 0 0 0 0 0 0

ans(:,:,2) =

0 0 0 0 0 0 0

0 2 1 0 0 0 0

0 0 2 0 1 0 0

0 1 0 1 2 0 0

0 1 2 0 2 1 0

0 1 2 1 2 2 0

0 0 0 0 0 0 0

ans(:,:,3) =

0 0 0 0 0 0 0

0 2 1 1 2 2 0

0 1 1 1 0 0 0

0 2 0 1 0 2 0

0 0 2 0 2 1 0

0 0 0 2 1 0 0

0 0 0 0 0 0 0

Dimensione di uscita per 2D

Si prega di sapere quale sarà l’entità della nostra produzione dopo aver eseguito alcune operazioni di convoluzione su di essa. Fortunatamente c’è una comoda formula che ci dice esattamente questo.

Se consideriamo la convoluzione di un ingresso, di dimensioni spaziali [H, W] imbottita di P, con un kernel quadrato di dimensioni F e utilizzando la falcata S, allora la dimensione di uscita della convoluzione è definita come:

outputSizeW=(W-F+2P)/S+1 outputSizeH=(H-F+2P)/S+1 output

F è la dimensione del kernel, normalmente usiamo kernel quadrati, quindi F è sia la larghezza che l’altezza del kernel

Attuazione dell’operazione di convoluzione

L’esempio che segue prevede un ingresso 5x5x3 (LxHx3), con un livello conv con i seguenti parametri Stride=2, Pad=1, F=3 (kernel 3×3), e K=2 (due filtri).

Il nostro ingresso ha 3 canali, quindi abbiamo bisogno di un peso del kernel 3x3x3. Abbiamo 2 filtri (K=2) quindi avremo 2 attivazioni di uscita alla fine. Inoltre possiamo calcolare la dimensione di queste due uscite: (5 – 3 + 2)/2 + 1 = 3.

Questo codice qui sotto (versione vaniglia) non può essere usato nella vita reale perché sarà lento ma è buono per una comprensione di base. Di solito le librerie di apprendimento profondo fanno la convoluzione come moltiplicazione a matrice singola, usando il metodo im2col/col2im.

%% Convoluzione n dimensioni

% Il codice seguente è solo un’estensione di conv2d_vanila per n dimensioni.

% Parametri:

% Ingresso: A x L x profondità

% K: kernel F x F x profondità

% S: stride (quanti pixel farà scorrere la finestra sull’ingresso)

% Questa implementazione è come il parametro “valido” sulla convoluzione normale

funzione outConv = convn_vanilla(input, kernel, S)

% Ottenere la dimensione dell’input in termini di righe e colli. I pesi devono avere

% stessa profondità del volume d’ingresso (immagine)

rowsIn, colsIn, ~] = dimensione (ingresso);

% Ottenere dimensio volume

depthInput = ndims(input);

% Ottenere la dimensione del kernel, considerando sempre un kernel quadrato

F = dimensione (kernel,1);

%% Inizializzare gli output

sizeRowsOut = ((rowsIn-F)/S) + 1;

sizeColsOut = ((colsIn-F)/S) + 1;

outConvAcc = zeri (sizeRowsOut , sizeColsOut, depthInput);

%% Fare la convoluzione

% Convolgere ogni canale sull’ingresso con il rispettivo canale del kernel,

% alla fine sommano tutti i risultati del canale.

per profondità=1:depthInput

% Seleziona il canale di ingresso e il canale di corrente del kernel

inputCurrDepth = input(:,:,depth);

kernelCurrDepth = kernel(:,:,depth);

% Iterate su ogni riga e col, (usando stride)

per r=1:S:(rowsIn-1)

per c=1:S:(colsIn-1)

% Evitare il campionamento fuori dall’immagine.

se (((c+F)-1) <= colsIn) && (((r+F)-1) <= rowsIn)

% Finestra di selezione sul volume d’ingresso (patch)

sampleWindow = inputCurrDepth(r:(r+F)-1,c:(c+F)-1);

% Fare il prodotto del punto

dotProd = somma(sampleWindow(:) .* kernelCurrDepth(:));

% Memorizza il risultato

outConvAcc(ceil(r/S),ceil(c/S),profondità) = dotProd;

fine

fine

fine

fine

% Elementi di somma sulla dimensione del volume d’ingresso (somma di tutti i canali)

outConv = somma(outConvAcc,depthInput);

fine