[Pytorch] MaxPool2d ceil_mode

Qu'est-ce que ceil_mode

Si vous voulez porter le modèle entraîné de Pytorch torchvision.models.googlenet vers Keras, vous pouvez être curieux.

Quel est le ceil_mode de MaxPool2d?

En regardant la documentation, il dit: "Si True, utilisez ceil (arrondi vers le haut) au lieu de floor (arrondi vers le haut) pour calculer la forme de sortie."

torch.nn — PyTorch master documentation

ceil_mode – when True, will use ceil instead of floor to compute the output shape

Ci-dessous, MaxPool2D, qui apparaît pour la première fois sur ** torchvision.models.googlenet **.

#L'entrée est(112, 112, 64)
MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=True)

Lorsque je calcule la taille de sortie, ** 55,5 **

output\_shape = \frac{input\_shape + 2 \times padding - kernel\_size}{stride} + 1 \\
= \frac{112 + 2 \times 0 - 3}{2} + 1 = 55.5

En regardant la taille de sortie réelle avec le résumé de la torche, c'est ** (ch = 64, 56, 56) **, donc il semble certainement être arrondi (ceil) après la virgule décimale.

MaxPool2d-4           [-1, 64, 56, 56]

Vérifiez le résultat de PyTorch

Insérez les exemples de données suivants de taille (10,10) dans MaxPool2d de kernel = (3,3), stride = (2,2) et voyez le résultat.

Exemple de données

import torch
import torch.nn as nn

>>> x = torch.arange(1, 101).view(1, 10, 10).float()
>>> x
tensor([[[  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.],
         [ 11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.,  20.],
         [ 21.,  22.,  23.,  24.,  25.,  26.,  27.,  28.,  29.,  30.],
         [ 31.,  32.,  33.,  34.,  35.,  36.,  37.,  38.,  39.,  40.],
         [ 41.,  42.,  43.,  44.,  45.,  46.,  47.,  48.,  49.,  50.],
         [ 51.,  52.,  53.,  54.,  55.,  56.,  57.,  58.,  59.,  60.],
         [ 61.,  62.,  63.,  64.,  65.,  66.,  67.,  68.,  69.,  70.],
         [ 71.,  72.,  73.,  74.,  75.,  76.,  77.,  78.,  79.,  80.],
         [ 81.,  82.,  83.,  84.,  85.,  86.,  87.,  88.,  89.,  90.],
         [ 91.,  92.,  93.,  94.,  95.,  96.,  97.,  98.,  99., 100.]]])
>>> x.shape
torch.Size([1, 10, 10])

ceil_mode = False padding = 1

>>> nn.MaxPool2d((3,3), stride=2, padding=1, ceil_mode=False)(x)               

#Taille de sortie(5, 5)
tensor([[[ 12.,  14.,  16.,  18.,  20.],
         [ 32.,  34.,  36.,  38.,  40.],
         [ 52.,  54.,  56.,  58.,  60.],
         [ 72.,  74.,  76.,  78.,  80.],
         [ 92.,  94.,  96.,  98., 100.]]])
output\_shape = \frac{input\_shape + 2 \times padding - kernel\_size}{stride} + 1 \\
= \frac{10 + 2 \times 1 - 3}{2} + 1 = 5.5

Tronquer après la virgule décimale, 5,5 → 5

padding = 0

>>> nn.MaxPool2d((3,3), stride=2, padding=0, ceil_mode=False)(x) 

#Taille de sortie(4, 4)
tensor([[[23., 25., 27., 29.],
         [43., 45., 47., 49.],
         [63., 65., 67., 69.],
         [83., 85., 87., 89.]]])
output\_shape = \frac{input\_shape + 2 \times padding - kernel\_size}{stride} + 1 \\
= \frac{10 + 2 \times 0 - 3}{2} + 1 = 4.5

Tronquer après la virgule décimale, 4,5 → 4

ceil_mode = True padding = 1

>>> nn.MaxPool2d((3,3), stride=2, padding=1, ceil_mode=True)(x) 

#Taille de sortie(6, 6)
tensor([[[ 12.,  14.,  16.,  18.,  20.,  20.],
         [ 32.,  34.,  36.,  38.,  40.,  40.],
         [ 52.,  54.,  56.,  58.,  60.,  60.],
         [ 72.,  74.,  76.,  78.,  80.,  80.],
         [ 92.,  94.,  96.,  98., 100., 100.],
         [ 92.,  94.,  96.,  98., 100., 100.]]])
output\_shape = \frac{input\_shape + 2 \times padding - kernel\_size}{stride} + 1 \\
= \frac{10 + 2 \times 1 - 3}{2} + 1 = 5.5

Arrondir après la virgule décimale, 5,5 → 6

padding = 0

>>> nn.MaxPool2d((3,3), stride=2, padding=0, ceil_mode=True)(x)  

#Taille de sortie(5, 5)
tensor([[[ 23.,  25.,  27.,  29.,  30.],
         [ 43.,  45.,  47.,  49.,  50.],
         [ 63.,  65.,  67.,  69.,  70.],
         [ 83.,  85.,  87.,  89.,  90.],
         [ 93.,  95.,  97.,  99., 100.]]])
output\_shape = \frac{input\_shape + 2 \times padding - kernel\_size}{stride} + 1 \\
= \frac{10 + 2 \times 0 - 3}{2} + 1 = 4.5

Arrondir après la virgule décimale, 4,5 → 5

Différence entre True / False de ceil_mode

Les tailles de sortie suivantes sont toutes (5, 5), mais quelle est la différence?

padding=1, ceil_mode=False

État de la mise en commun maximale

image.png

production

image.png

padding=0, ceil_mode=True

État de la mise en commun maximale

Puisqu'il n'y a pas de remplissage, la mise en commun est effectuée à partir du coin supérieur gauche. En arrondissant la forme de sortie, le résultat est le même que le remplissage uniquement à droite et en bas.

image.png

production

image.png

Vérifions le résultat de Keras

Insérez les exemples de données suivants de taille (10,10) dans MaxPool2d de kernel = (3,3), stride = (2,2) et voyez le résultat. MaxPooling2D de Keras n'a pas de paramètres de type ceil_mode.

Il semble que Keras tronque toujours le résultat du calcul de la forme de sortie après le point décimal (** ceil_mode = False ** dans Pytorch).

Exemple de données

Comme avec Pytorch, générez des données 10x10.

from tensorflow.keras.layers import MaxPooling2D
import numpy as np

x = np.arange(1, 101).reshape(1, 10, 10, 1).astype(np.float)

padding=1 Même sortie que ** padding = 1, ceil_mode = False ** sur Pytorch.

>>> out = MaxPooling2D((3,3), strides=(2,2))(ZeroPadding2D((1,1))(x))
>>> out = tf.transpose(out, perm=[0,3,1,2])
>>> with tf.Session() as sess:  
>>>     out_value = sess.run(out)
>>>     print(out_value)

#Taille de sortie(5, 5)
[[[[ 12.  14.  16.  18.  20.]
   [ 32.  34.  36.  38.  40.]
   [ 52.  54.  56.  58.  60.]
   [ 72.  74.  76.  78.  80.]
   [ 92.  94.  96.  98. 100.]]]]

padding=0 Même sortie que ** padding = 0, ceil_mode = False ** sur Pytorch.

>>> out = MaxPooling2D((3,3), strides=(2,2))(x)
>>> out = tf.transpose(out, perm=[0,3,1,2])
>>> with tf.Session() as sess:  
>>>     out_value = sess.run(out)
>>>     print(out_value)

#Taille de sortie(4, 4)
[[[[23. 25. 27. 29.]
   [43. 45. 47. 49.]
   [63. 65. 67. 69.]
   [83. 85. 87. 89.]]]]

Comment obtenir la même sortie que ceil_mode = True avec keras?

Lorsque ZeroPadding2D est défini comme suit, le remplissage zéro est effectué verticalement et horizontalement.

ZeroPadding2D((1,1))(x)

image.png

Il est également possible de modifier les paramètres de remplissage pour le haut et le bas, la gauche et la droite, comme indiqué ci-dessous. (Le remplissage nul n'est appliqué qu'en bas et à droite)

ZeroPadding2D(((0,1), (0,1)))(x)

image.png

En appliquant un remplissage nul uniquement en bas et à droite, nous avons pu obtenir le même résultat que ceil_mode = True.

>>> out = MaxPooling2D((3,3), strides=(2,2))(ZeroPadding2D(((0,1), (0,1)))(x))
>>> out = tf.transpose(out, perm=[0,3,1,2])
>>> with tf.Session() as sess:  
>>>     out_value = sess.run(out)
>>>     print(out_value)

#Taille de sortie(5, 5)
[[[[ 23.  25.  27.  29.  30.]
   [ 43.  45.  47.  49.  50.]
   [ 63.  65.  67.  69.  70.]
   [ 83.  85.  87.  89.  90.]
   [ 93.  95.  97.  99. 100.]]]]

Recommended Posts

[Pytorch] MaxPool2d ceil_mode
Installer pytorch
Liens PyTorch
Pratiquez Pytorch
Installez PyTorch