[PYTHON] [Mémo d'apprentissage] Deep Learning fait de zéro [Chapitre 5]

Apprendre en profondeur à partir de zéro Chapitre 5

Il semble que les chapitres 5 à 7 sont importants dans ce livre, Décrivez avec emphase

Deux façons de comprendre la méthode de rétropropagation ・ Compréhension par "formule mathématique" ・ Compréhension par "graphe de calcul"

Ce livre explique ce dernier

Graphique de calcul

Graphique de calcul: représentation graphique du processus de calcul Graphique: graphique en tant que structure de données, représenté par plusieurs nœuds et arêtes La figure ci-dessous est un graphique de calcul lorsque vous achetez une pomme de 100 yens par pièce et que la taxe à la consommation est de 10%. Propagation avant: Propagation du point de départ au point final du graphe de calcul Propagation arrière: propagation inverse de la propagation avant image.png

Fonctionnalités du graphe de calcul: Propagation de "calculs locaux" pour obtenir le résultat final Dans la figure ci-dessus, seules des pommes ont été utilisées, mais cela devient compliqué lorsqu'il y a d'autres achats. Peu importe ce que fait le tout, vous ne pouvez obtenir les résultats suivants qu'à partir des informations qui vous concernent (apple dans l'exemple).

Avantages du graphe de calcul: la "différenciation" peut être calculée efficacement par propagation dans la direction opposée

Rétropropagation du graphique calculé

Il faut du temps pour calculer le gradient de la fonction de perte du paramètre de poids du réseau de neurones par différenciation numérique. Par conséquent, la méthode de propagation de retour d'erreur est exécutée. Méthode de propagation d'erreur: une méthode pour calculer efficacement le gradient des paramètres de poids

Rétropropagation en supposant qu'il y a un calcul y = f (x) image.png

Couche d'addition

z=x+La différenciation de y est\\
\frac{\partial z}{\partial x} = 1 \\
\frac{\partial z}{\partial y} = 1 

Si cela apparaît dans le graphique de calcul image.png

Dans du code

class AddLayer:
    #constructeur
    def __init__(self):
        self.x = None
        self.y = None
    
    def forward(self, x, y):
        self.x = x
        self.y = y
        out = x+y
        
        return out

    def backward(self, dout):
        dx = dout * 1
        dy = dout * 1
        
        return dx, dy

Multiplier la couche

z=x*La différenciation de y est\\
\frac{\partial z}{\partial x} = y \\
\frac{\partial z}{\partial y} = x 

Si cela apparaît dans le graphique de calcul image.png

Dans du code

class MulLayer:
    #constructeur
    # self =Java ceci
    def __init__(self):
        self.x = None
        self.y = None
    
    def forward(self, x, y):
        self.x = x
        self.y = y
        out = x*y
        
        return out

    def backward(self, dout):
        dx = dout * self.y
        dy = dout * self.x


        return dx, dy

Couche Relu

y = \left\{
\begin{array}{ll}
x & (x \geq 0) \\
0 & (x \lt 0)
\end{array}
\right.
\frac{\partial y}{\partial x} = \left\{
\begin{array}{ll}
1 & (x \geq 0) \\
0 & (x \lt 0)
\end{array}
\right.

image.png

Dans du code

#Couche ReLU
class Relu:
    def __init__(self):
        self.mask = None
    
    def forward(self, x):
        self.mask = (x<=0)
        out = x.copy()
        out[self.mask] = 0

        return out

    def backward(self, dout):
        dout[self.mask] = 0
        dx = dout
    
        return dx

Couche sigmoïde

fonction sigmoïde y=\frac{1}{1+\exp(-x)} \\

image.png

Supplément graphique de calcul


\begin{align}

f(x)&=-x \\
\Rightarrow f'(x)&=-1\\
f(x)&=\exp(x) \\
\Rightarrow f'(x)&=\exp(x)\\
f(x)&=x+1 \\
\Rightarrow f'(x)&=1\\
f(x)&=1/x \\
\Rightarrow f'(x)&=-1/x^2=-f(x)^2\\

\end{align}
\begin{align}

\frac{\partial L}{\partial y}y^2\exp(-x) &=\frac{\partial L}{\partial y}y\frac{\exp(-x)}{1+\exp(-x)} \\
&=\frac{\partial L}{\partial y}y(1-y) \\

\end{align}

Dans du code

#Couche sigmoïde
class Sigmoid:
    def __init__(self):
        self.out = None
        
    def forward(self, x):
        out = 1 / (1 + np.exp(-x))
        self.out = out
        
        return out

    def backward(self, dout):
        dx = dout * (1.0 - self.out) * self.out
        
        return dx

Couche affine

image.png

Dans du code

#Version par lots Couche affine
class Affine:
    def __init__(self, W, b):
        self.W = W
        self.b = b
        self.x = None
        self.dW = None
        self.db = None
    
    def forward(self, x):
        self.x = x
        out = np.dot(x, self.W) + self.b
        
        return out

    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.dot(dout, axis=0)
        
        return dx

Preuve (cas simple de N = 1)


\begin{align}
\frac{\partial L}{\partial Y} \cdot W^T&=

\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1} & 
\frac{\partial Y}{\partial y_2}& 
\frac{\partial Y}{\partial y_2}
\end{matrix}\bigr)
\Biggl(
\begin{matrix}w_{11} & w_{21} \\
w_{12} & w_{22} \\ 
w_{13} & w_{23} 
\end{matrix}\Biggr)\\

&=\bigl(\begin{matrix}
\frac{\partial L}{\partial y_1}w_{11}+
\frac{\partial L}{\partial y_2}w_{12}+
\frac{\partial L}{\partial y_3}w_{13} &
\frac{\partial L}{\partial y_1}w_{21}+
\frac{\partial L}{\partial y_2}w_{22}+
\frac{\partial L}{\partial y_3}w_{23}
\end{matrix}\bigr)\\
&=\bigl(\begin{matrix}
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial x_1}
+\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial x_1}
+\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial x_1} &
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial x_2}
+\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial x_2}
+\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial x_2}
\end{matrix}\bigr)\\
&=\bigl(
\begin{matrix}
\frac{\partial L}{\partial Y}\frac{\partial Y}{\partial x_1} &
\frac{\partial L}{\partial Y}\frac{\partial Y}{\partial x_2} 
\end{matrix}\bigr)\\
&=\frac{\partial L}{\partial X}\\


X^T \cdot \frac{\partial L}{\partial Y} 
&=\Bigl(\begin{matrix}
x_1\\
x_2
\end{matrix}\Bigr)
\cdot
\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1} &
\frac{\partial L}{\partial y_2} &
\frac{\partial L}{\partial y_3}
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
x_1\frac{\partial L}{\partial y_1} &
x_1\frac{\partial L}{\partial y_2} &
x_1\frac{\partial L}{\partial y_3}\\
x_2\frac{\partial L}{\partial y_1} &
x_2\frac{\partial L}{\partial y_2} &
x_2\frac{\partial L}{\partial y_3}
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1}x_1 &
\frac{\partial L}{\partial y_2}x_1 &
\frac{\partial L}{\partial y_3}x_1\\
\frac{\partial L}{\partial y_1}x_2 &
\frac{\partial L}{\partial y_2}x_2 &
\frac{\partial L}{\partial y_3}x_2
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial w_{11}} &
\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial w_{12}} &
\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial w_{13}}\\
\frac{\partial L}{\partial y_1}\frac{\partial y_1}{\partial w_{21}} &
\frac{\partial L}{\partial y_2}\frac{\partial y_2}{\partial w_{22}} &
\frac{\partial L}{\partial y_3}\frac{\partial y_3}{\partial w_{23}}
\end{matrix}\bigr)\\
&=
\bigr(\begin{matrix}
\frac{\partial L}{\partial w_{11}} &
\frac{\partial L}{\partial w_{12}} &
\frac{\partial L}{\partial w_{13}}\\
\frac{\partial L}{\partial w_{21}} &
\frac{\partial L}{\partial w_{22}} &
\frac{\partial L}{\partial w_{23}}
\end{matrix}\bigr)\\
&=\frac{\partial L}{\partial W}\\


Supplément de calcul\\
Y&=X \cdot W+B\\
y_i&=x_1w_{1i}+x_2w_{2i}+b_i\\
Exemple)\frac{\partial y_3}{\partial w_{23}}&=x_2

\end{align}


Couche Softmax-with-Loss

\begin{align}

&(y_1, y_2, y_3):Sortie de couche Softmax\\
&(t_1, t_2, t_3):Données des enseignants\\
\\
&En d'autres termes(y_1-t_1, y_2-t_2, y_3-t_3)Est\\
&Différence entre la sortie de la couche Softmax et l'étiquette de l'enseignant\\

\end{align}

image.png

# SoftmaxWithLoss
class SofmaxWithLoss:
    def __init(self):
        self.loss = None
        self.y = None
        self.t = None
    
    def forward(self, x, t):
        self.t = t
        self.y = sofmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        
        return self.loss

    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        dx - (self.y - self.t) / bath_size
        
        return dx

Implémentation de la méthode de propagation des erreurs

Implémentation d'un réseau de neurones prenant en charge la méthode de propagation de retour d'erreur

Un réseau de neurones peut être créé en ajoutant simplement les couches nécessaires aux couches ci-dessus comme un bloc lego. Ajoutez quelques commentaires pendant que la source est active

# coding: utf-8
import sys, os
sys.path.append(os.pardir)  #Paramètres d'importation des fichiers dans le répertoire parent
import numpy as np
from common.layers import *
from common.gradient import numerical_gradient
from collections import OrderedDict


class TwoLayerNet:

    #-------------------------------------------------
    # __init__:Initialiser
    #     @self
    #     @input_size:Nombre de neurones dans la couche d'entrée
    #     @hidden_size:Nombre de neurones de couche cachée
    #     @output_size:Nombre de neurones dans la couche de sortie
    #     @weight_init_std:Échelle de distribution gaussienne à l'initialisation du poids
    #-------------------------------------------------
    def __init__(self, input_size, hidden_size, output_size, weight_init_std = 0.01):


        # params:Variable de type dictionnaire contenant les paramètres du réseau neuronal
        #Initialisation du poids
        self.params = {}
        self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
        self.params['b1'] = np.zeros(hidden_size)
        self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size) 
        self.params['b2'] = np.zeros(output_size)

        # layer:Variables de type dictionnaire "ordonnées" qui contiennent des couches du réseau neuronal
        #Génération de couches:Le but est de sauvegarder dans l'ordre
        #En conséquence, il est acceptable d'appeler simplement la couche à partir de l'inverse pour la propagation directe et la propagation inverse.
        self.layers = OrderedDict()
        self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
        self.layers['Relu1'] = Relu()
        self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])

        #La dernière couche du réseau neuronal:Ici SoftmaxWithLoss couche
        self.lastLayer = SoftmaxWithLoss()
        

    #-------------------------------------------------
    # predict:Effectuer la reconnaissance (inférence)
    #     @self
    #     @x:Données d'image (données d'entrée)
    #-------------------------------------------------
    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)
        
        return x

        
    #-------------------------------------------------
    # loss:Trouvez la fonction de perte
    #     @self
    #     @x:Données d'image (données d'entrée)
    #     @t:Données des enseignants
    #-------------------------------------------------
    def loss(self, x, t):
        y = self.predict(x)
        return self.lastLayer.forward(y, t)
    

    #-------------------------------------------------
    # accuracy:Trouver la précision de la reconnaissance
    #     @self
    #     @x:Données d'image (données d'entrée)
    #     @t:Données des enseignants
    #-------------------------------------------------
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        if t.ndim != 1 : t = np.argmax(t, axis=1)
        
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy
        

    #-------------------------------------------------
    # numerical_gradient:Trouvez le gradient pour le paramètre de poids par différenciation numérique (comme jusqu'au chapitre 4)
    #     @self
    #     @x:Données d'image (données d'entrée)
    #     @t:Données des enseignants
    #-------------------------------------------------
    def numerical_gradient(self, x, t):
        loss_W = lambda W: self.loss(x, t)
        
        grads = {}
        grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
        
        return grads


    #-------------------------------------------------
    # gradient:Trouvez le gradient du paramètre de poids par la méthode de rétropropagation
    #     @self
    #     @x:Données d'image (données d'entrée)
    #     @t:Données des enseignants
    #-------------------------------------------------
    def gradient(self, x, t):

        #point:Il déplace en fait la propagation implémentée sous forme de couche

        # forward:Propagation vers l'avant
        self.loss(x, t)

        # backward:Rétropropagation
        dout = 1
        dout = self.lastLayer.backward(dout)
        
        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)

        #Réglage
        grads = {}
        grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].db
        grads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].db

        return grads

Confirmation du gradient de la méthode de propagation des erreurs

Cette source est simplement une source pour confirmer qu'il n'y a pratiquement aucune différence de gradient entre la propagation directe et la propagation arrière.

# coding: utf-8
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
from two_layer_net import TwoLayerNet

#Lire les données
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

x_batch = x_train[:3]
t_batch = t_train[:3]

grad_numerical = network.numerical_gradient(x_batch, t_batch)
grad_backprop = network.gradient(x_batch, t_batch)

for key in grad_numerical.keys():
    diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) )
    print(key + ":" + str(diff))

Résultat d'exécution dans mon environnement W1:2.61413510374e-13 > 2.610.1^-13 W2:1.04099504538e-12 > 1.040.1^-12 b1:9.1090807423e-13 > 9.10.1^-13 b2:1.20348173094e-10 > 1.20.1^-10

Apprentissage à l'aide de la méthode de propagation des erreurs

Cette source est essentiellement un mini-lot qui est entraîné de manière itérative (met à jour les poids et les biais).

# coding: utf-8
import sys, os
sys.path.append(os.pardir)

import numpy as np
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet

#Lire les données
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

train_loss_list = []
train_acc_list = []
test_acc_list = []

iter_per_epoch = max(train_size / batch_size, 1)

for i in range(iters_num):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    #Pente
    #grad = network.numerical_gradient(x_batch, t_batch)
    grad = network.gradient(x_batch, t_batch)
    
    #mise à jour
    for key in ('W1', 'b1', 'W2', 'b2'):
        network.params[key] -= learning_rate * grad[key]
    
    loss = network.loss(x_batch, t_batch)
    train_loss_list.append(loss)
    
    if i % iter_per_epoch == 0:
        train_acc = network.accuracy(x_train, t_train)
        test_acc = network.accuracy(x_test, t_test)
        train_acc_list.append(train_acc)
        test_acc_list.append(test_acc)
        print(train_acc, test_acc)

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 made from scratch Chapitre 3 Mémo
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 5 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'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 à partir de zéro Note: Chapitre 1
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)
Apprentissage profond / Apprentissage profond à partir de zéro 2-Essayez de déplacer GRU
"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
"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
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
Python vs Ruby "Deep Learning from scratch" Chapitre 3 Implémentation d'un réseau neuronal à 3 couches