Argument de Tensorflow Strides

115

J'essaie de comprendre l' argument des foulées dans tf.nn.avg_pool, tf.nn.max_pool, tf.nn.conv2d.

La documentation dit à plusieurs reprises

foulées: une liste d'entiers dont la longueur est> = 4. La foulée de la fenêtre glissante pour chaque dimension du tenseur d'entrée.

Mes questions sont:

  1. Que représentent chacun des 4+ entiers?
  2. Pourquoi doivent-ils avoir des foulées [0] = foulées [3] = 1 pour les convnets?
  3. Dans cet exemple, nous voyons tf.reshape(_X,shape=[-1, 28, 28, 1]). Pourquoi -1?

Malheureusement, les exemples dans la documentation pour remodeler en utilisant -1 ne se traduisent pas trop bien dans ce scénario.

jfbeltran
la source

Réponses:

224

Les opérations de regroupement et de convolution font glisser une «fenêtre» sur le tenseur d'entrée. A tf.nn.conv2dtitre d'exemple: Si le tenseur d'entrée a 4 dimensions [batch, height, width, channels]:, alors la convolution opère sur une fenêtre 2D sur les height, widthdimensions.

stridesdétermine le décalage de la fenêtre dans chacune des dimensions. L'utilisation typique définit le premier (le lot) et le dernier (la profondeur) foulée à 1.

Prenons un exemple très concret: exécution d'une convolution 2D sur une image d'entrée 32x32 en niveaux de gris. Je dis niveaux de gris car l'image d'entrée a alors une profondeur = 1, ce qui permet de rester simple. Laissez cette image ressembler à ceci:

00 01 02 03 04 ...
10 11 12 13 14 ...
20 21 22 23 24 ...
30 31 32 33 34 ...
...

Lançons une fenêtre de convolution 2x2 sur un seul exemple (taille du lot = 1). Nous donnerons à la convolution une profondeur de canal de sortie de 8.

L'entrée de la convolution a shape=[1, 32, 32, 1].

Si vous spécifiez strides=[1,1,1,1]avec padding=SAME, la sortie du filtre sera [1, 32, 32, 8].

Le filtre créera d'abord une sortie pour:

F(00 01
  10 11)

Et puis pour:

F(01 02
  11 12)

etc. Ensuite, il passera à la deuxième ligne, calculant:

F(10, 11
  20, 21)

puis

F(11, 12
  21, 22)

Si vous spécifiez une foulée de [1, 2, 2, 1], les fenêtres ne se chevauchent pas. Il calculera:

F(00, 01
  10, 11)

puis

F(02, 03
  12, 13)

La foulée fonctionne de la même manière pour les opérateurs de mise en commun.

Question 2: Pourquoi les foulées [1, x, y, 1] pour les réseaux

Le premier est le lot: vous ne voulez généralement pas ignorer les exemples dans votre lot, ou vous n'auriez pas dû les inclure en premier lieu. :)

Le dernier 1 est la profondeur de la convolution: vous ne voulez généralement pas sauter les entrées, pour la même raison.

L'opérateur conv2d est plus général, vous pouvez donc créer des convolutions qui font glisser la fenêtre le long d'autres dimensions, mais ce n'est pas une utilisation typique dans les convnets. L'utilisation typique est de les utiliser dans l'espace.

Pourquoi remodeler à -1 -1 est un espace réservé qui dit "ajustez si nécessaire pour correspondre à la taille nécessaire pour le tenseur complet." C'est un moyen de rendre le code indépendant de la taille du lot d'entrée, afin que vous puissiez modifier votre pipeline et ne pas avoir à ajuster la taille du lot partout dans le code.

dga
la source
5
@derek parce que (d'après le texte) "Nous donnerons à la convolution une profondeur de canal de sortie de 8.". C'est quelque chose que vous pouvez choisir lors de la configuration de la convolution, et le répondant a choisi 8.
etarion
17

Les entrées sont en 4 dimensions et sont de forme: [batch_size, image_rows, image_cols, number_of_colors]

Les foulées, en général, définissent un chevauchement entre les opérations d'application. Dans le cas de conv2d, il spécifie quelle est la distance entre les applications consécutives des filtres convolutifs. La valeur de 1 dans une dimension spécifique signifie que nous appliquons l'opérateur à chaque ligne / colonne, la valeur de 2 signifie chaque seconde, et ainsi de suite.

Re 1) Les valeurs qui comptent pour les convolutions sont les 2e et 3e et elles représentent le chevauchement dans l'application des filtres convolutifs le long des lignes et des colonnes. La valeur de [1, 2, 2, 1] indique que nous voulons appliquer les filtres à chaque deuxième ligne et colonne.

Re 2) Je ne connais pas les limites techniques (peut-être l'exigence de CuDNN) mais généralement les gens utilisent des enjambées le long des dimensions des lignes ou des colonnes. Cela n'a pas nécessairement de sens de le faire sur la taille du lot. Pas sûr de la dernière dimension.

Re 3) Mettre -1 pour l'une des dimensions signifie "définir la valeur de la première dimension de sorte que le nombre total d'éléments dans le tenseur reste inchangé". Dans notre cas, le -1 sera égal à batch_size.

Rafał Józefowicz
la source
11

Commençons par ce que fait Stride dans un cas à 1 dim.

Supposons que votre input = [1, 0, 2, 3, 0, 1, 1]et kernel = [2, 1, 3]le résultat de la convolution est [8, 11, 7, 9, 4], qui est calculé en faisant glisser votre noyau sur l'entrée, en effectuant une multiplication par élément et en additionnant tout. Comme ça :

  • 8 = 1 * 2 + 0 * 1 + 2 * 3
  • 11 = 0 * 2 + 2 * 1 + 3 * 3
  • 7 = 2 * 2 + 3 * 1 + 0 * 3
  • 9 = 3 * 2 + 0 * 1 + 1 * 3
  • 4 = 0 * 2 + 1 * 1 + 1 * 3

Ici, nous glissons d'un élément, mais rien ne vous arrête en utilisant un autre nombre. Ce nombre est votre foulée. Vous pouvez considérer cela comme un sous-échantillonnage du résultat de la convolution à un pas en prenant simplement chaque résultat s-ème.

Connaissant la taille d'entrée i , la taille du noyau k , la foulée s et le remplissage p, vous pouvez facilement calculer la taille de sortie de la convolution comme suit:

entrez la description de l'image ici

Ici || opérateur signifie opération au plafond. Pour une couche de regroupement s = 1.


Boîtier N-dim.

Connaître le calcul pour un cas à 1 dim., N-dim est facile une fois que vous voyez que chaque dim est indépendant. Vous faites donc simplement glisser chaque dimension séparément. Voici un exemple pour 2-d . Notez que vous n'avez pas besoin d'avoir la même foulée à toutes les dimensions. Donc, pour une entrée / noyau N-dim, vous devez fournir N foulées.


Alors maintenant, il est facile de répondre à toutes vos questions:

  1. Que représentent chacun des 4+ entiers? . conv2d , pool vous indique que cette liste représente les progrès entre chaque dimension. Notez que la longueur de la liste des foulées est la même que le rang du tenseur du noyau.
  2. Pourquoi doivent-ils avoir des foulées [0] = foulées 3 = 1 pour les réseaux? . La première dimension est la taille du lot, la dernière est les canaux. Il ne sert à rien de sauter ni batch ni channel. Donc, vous les faites 1. Pour la largeur / hauteur, vous pouvez sauter quelque chose et c'est pourquoi ils pourraient ne pas être 1.
  3. tf.reshape (_X, forme = [- 1, 28, 28, 1]). Pourquoi -1? tf.reshape l' a couvert pour vous:

    Si l'un des composants de la forme est la valeur spéciale -1, la taille de cette dimension est calculée de sorte que la taille totale reste constante. En particulier, une forme de [-1] s'aplatit en 1-D. Au plus un composant de la forme peut être -1.

Salvador Dali
la source
2

@dga a fait un travail formidable en expliquant et je ne saurais être assez reconnaissant à quel point cela a été utile. De la même manière, j'aimerais partager mes découvertes sur le stridefonctionnement de la convolution 3D.

Selon la documentation TensorFlow sur conv3d, la forme de l'entrée doit être dans cet ordre:

[batch, in_depth, in_height, in_width, in_channels]

Expliquons les variables de l'extrême droite vers la gauche à l'aide d'un exemple. En supposant que la forme d'entrée est input_shape = [1000,16,112,112,3]

input_shape[4] is the number of colour channels (RGB or whichever format it is extracted in)
input_shape[3] is the width of the image
input_shape[2] is the height of the image
input_shape[1] is the number of frames that have been lumped into 1 complete data
input_shape[0] is the number of lumped frames of images we have.

Vous trouverez ci-dessous une documentation récapitulative sur l'utilisation de la foulée.

foulées: Une liste d'entiers dont la longueur est> = 5. Tenseur 1-D de longueur 5. La foulée de la fenêtre coulissante pour chaque dimension d'entrée. Doit avoirstrides[0] = strides[4] = 1

Comme indiqué dans de nombreux travaux, les foulées signifient simplement combien de pas une fenêtre ou un noyau s'éloigne de l'élément le plus proche, qu'il s'agisse d'une trame de données ou d'un pixel (ceci est paraphrasé d'ailleurs).

D'après la documentation ci-dessus, une foulée en 3D ressemblera à ceci: foulées = (1, X , Y , Z , 1).

La documentation le souligne strides[0] = strides[4] = 1.

strides[0]=1 means that we do not want to skip any data in the batch 
strides[4]=1 means that we do not want to skip in the channel 

foulées [X] signifie le nombre de sauts que nous devons faire dans les cadres regroupés. Donc, par exemple, si nous avons 16 images, X = 1 signifie utiliser chaque image. X = 2 signifie utiliser chaque seconde image et ça continue

les foulées [y] et les foulées [z] suivent l'explication de @dga donc je ne vais pas refaire cette partie.

Dans les keras cependant, il vous suffit de spécifier un tuple / liste de 3 entiers, spécifiant les foulées de la convolution le long de chaque dimension spatiale, où la dimension spatiale est foulée [x], foulées [y] et foulées [z]. foulées [0] et foulées [4] est déjà réglé par défaut sur 1.

J'espère que quelqu'un trouvera cela utile!

Rockyne
la source