Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen Implementierung der Backpropagation | Neural Network von Grund Auf
Einführung in Neuronale Netze

bookImplementierung der Backpropagation

Allgemeiner Ansatz

Bei der Vorwärtspropagation nimmt jede Schicht ll die Ausgaben der vorherigen Schicht, al1a^{l-1}, als Eingaben und berechnet ihre eigenen Ausgaben. Daher nimmt die Methode forward() der Klasse Layer den Vektor der vorherigen Ausgaben als einzigen Parameter, während die restlichen benötigten Informationen innerhalb der Klasse gespeichert werden.

Bei der Rückwärtspropagation benötigt jede Schicht ll nur dalda^l, um die jeweiligen Gradienten zu berechnen und dal1da^{l-1} zurückzugeben. Die Methode backward() nimmt daher den Vektor dalda^l als Parameter. Die übrigen erforderlichen Informationen sind bereits in der Klasse Layer gespeichert.

Ableitungen von Aktivierungsfunktionen

Da für die Rückwärtspropagation Ableitungen von Aktivierungsfunktionen benötigt werden, sollten Aktivierungsfunktionen wie ReLU und Sigmoid als Klassen und nicht als eigenständige Funktionen strukturiert werden. Dadurch können wir sowohl:

  1. Die Aktivierungsfunktion selbst (implementiert über die Methode __call__()), sodass sie direkt in der Klasse Layer mit self.activation(z) angewendet werden kann;
  2. Ihre Ableitung (implementiert über die Methode derivative()), was eine effiziente Rückwärtspropagation ermöglicht und in der Klasse Layer als self.activation.derivative(z) verwendet wird.

Durch die Strukturierung von Aktivierungsfunktionen als Objekte können wir sie einfach an die Klasse Layer übergeben und dynamisch verwenden.

ReLU

Die Ableitung der ReLU-Aktivierungsfunktion ist wie folgt, wobei ziz_i ein Element des Vektors der Voraktivierungen zz ist:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Sigmoid

Die Ableitung der Sigmoid-Aktivierungsfunktion ist wie folgt:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Für beide dieser Aktivierungsfunktionen wenden wir sie auf den gesamten Vektor zz an, ebenso wie deren Ableitungen. NumPy führt die Operation intern für jedes Element des Vektors aus. Wenn zum Beispiel der Vektor zz 3 Elemente enthält, ergibt sich die Ableitung wie folgt:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} ) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

Die backward()-Methode

Die Methode backward() ist zuständig für die Berechnung der Gradienten anhand der folgenden Formeln:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} und zlz^l werden in der Klasse inputs als die Attribute outputs bzw. Layer gespeichert. Die Aktivierungsfunktion ff wird als Attribut activation gespeichert.

Sobald alle erforderlichen Gradienten berechnet wurden, können Gewichte und Biases aktualisiert werden, da sie für weitere Berechnungen nicht mehr benötigt werden:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Daher ist learning_rate (α\alpha) ein weiterer Parameter dieser Methode.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Hinweis

Der Operator * führt eine elementweise Multiplikation durch, während die Funktion np.dot() das Skalarprodukt in NumPy berechnet. Das Attribut .T transponiert ein Array.

question mark

Welche der folgenden Aussagen beschreibt die Rolle der Methode backward() in der Klasse Layer während der Backpropagation am besten?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 2. Kapitel 8

Fragen Sie AI

expand

Fragen Sie AI

ChatGPT

Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen

Awesome!

Completion rate improved to 4

bookImplementierung der Backpropagation

Swipe um das Menü anzuzeigen

Allgemeiner Ansatz

Bei der Vorwärtspropagation nimmt jede Schicht ll die Ausgaben der vorherigen Schicht, al1a^{l-1}, als Eingaben und berechnet ihre eigenen Ausgaben. Daher nimmt die Methode forward() der Klasse Layer den Vektor der vorherigen Ausgaben als einzigen Parameter, während die restlichen benötigten Informationen innerhalb der Klasse gespeichert werden.

Bei der Rückwärtspropagation benötigt jede Schicht ll nur dalda^l, um die jeweiligen Gradienten zu berechnen und dal1da^{l-1} zurückzugeben. Die Methode backward() nimmt daher den Vektor dalda^l als Parameter. Die übrigen erforderlichen Informationen sind bereits in der Klasse Layer gespeichert.

Ableitungen von Aktivierungsfunktionen

Da für die Rückwärtspropagation Ableitungen von Aktivierungsfunktionen benötigt werden, sollten Aktivierungsfunktionen wie ReLU und Sigmoid als Klassen und nicht als eigenständige Funktionen strukturiert werden. Dadurch können wir sowohl:

  1. Die Aktivierungsfunktion selbst (implementiert über die Methode __call__()), sodass sie direkt in der Klasse Layer mit self.activation(z) angewendet werden kann;
  2. Ihre Ableitung (implementiert über die Methode derivative()), was eine effiziente Rückwärtspropagation ermöglicht und in der Klasse Layer als self.activation.derivative(z) verwendet wird.

Durch die Strukturierung von Aktivierungsfunktionen als Objekte können wir sie einfach an die Klasse Layer übergeben und dynamisch verwenden.

ReLU

Die Ableitung der ReLU-Aktivierungsfunktion ist wie folgt, wobei ziz_i ein Element des Vektors der Voraktivierungen zz ist:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Sigmoid

Die Ableitung der Sigmoid-Aktivierungsfunktion ist wie folgt:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Für beide dieser Aktivierungsfunktionen wenden wir sie auf den gesamten Vektor zz an, ebenso wie deren Ableitungen. NumPy führt die Operation intern für jedes Element des Vektors aus. Wenn zum Beispiel der Vektor zz 3 Elemente enthält, ergibt sich die Ableitung wie folgt:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} ) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

Die backward()-Methode

Die Methode backward() ist zuständig für die Berechnung der Gradienten anhand der folgenden Formeln:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} und zlz^l werden in der Klasse inputs als die Attribute outputs bzw. Layer gespeichert. Die Aktivierungsfunktion ff wird als Attribut activation gespeichert.

Sobald alle erforderlichen Gradienten berechnet wurden, können Gewichte und Biases aktualisiert werden, da sie für weitere Berechnungen nicht mehr benötigt werden:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Daher ist learning_rate (α\alpha) ein weiterer Parameter dieser Methode.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Hinweis

Der Operator * führt eine elementweise Multiplikation durch, während die Funktion np.dot() das Skalarprodukt in NumPy berechnet. Das Attribut .T transponiert ein Array.

question mark

Welche der folgenden Aussagen beschreibt die Rolle der Methode backward() in der Klasse Layer während der Backpropagation am besten?

Select the correct answer

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 2. Kapitel 8
some-alt