Le operazioni di pooling e convoluzionale fanno scorrere una "finestra" sul tensore di input. Usando tf.nn.conv2d
come esempio: Se il tensore di input ha 4 dimensioni [batch, height, width, channels]
:, allora la convoluzione opera su una finestra 2D sulle height, width
dimensioni.
strides
determina di quanto si sposta la finestra in ciascuna delle dimensioni. L'uso tipico imposta il primo passo (il lotto) e l'ultimo (la profondità) a 1.
Usiamo un esempio molto concreto: eseguire una convoluzione 2-d su un'immagine di input in scala di grigi 32x32. Dico scala di grigi perché l'immagine di input ha profondità = 1, il che aiuta a mantenerlo semplice. Lascia che l'immagine abbia questo aspetto:
00 01 02 03 04 ...
10 11 12 13 14 ...
20 21 22 23 24 ...
30 31 32 33 34 ...
...
Eseguiamo una finestra di convoluzione 2x2 su un singolo esempio (dimensione batch = 1). Daremo alla convoluzione una profondità del canale di uscita di 8.
L'input per la convoluzione ha shape=[1, 32, 32, 1]
.
Se si specifica strides=[1,1,1,1]
con padding=SAME
, l'output del filtro sarà [1, 32, 32, 8].
Il filtro creerà prima un output per:
F(00 01
10 11)
E poi per:
F(01 02
11 12)
e così via. Quindi passerà alla seconda riga, calcolando:
F(10, 11
20, 21)
poi
F(11, 12
21, 22)
Se specifichi un passo di [1, 2, 2, 1] non verranno sovrapposte le finestre. Calcolerà:
F(00, 01
10, 11)
e poi
F(02, 03
12, 13)
Il passo funziona in modo simile per gli operatori di pooling.
Domanda 2: Perché passi [1, x, y, 1] per le convnet
Il primo è il batch: di solito non vuoi saltare gli esempi nel tuo batch, o non avresti dovuto includerli in primo luogo. :)
L'ultimo 1 è la profondità della convoluzione: di solito non vuoi saltare gli input, per lo stesso motivo.
L'operatore conv2d è più generale, in modo da potrebbe creare circonvoluzioni che scorrono lungo la finestra di altre dimensioni, ma che non è un uso tipico in convnets. L'utilizzo tipico è quello di usarli spazialmente.
Perché reshape a -1 -1 è un segnaposto che dice "aggiusta come necessario per abbinare la dimensione necessaria per l'intero tensore". È un modo per rendere il codice indipendente dalla dimensione del batch di input, in modo da poter modificare la pipeline e non dover regolare la dimensione del batch ovunque nel codice.