Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Leer Implementatie van Backpropagation | Neuraal Netwerk Vanaf Nul
Introductie tot Neurale Netwerken

bookImplementatie van Backpropagation

Algemene aanpak

Bij voorwaartse propagatie neemt elke laag ll de uitvoer van de vorige laag, al1a^{l-1}, als invoer en berekent zijn eigen uitvoer. Daarom neemt de forward()-methode van de Layer-klasse de vector van vorige uitkomsten als enige parameter, terwijl de overige benodigde informatie binnen de klasse wordt opgeslagen.

Bij achterwaartse propagatie heeft elke laag ll alleen dalda^l nodig om de respectievelijke gradiënten te berekenen en dal1da^{l-1} terug te geven, dus de backward()-methode neemt de dalda^l-vector als parameter. De overige benodigde informatie is al opgeslagen in de Layer-klasse.

Afgeleiden van activatiefuncties

Omdat de afgeleiden van activatiefuncties vereist zijn voor achterwaartse propagatie, moeten activatiefuncties zoals ReLU en sigmoid als klassen worden geïmplementeerd in plaats van als losse functies. Deze structuur maakt het mogelijk beide componenten duidelijk te definiëren:

  1. De activatiefunctie zelf — geïmplementeerd met de __call__()-methode, zodat deze direct kan worden toegepast in de Layer-klasse met self.activation(z);
  2. De afgeleide ervan — geïmplementeerd met de derivative()-methode, waardoor efficiënte berekening tijdens achterwaartse propagatie mogelijk is via self.activation.derivative(z).

Het representeren van activatiefuncties als objecten maakt het eenvoudig om ze aan verschillende lagen door te geven en dynamisch toe te passen tijdens zowel voorwaartse als achterwaartse propagatie.

ReLu

De afgeleide van de ReLU-activatiefunctie is als volgt, waarbij ziz_i een element is van de vector van pre-activaties zz:

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

De afgeleide van de sigmoid activatiefunctie is als volgt:

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)

Voor beide activatiefuncties wordt de bewerking toegepast op de volledige vector zz, evenals op de afgeleide daarvan. NumPy voert de berekening elementgewijs uit, wat betekent dat elk element van de vector onafhankelijk wordt verwerkt.

Als de vector zz bijvoorbeeld drie elementen bevat, wordt de afgeleide als volgt berekend:

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}

De backward()-methode

De backward()-methode is verantwoordelijk voor het berekenen van de gradiënten met behulp van de onderstaande formules:

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} en zlz^l worden respectievelijk opgeslagen als de attributen inputs en outputs in de Layer-klasse. De activatiefunctie ff wordt opgeslagen als het attribuut activation.

Zodra alle benodigde gradiënten zijn berekend, kunnen de gewichten en biases worden bijgewerkt, aangezien ze niet langer nodig zijn voor verdere berekeningen:

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}

Daarom is learning_rate (α\alpha) een andere parameter van deze 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
Opmerking

De *-operator voert elementgewijze vermenigvuldiging uit, terwijl de functie np.dot() een dotproduct uitvoert in NumPy. Het attribuut .T transponeert een array.

question mark

Welke van de volgende omschrijvingen geeft het beste de rol van de methode backward() in de klasse Layer weer tijdens backpropagation?

Select the correct answer

Was alles duidelijk?

Hoe kunnen we het verbeteren?

Bedankt voor je feedback!

Sectie 2. Hoofdstuk 8

Vraag AI

expand

Vraag AI

ChatGPT

Vraag wat u wilt of probeer een van de voorgestelde vragen om onze chat te starten.

Awesome!

Completion rate improved to 4

bookImplementatie van Backpropagation

Veeg om het menu te tonen

Algemene aanpak

Bij voorwaartse propagatie neemt elke laag ll de uitvoer van de vorige laag, al1a^{l-1}, als invoer en berekent zijn eigen uitvoer. Daarom neemt de forward()-methode van de Layer-klasse de vector van vorige uitkomsten als enige parameter, terwijl de overige benodigde informatie binnen de klasse wordt opgeslagen.

Bij achterwaartse propagatie heeft elke laag ll alleen dalda^l nodig om de respectievelijke gradiënten te berekenen en dal1da^{l-1} terug te geven, dus de backward()-methode neemt de dalda^l-vector als parameter. De overige benodigde informatie is al opgeslagen in de Layer-klasse.

Afgeleiden van activatiefuncties

Omdat de afgeleiden van activatiefuncties vereist zijn voor achterwaartse propagatie, moeten activatiefuncties zoals ReLU en sigmoid als klassen worden geïmplementeerd in plaats van als losse functies. Deze structuur maakt het mogelijk beide componenten duidelijk te definiëren:

  1. De activatiefunctie zelf — geïmplementeerd met de __call__()-methode, zodat deze direct kan worden toegepast in de Layer-klasse met self.activation(z);
  2. De afgeleide ervan — geïmplementeerd met de derivative()-methode, waardoor efficiënte berekening tijdens achterwaartse propagatie mogelijk is via self.activation.derivative(z).

Het representeren van activatiefuncties als objecten maakt het eenvoudig om ze aan verschillende lagen door te geven en dynamisch toe te passen tijdens zowel voorwaartse als achterwaartse propagatie.

ReLu

De afgeleide van de ReLU-activatiefunctie is als volgt, waarbij ziz_i een element is van de vector van pre-activaties zz:

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

De afgeleide van de sigmoid activatiefunctie is als volgt:

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)

Voor beide activatiefuncties wordt de bewerking toegepast op de volledige vector zz, evenals op de afgeleide daarvan. NumPy voert de berekening elementgewijs uit, wat betekent dat elk element van de vector onafhankelijk wordt verwerkt.

Als de vector zz bijvoorbeeld drie elementen bevat, wordt de afgeleide als volgt berekend:

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}

De backward()-methode

De backward()-methode is verantwoordelijk voor het berekenen van de gradiënten met behulp van de onderstaande formules:

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} en zlz^l worden respectievelijk opgeslagen als de attributen inputs en outputs in de Layer-klasse. De activatiefunctie ff wordt opgeslagen als het attribuut activation.

Zodra alle benodigde gradiënten zijn berekend, kunnen de gewichten en biases worden bijgewerkt, aangezien ze niet langer nodig zijn voor verdere berekeningen:

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}

Daarom is learning_rate (α\alpha) een andere parameter van deze 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
Opmerking

De *-operator voert elementgewijze vermenigvuldiging uit, terwijl de functie np.dot() een dotproduct uitvoert in NumPy. Het attribuut .T transponeert een array.

question mark

Welke van de volgende omschrijvingen geeft het beste de rol van de methode backward() in de klasse Layer weer tijdens backpropagation?

Select the correct answer

Was alles duidelijk?

Hoe kunnen we het verbeteren?

Bedankt voor je feedback!

Sectie 2. Hoofdstuk 8
some-alt