Qual è la differenza tra 'SAME' e 'VALID' padding in tf.nn.max_pool of tensorflow?


309

Qual è la differenza tra 'SAME' e 'VALID' padding in tf.nn.max_poolof tensorflow?

Secondo me, 'VALIDO' significa che non ci sarà alcuna imbottitura zero al di fuori dei bordi quando facciamo il pool massimo.

Secondo una guida all'aritmetica della convoluzione per l'apprendimento profondo , si dice che non ci sarà alcuna imbottitura nell'operatore del pool, ovvero usare semplicemente 'VALID' di tensorflow. Ma in cosa consiste l'imbottitura "SAME" di max pool tensorflow?


3
Controlla tensorflow.org/api_guides/python/… per i dettagli, ecco come l'ha fatto.
GabrielChu,


4
Dai un'occhiata a queste fantastiche gif per capire come funzionano le imbottiture e il passo. Link
Deepak

1
@GabrielChu il tuo link sembra essere morto ed è ora un reindirizzamento a una panoramica generale.
opaco

Mentre Tensorflow si aggiorna alla 2.0, le cose verranno sostituite da Keras e credo che tu possa trovare le informazioni sul pool nelle documentazioni di Keras. @matt
GabrielChu

Risposte:


163

Faccio un esempio per renderlo più chiaro:

  • x: input immagine di forma [2, 3], 1 canale
  • valid_pad: pool massimo con kernel 2x2, falcata 2 e imbottitura VALID.
  • same_pad: max pool con kernel 2x2, stride 2 e SAME padding (questo è il modo classico di procedere)

Le forme di output sono:

  • valid_pad: qui, nessuna imbottitura, quindi la forma di output è [1, 1]
  • same_pad: qui, riempiamo l'immagine con la forma [2, 4] (con -infe quindi applichiamo il pool massimo), quindi la forma di output è [1, 2]

x = tf.constant([[1., 2., 3.],
                 [4., 5., 6.]])

x = tf.reshape(x, [1, 2, 3, 1])  # give a shape accepted by tf.nn.max_pool

valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

valid_pad.get_shape() == [1, 1, 1, 1]  # valid_pad is [5.]
same_pad.get_shape() == [1, 1, 2, 1]   # same_pad is  [5., 6.]


603

Se ti piace ascii art:

  • "VALID" = senza imbottitura:

       inputs:         1  2  3  4  5  6  7  8  9  10 11 (12 13)
                      |________________|                dropped
                                     |_________________|
  • "SAME" = con riempimento zero:

                   pad|                                      |pad
       inputs:      0 |1  2  3  4  5  6  7  8  9  10 11 12 13|0  0
                   |________________|
                                  |_________________|
                                                 |________________|

In questo esempio:

  • Larghezza input = 13
  • Larghezza filtro = 6
  • Passo = 5

Appunti:

  • "VALID" elimina sempre e solo le colonne più a destra (o le righe più in basso).
  • "SAME" tenta di riempire uniformemente sinistra e destra, ma se la quantità di colonne da aggiungere è dispari, aggiungerà la colonna aggiuntiva a destra, come nel caso di questo esempio (la stessa logica si applica in verticale: potrebbe esserci una riga aggiuntiva di zeri in basso).

modificare :

Circa il nome:

  • Con il "SAME"padding, se usi un passo di 1, gli output del layer avranno lo stesso dimensioni spaziali dei suoi input.
  • Con il "VALID"padding non ci sono input di padding "inventati". Il layer utilizza solo dati di input validi .

È corretto affermare che "SAME" significa "utilizzare zero-padding per assicurarsi che la dimensione del filtro non debba cambiare se la larghezza dell'immagine non è un multiplo della larghezza del filtro o l'altezza dell'immagine non è un multiplo dell'altezza del filtro "? Come in "pad con zeri fino a un multiplo della larghezza del filtro" se la larghezza è il problema?
StatsSorceress

2
Rispondere alla mia domanda secondaria: NO, non è questo il punto di riempimento zero. Scegli la dimensione del filtro per lavorare con l'input (incluso il riempimento zero), ma non scegli il riempimento zero dopo la dimensione del filtro.
StatsSorceress il

Non capisco la tua risposta @StatsSorceress. Mi sembra che tu abbia aggiunto abbastanza zeri (nel modo più simmetrico possibile) in modo che tutti gli input siano coperti da qualche filtro, vero?
Guillefix,

2
Ottima risposta, solo per aggiungere: nel caso in cui i valori del tensore possano essere negativi, il riempimento per max_pooling è con -inf.
Tones29

Che cosa succede se la larghezza di input è un numero pari quando ksize = 2, stride = 2 e con lo stesso padding? ... allora non dovrebbe essere a zero, giusto? .... Lo sto dicendo quando guardo il repository del codice darkflow , stanno usando SAME pad, stride = 2, ksize = 2 per maxpool .... dopo il passaggio massimo la larghezza dell'immagine è ridotta a 208 pixel da 416 pixel di larghezza. Qualcuno può chiarire questo?
K.vindi,

161

Quando strideè 1 (più tipico con convoluzione che in pool), possiamo pensare alla seguente distinzione:

  • "SAME": la dimensione dell'output è uguale alla dimensione dell'input. Ciò richiede che la finestra del filtro scivoli fuori dalla mappa di input, quindi la necessità di pad.
  • "VALID": La finestra del filtro rimane nella posizione valida all'interno della mappa di input, quindi la dimensione dell'output si riduce di filter_size - 1. Non si verifica alcuna imbottitura.

65
Questo è finalmente utile. Fino a questo punto, è emerso che SAMEe VALIDpossono così sono stati chiamati fooebar
omatai

7
Penso che "la dimensione dell'output sia uguale alla dimensione dell'input" è vera solo quando la lunghezza del passo è 1.
omsrisagar

92

L' esempio Convolution di TensorFlow offre una panoramica della differenza tra SAMEe VALID:

  • Per l' SAMEimbottitura, l'altezza e la larghezza di uscita sono calcolate come:

    out_height = ceil(float(in_height) / float(strides[1]))
    out_width  = ceil(float(in_width) / float(strides[2]))

E

  • Per l' VALIDimbottitura, l'altezza e la larghezza di uscita sono calcolate come:

    out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
    out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))

46

Il riempimento è un'operazione per aumentare la dimensione dei dati di input. Nel caso di dati monodimensionali, basta aggiungere / anteporre l'array con una costante, in una matrice surround 2-dim con queste costanti. In n-dim circondi l'ipercubo n-dim con la costante. Nella maggior parte dei casi questa costante è zero e si chiama zero-padding.

Ecco un esempio di zero-padding con p=1applicato al tensore 2-d: inserisci qui la descrizione dell'immagine


Puoi usare il padding arbitrario per il tuo kernel ma alcuni dei valori di padding sono usati più frequentemente di altri:

  • Imbottitura VALIDA . Il caso più semplice, significa nessuna imbottitura. Lascia i tuoi dati come prima.
  • Imbottitura SAME a volte chiamata imbottitura HALF . Si chiama SAME perché per una convoluzione con un passo = 1, (o per il pooling) dovrebbe produrre output della stessa dimensione dell'input. Si chiama HALF perché per un kernel di dimensionik inserisci qui la descrizione dell'immagine
  • L'imbottitura COMPLETA è l'imbottitura massima che non provoca una convoluzione rispetto solo agli elementi imbottiti. Per un kernel di dimensioni k, questa imbottitura è uguale a k - 1.

Per usare un'imbottitura arbitraria in TF, puoi usare tf.pad()


32

Spiegazione rapida

VALID: Non applicare alcuna imbottitura, ovvero supporre che tutte le dimensioni siano valide in modo che l'immagine in ingresso venga coperta completamente dal filtro e dal passo specificati.

SAME: Applica l'imbottitura all'input (se necessario) in modo che l'immagine in input venga completamente coperta dal filtro e dal passo specificato. Per il passo 1, questo assicurerà che le dimensioni dell'immagine in uscita siano le stesse dell'input.

Appunti

  • Questo vale sia per i livelli conv, sia per i livelli massimi di pool allo stesso modo
  • Il termine "valido" è un po 'improprio perché le cose non diventano "non valide" se si rilascia parte dell'immagine. A volte potresti persino volerlo. Questo dovrebbe probabilmente essere chiamato NO_PADDINGinvece.
  • Anche il termine "stesso" è un termine improprio perché ha senso solo per il passo di 1 quando la dimensione di output è uguale alla dimensione di input. Per un passo di 2, le dimensioni di uscita saranno la metà, ad esempio. Questo dovrebbe probabilmente essere chiamato AUTO_PADDINGinvece.
  • In SAME(cioè modalità auto-pad), Tensorflow proverà a distribuire uniformemente il riempimento sia a sinistra che a destra.
  • In VALID(cioè nessuna modalità di riempimento), Tensorflow lascerà cadere le celle a destra e / o in basso se il filtro e il passo non coprono completamente l'immagine di input.

19

Sto citando questa risposta dai documenti ufficiali di tensorflow https://www.tensorflow.org/api_guides/python/nn#Convolution Per il padding 'SAME', l'altezza e la larghezza dell'output sono calcolate come:

out_height = ceil(float(in_height) / float(strides[1]))
out_width  = ceil(float(in_width) / float(strides[2]))

e l'imbottitura in alto e a sinistra sono calcolate come:

pad_along_height = max((out_height - 1) * strides[1] +
                    filter_height - in_height, 0)
pad_along_width = max((out_width - 1) * strides[2] +
                   filter_width - in_width, 0)
pad_top = pad_along_height // 2
pad_bottom = pad_along_height - pad_top
pad_left = pad_along_width // 2
pad_right = pad_along_width - pad_left

Per l'imbottitura "VALIDA", l'altezza e la larghezza dell'uscita sono calcolate come:

out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))

e i valori di riempimento sono sempre zero.


1
Francamente questa è l'unica risposta valida e completa in circolazione, non limitata a passi di 1. E tutto ciò che serve è una citazione dai documenti. +1
P-Gn,

1
Molto utile avere questa risposta in giro, specialmente perché il link a cui fai riferimento non funziona più e sembra che Google abbia cancellato tali informazioni dal sito Web di tf!
Daniel

12

Sono disponibili tre opzioni di riempimento: valido (nessuna imbottitura), uguale (o metà), completo. Puoi trovare spiegazioni (in Theano) qui: http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html

  • Imbottitura valida o assente:

Il padding valido non comporta alcun padding zero, quindi copre solo l'input valido, esclusi gli zeri generati artificialmente. La lunghezza dell'output è ((la lunghezza dell'input) - (k-1)) per la dimensione del kernel k se il passo s = 1.

  • Stessa o mezza imbottitura:

Lo stesso padding rende le dimensioni delle uscite uguali a quelle degli input quando s = 1. Se s = 1, il numero di zeri riempiti è (k-1).

  • Imbottitura completa:

Il riempimento completo significa che il kernel gira su tutti gli input, quindi alle estremità, il kernel può incontrare l'unico input e altri zeri. Il numero di zeri riempiti è 2 (k-1) se s = 1. La lunghezza dell'output è ((la lunghezza dell'ingresso) + (k-1)) se s = 1.

Pertanto, il numero di imbottiture: (valido) <= (stesso) <= (completo)


8

Imbottitura on / off. Determina la dimensione effettiva dell'input.

VALID:Nessuna imbottitura. Le operazioni di convoluzione ecc. Vengono eseguite solo in luoghi "validi", ovvero non troppo vicini ai bordi del tensore.
Con un kernel di 3x3 e un'immagine di 10x10, eseguiresti una convoluzione nell'area 8x8 all'interno dei bordi.

SAME:L'imbottitura è fornita. Ogni volta che l'operazione fa riferimento a un vicinato (non importa quanto grande), vengono forniti valori zero quando quel vicinato si estende al di fuori del tensore originale per consentire a quell'operazione di funzionare anche sui valori di confine.
Con un kernel di 3x3 e un'immagine di 10x10, eseguiresti una convoluzione sull'intera area 10x10.


8

Imbottitura VALIDA : si tratta dell'imbottitura zero. Spero non ci sia confusione.

x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
print (valid_pad.get_shape()) # output-->(1, 2, 1, 1)

STESSA imbottitura: questo è un po 'difficile da capire in primo luogo perché dobbiamo considerare due condizioni separatamente come menzionato nei documenti ufficiali .

Prendiamo input as , output as , padding as , stride as e dimensione del kernel as (viene considerata solo una singola dimensione)

Caso 01 ::

Caso 02 ::

è calcolato in modo tale che il valore minimo che può essere preso per l'imbottitura. Poiché il valore di è noto, il valore di può essere trovato utilizzando questa formula .

Facciamo questo esempio:

x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
print (same_pad.get_shape()) # --> output (1, 2, 2, 1)

Qui la dimensione di x è (3,4). Quindi se viene presa la direzione orizzontale (3):

Se viene presa la direzione verticale (4):

Spero che questo possa aiutare a capire come funziona effettivamente l' imbottitura SAME in TF.


7

Sulla base della spiegazione qui e in seguito alla risposta di Tristan, di solito utilizzo queste funzioni rapide per i controlli di integrità.

# a function to help us stay clean
def getPaddings(pad_along_height,pad_along_width):
    # if even.. easy..
    if pad_along_height%2 == 0:
        pad_top = pad_along_height / 2
        pad_bottom = pad_top
    # if odd
    else:
        pad_top = np.floor( pad_along_height / 2 )
        pad_bottom = np.floor( pad_along_height / 2 ) +1
    # check if width padding is odd or even
    # if even.. easy..
    if pad_along_width%2 == 0:
        pad_left = pad_along_width / 2
        pad_right= pad_left
    # if odd
    else:
        pad_left = np.floor( pad_along_width / 2 )
        pad_right = np.floor( pad_along_width / 2 ) +1
        #
    return pad_top,pad_bottom,pad_left,pad_right

# strides [image index, y, x, depth]
# padding 'SAME' or 'VALID'
# bottom and right sides always get the one additional padded pixel (if padding is odd)
def getOutputDim (inputWidth,inputHeight,filterWidth,filterHeight,strides,padding):
    if padding == 'SAME':
        out_height = np.ceil(float(inputHeight) / float(strides[1]))
        out_width  = np.ceil(float(inputWidth) / float(strides[2]))
        #
        pad_along_height = ((out_height - 1) * strides[1] + filterHeight - inputHeight)
        pad_along_width = ((out_width - 1) * strides[2] + filterWidth - inputWidth)
        #
        # now get padding
        pad_top,pad_bottom,pad_left,pad_right = getPaddings(pad_along_height,pad_along_width)
        #
        print 'output height', out_height
        print 'output width' , out_width
        print 'total pad along height' , pad_along_height
        print 'total pad along width' , pad_along_width
        print 'pad at top' , pad_top
        print 'pad at bottom' ,pad_bottom
        print 'pad at left' , pad_left
        print 'pad at right' ,pad_right

    elif padding == 'VALID':
        out_height = np.ceil(float(inputHeight - filterHeight + 1) / float(strides[1]))
        out_width  = np.ceil(float(inputWidth - filterWidth + 1) / float(strides[2]))
        #
        print 'output height', out_height
        print 'output width' , out_width
        print 'no padding'


# use like so
getOutputDim (80,80,4,4,[1,1,1,1],'SAME')

6

Per riassumere, un'imbottitura "valida" significa nessuna imbottitura. La dimensione di output del livello convoluzionale si riduce in base alla dimensione dell'input e alla dimensione del kernel.

Al contrario, "stessa" imbottitura significa usare l'imbottitura. Quando il passo è impostato su 1, la dimensione di output del livello convoluzionale viene mantenuta come dimensione di input aggiungendo un certo numero di 'bordo 0' attorno ai dati di input durante il calcolo della convoluzione.

Spero che questa descrizione intuitiva sia di aiuto.


5

Formula generale

Qui, W e H sono la larghezza e l'altezza dell'input, F le dimensioni del filtro, P la dimensione del riempimento (ovvero il numero di righe o colonne da riempire)

Per imbottitura SAME:

STESSA imbottitura

Per imbottitura VALID:

Imbottitura VALIDA


2

A completamento della grande risposta di YvesgereY, ho trovato questa visualizzazione estremamente utile:

Visualizzazione dell'imbottitura

Imbottitura ' valida " è la prima cifra. La finestra del filtro rimane all'interno dell'immagine.

L'imbottitura " uguale " è la terza figura. L'output ha le stesse dimensioni.


L'ho trovato in questo articolo .


0

Risposta compatibile Tensorflow 2.0 : spiegazioni dettagliate sono state fornite sopra, riguardo al riempimento "valido" e "stesso".

Tuttavia, specificherò diverse funzioni di pooling e i rispettivi comandi in Tensorflow 2.x (>= 2.0), a beneficio della comunità.

Funzioni in 1.x :

tf.nn.max_pool

tf.keras.layers.MaxPool2D

Average Pooling => None in tf.nn, tf.keras.layers.AveragePooling2D

Funzioni in 2.x :

tf.nn.max_poolse utilizzato in 2.xe tf.compat.v1.nn.max_pool_v2oppure oppure tf.compat.v2.nn.max_pool, se migrato da 1.xa 2.x.

tf.keras.layers.MaxPool2D se usato in 2.xe

tf.compat.v1.keras.layers.MaxPool2Doppure tf.compat.v1.keras.layers.MaxPooling2Doppure tf.compat.v2.keras.layers.MaxPool2Doppure tf.compat.v2.keras.layers.MaxPooling2D, se migrato da 1.xa 2.x.

Average Pooling => tf.nn.avg_pool2do tf.keras.layers.AveragePooling2Dse utilizzato in TF 2.xe

tf.compat.v1.nn.avg_pool_v2oppure tf.compat.v2.nn.avg_pooloppure tf.compat.v1.keras.layers.AveragePooling2Doppure tf.compat.v1.keras.layers.AvgPool2Doppure tf.compat.v2.keras.layers.AveragePooling2Doppure tf.compat.v2.keras.layers.AvgPool2D, se migrato da 1.xa 2.x.

Per ulteriori informazioni sulla migrazione da Tensorflow 1.xa 2.x, fare riferimento a questa guida alla migrazione .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.