Le operazioni di pooling e convoluzionale fanno scorrere una "finestra" sul tensore di input. Usando tf.nn.conv2dcome esempio: Se il tensore di input ha 4 dimensioni [batch, height, width, channels]:, allora la convoluzione opera su una finestra 2D sulle height, widthdimensioni.
stridesdetermina 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.