[PYTHON] Foulées pliées et mise en commun moyenne

introduction

AveragePooling2D et MaxPooling2D sont souvent utilisés pour réduire de moitié la taille de l'image dans les opérations de convolution d'apprentissage en profondeur. En divisant par deux la taille de l'image, la taille du noyau du filtre sera sensiblement plus grande dans la couche de convolution suivante. D'autre part, les foulées dans Conv2D sont également parfois utilisées pour réduire de moitié la taille de l'image. Voyons comment cette différence peut affecter la largeur du filtre de l'opération de convolution.

※Mise en garde Si chaque couche contient la fonction d'activation relu, il n'est pas possible de la convertir en une simple convolution comme décrit ci-dessous. Par conséquent, la discussion suivante est limitée à la condition qu'elle ne tient que lorsque la fonction d'activation n'existe pas.

1. Calcul de convolution de scipy.signal

Tout d'abord, assurez-vous que la convolution bidimensionnelle peut être calculée en utilisant scipy.signal.correlate2d () et scipy.signal.convolve2d (). Si A1 et B1 sont définis de manière appropriée, le résultat de la convolution de A1 dans le B1 familier pourrait être obtenu par correlate2d (). Notez également que lors de l'utilisation de convolve2d (), il est nécessaire d'inverser l'ordre de la matrice.

python


import numpy as np
import scipy.signal as sp

A1 = np.random.randint(0,2,(3,3))
B1 = np.random.randint(-4,5,(7,7))
C1 = sp.correlate2d(B1, A1, mode='valid')
C2 = sp.convolve2d(B1, A1[::-1,::-1], mode='valid')

print('A1=\n', A1)
print('B1=\n', B1)
print('C1=\n', C1)
print('C2=\n', C2)
-----------------------------------------------
A1=
 [[0 1 0]
 [0 0 0]
 [1 0 1]]
B1=
 [[-1 -3  4 -3  1 -2 -2]
 [-3 -4 -2 -2  1  3  2]
 [-1 -4  2  3  3  3 -3]
 [ 3 -3 -2  1  3 -1  0]
 [ 2 -4  0  2  4  0  2]
 [ 4  0 -3  4  4  3  0]
 [ 0 -4 -2  4  3 -3  1]]
C1=
 [[-2  3  2  7 -2]
 [-3 -4 -1  1  6]
 [-2  0  7  5  9]
 [-2  2  2 10  3]
 [-6  0  3  5  4]]
C2=
 [[-2  3  2  7 -2]
 [-3 -4 -1  1  6]
 [-2  0  7  5  9]
 [-2  2  2 10  3]
 [-6  0  3  5  4]]

2. Lorsque le pliage 3x3 est appliqué deux fois

Dans la description de Keras, à quel type d'opération de convolution est équivalent lorsque la convolution 3x3 est appliquée deux fois comme indiqué ci-dessous? Cela équivaut à une convolution 5x5, comme beaucoup le savent. (* Cependant, à condition qu'il n'y ait pas de fonction d'activation relu pendant la convolution)

python



x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

On peut montrer que C1 est le résultat de la convolution de A1 => A2 dans B1 comme indiqué ci-dessous, et E1 est le résultat de la convolution avec D1 comme résultat de la recherche de la convolution de A1 et A2. Par conséquent, deux plis 3x3 sont égaux à un pli 5x5, Le filtre de convolution 5x5 peut être calculé avec D1 = sp.convolve2d (A1, A2, mode = 'full').

python


import numpy as np
import scipy.signal as sp

A1 = np.random.randint(0,2,(3,3))
A2 = np.random.randint(0,2,(3,3))
B1 = np.random.randint(-4,5,(7,7))
C1 = sp.correlate2d(B1, A1, mode='valid')
C2 = sp.correlate2d(C1, A2, mode='valid')
D1 = sp.convolve2d(A1, A2, mode='full')
E1 = sp.correlate2d(B1, D1, mode='valid')

print('A1=\n', A1)
print('A2=\n', A2)
print('B1=\n', B1)
print('C1=\n', C1)
print('C2=\n', C2)
print('D1=\n', D1)
print('E1=\n', E1)
----------------------------------------------
A1=
 [[1 0 1]
 [1 1 1]
 [0 0 0]]
A2=
 [[0 0 1]
 [0 1 0]
 [0 0 0]]
B1=
 [[-3 -4  4 -4  0 -2  3]
 [ 2  0 -3  3  4  2 -4]
 [ 0  4 -4  0  1  1  2]
 [-4 -3  0 -1 -3  0 -2]
 [ 4  1  2 -2 -3 -1  1]
 [ 3 -1 -1 -4 -1  3 -2]
 [ 4  0 -1 -3 -4 -4 -3]]
C1=
 [[  0  -8   8   3   5]
 [ -1   3  -2   7   4]
 [-11   0  -7  -3  -2]
 [  3  -3  -6  -7  -8]
 [  7  -7  -7  -5  -2]]
C2=
 [[ 11   1  12]
 [ -2   0   1]
 [-10  -9  -9]]
D1=
 [[0 0 1 0 1]
 [0 1 1 2 1]
 [0 1 1 1 0]
 [0 0 0 0 0]
 [0 0 0 0 0]]
E1=
 [[ 11   1  12]
 [ -2   0   1]
 [-10  -9  -9]]

3. Lorsque le pliage 5x5 est appliqué une fois

Considérez le contraire de 2. Si une convolution 5x5 est présente une fois, est-il possible de la décomposer en deux convolutions 3x3? Si théoriquement un filtre de convolution 5x5 1 et 3x3 convolution 1 est évident, alors le poids de l'autre convolution 3x3 peut être calculé comme la convolution inverse. Si D1 = convolve2d (A1, A2), alors ʻA2 = deconvolve2d (D1, A1) `.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (5, 5), padding="valid")(x)

Cependant, la ** fonction de convolution inverse bidimensionnelle ** n'existe pas dans scipy, donc je n'ai pas pu la confirmer dans scipy. En utilisant la fonction de convolution inverse pour les images, nous avons obtenu des valeurs approximatives de convolution inverse dans F1 et F2 comme indiqué ci-dessous. En premier lieu, le nombre de paramètres pour toute convolution 5x5 est de 25, tandis que le nombre de paramètres pour 2 convolutions 3x3 est de 18, il est donc impossible d'afficher toutes les convolutions 5x5 avec 2 convolutions 3x3 en termes de nombre de paramètres.

python


import numpy as np
import scipy.signal as sp
from skimage import restoration

A1 = np.random.randint(0,2,(3,3))
A2 = np.random.randint(0,2,(3,3))
D1 = sp.convolve2d(A1, A2, mode='full')
F1, _ = restoration.unsupervised_wiener(D1, A2)
F2, _ = restoration.unsupervised_wiener(D1, A1)

print('A1=\n', A1)
print('A2=\n', A2)
print('D1=\n', D1)
print('F1=\n', F1[1:-1,1:-1])
print('F2=\n', F2[1:-1,1:-1])
---------------------------------
A1=
 [[1 1 0]
 [1 0 0]
 [0 1 1]]
A2=
 [[0 0 0]
 [1 1 1]
 [0 0 0]]
D1=
 [[0 0 0 0 0]
 [1 2 2 1 0]
 [1 1 1 0 0]
 [0 1 2 2 1]
 [0 0 0 0 0]]
F1=
 [[ 0.96529897  0.89627574  0.13951081]
 [ 0.7975316   0.15137364 -0.02074955]
 [ 0.0798071   0.92025068  0.92801951]]
F2=
 [[ 0.00971747  0.0117676   0.00229734]
 [ 0.96429178  0.99937217  0.97182209]
 [-0.00158553  0.03361686 -0.00815724]]

Résumé ・ Toute convolution 3x3 2 fois peut être convertie en convolution 5x5 1 fois => Vrai ・ Une convolution arbitraire 5x5 peut être convertie en deux convolutions 3x3 => Faux (une valeur approximative est possible)

4. Dans le cas de la mise en commun moyenne ((2,2))

À propos, la mise en commun moyenne avec la taille de la piscine (2,2) est Conv2D avec x = Conv2D (1, (2, 2), padding =" valid ", strides = 2) (x) et poids du filtre de convolution ((0.25,0.25), (0.25,0.25)) Je veux montrer que c'est égal à une opération. Si le filtre de lissage A1 est défini comme suit, le résultat D2 obtenu en convoluant A1 en B1 et en effectuant le traitement des foulées est égal au résultat C1 de la mise en commun moyenne.

A1: filtre de lissage image.png

python


x = Input(shape=(28, 28, 1))
x = AveragePooling2D((2, 2))(x)

python


import numpy as np
import scipy.signal as sp
import skimage.measure

A1 = np.ones((2,2))/4
B1 = np.random.randint(-4,5,(8,8))*4
C1 = skimage.measure.block_reduce(B1, (2,2), np.average)
D1 = sp.correlate2d(B1, A1, mode='valid')
D2 = D1[::2,::2]

print('A1=\n', A1)
print('B1=\n', B1)
print('C1=\n', C1)
print('D1=\n', D1)
print('D2=\n', D2)
---------------------------------
A1=
 [[0.25 0.25]
 [0.25 0.25]]
B1=
 [[-12  -4   0   8  -4   4 -12  -8]
 [  4  -4   8 -12  -8 -16 -12  -8]
 [-16 -16 -16   8   8 -16 -12   0]
 [-12  -8  -4  16  -4  -8 -16  -4]
 [-12  -8 -12  16  -4   4  -4   0]
 [-12 -12   4  -8 -12   8   0  16]
 [ -8  16   8  16 -12 -12 -16   0]
 [ -8   4   4 -12  12  -4 -16   4]]
C1=
 [[ -4.   1.  -6. -10.]
 [-13.   1.  -5.  -8.]
 [-11.   0.  -1.   3.]
 [  1.   4.  -4.  -7.]]
D1=
 [[ -4.   0.   1.  -4.  -6.  -9. -10.]
 [ -8.  -7.  -3.  -1.  -8. -14.  -8.]
 [-13. -11.   1.   7.  -5. -13.  -8.]
 [-10.  -8.   4.   6.  -3.  -6.  -6.]
 [-11.  -7.   0.  -2.  -1.   2.   3.]
 [ -4.   4.   5.  -4.  -7.  -5.   0.]
 [  1.   8.   4.   1.  -4. -12.  -7.]]
D2=
 [[ -4.   1.  -6. -10.]
 [-13.   1.  -5.  -8.]
 [-11.   0.  -1.   3.]
 [  1.   4.  -4.  -7.]]

Par conséquent, la mise en commun moyenne est égale à: Cependant, la valeur du filtre est un filtre de lissage.

python


x = Input(shape=(28, 28, 1))
x = AveragePooling2D((2, 2))(x)
---------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)

5. Pour Conv2D + AveragePooling ((2,2))

Si vous avez Conv2D et Average Pooling comme ci-dessous, je voudrais résoudre ce problème à une simple convolution.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

À ce stade, si le traitement du filtre A2 de convolution 3x3 après AveragePooling est considéré sans AveragePooling, on peut voir qu'il est égal au résultat de la convolution du filtre de convolution 6x6 A3, qui est deux fois la taille remplie avec la même valeur, puis en le multipliant par des foulées. .. A2: image.png A3: image.png Ci-dessous, on peut confirmer que C3 et E2 sont égaux.

python


import numpy as np
import scipy.signal as sp
import skimage.measure

A1 = np.random.randint(0,2,(3,3))
A2 = np.random.randint(0,2,(3,3))
A3 = np.repeat(A2, 2, axis=0)
A3 = np.repeat(A3, 2, axis=1)
B1 = np.random.randint(-4,5,(12,12))
C1 = sp.correlate2d(B1, A1, mode='valid')
C2 = skimage.measure.block_reduce(C1, (2,2), np.average)
C3 = sp.correlate2d(C2, A2, mode='valid')
D1 = sp.convolve2d(A1, A3, mode='full')
E1 = sp.correlate2d(B1, D1, mode='valid')/4
E2 = E1[::2,::2]

print('A1=\n', A1)
print('A2=\n', A2)
print('A3=\n', A3)
print('B1=\n', B1)
print('C1=\n', C1)
print('C2=\n', C2)
print('C3=\n', C3)
print('D1=\n', D1)
print('E1=\n', E1)
print('E2=\n', E2)
------------------------------
A1=
 [[0 0 1]
 [1 0 0]
 [0 0 1]]
A2=
 [[1 1 1]
 [0 0 0]
 [0 0 1]]
A3=
 [[1 1 1 1 1 1]
 [1 1 1 1 1 1]
 [0 0 0 0 0 0]
 [0 0 0 0 0 0]
 [0 0 0 0 1 1]
 [0 0 0 0 1 1]]
B1=
 [[ 0 -2 -1 -3 -4  2 -3 -1 -3 -4 -2  1]
 [ 4 -1  2 -4 -4  4 -1 -1 -4 -2  2  2]
 [ 1 -4  3  3 -2  2  3 -2 -3  4 -1  2]
 [-3 -1 -4  4  0  3  1  0  0  0 -4  1]
 [ 3  1  4  1 -2 -2  2  1 -3  0  3 -3]
 [-4  0  3 -4  3  4  2  0  3  0  1 -4]
 [ 1 -3 -1 -1  3 -4 -2  3 -4  1  0 -3]
 [ 1 -4  0  4  4  3 -2 -4  3 -2  3  0]
 [ 0  2 -2  3  3  3  2 -2 -1  0  1 -1]
 [-4 -4  2 -2 -4 -1  4  4 -1  3 -1  4]
 [ 4  4 -2 -1 -1  0  4 -2  3  3 -4  4]
 [-4 -3  0 -1 -2  0 -2  3  3 -1 -2 -4]]
C1=
 [[  6  -1  -4   0  -4   1  -7  -1  -7   1]
 [ -1  -4  -1  10  -2   1  -1  -4  -5   7]
 [  4   3  -8   4   5   2  -5   4   2  -1]
 [  2   1   7   8   1  -2   5   1  -6  -3]
 [ -1   0   4 -10   3   8  -5   1   6  -6]
 [  4  -3   6   6   3  -8   4   1   0  -3]
 [ -2  -2   6   3   4   4  -7  -3   4  -6]
 [  2   4  -2   5   5   3   4  -1   1   4]
 [ -8  -2   4   1   2  -5   6   7  -4   6]
 [  6   1  -8  -2   1   7   6   0   0   3]]
C2=
 [[ 0.    1.25 -1.   -3.25 -1.  ]
 [ 2.5   2.75  1.5   1.25 -2.  ]
 [ 0.    1.5   1.5   0.25 -0.75]
 [ 0.5   3.    4.   -1.75  0.75]
 [-0.75 -1.25  1.25  4.75  1.25]]
C3=
 [[ 1.75 -2.75 -6.  ]
 [10.75  3.75  1.5 ]
 [ 4.25  8.    2.25]]
D1=
 [[0 0 1 1 1 1 1 1]
 [1 1 2 2 2 2 1 1]
 [1 1 2 2 2 2 1 1]
 [0 0 1 1 1 1 1 1]
 [0 0 0 0 0 0 1 1]
 [0 0 0 0 1 1 1 1]
 [0 0 0 0 1 1 1 1]
 [0 0 0 0 0 0 1 1]]
E1=
 [[ 1.75 -3.25 -2.75 -2.75 -6.  ]
 [ 4.   -0.75  0.    3.25 -0.5 ]
 [10.75  6.25  3.75  5.    1.5 ]
 [ 6.5   7.    9.25  3.25  2.5 ]
 [ 4.25  5.5   8.    3.    2.25]]
E2=
 [[ 1.75 -2.75 -6.  ]
 [10.75  3.75  1.5 ]
 [ 4.25  8.    2.25]]

Autrement dit, le modèle composé de Conv2D et de regroupement moyen ci-dessous peut être organisé comme suit.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (8, 8), padding="valid", strides=2)(x)

6. Pour Conv2D + AveragePooling ((2,2)) 2

Si vous avez Conv2D et Average Pooling comme ci-dessous, je voudrais résoudre ce problème à une simple convolution.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

Cela peut être calculé comme suit: Vous pouvez voir que le résultat de la multiplication de Conv2D et AveragePooling est C5, qui est 6x6 et égal au résultat de E3, qui est multiplié par foulées2 deux fois.

python


import numpy as np
import scipy.signal as sp
import skimage.measure

A1 = np.random.randint(0,2,(3,3))
A2 = np.random.randint(0,2,(3,3))
A3 = np.random.randint(0,2,(3,3))
A4 = np.repeat(A2, 2, axis=0)
A4 = np.repeat(A4, 2, axis=1)
A5 = np.repeat(A3, 2, axis=0)
A5 = np.repeat(A5, 2, axis=1)
B1 = np.random.randint(-4,5,(26,26))*4
C1 = sp.correlate2d(B1, A1, mode='valid')
C2 = skimage.measure.block_reduce(C1, (2,2), np.average)
C3 = sp.correlate2d(C2, A2, mode='valid')
C4 = skimage.measure.block_reduce(C3, (2,2), np.average)
C5 = sp.correlate2d(C4, A3, mode='valid')
D1 = sp.convolve2d(A1, A4, mode='full')
E1 = sp.correlate2d(B1, D1, mode='valid')/4
E2 = E1[::2,::2]
E3 = sp.correlate2d(E2, A5, mode='valid')/4
E3 = E3[::2,::2]

print('A1=\n', A1)
print('A2=\n', A2)
print('A3=\n', A3)
print('A4=\n', A4)
print('A5=\n', A5)
print('C5=\n', C5)
print('E3=\n', E3)
--------------------------
A1=
 [[1 1 0]
 [1 0 0]
 [0 0 0]]
A2=
 [[0 0 0]
 [0 0 0]
 [1 1 0]]
A3=
 [[1 0 1]
 [0 0 1]
 [1 0 1]]
A4=
 [[0 0 0 0 0 0]
 [0 0 0 0 0 0]
 [0 0 0 0 0 0]
 [0 0 0 0 0 0]
 [1 1 1 1 0 0]
 [1 1 1 1 0 0]]
A5=
 [[1 1 0 0 1 1]
 [1 1 0 0 1 1]
 [0 0 0 0 1 1]
 [0 0 0 0 1 1]
 [1 1 0 0 1 1]
 [1 1 0 0 1 1]]
C5=
 [[ -6.75 -15.5  -45.5 ]
 [-32.5    1.25   9.75]
 [-15.5    5.75 -28.  ]]
E3=
 [[ -6.75 -15.5  -45.5 ]
 [-32.5    1.25   9.75]
 [-15.5    5.75 -28.  ]]

Autrement dit, le modèle composé de Conv2D et de regroupement moyen ci-dessous peut être organisé comme suit.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)

En passant, ce qui précède est la limite à organiser comme une expression équivalente. Cependant, l'équation ci-dessus peut être arrangée un peu plus si la valeur approximative est autorisée et la convolution est décomposée par la convolution inverse comme indiqué en 3. Si vous trouvez le filtre de convolution 5x5 par la convolution inverse du filtre de lissage 2x2

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x) # AveragePooling2D((2,2))
x = Conv2D(1, (6, 6), padding="valid")(x)
x = Conv2D(1, (1, 1), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (12, 12), padding="valid", strides=2)(x)
x = Conv2D(1, (1, 1), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (4, 4), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = AveragePooling2D((4,4))(x)

Ici, le filtre de convolution 5x5 est un filtre de convolution obtenu par convolution inverse d'un filtre de lissage 2x2 à partir d'un filtre de convolution 6x6 dans lequel un filtre de convolution 3x3 est rempli de la même valeur. Le filtre de convolution 9x9 est un filtre de convolution obtenu par convolution inverse d'un filtre de lissage 4x4 à partir d'un filtre de convolution 12x12 dans lequel un filtre de convolution 3x3 est quatre fois rempli de la même valeur. Autrement dit, la convolution est résumée comme suit.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (18, 18), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (15, 15), padding="valid")(x)
x = AveragePooling2D((4,4))(x)

7. Lorsque Conv2D + foulées = 2

Considérez un modèle qui contient la foulée suivante. Ceci est proche dans le sens où la convolution 3x3 est effectuée 3 fois et la taille de l'image est divisée par deux comme en 6. De plus, le nombre de paramètres utilisés dans le calcul est le même en termes de nombre de poids car il y a trois filtres 3x3.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

Si vous permettez à la convolution d'être démontée comme en 3.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (12, 12), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (4, 4), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(28, 28, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = AveragePooling2D((4,4))(x)

On constate que la taille du filtre à convolution est légèrement inférieure à celle de 6. Si vous souhaitez que la taille du filtre de convolution soit la même que pour Average Pooling 2D, je pense qu'il est nécessaire d'augmenter la taille du filtre de 1 lors de l'utilisation de foulées.

python


x = Input(shape=(28, 28, 1))
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

8. Pour les modèles à plusieurs étages

--Pour AveragePooling2D

python


x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = AveragePooling2D((2,2))(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

Si le rabattement est permis par la convolution inverse du filtre de lissage,

python


x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid")(x)
x = Conv2D(1, (1, 1), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (10, 10), padding="valid", strides=2)(x)
x = Conv2D(1, (10, 10), padding="valid", strides=2)(x)
x = Conv2D(1, (12, 12), padding="valid", strides=2)(x)
x = Conv2D(1, (1, 1), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (12, 12), padding="valid")(x)
x = Conv2D(1, (1, 1), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (18, 18), padding="valid", strides=2)(x)
x = Conv2D(1, (24, 24), padding="valid", strides=2)(x)
x = Conv2D(1, (1, 1), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (17, 17), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (24, 24), padding="valid")(x)
x = Conv2D(1, (1, 1), padding="valid", strides=8)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (17, 17), padding="valid")(x)
x = Conv2D(1, (48, 48), padding="valid", strides=2)(x)
x = Conv2D(1, (1, 1), padding="valid", strides=8)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (17, 17), padding="valid")(x)
x = Conv2D(1, (33, 33), padding="valid")(x)
x = Conv2D(1, (16, 16), padding="valid", strides=16)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (63, 63), padding="valid")(x)
x = AveragePooling2D((16,16))(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (78, 78), padding="valid", strides=16)(x)

On peut voir que la taille de la convolution de chaque couche augmente comme ** (3 → 5 → 9 → 17 → 33) ** à chaque fois qu'elle passe par Average Pooling 2D. En bref, la taille des plis de chaque couche double.

--Lorsque Conv2D + foulées = 2

python


x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

Si le rabattement est permis par la convolution inverse du filtre de lissage,

python


x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid")(x)
x = Conv2D(1, (1, 1), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
x = Conv2D(1, (6, 6), padding="valid", strides=2)(x)
x = Conv2D(1, (12, 12), padding="valid", strides=2)(x)
x = Conv2D(1, (1, 1), padding="valid", strides=2)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (12, 12), padding="valid")(x)
x = Conv2D(1, (1, 1), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (10, 10), padding="valid", strides=2)(x)
x = Conv2D(1, (24, 24), padding="valid", strides=2)(x)
x = Conv2D(1, (1, 1), padding="valid", strides=4)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (2, 2), padding="valid", strides=2)(x)
x = Conv2D(1, (24, 24), padding="valid")(x)
x = Conv2D(1, (1, 1), padding="valid", strides=8)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (48, 48), padding="valid", strides=2)(x)
x = Conv2D(1, (1, 1), padding="valid", strides=8)(x)
-----------------------------------------
x = Input(shape=(224, 224, 1))
x = Conv2D(1, (2, 2), padding="valid")(x)
x = Conv2D(1, (3, 3), padding="valid")(x)
x = Conv2D(1, (5, 5), padding="valid")(x)
x = Conv2D(1, (9, 9), padding="valid")(x)
x = Conv2D(1, (33, 33), padding="valid")(x)
x = Conv2D(1, (16, 16), padding="valid", strides=16)(x)
-----------------------------------------

On peut voir que la taille de la convolution de chaque couche augmente comme ** (2 → 3 → 5 → 9 → 33) ** à chaque fois que les foulées = 2. Par rapport à AveragePooling, seule la taille de pliage de la couche finale semble déséquilibrée.

python


x = Input(shape=(224, 224, 1))
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid", strides=2)(x)
x = Conv2D(1, (2, 2), padding="valid")(x)

Si la taille de la convolution finale est 2x2, la taille de la convolution sera ** (2 → 3 → 5 → 9 → 17) **. Cependant, la convolution 2x2 ne contribue pas à accélérer, il est donc inutile de l'utiliser.

python


x = Input(shape=(224, 224, 1))
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (4, 4), padding="valid", strides=2)(x)
x = Conv2D(1, (3, 3), padding="valid")(x)

De plus, si vous utilisez la convolution 4x4 comme décrit ci-dessus, vous pouvez reproduire ** (3 → 5 → 9 → 17 → 33) ** similaire à la mise en commun moyenne. Cela suggère que la taille du filtre est réduite de 1 à Conv2D + foulées = 2 par la quantité que le filtre de lissage 2x2 de la mise en commun moyenne est calculé pour la convolution inverse. Considérant un filtre 4x4 avec Conv2D + foulées = 2, il y a un inconvénient que le nombre de paramètres est plus grand que la mise en commun moyenne. (À l'inverse, cela peut être un mérite) Se demander s'il est possible de générer un filtre de convolution qui extrait des caractéristiques de toute taille à l'aide de filtres de convolution de différentes tailles nous rappelle le problème de la mesure de poids continus avec un nombre fini de poids.

Résumé:

Nous avons pris en compte la taille du filtre de convolution lors de l'utilisation des foulées Conv2D et du regroupement moyen. Les deux sont des processus qui divisent par deux la taille de l'image, mais il a été suggéré que la taille du filtre de convolution est inférieure à la mise en commun moyenne lors de l'utilisation de foulées Conv2D. Cependant, il n'est possible de s'organiser de cette manière que lorsqu'il n'y a pas de fonction d'activation relu et que la convolution peut être décomposée en deux par convolution inverse, il faut donc noter qu'une telle disposition n'est pas possible dans un modèle général. est.

Recommended Posts

Foulées pliées et mise en commun moyenne
Introduction au Deep Learning ~ Pliage et mise en commun ~
Grad-CAM et convolution dilatée
Graphique à barres de bougie et tracé de la moyenne mobile