[PYTHON] Deep Learning / Deep Learning von Grund auf neu Kapitel 5 Memo

1. Zuallererst

Ich lese ein Meisterwerk, ** "Deep Learning from Zero" **. Diesmal ist das Memo von Kapitel 5. Um den Code auszuführen, laden Sie den gesamten Code von Github herunter und verwenden Sie jupyter notebook in ch05.

2. Implementierung der Fehlerrückübertragung (keine Schichtgenerierung)

Am Ende von Kapitel 5 befindet sich ein Code (twoLayerNet.py & train_neuralnet.py), der eine Ebene erstellt und eine Fehlerausbreitung durchführt. Zuvor befindet sich der Code, der eine Fehlerausbreitung ohne Generierung einer Ebene durchführt, bereits in Kapitel 4. Es gibt (auch twoLayerNet.py & train_neuralnet.py), also werde ich es von dort aus versuchen.

Wie in Kapitel 4, um die Sichtbarkeit zu verbessern, ist es, wenn wir es in einem Code zusammenfassen, fast dasselbe wie beim letzten Mal, nur die --- Gradientenberechnung --- ist anders. Vorerst werde ich es verschieben.

import sys, os
sys.path.append(os.pardir)  #Einstellungen zum Importieren von Dateien in das übergeordnete Verzeichnis
from common.functions import *  #Funktion im gemeinsamen Ordner.Stellen Sie ein, dass alle Funktionen in py verwendet werden sollen
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist

class TwoLayerNet:
    #Parameterinitialisierung
    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)

    #Vorwärtsausbreitung
    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
        
    #Verlustberechnung
    def loss(self, x, t):
        y = self.predict(x)
        
        return cross_entropy_error(y, t)

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

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

#Daten lesen
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

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

#Grundeinstellung
iters_num = 10000  #Anzahl der Hinrichtungen
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]
    
    #Gradientenberechnung
    grad = network.gradient(x_batch, t_batch)
    
    #Parameteraktualisierung
    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)

    #Genauigkeitsanzeige
    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))

#Zeichnen eines Diagramms
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 Toll! Im Vergleich zur numerischen Differenzierung ist die Ausführungsgeschwindigkeit so unterschiedlich wie Himmel und Erde. Es ist super schnell! (Tatsächlich ist die numerische Differenzierung extrem langsam.)

Der Inhalt des Codes wurde bereits in Kapitel 4 Memo erläutert, mit Ausnahme von --- Gradientenberechnung ---. Wenn Sie ihn also sehen möchten, Kapitel 4 Memo. Bitte beziehen Sie sich auf Artikel / be171ff7626d370072d1). In diesem Kapitel wird nur der Gradientenberechnungsteil erläutert.

3. Gradientenberechnung

Wenn Sie einen Teil des Gradientenberechnungscodes mit einem Berechnungsdiagramm erklären, sieht es so aus. スクリーンショット 2020-05-02 19.34.48.png Die Summe von "grad [" b2 "] = np.sum (dy, axis = 0)" ist die Entsprechung zur Stapelverarbeitung. Trotzdem bin ich beeindruckt, dass die scheinbar komplizierte Fehler-Backpropagation durch Matrixoperationen ersetzt wird.

4. Ableitung der Fehlerrückausbreitungsformel

Leiten Sie zunächst $ \ frac {\ partielles L} {\ partielles W2} = z1 ^ {T} * dy $ ab. Abhängig von der Kettenrate スクリーンショット 2020-05-02 16.39.35.png

Als nächstes leiten wir $ \ frac {\ partielles y} {\ partielles Z1} = \ frac {\ partielles y} {\ partielles a2} W2 ^ T $ ab.

スクリーンショット 2020-05-02 18.45.24.png Der Übergang von der Welt der numerischen Differenzierung zur Welt der Rückausbreitung von Fehlern durch Matrixoperation ist wirklich innovativ, nicht wahr?

5. Schichterzeugung

Wie bereits erwähnt, können Sie eine praktische Ausführungsgeschwindigkeit erzielen, indem Sie die Matrixoperationsformel sowohl für die Vorwärtsausbreitung als auch für die Fehlerrückübertragung direkt in den Code schreiben. Das Schreiben des Codes ist jedoch etwas mühsam, nicht wahr? Es gibt also eine Möglichkeit, eine Ebene zu generieren und den Code einfacher zu schreiben.

Um eine Ebene zu generieren, importieren Sie zuerst das OrderedDict mit "aus Sammlungen importieren Sie OrderedDict".

class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, 
        # ................
        #Schichterzeugung
        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()

Instanziieren Sie OrderedDict mit self.layers = OrderedDict () während der Ersteinrichtung der Klasse TwoLayerNet.

OrderedDict wird einschließlich der Bestellung gespeichert. Wenn Sie also "Affine1", "Relu1", "Affine2", den Layernamen und den Prozess in der Reihenfolge im Wörterbuch "self.layers" registrieren, wird die Bestellung ebenfalls gespeichert.

Nur die letzte Ebene hat eine andere Fehler-Backpropagation-Formel. Behandeln Sie sie daher separat als "self.lastLayer".

    #Vorwärtsausbreitung
    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)        
        return x
        
    #Vorwärtsausbreitung / Verlustberechnung
    def loss(self, x, t):
        y = self.predict(x)
        return self.lastLayer.forward(y, t)

Dann liest "Forward Propagation" Predict "einfach die Layernamen einzeln aus dem Wörterbuch" self.layers "und führt den" Forward "-Prozess wiederholt aus, unabhängig davon, wie viele Layer es gibt Alles was Sie brauchen ist Code.

Vorwärtsausbreitung / Verlustberechnung "Verlust" breitet sich auch vorwärts aus und führt nur eine "Vorwärts" -Verarbeitung der letzten Schicht mit "self.lastLayer.forward (y, t)" durch. Selbst wenn sich der Verarbeitungsinhalt der letzten Schicht ändert, ändert sich dies Es bleibt der Code.

   #Gradientenberechnung
   def gradient(self, x, t):
        #Vorwärtsausbreitung / Verlustberechnung
        self.loss(x, t)

        #Fehler bei der Weitergabe
        dout = 1
        dout = self.lastLayer.backward(dout)  #Ersetzen Sie das Rückwärtsergebnis der letzten Schicht durch Dout
        layers = list(self.layers.values())  #Wörterbuch selbst.Lesen Sie den Ebenennamen aus den Ebenen
        layers.reverse()  #Kehren Sie die Reihenfolge der Ebenennamen um
        for layer in layers:  #Lesen Sie den Namen der invertierten Ebene
            dout = layer.backward(dout)  #Führen Sie den Layernamen rückwärts aus

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

Die Gradientenberechnung ist auch dann dieselbe, wenn sich die Kombination der Ebenen ändert. Das ist praktisch, nicht wahr?

Lassen Sie uns nun den Code mit Layer-Generierung ausführen.

6. Implementierung der Fehlerrückausbreitung (mit Schichtgenerierung)

Nach wie vor kombinieren wir twoLayerNet.py und train_neuralnet.py für eine bessere Code-Sichtbarkeit. Außerdem wird der Zeichnungsteil des Diagramms hinzugefügt.

import sys, os
sys.path.append(os.pardir)  #Einstellungen zum Importieren von Dateien in das übergeordnete Verzeichnis
from common.layers import *  #Ebenen im gemeinsamen Ordner.Stellen Sie ein, dass alle Funktionen in py verwendet werden sollen
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from collections import OrderedDict  #OrderedDict importieren

class TwoLayerNet:
    #Initialisieren
    def __init__(self, input_size, hidden_size, output_size, weight_init_std = 0.01):
        #Parameterinitialisierung
        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)

        #Schichterzeugung
        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()

    #Vorwärtsausbreitung
    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)        
        return x
        
    #Vorwärtsausbreitung / Verlustberechnung
    def loss(self, x, t):
        y = self.predict(x)
        return self.lastLayer.forward(y, t)

    #Genauigkeitsberechnung
    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
        
    #Gradientenberechnung
    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)

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


#Daten lesen
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)

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

#Grundeinstellung
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]
    
    #Gradientenberechnung
    grad = network.gradient(x_batch, t_batch)
    
    #Parameteraktualisierung
    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)
    
    #Genauigkeitsanzeige
    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)

#Zeichnen eines Diagramms
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 Die Genauigkeit ist im Vergleich zum Fall ohne Schichterzeugung um etwa +3 Punkte verbessert. Der Grund dafür ist natürlich nicht die Schichterzeugung. Dies liegt daran, dass die Aktivierungsfunktion von "Sigmoid" auf "ReLU" geändert wurde.

Recommended Posts

Deep Learning / Deep Learning von Grund auf neu 2 Kapitel 4 Memo
Deep Learning / Deep Learning von Grund auf neu Kapitel 3 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 5 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 7 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 8 Memo
Deep Learning / Deep Learning von Grund auf neu Kapitel 5 Memo
Deep Learning / Deep Learning von Grund auf neu Kapitel 4 Memo
Deep Learning / Deep Learning von Grund auf neu 2 Kapitel 3 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 6 Memo
[Lernnotiz] Deep Learning von Grund auf neu gemacht [Kapitel 7]
Deep Learning / Deep Learning von Grund auf neu Kapitel 6 Memo
[Lernnotiz] Deep Learning von Grund auf neu gemacht [Kapitel 5]
Deep Learning / Deep Learning von Grund auf neu Kapitel 7 Memo
[Lernnotiz] Deep Learning von Grund auf neu gemacht [~ Kapitel 4]
Deep Learning von Grund auf neu Kapitel 2 Perceptron (Memo lesen)
Verbessertes Lernen, um von null bis tief zu lernen
"Deep Learning from Grund" Memo zum Selbststudium (Teil 12) Deep Learning
Deep Learning von Grund auf neu
Selbststudien-Memo "Deep Learning from Grund" (unlesbares Glossar)
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 9) MultiLayerNet-Klasse
[Lernnotiz] Deep Learning von Grund auf ~ Implementierung von Dropout ~
"Deep Learning from Grund" Memo zum Selbststudium (10) MultiLayerNet-Klasse
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 11) CNN
Deep Learning von Grund auf 1-3 Kapitel
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 19) Datenerweiterung
Python-Lernnotiz für maschinelles Lernen von Chainer aus Kapitel 2
Deep Learning 2 von Grund auf 1.3 Verarbeitung natürlicher Sprache 1.3 Zusammenfassung
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 1
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 5
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 2
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 3
Ein Amateur stolperte in Deep Learning von Grund auf neu. Hinweis: Kapitel 7
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 5
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 1
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 4
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 4
Deep Learning Memo von Grund auf neu gemacht
Tiefes Lernen
Ein Amateur stolperte in Deep Learning von Grund auf neu Hinweis: Kapitel 2
Selbststudien-Memo "Deep Learning from Grund" (Nr. 15) TensorFlow-Anfänger-Tutorial
Deep Learning Tutorial aus dem Umgebungsbau
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 14) Führen Sie das Programm in Kapitel 4 in Google Colaboratory aus
"Deep Learning from Grund" Memo zum Selbststudium (Teil 8) Ich habe die Grafik in Kapitel 6 mit matplotlib gezeichnet
Selbststudien-Memo "Deep Learning from Grund" (Nr. 13) Verwenden Sie Google Colaboratory
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 10-2) Anfangswert des Gewichts
Tiefes Lernen von Grund auf neu (Vorwärtsausbreitung)
Tiefes Lernen / Tiefes Lernen von Grund auf 2-Versuchen Sie, GRU zu bewegen
Bildausrichtung: von SIFT bis Deep Learning
[Windows 10] Aufbau einer "Deep Learning from Scratch" -Umgebung
Lernbericht über das Lesen von "Deep Learning von Grund auf neu"
[Deep Learning von Grund auf neu] Über die Optimierung von Hyperparametern
Deep Learning aus den mathematischen Grundlagen (während der Teilnahme)
LPIC201 Studiennotiz
Django Lernnotiz
Deep Learning Memorandum
Starten Sie Deep Learning
Python vs Ruby "Deep Learning von Grund auf neu" Kapitel 2 Logikschaltung von Perceptron