[PYTHON] Deep learning / Deep learning made from scratch Chapitre 7 Mémo

1.Tout d'abord

Je lis un chef-d'œuvre, ** "Deep Learning from Zero" **. Cette fois, c'est un mémo du chapitre 7. Pour exécuter le code, téléchargez le code complet depuis Github et utilisez le notebook jupyter dans ch07.

2. Exemple de mise en œuvre

Je vais implémenter un exemple pour déplacer réellement ** Convolution, Pooling ** que j'ai étudié dans le manuel. Les données utilisées sont MNIST, et les poids du filtre de convolution sont appris (params.pkl enregistré dans le dossier ch07). Le code de convolution et de regroupement est importé de common / layer.py et utilisé.

Tout d'abord, exécutons-le.

import sys, os
sys.path.append(os.pardir)  #Paramètres d'importation des fichiers dans le répertoire parent
import numpy as np
import matplotlib.pyplot as plt
from simple_convnet import SimpleConvNet
from common.layers import *  #Importation de couches
from dataset.mnist import load_mnist

#Fonction d'affichage(FH, FW) 
def show(filters):    
    FH, FW = filters.shape  
    fig = plt.figure(figsize=(FH*0.1, FW*0.1))  #Spécification de la taille de l'écran
    plt.imshow(((filters)), cmap='gray')
    plt.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)  #Effacer l'échelle / l'étiquette de l'axe
    plt.show()

#Lire les données MNIST
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
x_train = x_train[5:6]  #Sélectionnez la 5ème donnée depuis le début

#Chargement des paramètres appris
network = SimpleConvNet()  #Instancier SimpleConvNet
network.load_params("params.pkl")  #Lire l'intégralité du paramètre
W1, b1 = network.params['W1'][:1], network.params['b1'][:1]  #Seulement le premier

#Génération de couches
conv = Convolution(W1, b1, stride=1, pad=0)  
pool = Pooling(pool_h=2, pool_w=2, stride=2, pad=0)

#Propagation vers l'avant
out1 = conv.forward(x_train)  #Plier
out2 = pool.forward(out1)  #mise en commun

#afficher
print('input.shape = ',x_train.shape)
show(x_train.reshape(28, 28))
print('filter.shape = ', W1.shape)
show(W1.reshape(5, 5))
print('convolution.shape = ', out1.shape)
show(out1.reshape(24, 24))
print('pooling.shape = ', out2.shape)
show(out2.reshape(12, 12))

スクリーンショット 2020-05-13 09.31.29.png

L'image MNIST (1, 1, 28, 28) est contournée avec filter5 * 5, padding = 0, stride = 1, et les données de (1, 1, 24, 24) sont en outre filtrées2 * 2, padding = 0, La mise en commun se fait avec stride = 2 (1, 1, 12, 12) et les données sont obtenues.

Regardons maintenant les points clés du code.

3.Convolution

# ------------- from common_layers.py -------------
    def forward(self, x):
        FN, C, FH, FW = self.W.shape
        N, C, H, W = x.shape
        out_h = 1 + int((H + 2*self.pad - FH) / self.stride)
        out_w = 1 + int((W + 2*self.pad - FW) / self.stride)

        #① Convertissez les données d'image en données matricielles avec im2col
        col = im2col(x, FH, FW, self.stride, self.pad)

        #② Remodelez le filtre et développez-le dans un tableau à deux dimensions
        col_W = self.W.reshape(FN, -1).T

        #③ Calculez la sortie par calcul matriciel
        out = np.dot(col, col_W) + self.b

        #④ Ajustez la forme de la sortie
        out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)

        self.x = x
        self.col = col
        self.col_W = col_W
        return out

Un diagramme montrant comment une image en 4 dimensions (taille de lot, nombre de canaux, hauteur d'image, largeur d'image) est traitée par l'opération de convolution ressemble à ceci. スクリーンショット 2020-05-10 15.44.23.png Jetons un œil à la fonction ** ① im2col ** la plus importante.

4.im2col

# ------------- from common_layers.py -------------
def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    N, C, H, W = input_data.shape
    out_h = (H + 2*pad - filter_h)//stride + 1
    out_w = (W + 2*pad - filter_w)//stride + 1
    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
    col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))

    # 24*24 filtres 5*Trancher 5 fois(stride=Quand 1)
    for y in range(filter_h):  #5 boucles
        y_max = y + stride*out_h  # y_max = y + 24
        for x in range(filter_w):  #5 boucles
            x_max = x + stride*out_w  # x_max = x + 24

            #y à y+Jusqu'à 24,x à x+Jusqu'à 24、スライシング
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

    col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
    return col

y: y_max: stride, x: x_max: stride signifie que la plage de y à y_max est spécifiée pour chaque foulée, et la plage de x à x_max est spécifiée pour chaque foulée.

Avec y_max = y + 24, x_max = x + 24, stride = 1, chaque boucle for est une double boucle 5 fois, vous finissez donc par trancher 5 * 5 fois avec un ** filtre 24 * 24 **.

D'un autre côté, compte tenu de ce que vous avez appris dans le manuel, vous devriez être capable de trancher 24 * 24 fois avec un ** filtre 5 * 5 **. Si vous le transformez en code, il ressemblera à ceci.

    # 5*24 avec 5 filtres*Trancher 24 fois(stride=Quand 1)
    for y in range(0, out_h, stride):    
        for x in range(0, out_w, stride):  
            col[:, :, y, x, :, :] = img[:, :, y:y+filter_h, x:x+filter_w]

En effet, le nombre total d'éléments traités par le ** filtre 24 * 24 tranchant 5 * 5 fois ** et le filtre ** 5 * 5 découpant 24 * 24 fois ** est le même. Si les résultats sont les mêmes, quel est le meilleur? Bien sûr, ** l'ancien **. La raison est que le nombre de boucles for, qui prend beaucoup de temps de traitement, est extrêmement faible.

Si vous montrez les deux méthodes dans la figure, cela ressemble à ceci スクリーンショット 2020-05-11 21.47.25.png

5. Comparaison de deux im2cols

Vérifions si les résultats des deux sont vraiment les mêmes. Exécutez le code suivant pour visualiser le ʻim2cold'origine et la fonctionmy_im2col` qui tranche ** 24 * 24 fois avec un filtre ** 5 * 5, y compris les données en cours de calcul.

import sys, os
sys.path.append(os.pardir)  #Paramètres d'importation des fichiers dans le répertoire parent
import numpy as np
from dataset.mnist import load_mnist
import matplotlib.pyplot as plt

#Fonction d'affichage des données( x =Largeur d'affichage, y=Hauteur d'affichage, nx =Le nombre de colonnes)
def show(filters, x, y, nx, margin=1, scale=10):
    FN, C, FH, FW = filters.shape
    ny = int(np.ceil(FN / nx))    
    fig = plt.figure(figsize=(x, y))
    fig.subplots_adjust(left=0, right=1.3, bottom=0, top=1.3, hspace=0.05, wspace=0.05)
    
    for i in range(FN):
        ax = fig.add_subplot(ny, nx, i+1, xticks=[], yticks=[])
        ax.imshow(filters[i, 0], cmap='gray', interpolation='nearest') 
    plt.show()

def my_im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    N, C, H, W = input_data.shape
    out_h = (H + 2*pad - filter_h)//stride + 1  #Hauteur de sortie
    out_w = (W + 2*pad - filter_w)//stride + 1  #Largeur de sortie
    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')  #Remplissage d'image
    col = np.zeros((N, C, out_h, out_w, filter_h, filter_w))  #préparation de la matrice de calcul col
    
    # 5*24 avec 5 filtres*Trancher 24 fois(stride=Quand 1)
    for y in range(0, out_h, stride):    
        for x in range(0, out_w, stride):  
            col[:, :, y, x, :, :] = img[:, :, y:y+filter_h, x:x+filter_w]
            
    # check1
    print('col.shape after slicing = ', col.shape)
    show(col.reshape(576, 1, 5, 5), x = 3.5, y = 3.5, nx = 24)
    
    #Transposer et remodeler
    col = col.transpose(0, 2, 3, 1, 4, 5).reshape(N*out_h*out_w, -1)
    
    # check2
    print('col.shape after transpose & reshape = ', col.shape)
    show(col.reshape(1, 1, 25, 576), x = 18, y =3, nx=1)
    
    return col

def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    N, C, H, W = input_data.shape
    out_h = (H + 2*pad - filter_h)//stride + 1  #Hauteur de sortie
    out_w = (W + 2*pad - filter_w)//stride + 1  #Largeur de sortie
    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')  #Remplissage d'image
    col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))  #préparation de la matrice de calcul col

    # 24*24 filtres 5*Trancher 5 fois(stride=Quand 1)
    for y in range(filter_h):
        y_max = y + stride*out_h
        for x in range(filter_w):
            x_max = x + stride*out_w
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
            
    # check1
    print('col.shape after slicing = ', col.shape)
    show(col.reshape(25, 1, 24, 24), x = 3.5, y = 3.5, nx = 5)
            
    #Transposer et remodeler
    col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
    
    # check2
    print('col.shape after transpose & reshape = ', col.shape)
    show(col.reshape(1, 1, 25, 576), x = 18, y =3, nx=1)
    
    return col

#Lire les données MNIST
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=False)
x_train = x_train[5:6]  #Sélectionnez la 5ème donnée depuis le début

out1 = my_im2col(x_train, 5, 5)
out2 = im2col(x_train, 5, 5)
print('all elements are same = ', (out1 == out2).all()) #Si tous les éléments sont égaux

スクリーンショット 2020-05-10 19.20.10.png スクリーンショット 2020-05-10 19.20.24.png La première moitié est le résultat de my_im2col et la seconde moitié est le résultat de ʻim2col`. Dans les deux cas, col.shape après transpose & reshape est en fait de 576 lignes x 25 colonnes, ce qui est verticalement long, mais cela n'a pas l'air bien, donc l'affichage est horizontalement long avec 25 lignes x 576 colonnes en permutant les lignes et les colonnes. Je vais. Et si vous regardez les deux images, elles ont certainement le même motif.

Dans la dernière ligne de la sortie, ** True ** lors de la comparaison de tous les éléments du tableau multidimensionnel **, nous pouvons donc voir que my_im2col et ʻim2col` donnent exactement le même résultat. En général, si stride = 1, il vous suffit de ** filter_h * filter_w slice **. C'est une excellente technique, n'est-ce pas?

Voici un exemple simple et intuitif des raisons pour lesquelles vous pouvez faire cela. スクリーンショット 2020-05-13 09.02.10.png

6.Pooling

# ------------- from common_layers.py -------------
    def forward(self, x):
        N, C, H, W = x.shape
        out_h = int(1 + (H - self.pool_h) / self.stride)
        out_w = int(1 + (W - self.pool_w) / self.stride)

        col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
        col = col.reshape(-1, self.pool_h*self.pool_w)

        arg_max = np.argmax(col, axis=1)
        out = np.max(col, axis=1)
        out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)

        self.x = x
        self.arg_max = arg_max
        return out

Cela ressemble à ceci lorsque l'image 4D (taille du lot, nombre de canaux, hauteur de l'image, largeur de l'image) est traitée par Pooling.

スクリーンショット 2020-05-10 20.24.24.png Semblable à la convolution, la fonction im2col est utilisée pour obtenir la matrice et la traiter avec pool_h, pool_w, stride et pad comme arguments.

Recommended Posts

[Mémo d'apprentissage] Le Deep Learning fait de zéro [Chapitre 7]
Deep learning / Deep learning made from scratch Chapitre 6 Mémo
[Mémo d'apprentissage] Deep Learning fait de zéro [Chapitre 5]
[Mémo d'apprentissage] Le Deep Learning fait de zéro [Chapitre 6]
Deep learning / Deep learning made from scratch Chapitre 7 Mémo
[Mémo d'apprentissage] Deep Learning fait de zéro [~ Chapitre 4]
Deep Learning from scratch Chapter 2 Perceptron (lecture du mémo)
Deep learning / Deep learning from scratch 2 Chapitre 4 Mémo
Deep learning / Deep learning made from scratch Chapitre 3 Mémo
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 7 Mémo
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 8 Mémo
Deep learning / Deep learning made from scratch Chapitre 5 Mémo
Deep learning / Deep learning made from scratch Chapitre 4 Mémo
Deep learning / Deep learning from scratch 2 Chapitre 3 Mémo
Mémo d'apprentissage profond créé à partir de zéro
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 6 Mémo
Apprentissage profond à partir de zéro
Mémo d'auto-apprentissage "Deep Learning from scratch" (partie 12) Deep learning
Mémo d'auto-apprentissage "Deep Learning from scratch" (glossaire illisible)
Apprentissage profond à partir de zéro 1 à 3 chapitres
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 9) Classe MultiLayerNet
Deep Learning from scratch ① Chapitre 6 "Techniques liées à l'apprentissage"
[Mémo d'apprentissage] Apprentissage profond à partir de zéro ~ Mise en œuvre de l'abandon ~
Mémo d'auto-apprentissage «Deep Learning from scratch» (10) Classe MultiLayerNet
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 11) CNN
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 19) Augmentation des données
Application de Deep Learning 2 à partir de zéro Filtre anti-spam
Apprentissage profond à partir de zéro (calcul des coûts)
Un amateur a trébuché dans le Deep Learning ❷ fait à partir de zéro Note: Chapitre 5
Un amateur a trébuché dans le Deep Learning ❷ fait à partir de zéro Note: Chapitre 2
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 3
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 7
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 5
Un amateur a trébuché dans le Deep Learning ❷ fait de zéro Note: Chapitre 1
Un amateur a trébuché dans le Deep Learning ❷ fait à partir de zéro Note: Chapitre 4
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 18) One! Miaou! Grad-CAM!
Un amateur a trébuché dans le Deep Learning à partir de zéro.
Un amateur a trébuché dans le Deep Learning à partir de zéro Note: Chapitre 2
Mémo d'auto-apprentissage "Deep Learning from scratch" (n ° 15) Tutoriel pour débutants TensorFlow
Apprentissage profond à partir de zéro (propagation vers l'avant)
"Deep Learning from scratch" avec Haskell (inachevé)
[Windows 10] Construction de l'environnement "Deep Learning from scratch"
Enregistrement d'apprentissage de la lecture "Deep Learning from scratch"
[Deep Learning from scratch] À propos de l'optimisation des hyper paramètres
Écrivez vos impressions sur l'édition du framework Deep Learning 3 créée à partir de zéro
Mémo d'auto-apprentissage "Deep Learning from scratch" (n ° 13) Essayez d'utiliser Google Colaboratory
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 10-2) Valeur initiale du poids
Chapitre 3 Réseau de neurones Ne découpez que les bons points de Deeplearning à partir de zéro
Django memo n ° 1 à partir de zéro
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 14) Exécutez le programme du chapitre 4 sur Google Colaboratory
Mémo d'auto-apprentissage "Deep Learning from scratch" (partie 8) J'ai dessiné le graphique du chapitre 6 avec matplotlib
Chapitre 2 Implémentation de Perceptron Ne découpez que les bons points de Deeplearning à partir de zéro
GitHub du bon livre "Deep Learning from scratch"
Résumé Python vs Ruby "Deep Learning from scratch"
Python vs Ruby «Deep Learning from scratch» Chapitre 2 Circuit logique par Perceptron
Python vs Ruby "Deep Learning from scratch" Chapitre 4 Implémentation de la fonction de perte
Chapitre 1 Introduction à Python Découpez uniquement les bons points de Deeplearning à partir de zéro
[Deep Learning from scratch] J'ai implémenté la couche Affine