[PYTHON] "Deep Learning from Grund" Memo zum Selbststudium (10) MultiLayerNet-Klasse

Während ich "Deep Learning from Grund" (gelesen von Yasuki Saito, veröffentlicht von O'Reilly Japan) lese, werde ich die Websites notieren, auf die ich mich bezog. Teil 9 ← → Teil 11

Nachdem wir die Implementierung in Schichten in Kapitel 5 erklärt haben, werden wir das Programm selbst in Kapitel 6 und höher nicht viel erklären. Das Beispielprogramm befindet sich in der Datei, die Sie zuerst heruntergeladen haben. Sie sollten es daher selbst ausführen und den Inhalt überprüfen. Für Anfänger ist es jedoch recht schwierig.

Nun, ich werde nach und nach gehen.

Lassen Sie uns den Inhalt der MultiLayerNet-Klasse in Kapitel 6 überprüfen

Kapitel 3 enthielt eine grundlegende Erklärung des neuronalen Netzes, und Kapitel 4 implementierte die zweischichtige neuronale Netzwerkklasse TwoLayerNet. Danach gab es verschiedene Erklärungen und es wurde die MultiLayerNet-Klasse. Es sieht sehr kompliziert aus, aber die Grundlagen sind die gleichen wie bei TwoLayerNet. Wenn Sie sich den Inhalt der Bibliotheksschicht.py ansehen, auf die diese Klasse verweist, entspricht dies der von der TwoLayerNet-Klasse verwendeten. Was kompliziert aussieht, ist Schichtweise implementiert, um die Vielseitigkeit des Programms zu erhöhen Die Aktivierungsfunktion, die Parameteraktualisierungsmethode, der anfängliche Gewichtswert usw. können jetzt ausgewählt werden. Es scheint von zu sein.

Wenn Sie das Programm verstehen möchten, müssen Sie es zeilenweise manuell verfolgen.

Verfolgen wir also das Programm auf P192.

Generieren Sie ein neuronales Netzobjektnetzwerk

weight_decay_lambda = 0.1

network = MultiLayerNet(input_size=784, 
                        hidden_size_list=[100, 100, 100, 100, 100, 100],
                        output_size=10,
                        weight_decay_lambda=weight_decay_lambda)

input_size = 784 bedeutet, MNIST-Daten mit 784 Elementen zu verwenden. output_size = 10 bedeutet, dass 10 Ergebnisse erkannt wurden. damit hidden_size_list=[100, 100, 100, 100, 100, 100] Was passiert innerhalb des Netzwerkobjekts?

Bei der Initialisierung in der Definition von MultiLayerNet in multi_layer_net.py

    def __init__(self, input_size, hidden_size_list, output_size,
                 activation='relu', weight_init_std='relu', weight_decay_lambda=0):
        self.input_size = input_size
        self.output_size = output_size
        self.hidden_size_list = hidden_size_list
        self.hidden_layer_num = len(hidden_size_list)
        self.weight_decay_lambda = weight_decay_lambda
        self.params = {}

        #Gewichtsinitialisierung
        self.__init_weight(weight_init_std)

Ich habe es bei der Objekterstellung weggelassen Aktivierung = 'relu' Verwenden Sie relu als Aktivierungsfunktion weight_init_std = 'relu' Der Anfangswert des Gewichts ist mit relu kompatibel. Verwenden Sie den Anfangswert von He. self.hidden_layer_num = len (hidden_size_list) Erstellt so viele Ebenen für versteckte Ebenen, wie Elemente in der Liste hidden_size_list enthalten sind. Es sollte sein.

Generieren Sie eine Ebene

Also für Schleife so viele wie die Anzahl der Elemente

        #Schichterzeugung
        activation_layer = {'sigmoid': Sigmoid, 'relu': Relu}
        self.layers = OrderedDict()
        for idx in range(1, self.hidden_layer_num+1):
            self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)],
                                                      self.params['b' + str(idx)])
            self.layers['Activation_function' + str(idx)] = activation_layer[activation]()

Am Ende davon als Ausgabeebene last_layer SoftmaxWithLoss Wird hinzugefügt werden.

        idx = self.hidden_layer_num + 1
        self.layers['Affine' + str(idx)] = Affine(self.params['W' + str(idx)],
            self.params['b' + str(idx)])

        self.last_layer = SoftmaxWithLoss()

Mit anderen Worten, es gibt 6 versteckte Schichten + 1 Ausgangsschicht, wodurch ein 7-Schicht-Netzwerk entsteht. Der Inhalt der Listenebenen lautet wie folgt:

OrderedDict([ ('Affine1', Affine(params[W1],params[b1])), ('Activation_function1', Relu), ('Affine2', Affine(params[W2],params[b2])), ('Activation_function2', Relu), ('Affine3', Affine(params[W3],params[b3])), ('Activation_function3', Relu), ('Affine4', Affine(params[W4],params[b4])), ('Activation_function4', Relu), ('Affine5', Affine(params[W5],params[b5])), ('Activation_function5', Relu), ('Affine6', Affine(params[W6],params[b6])), ('Activation_function6', Relu), ('Affine7', Affine(params[W7],params[b7])) ])

Indem Sie es Schicht für Schicht implementieren, können Sie sehen, dass die Anzahl der ausgeblendeten Ebenen durch die Anzahl der Elemente in hidden_size_list angegeben werden kann. Wenn Sie ungefähr 6 Ebenen haben, können Sie die Anzahl der Ebenen im Programm wie in der TwoLayerNet-Klasse erhöhen. Wenn diese jedoch 100 erreichen, ist dies eine Verschwendung.

Lass mich lernen

MNIST-Daten werden diesem Netzwerkobjekt zum Training übergeben.

optimizer = SGD(lr=0.01)

for i in range(1000000000):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]

    grads = network.gradient(x_batch, t_batch)
    optimizer.update(network.params, grads)

In einer Mini-Batch-Schleife grads = network.gradient(x_batch, t_batch) Also suche ich einen Farbverlauf Der Inhalt der Absolventen sieht so aus

{ 'W1': array([[-0.00240062, -0.01276378, 0.00096349, ..., 0.0054993 ], [-0.00232299, -0.0022137 , 0.0036697 , ..., -0.00693252], ..., [-0.00214929, 0.00358515, -0.00982791, ..., 0.00342722]]), 'b1': array([-4.51501921e-03, 5.25825778e-03, ..., -8.60827293e-03]), 'W2': array([[ 0.00394647, -0.01781943, 0.00114132, ..., 0.0029042 ], [-0.00551014, 0.00238989, 0.01442266, ..., 0.00171659], ..., [ 0.00279524, 0.01496588, 0.01859664, ..., -0.02194152]]), 'b2': array([ 2.08738753e-03, -8.28071395e-03, ..., 1.22945079e-02]), 'W3': array([[ ..., ]]), 'b3': array([ ..., ]), 'W4': array([[ ..., ]]), 'b4': array([ ..., ]), 'W5': array([[ ..., ]]), 'b5': array([ ..., ]), 'W6': array([[ ..., ]]), 'b6': array([ ..., ]), 'W7': array([ [ 6.72420338e-02,3.36979669e-04,1.26773417e-02,-2.30916938e-03, -4.84414774e-02, -2.58458587e-02,-5.26754173e-02,3.61136740e-02,-4.29689699e-03, -2.85799599e-02], [ ...], [-1.68008362e-02, 6.87882255e-03, -3.15578291e-03, -8.00362948e-04, 8.81555008e-03, -9.23032804e-03,-1.83337109e-02, 2.17933554e-02, -6.52331525e-03, 1.50930257e-02] ]), 'b7': array([ 0.11697053, -0.02521648, 0.03697393, -0.015763 , -0.0456317 , -0.03476072, -0.05961871, 0.0096403 , 0.03581566, -0.01840983]) }

Im Inhalt der letzten Noten ['W7'] wird die Wahrscheinlichkeit, welche der von der Softmax-Funktion ausgegebenen Zahlen 0 bis 9 in eine Liste von 10 Elementen umgewandelt wird, und die Anzahl der Zeilen der gelesenen Trainingsdaten angeordnet. Ich bin raus. Und

    optimizer.update(network.params, grads)

Aktualisieren Sie, indem Sie den Inhalt von Absolventen vom Inhalt der Parameterparameter mit der Aktualisierungsmethode der Funktion SGD der Bibliothek optimizer.py im allgemeinen Ordner subtrahieren. Im obigen Beispiel aktualisieren wir mit der SGD-Methode. Zusätzlich zu SGD sind Momentum, AdaGrad, Adam und RMSprop in der Bibliothek definiert.

Die aktualisierten Parameter werden für die nächste Stapelverarbeitung verwendet, sodass das Lernen in den Stapelschleifen fortgesetzt wird.

Was macht die Gradientenmethode?

Diese Gradientenmethode ermittelt dann den Gradienten des Gewichtungsparameters durch die Fehlerrückausbreitungsmethode. Berechnen Sie zuerst den Wert der Verlustfunktion in Vorwärtsrichtung und verfolgen Sie dann die Schicht, die beim Erstellen des Netzwerkobjekts in umgekehrter Richtung festgelegt wurde, um den Gradienten zu erhalten.

    def gradient(self, x, t):
        # forward
        self.loss(x, t)

        # backward
        dout = 1
        dout = self.last_layer.backward(dout)

        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)

        #Aufbau
        grads = {}
        for idx in range(1, self.hidden_layer_num+2):
            grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + self.weight_decay_lambda * self.layers['Affine' + str(idx)].W
            grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db

        return grads

Zunaechst, self.loss(x, t) Das habe ich nicht wirklich verstanden. Ich führe eine Funktion aus, aber es sieht nicht so aus, als würde ich das Ergebnis als nächstes verwenden. Also habe ich versucht, den Inhalt zu verfolgen. Was wir ausführen, ist der in multi_layer_net.py definierte Funktionsverlust.

Ich habe versucht, den Verlust der Verlustfunktion zu verfolgen

network.loss(x_batch, t_batch)

62.09479496490768

    def loss(self, x, t):
        y = self.predict(x)
        weight_decay = 0
        for idx in range(1, self.hidden_layer_num + 2):
            W = self.params['W' + str(idx)]
            weight_decay += 0.5 * self.weight_decay_lambda * np.sum(W ** 2)

        return self.last_layer.forward(y, t) + weight_decay

In der Verlustfunktion sagt Predict das Ergebnis y aus den Eingabedaten voraus. Dabei wird die Vorwärtsmethode der Ebene von Affine1 nach Affine7 ausgeführt.

    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)
        return x

Berechnen Sie weight_decay aus Gewichten (Parameter ['W1'] usw.), um Überlernen zu vermeiden, und fügen Sie diese hinzu Ausgabe.

weight_decay

59.84568388277881

network.last_layer.forward(y, t_batch)

2.2491110821288687

self.last_layer.forward (y, t) ist die Initialisierung der MultiLayerNet-Klasse.

self.last_layer = SoftmaxWithLoss()

Da es definiert ist als, wird tatsächlich die in layer.py definierte Forward-Methode von SoftmaxWithLoss () ausgeführt.

class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None #Ausgabe von Softmax
        self.t = None #Lehrerdaten

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        
        return self.loss

    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        if self.t.size == self.y.size: #Lehrerdaten sind eins-hot-Für Vektor
            dx = (self.y - self.t) / batch_size
        else:
            dx = self.y.copy()
            dx[np.arange(batch_size), self.t] -= 1
            dx = dx / batch_size
        
        return dx

Bei dieser Vorwärtsmethode wird der Kreuzentropiefehler berechnet und zurückgegeben.

network.last_layer.loss

2.2491110821288687

from common.functions import *
cross_entropy_error(network.last_layer.y, network.last_layer.t)

2.2491110821288687

Indem ich das sagte, wusste ich, worauf ich mich bezog und was ich mit self.loss (x, t) machte.

damit,

Die SoftmaxWithLoss-Funktion verwendet dann die Rückwärtsmethode bei der Fehlerrückübertragung, um den Gradienten zu ermitteln. Es bezieht sich auf self.y und self.t, die Variablen sind, die festgelegt werden, wenn die Forward-Methode ausgeführt wird. Mit anderen Worten, ** der erste Selbstverlust (x, t) sucht nicht nach der Verlustfunktion, sondern bereitet die Verwendung der Rückwärtsmethode in der Fehler-Backpropagation-Methode ** vor.

Um zurück zu gehen, muss man vorwärts gehen. Wenn man es versteht, ist das eine Selbstverständlichkeit.

Finden Sie den Farbverlauf mit rückwärts

Berechnen Sie nach dem Ausführen von self.loss (x, t) und dem Einstellen des vorhergesagten Werts aus den Eingabedaten den Gradienten mit der Methode der Fehlerrückübertragung.

        # backward
        dout = 1
        dout = self.last_layer.backward(dout)

self.last_layer.backward (dout) steht für SoftmaxWithLoss.backward (). dout gibt eine Liste der Unterschiede zwischen dem vorhergesagten Wert y und der Lehrerbezeichnung t zurück. [y1 - t1, y2 - t2, y3 - t3, ・ ・ ・, y100 - t100]

        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)

In layer.reverse () werden die gestapelten Ebenen umgekehrt und dout = layer.backward (dout) wird wiederholt, um den Gradienten zu ermitteln. Wenn Sie die Iteration erweitern, sieht sie folgendermaßen aus.

dout = layers[0].backward(dout)  #Affine7
dout = layers[1].backward(dout)  #Activation_function6 Relu
dout = layers[2].backward(dout)  #Affine6
dout = layers[3].backward(dout)  #Activation_function5 Relu
dout = layers[4].backward(dout)  #Affine5
dout = layers[5].backward(dout)  #Activation_function4 Relu
dout = layers[6].backward(dout)  #Affine4
dout = layers[7].backward(dout)  #Activation_function3 Relu
dout = layers[8].backward(dout)  #Affine3
dout = layers[9].backward(dout)  #Activation_function2 Relu
dout = layers[10].backward(dout) #Affine2
dout = layers[11].backward(dout) #Activation_function1 Relu
dout = layers[12].backward(dout) #Affine1

Das self.x self.W, auf das in jeder Affine-Ebene verwiesen wird, wurde bei der Ausführung der Forward-Methode festgelegt.

class Affine:
    def __init__(self, W, b):
        self.W =W
        self.b = b
        
        self.x = None
        self.original_x_shape = None
        #Differenzierung von Gewichts- / Bias-Parametern
        self.dW = None
        self.db = None

    def forward(self, x):
        #Tensol kompatibel
        self.original_x_shape = x.shape
        x = x.reshape(x.shape[0], -1)
        self.x = x

        out = np.dot(self.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.sum(dout, axis=0)
        
        dx = dx.reshape(*self.original_x_shape)  #Kehren Sie zur Form der Eingabedaten zurück (kompatibel mit Tensor).
        return dx

Stellen Sie unter Verwendung von dw und db, die für jede Schicht erhalten wurden, das Gewicht und den Vorspannungsgradienten jeder Schicht ein und geben Sie ihn als Wert der Funktion zurück.

        #Aufbau
        grads = {}
        for idx in range(1, self.hidden_layer_num+2):
            grads['W' + str(idx)] = self.layers['Affine' + str(idx)].dW + self.weight_decay_lambda * self.layers['Affine' + str(idx)].W
            grads['b' + str(idx)] = self.layers['Affine' + str(idx)].db

Mit dem zurückgegebenen Gradienten werden die Parameter aktualisiert und der Mini-Batch-Prozess endet einmal.

    grads = network.gradient(x_batch, t_batch)
    optimizer.update(network.params, grads)
class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr
        
    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key] 

lr ist die Lernrate In diesem Beispiel wird 0,01 festgelegt.

MultiLayerNetExtend-Klasse

Die MultiLayerNetExtend-Klasse in multi_layer_net_extend.py unterstützt Dropout- und Batch-Normalisierung bei der Layer-Generierung, die Grundlagen sind jedoch dieselben wie bei MultiLayerNet.

Teil 9 ← → Teil 11

Recommended Posts

"Deep Learning from Grund" Memo zum Selbststudium (Nr. 9) MultiLayerNet-Klasse
"Deep Learning from Grund" Memo zum Selbststudium (10) MultiLayerNet-Klasse
"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. 11) CNN
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 19) Datenerweiterung
Deep Learning von Grund auf neu
[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 6]
Selbststudien-Memo "Deep Learning from Grund" (Nr. 18) Eins! Miau! Grad-CAM!
Deep Learning / Deep Learning von Grund auf neu Kapitel 7 Memo
Selbststudien-Memo "Deep Learning from Grund" (Nr. 15) TensorFlow-Anfänger-Tutorial
[Lernnotiz] Deep Learning von Grund auf neu gemacht [~ Kapitel 4]
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
Deep Learning von Grund auf neu Kapitel 2 Perceptron (Memo lesen)
Deep Learning von Grund auf 1-3 Kapitel
Deep Learning / Deep Learning von Grund auf neu Kapitel 3 Memo
Deep Learning / Deep Learning von Null 2 Kapitel 5 Memo
Tiefes Lernen von Grund auf neu (Kostenberechnung)
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 Memo von Grund auf neu gemacht
Deep Learning / Deep Learning von Null 2 Kapitel 6 Memo
"Deep Learning from Grund" Memo zum Selbststudium (Nr. 17) Ich habe versucht, DeepConvNet mit Keras zu erstellen
Tiefes Lernen von Grund auf neu (Vorwärtsausbreitung)
Tiefes Lernen / Tiefes Lernen von Grund auf 2-Versuchen Sie, GRU zu bewegen
"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 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
Python-Klasse (Python-Lernnotiz ⑦)
Deep Learning von Grund auf neu ① Kapitel 6 "Lerntechniken"
Python vs Ruby "Deep Learning von Grund auf neu" Zusammenfassung
[Deep Learning von Grund auf neu] Ich habe die Affine-Ebene implementiert
Anwendung von Deep Learning 2 von Grund auf neu Spam-Filter
Ich habe versucht, Dropout zu erklären
Deep Learning / LSTM Scratch Code
[Deep Learning von Grund auf neu] Implementierung der Momentum-Methode und der AdaGrad-Methode
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
Erstellen Sie mit Docker eine Umgebung für "Deep Learning von Grund auf neu"
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 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 2
Ich habe versucht, Perceptron Teil 1 [Deep Learning von Grund auf neu] zu implementieren.
Ein Memo bei der Ausführung des Beispielcodes von Deep Learning, der mit Google Colaboratory von Grund auf neu erstellt wurde
Deep Learning Tutorial aus dem Umgebungsbau
[Deep Learning von Grund auf neu] Methoden zur Aktualisierung der wichtigsten Parameter für neuronale Netze
Lua-Version Deep Learning von Grund auf neu Teil 6 [Inferenzverarbeitung für neuronale Netze]
Warum ModuleNotFoundError: In "Deep Learning from Grund" wird kein Modul mit dem Namen "didaset.mnist" angezeigt.
Schreiben Sie Ihre Eindrücke von der Deep Learning 3 Framework Edition, die von Grund auf neu erstellt wurde