web-dev-qa-db-fra.com

Quelle est la différence entre un remplissage 'SAME' et 'VALID' dans tf.nn.max_pool of tensorflow?

Quelle est la différence entre les remplissages 'SAME' et 'VALID' dans tf.nn.max_pool de tensorflow?

À mon avis, 'VALID' signifie qu'il n'y aura pas de remplissage à zéro en dehors des bords lorsque nous faisons un pool maximum. 

Selon Un guide d’arithmétique de convolution pour un apprentissage en profondeur , il indique qu’il n’y aura pas d’opérateur de remplissage dans le pool, c’est-à-dire que vous utiliserez simplement 'VALID' de tensorflow. Mais quel est le remplissage 'SAME' du pool maximum dans tensorflow?

204
karl_TUM

Je vais donner un exemple pour le rendre plus clair:

  • x: image d'entrée de forme [2, 3], 1 canal
  • valid_pad: pool maximum avec noyau 2x2, stride 2 et remplissage VALID.
  • same_pad: pool max avec noyau 2x2, stride 2 et remplissage SAME (c'est le classic way to go)

Les formes de sortie sont:

  • valid_pad: ici, pas de remplissage, la forme de sortie est donc [1, 1]
  • same_pad: ici, nous plaçons l'image sur la forme [2, 4] (avec -inf puis appliquons le pool maximum), donc la forme de sortie est [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.]

118
Olivier Moindrot

Si vous aimez l'art ascii:

  • "VALID" = sans remplissage:

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

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

Dans cet exemple:

  • Largeur d'entrée = 13
  • Largeur du filtre = 6
  • Stride = 5

Remarques:

  • "VALID" ne supprime jamais que les colonnes les plus à droite (ou les lignes les plus basses).
  • "SAME" essaie de jouer uniformément à gauche et à droite, mais si le nombre de colonnes à ajouter est impair, la colonne supplémentaire sera ajoutée à droite, comme dans cet exemple rangée de zéros en bas).
431
MiniQuark

Quand stride est 1 (plus typique avec convolution que pool), on peut penser à la distinction suivante:

  • "SAME": la taille de sortie est égale à identique en tant que taille d'entrée. Cela nécessite que la fenêtre de filtrage glisse en dehors de la carte d’entrée, d’où la nécessité d’appuyer. 
  • "VALID": la fenêtre de filtre reste à la position valide dans la mappe d'entrée, ainsi la taille de sortie est réduite de filter_size - 1. Aucun remplissage ne se produit.
102
YvesgereY

Le TensorFlow Convolution example donne un aperçu de la différence entre SAME et VALID:

  • Pour le remplissage SAME, la hauteur et la largeur en sortie sont calculées comme suit:

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

Et

  • Pour le remplissage VALID, la hauteur et la largeur en sortie sont calculées comme suit:

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

Le rembourrage est une opération visant à augmenter la taille des données d'entrée. Dans le cas de données à une dimension, vous ajoutez simplement/préfixez le tableau avec une constante; dans la matrice à 2 dimensions, vous entourez la matrice avec ces constantes. Dans n-dim, vous entourez votre hypercube n-dim avec la constante. Dans la plupart des cas, cette constante est égale à zéro et est appelée zéro-remplissage.

Voici un exemple de remplissage à zéro avec p=1 appliqué au tenseur 2D: enter image description here


Vous pouvez utiliser un remplissage arbitraire pour votre noyau, mais certaines des valeurs de remplissage sont utilisées plus fréquemment que d'autres:

  • Rembourrage VALID. Le cas le plus simple, signifie pas de rembourrage du tout. Laissez simplement vos données les mêmes qu’elles étaient.
  • SAME padding parfois appelé HALF padding. Cela s'appelle MÊME, car pour une convolution avec stride = 1 (ou pour la mise en pool), il devrait produire une sortie de la même taille que l'entrée. Il s’appelle HALF car pour un noyau de taille kenter image description here
  • FULL padding est le remplissage maximum qui n'entraîne pas une convolution uniquement d'éléments lignés. Pour un noyau de taille k, ce remplissage est égal à k - 1.

Pour utiliser un remplissage arbitraire dans TF, vous pouvez utiliser tf.pad()

38
Salvador Dali

Explication rapide

VALID: N'appliquez aucun remplissage, c'est-à-dire que toutes les dimensions sont valid, de sorte que l'image d'entrée soit entièrement couverte par le filtre et la foulée spécifiées.

SAME: appliquez un remplissage à l'entrée (si nécessaire) de sorte que l'image d'entrée soit entièrement couverte par le filtre et la foulée que vous avez spécifiées. Pour le pas 1, cela garantira que la taille de l'image de sortie est égale à identique comme entrée.

Remarques

  • Ceci s’applique de la même manière aux couches de conv et au maximum de couches.
  • Le terme "valide" est un peu impropre car les choses ne deviennent pas "invalides" si vous supprimez une partie de l'image. Parfois, vous pourriez même vouloir cela. Cela aurait probablement dû s'appeler NO_PADDING à la place.
  • Le terme "identique" est également abusif, car il n'a de sens que pour un pas de 1 lorsque la dimension de sortie est identique à la dimension d'entrée. Pour une foulée de 2, les dimensions de sortie seront de moitié, par exemple. Cela aurait probablement dû s'appeler AUTO_PADDING à la place.
  • Dans SAME (c.-à-d. Le mode de remplissage automatique), Tensorflow essaiera de répartir le remplissage de manière uniforme à gauche et à droite.
  • Dans VALID (c’est-à-dire sans mode de remplissage), Tensorflow déposera les cellules droites et/ou inférieures si votre filtre et votre foulée ne couvrent pas complètement l’image d’entrée.
19
Shital Shah

Il existe trois choix de rembourrage: valide (pas de rembourrage), identique (ou à moitié), complet. Vous pouvez trouver des explications (dans Theano) ici: http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html

  • Valide ou pas de remplissage:

Le remplissage valide n'implique aucun remplissage nul, il ne couvre donc que les entrées valides, à l'exclusion des zéros générés artificiellement. La longueur de la sortie est ((la longueur de l'entrée) - (k-1)) pour la taille du noyau k si le pas s = 1.

  • Rembourrage identique ou partiel:

Le même remplissage fait en sorte que la taille des sorties soit identique à celle des entrées lorsque s = 1. Si s = 1, le nombre de zéros remplis est égal à (k-1).

  • Rembourrage complet:

Le remplissage complet signifie que le noyau fonctionne sur toutes les entrées. Ainsi, aux extrémités, le noyau peut rencontrer la seule entrée et les zéros restants. Le nombre de zéros remplis est 2(k-1) si s = 1. La longueur de la sortie est ((la longueur de l'entrée) + (k-1)) si s = 1.

Par conséquent, le nombre de paddings: (valide) <= (identique) <= (complet)

10

Je cite cette réponse de la documentation officielle de tensorflow https://www.tensorflow.org/api_guides/python/nn#Convolution Pour le remplissage 'SAME', la hauteur et la largeur de sortie sont calculées comme suit:

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

et le remplissage en haut et à gauche sont calculés comme suit:

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

Pour le remplissage 'VALID', la hauteur et la largeur de sortie sont calculées comme suit:

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

et les valeurs de remplissage sont toujours égales à zéro.

9
Vaibhav Dixit

Sur la base de l'explication ici et suite à la réponse de Tristan, j'utilise généralement ces fonctions rapides pour les contrôles de cohérence.

# 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')
5
ahmedhosny

Rembourrage on/off. Détermine la taille effective de votre entrée .

VALID: Pas de remplissage. Les opérations de convolution, etc., ne sont exécutées qu’aux emplacements "valides", c’est-à-dire qu’ils ne sont pas trop proches des limites de votre tenseur. 
Avec un noyau de 3x3 et une image de 10x10, vous effectueriez une convolution sur la zone 8x8 à l'intérieur des frontières .

SAME: Le rembourrage est fourni. Chaque fois que votre opération fait référence à un voisinage (quelle que soit sa taille), des valeurs zéro sont fournies lorsque ce voisinage dépasse du tenseur d'origine pour permettre à cette opération de fonctionner également sur les valeurs de bordure. 
Avec un noyau de 3x3 et une image de 10x10, vous effectueriez une convolution sur la totalité de la zone 10x10.

4
Laine Mikael

VALIDE padding: c'est un padding nul. J'espère qu'il n'y a pas de confusion. 

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)

SAME padding: C'est un peu difficile à comprendre en premier lieu car nous devons considérer 2 conditions séparément comme indiqué dans le document officiel

Prenons l'entrée comme  , sortie en tant que , rembourrage comme , foulée comme  et la taille du noyau comme . (singal dimentina est considéré)

Cas 01:  :

Cas 02: 

est calculée su que la valeur minimale pouvant être prise pour le remplissage. Depuis la valeur de  est connue, valeur de  peut être trouvé en utilisant ce formulaire 

Travaillons cet exemple:

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)

Ici la dimension de x est (3,4). Alors si la direction horizontale est prise (3):

Si la direction verticale est prise (4):

J'espère que cela vous aidera à comprendre comment fonctionne réellement LE M&ECIRC;ME remplissage dans TF. 

2
GPrathap

 General Formula

Ici, W et H sont la largeur et la hauteur de l’entrée, F sont les dimensions du filtre, P est la taille de remplissage (c'est-à-dire le nombre de lignes ou de colonnes à remplir)

Pour SAME padding: 

 SAME Padding

Pour un remplissage VALIDE: 

 VALID padding

0
Shivam Kushwaha