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 die Ableitungen von Aktivierungsfunktionen für die Rückwärtspropagation benötigt werden, sollten Aktivierungsfunktionen wie ReLU und Sigmoid als Klassen und nicht als eigenständige Funktionen implementiert werden. Diese Struktur ermöglicht es, beide Komponenten klar zu definieren:

  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 Berechnung während der Rückwärtspropagation über self.activation.derivative(z) ermöglicht.

Die Darstellung von Aktivierungsfunktionen als Objekte erleichtert es, sie an verschiedene Schichten zu übergeben und sowohl während der Vorwärts- als auch der Rückwärtspropagation dynamisch anzuwenden.

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 lautet:

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)

Bei beiden Aktivierungsfunktionen wird die Operation auf den gesamten Vektor zz sowie auf dessen Ableitung angewendet. NumPy führt die Berechnung dabei elementweise durch, das heißt, jedes Element des Vektors wird unabhängig voneinander verarbeitet.

Enthält der Vektor zz beispielsweise drei Elemente, wird die Ableitung wie folgt berechnet:

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

Die backward()-Methode

Die Methode backward() ist verantwortlich für das Berechnen 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 benötigten 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

Suggested prompts:

Can you explain how the backward() method uses the stored attributes in the Layer class?

What is the purpose of the derivative() method in the activation function classes?

Could you provide an example of how forward and backward propagation work together in a simple neural network?

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 die Ableitungen von Aktivierungsfunktionen für die Rückwärtspropagation benötigt werden, sollten Aktivierungsfunktionen wie ReLU und Sigmoid als Klassen und nicht als eigenständige Funktionen implementiert werden. Diese Struktur ermöglicht es, beide Komponenten klar zu definieren:

  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 Berechnung während der Rückwärtspropagation über self.activation.derivative(z) ermöglicht.

Die Darstellung von Aktivierungsfunktionen als Objekte erleichtert es, sie an verschiedene Schichten zu übergeben und sowohl während der Vorwärts- als auch der Rückwärtspropagation dynamisch anzuwenden.

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 lautet:

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)

Bei beiden Aktivierungsfunktionen wird die Operation auf den gesamten Vektor zz sowie auf dessen Ableitung angewendet. NumPy führt die Berechnung dabei elementweise durch, das heißt, jedes Element des Vektors wird unabhängig voneinander verarbeitet.

Enthält der Vektor zz beispielsweise drei Elemente, wird die Ableitung wie folgt berechnet:

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

Die backward()-Methode

Die Methode backward() ist verantwortlich für das Berechnen 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 benötigten 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