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

1. Zuallererst

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

2. Lernen eines zweischichtigen neuronalen Netzwerks

Am Ende von Kapitel 4 gibt es einen Code (train_neuralnet.py), der ein zweischichtiges neuronales Netzwerk trainiert, indem der Gradient von Parametern durch numerische Differenzierung berechnet wird. Dieses Mal werde ich diesen Code ausführen und dann die Details durchgehen. Der Code von Github ist jedoch nicht derselbe, aber einige Änderungen und Ergänzungen werden wie folgt vorgenommen.

** 1) Entsprechung zu langsamer Ausführungsgeschwindigkeit ** Obwohl die Verwendung der "numerischen Differenzierung" sehr viel Zeit in Anspruch nimmt, wird die zweite Genauigkeitsberechnung nach einigen Stunden angezeigt, wenn die Genauigkeitsanzeige alle 600 Iter (alle 1 Epoche) angezeigt wird. Um das Ergebnis in etwas mehr als einer Stunde zu sehen, stellen Sie die "Präzisionsanzeige" auf "alle 1 Iter", die "Ausführungszahl von 10000 bis 100" und die "Lernrate von 0,1 bis 1,0" ein.

** 2) Reduzieren Sie die Anzahl der externen Anrufcodes, um die Sichtbarkeit zu verbessern ** Das Merkmal von Zero Work ist, dass der bereits erläuterte Code so oft wie möglich von außen aufgerufen wird und der gleichzeitig anzuzeigende Code so präzise wie möglich ausgedrückt wird. Das Aufrufen von "two_layer_net.py" von "train_neuralnet.py" und "gradient.py" im "gemeinsamen Ordner" von "two_layer_net.py" ist jedoch sehr verwirrend. Also werde ich diesen Bereich zu train_neuralnet.py hinzufügen, um die Aussichten zu verbessern.

Es wird jedoch nur "function.py" im "gemeinsamen Ordner" als externer Code verwendet (Sigmoid, Sofytmax, Cross_entropy_error usw.).

Lassen Sie uns zuerst den folgenden Code ausführen.

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 numerical_gradient(self, x, t):   
        loss_W = lambda W: self.loss(x, t)        
        grads = {}
        grads['W1'] = numerical_gradient2(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient2(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient2(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient2(loss_W, self.params['b2'])        
        return grads
    
    #Numerische Differenzierung
    def numerical_gradient2(f, x):   
        h = 1e-4 # 0.0001
        grad = np.zeros_like(x)
    
        it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
        while not it.finished:
            idx = it.multi_index
            tmp_val = x[idx]
            x[idx] = tmp_val + h
            fxh1 = f(x) # f(x+h)
        
            x[idx] = tmp_val - h 
            fxh2 = f(x) # f(x-h)
            grad[idx] = (fxh1 - fxh2) / (2*h)
        
            x[idx] = tmp_val #Stellen Sie den Wert wieder her
            it.iternext()           
        return grad  
            
#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 = 100  #Die Ausführungsanzahl wurde von 10000 auf 100 geändert
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 1   #Die Lernrate beträgt 0.1 → 1.Wechseln Sie zu 0
train_loss_list, train_acc_list, test_acc_list = [], [], []
iter_per_epoch = 1  #Die Genauigkeitsanzeige ändert sich von 1 Epoche auf 1 Iter

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.numerical_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)
        
        #Anzeige(iter und trainieren_Verlust hinzufügen)
        print('[iter='+str(i)+'] '+'train_loss='+str(loss)+', '+'train_acc='+str(train_acc)+', '+'test_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("iter")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()

スクリーンショット 2020-04-29 16.40.37.png Es dauerte 75 Minuten, um 100iter auf meinem "Macbook Air" laufen zu lassen. Wie wäre es, wenn Sie das Genauigkeitsdiagramm, das 16epoch (= 9600iter) ausgeführt hat, auch bei numerischer Differenzierung in den Text einfügen? Abgesehen davon nimmt die numerische Differenzierung enorm viel Zeit in Anspruch.

3. Klasse 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)

Dies ist der Teil, der beim Instanziieren einer Klasse nur einmal ausgeführt wird. Hier wird jeder Parameter initialisiert. "np.random.randn ()" ist die Erzeugung einer Normalverteilung mit einem Mittelwert von 0 und einer Varianz von 1, und "np.zeros ()" ist die Erzeugung einer Nullmatrix. Die Größe jeder Matrix ist wie folgt. スクリーンショット 2020-04-29 17.32.04.png

    #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

Dies ist der Vorwärtsausbreitungsteil. Lesen Sie die in den Wörterbuchparametern gespeicherte Matrix der Gewichte 'W1', 'W2' und Bias 'b1', 'b2' und geben Sie sie durch Matrixoperation weiter.

    #Verlustberechnung
    def loss(self, x, t):
        y = self.predict(x)        
        return cross_entropy_error(y, t)

Dies ist der Teil, der den Verlust berechnet. Finden Sie die Kreuzentropie von y und die Lehrerdaten t, die Sie erhalten, indem Sie die Vorwärtsausbreitung früher aufrufen. Cross Entropy verwendet die Funktionen in function.py im common folder. Vorerst,

スクリーンショット 2020-04-30 08.44.59.png

y [np.arange (batch_size), t] bedeutet, das entsprechende Element von y gemäß dem richtigen Antwortetikett in der Reihenfolge t zu schneiden.

    #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

Dies ist der Teil der Genauigkeitsberechnung. Y wird aus den Eingabedaten x abgeleitet, die Indizes von y und das richtige Antwortetikett t werden herausgenommen, und die Zahl, wenn die beiden Indizes gleich sind, wird durch die Anzahl der Daten von x geteilt, um die Genauigkeit zu berechnen.

    #Gradientenberechnung
    def numerical_gradient(self, x, t):   
        loss_W = lambda W: self.loss(x, t)        
        grads = {}
        grads['W1'] = numerical_gradient2(loss_W, self.params['W1'])
        grads['b1'] = numerical_gradient2(loss_W, self.params['b1'])
        grads['W2'] = numerical_gradient2(loss_W, self.params['W2'])
        grads['b2'] = numerical_gradient2(loss_W, self.params['b2'])        
        return grads

Dies ist der Teil der Gradientenberechnung. Verwenden Sie die später angezeigte Funktion "numerischer Gradient2", um die Ergebnisse der Gradientenberechnung in einem Wörterbuchformat zusammenzufassen. Die Argumente sind der "Verlustfunktionsausdruck", der die Kreuzentropie basierend auf x und der korrekten Antwortbezeichnung t und die "Parameterspezifikation" findet.

Das Original ist übrigens "grads ['W1'] = numerischer_gradient (loss_W, self.params ['W1'])", oder? Ist es rekursive Verwendung? Zuerst dachte ich, aber das ist es nicht.

Im Original enthält "TwoLayerNet.py" am Anfang eine Beschreibung von "from common.gradient import numerischer_gradient", und die "numerische_gradient-Funktion" in "gradient.py" im "gemeinsamen Ordner" wird importiert. Verwenden Sie sie daher. Hier ist was du tust. Es gibt weniger Fehler, wenn Sie den Namen hier ändern, also habe ich den Namen in "numerischer_gradient2" geändert.

    #Numerische Differenzierung
    def numerical_gradient2(f, x):   
        h = 1e-4 # 0.0001

        #Nullmatrixgrad, der das Berechnungsergebnis des Gradienten speichert(Größe angegeben durch x)Bereiten
        grad = np.zeros_like(x)

        #Sequentielle Indizierung der Matrix x(Geben Sie Zeile und Spalte an)Machen
        it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
        
        #Fahren Sie fort, bis alle Zeilen und Spalten der Matrix x angegeben sind
        while not it.finished:
            
            idx = it.multi_index  #zu idx(Linie,Säule)Ersatz
            tmp_val = x[idx]  #tmp der durch idx angegebene Wert von x_In val speichern
            
            #Berechnen Sie den Verlust, indem Sie eine kleine Zahl h addieren und sich vorwärts ausbreiten
            x[idx] = tmp_val + h
            fxh1 = f(x) # f(x+h)

            #Berechnen Sie den Verlust, indem Sie eine kleine Zahl h subtrahieren und sich vorwärts ausbreiten
            x[idx] = tmp_val - h 
            fxh2 = f(x) # f(x-h)

            #Berechnen Sie die Steigung des entsprechenden Index
            grad[idx] = (fxh1 - fxh2) / (2*h)

            x[idx] = tmp_val #Stellen Sie den gespeicherten Wert wieder her
            it.iternext()  #Führen Sie den folgenden Index aus
        return grad  

Dies ist der Teil, der die numerische Differenzierung durchführt. Einfach ausgedrückt, addieren Sie für jeden der Parameter einen kleinen Wert h, um die Ausbreitung / den Verlust vorwärts zu berechnen, subtrahieren Sie einen kleinen Wert h, um die Ausbreitung / den Verlust vorwärts zu berechnen, und den Gradienten, abhängig davon, wie sich die beiden Verlustberechnungen geändert haben. Ich habe entschieden. ``

Diesmal beträgt die Anzahl der Parameter 784 * 50 = 39.200 für W1, 50 * 10 = 500 für W2, 50 für b1 und 10 für b2 für insgesamt 39.760. Da die Vorwärtsausbreitungs- / Verlustberechnung für jeden Parameter zweimal durchgeführt wird, werden für jede Parameteraktualisierung des Netzwerks 79.520 Vorwärtsausbreitungs- / Verlustberechnungen durchgeführt. Die Operation ist extrem langsam.

Jetzt habe ich einen np.nditer, mit dem ich im Code nicht vertraut bin. Normalerweise verwendet die Indexspezifikation der Matrix for loop für die Zeilenspezifikation + for loop und double loop für die Spaltenspezifikation, aber dieser np.nditer kann dies nur einmal tun.

Wie ich zuvor erklärt habe, befindet sich dieser Code ursprünglich in "gradient.py" im "gemeinsamen Ordner". Der ursprüngliche Funktionsname ist verwirrend mit "numerischer_gradient" (wie der Funktionsname in der Gradientenberechnung), daher wird er diesmal in "numerischer_gradient2" geändert.

4. Körperteil

#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 = 100  #Die Ausführungsanzahl wurde von 10000 auf 100 geändert
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 1   #Die Lernrate beträgt 0.1 → 1.Wechseln Sie zu 0
train_loss_list, train_acc_list, test_acc_list = [], [], []
iter_per_epoch = 1  #Die Genauigkeitsanzeige ändert sich von 1 Epoche auf 1 Iter

Instanziieren Sie nach dem Laden der Daten die Klasse "TwoLayerNet". Da input_size = 784, hidden_size = 50, output_size = 10 ist, sind die Modell- und Matrixoperation wie folgt. スクリーンショット 2020-04-30 12.56.08.png

for i in range(iters_num):

    #Holen Sie sich Mini-Batch-Daten
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    #Gradientenberechnung
    grad = network.numerical_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)

        #Anzeige(iter und trainieren_Verlust hinzufügen)
        print('[iter='+str(i)+'] '+'train_loss='+str(loss)+', '+'train_acc='+str(train_acc)+', '+'test_acc='+str(test_acc))

Bereiten Sie zunächst die Daten für das Mini-Batch-Lernen vor. np.random.choice (train_size, batch_size) weist batch_mask das Ergebnis der zufälligen Auswahl von 100 von 60.000 Zugdaten (welche Nummer ausgewählt wurde) zu und verwendet es für Trainingsdaten. Und erhalten Sie das richtige Antwortetikett.

Als nächstes Gradientenberechnung. Rufen Sie die Funktion "numerischer Gradient" der "TwoLayerNet-Klasse" auf und ermitteln Sie, wie bereits erläutert, den Gradienten durch numerische Differenzierung für jeden Parameter.

Anschließend werden die Parameter mit dem berechneten Gradienten aktualisiert, der Verlust berechnet und aufgezeichnet sowie die Genauigkeit angezeigt.

#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("iter")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()

Nach Abschluss des Trainings wird das Genauigkeitsdiagramm angezeigt. Dies bedarf keiner Erklärung.

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
Deep Learning / Deep Learning von Grund auf neu Kapitel 6 Memo
[Lernnotiz] Deep Learning von Grund auf neu gemacht [Kapitel 5]
[Lernnotiz] Deep Learning von Grund auf neu gemacht [Kapitel 6]
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
Selbststudien-Memo "Deep Learning from Grund" (unlesbares Glossar)
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 9) MultiLayerNet-Klasse
Deep Learning von Grund auf neu ① Kapitel 6 "Lerntechniken"
[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
Tiefes Lernen von Grund auf neu (Kostenberechnung)
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 über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 1
Ein Amateur stolperte über Deep Learning ❷ von Grund auf neu Hinweis: Kapitel 4
Selbststudien-Memo "Deep Learning from Grund" (Nr. 18) Eins! Miau! Grad-CAM!
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
"Deep Learning von Grund auf neu" mit Haskell (unvollendet)
[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
Starten Sie Deep Learning