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

1.Tout d'abord

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

2. Mise en œuvre de la propagation des erreurs (pas de génération de couche)

À la fin du chapitre 5, il y a un code (twoLayerNet.py & train_neuralnet.py) qui génère une couche et effectue la propagation des erreurs, mais avant cela, le code qui génère une couche et effectue la propagation des erreurs se trouve déjà dans le chapitre 4. Il y a (aussi twoLayerNet.py & train_neuralnet.py), donc je vais l'essayer à partir de là.

Comme nous l'avons fait au chapitre 4, pour améliorer la visibilité, si nous le rassemblons dans un code, c'est presque le même que la dernière fois, seul le --- calcul du gradient --- est différent. Pour le moment, je vais le proposer.

import sys, os
sys.path.append(os.pardir)  #Paramètres d'importation des fichiers dans le répertoire parent
from common.functions import *  #fonction dans le dossier commun.Configuré pour utiliser toutes les fonctions de py
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist

class TwoLayerNet:
    #Initialisation des paramètres
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):        
        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)

    #Propagation vers l'avant
    def predict(self, x):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
    
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)        
        return y
        
    #Calcul des pertes
    def loss(self, x, t):
        y = self.predict(x)
        
        return cross_entropy_error(y, t)

    #Calcul de la précision
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        t = np.argmax(t, axis=1)
        
        accuracy = np.sum(y == t) / float(x.shape[0])
        return accuracy

    # -----------------Calcul du gradient-------------------
    def gradient(self, x, t):
        W1, W2 = self.params['W1'], self.params['W2']
        b1, b2 = self.params['b1'], self.params['b2']
        grads = {}
        
        batch_num = x.shape[0]
        
        # forward
        a1 = np.dot(x, W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1, W2) + b2
        y = softmax(a2)
        
        # backward
        dy = (y - t) / batch_num
        grads['W2'] = np.dot(z1.T, dy)
        grads['b2'] = np.sum(dy, axis=0)
        
        dz1 = np.dot(dy, W2.T)
        da1 = sigmoid_grad(a1) * dz1
        grads['W1'] = np.dot(x.T, da1)
        grads['b1'] = np.sum(da1, axis=0)
        return grads
    # ------------------------------------------------

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

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

#Réglage initial
iters_num = 10000  #Nombre d'exécutions
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]
    
    #Calcul du gradient
    grad = network.gradient(x_batch, t_batch)
    
    #Mise à jour des paramètres
    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)

    #Affichage de la précision
    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 | " + str(train_acc) + ", " + str(test_acc))

#Dessiner un graphique
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()

スクリーンショット 2020-04-30 18.23.01.png Génial! Par rapport à la différenciation numérique, la vitesse d'exécution est aussi différente que le ciel et la terre. C'est super rapide! (En fait, la différenciation numérique est extrêmement lente)

Le contenu du code a déjà été expliqué dans le chapitre 4 Memo sauf pour --- Calcul du gradient ---, donc si vous voulez le voir, [Chapter 4 Memo](https://qiita.com/jun40vn/ Veuillez vous référer aux articles / be171ff7626d370072d1). Dans ce chapitre, seule la partie calcul du gradient est expliquée.

3. Calcul du gradient

Si vous expliquez une partie du code de calcul de gradient avec un graphique de calcul, cela ressemble à ceci. スクリーンショット 2020-05-02 19.34.48.png La somme de grades ['b2'] = np.sum (dy, axis = 0) est la correspondance avec le traitement par lots. Même ainsi, je suis impressionné par le fait que la rétropropagation des erreurs apparemment compliquée est remplacée par des opérations matricielles.

4. Dérivation de la formule de propagation des erreurs

Tout d'abord, dérivez $ \ frac {\ partial L} {\ partial W2} = z1 ^ {T} * dy $. En fonction du taux de chaîne スクリーンショット 2020-05-02 16.39.35.png

Ensuite, nous dérivons $ \ frac {\ partial y} {\ partial Z1} = \ frac {\ partial y} {\ partial a2} W2 ^ T $.

スクリーンショット 2020-05-02 18.45.24.png Le passage du monde de la différenciation numérique au monde de la rétropropagation des erreurs par opération matricielle est vraiment innovant, n'est-ce pas?

5. Génération de couches

Comme mentionné précédemment, vous pouvez obtenir une vitesse d'exécution pratique en écrivant la formule d'opération de la matrice directement dans le code pour la propagation directe et la propagation arrière d'erreur, mais l'écriture du code est un peu gênante, n'est-ce pas? Il existe donc un moyen de générer une couche et d'écrire le code plus simplement.

Pour générer une couche, importez d'abord le OrderedDict avec from collections import OrderedDict.

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, 
        # ................
        #Génération de couches
        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'])
        self.lastLayer = SoftmaxWithLoss()

Instanciez OrderedDict avec self.layers = OrderedDict () lors de la configuration initiale de la classe TwoLayerNet.

OrderedDict est mémorisé, y compris l'ordre, donc si vous enregistrez ʻAffine1, Relu1, ʻAffine2 et les noms et processus de couches dans le dictionnaire self.layers dans l'ordre, l'ordre sera également mémorisé.

Seule la couche finale a une formule de rétropropagation d'erreur différente, alors traitez-la séparément comme «self.lastLayer».

    #Propagation vers l'avant
    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)        
        return x
        
    #Calcul de la propagation / perte vers l'avant
    def loss(self, x, t):
        y = self.predict(x)
        return self.lastLayer.forward(y, t)

Ensuite, la propagation vers l'avant predire lit simplement les noms de couches un par un dans le dictionnaire self.layers et exécute le processus forward` à plusieurs reprises, donc peu importe le nombre de couches Tout ce dont vous avez besoin est du code.

Le calcul de propagation / perte vers l'avant perte '' se propage également vers l'avant et n'effectue que le traitement avant '' de la couche finale avec self.lastLayer.forward (y, t), donc même si le contenu de traitement de la couche finale change, cela Cela reste le code.

   #Calcul du gradient
   def gradient(self, x, t):
        #Calcul de la propagation / perte vers l'avant
        self.loss(x, t)

        #Erreur de propagation de retour
        dout = 1
        dout = self.lastLayer.backward(dout)  #Remplacez le résultat arrière de la dernière couche par dout
        layers = list(self.layers.values())  #Dictionnaire self.Lire le nom du calque à partir des calques
        layers.reverse()  #Inverser l'ordre des noms de calques
        for layer in layers:  #Lire le nom du calque inversé
            dout = layer.backward(dout)  #Exécuter en arrière du nom du calque

        # ..................
        return grads

Et le calcul du gradient est le même même si la combinaison des couches change. C'est pratique, n'est-ce pas?

Maintenant, exécutons le code avec la génération de couches.

6. Mise en œuvre de la propagation des erreurs (avec génération de couches)

Comme précédemment, nous allons combiner twoLayerNet.py et train_neuralnet.py pour une meilleure visibilité du code. De plus, la partie dessin du graphique est ajoutée.

import sys, os
sys.path.append(os.pardir)  #Paramètres d'importation des fichiers dans le répertoire parent
from common.layers import *  #calques dans le dossier commun.Configuré pour utiliser toutes les fonctions de py
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from collections import OrderedDict  #Importer OrderedDict

class TwoLayerNet:
    #Initialisation
    def __init__(self, input_size, hidden_size, output_size, weight_init_std = 0.01):
        #Initialisation des paramètres
        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)

        #Génération de couches
        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'])
        self.lastLayer = SoftmaxWithLoss()

    #Propagation vers l'avant
    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)        
        return x
        
    #Calcul de la propagation / perte vers l'avant
    def loss(self, x, t):
        y = self.predict(x)
        return self.lastLayer.forward(y, t)

    #Calcul de la précision
    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
        
    #Calcul du gradient
    def gradient(self, x, t):
        # forward
        self.loss(x, t)

        # backward
        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


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

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

#Réglage initial
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]
    
    #Calcul du gradient
    grad = network.gradient(x_batch, t_batch)
    
    #Mise à jour des paramètres
    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)
    
    #Affichage de la précision
    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)

#Dessiner un graphique
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()

スクリーンショット 2020-05-03 16.05.56.png La précision est améliorée d'environ +3 points par rapport au cas sans génération de couche. La raison en est, bien entendu, pas la génération de couches. C'est parce que la fonction d'activation est passée de «sigmoïde» à «ReLU».

Recommended Posts

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 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
Deep Learning / Deep Learning à partir de Zero 2 Chapitre 6 Mémo
[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]
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)
Apprentissage amélioré pour apprendre de zéro à profond
Mémo d'auto-apprentissage "Deep Learning from scratch" (partie 12) Deep learning
Apprentissage profond à partir de zéro
Mémo d'auto-apprentissage "Deep Learning from scratch" (glossaire illisible)
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 9) Classe MultiLayerNet
[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
Apprentissage profond à partir de zéro 1 à 3 chapitres
Mémo d'auto-apprentissage «Deep Learning from scratch» (n ° 19) Augmentation des données
Mémo d'apprentissage Python pour l'apprentissage automatique par Chainer du chapitre 2
Deep Learning 2 from scratch 1.3 Traitement du langage naturel 1.3 Résumé
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
Un amateur a trébuché dans le Deep Learning à partir de zéro.
Mémo d'apprentissage profond créé à partir de zéro
L'apprentissage en profondeur
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
Tutoriel d'apprentissage en profondeur de la construction d'environnement
"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
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
Apprentissage profond à partir de zéro (propagation vers l'avant)
Apprentissage profond / Apprentissage profond à partir de zéro 2-Essayez de déplacer GRU
Alignement d'image: du SIFT au deep learning
[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
Apprentissage profond à partir des bases mathématiques (pendant la fréquentation)
Note d'étude LPIC201
Mémo d'apprentissage Django
Mémorandum d'apprentissage profond
Commencer l'apprentissage en profondeur
Python vs Ruby «Deep Learning from scratch» Chapitre 2 Circuit logique par Perceptron