Implementering av Backpropagation
Allmän metod
Vid framåtriktad spridning tar varje lager l utdata från föregående lager, al−1, som indata och beräknar sina egna utdata. Därför tar metoden forward()
i klassen Layer
vektorn av föregående utdata som sin enda parameter, medan övrig nödvändig information lagras inom klassen.
Vid bakåtriktad spridning behöver varje lager l endast dal för att beräkna respektive gradienter och returnera dal−1, så metoden backward()
tar vektorn dal som sin parameter. Övrig nödvändig information är redan lagrad i klassen Layer
.
Derivator av aktiveringsfunktioner
Eftersom derivator av aktiveringsfunktioner behövs för bakåtriktad spridning, bör aktiveringsfunktioner som ReLU och sigmoid struktureras som klasser istället för fristående funktioner. Detta gör det möjligt att definiera både:
- Själva aktiveringsfunktionen (implementerad via metoden
__call__()
), vilket möjliggör direkt användning i klassenLayer
medself.activation(z)
; - Dess derivata (implementerad via metoden
derivative()
), vilket möjliggör effektiv bakåtriktad spridning och används i klassenLayer
somself.activation.derivative(z)
.
Genom att strukturera aktiveringsfunktioner som objekt kan de enkelt överföras till klassen Layer
och användas dynamiskt.
ReLu
Derivatan av ReLU-aktiveringsfunktionen är följande, där zi är ett element i vektorn av pre-aktiveringar z:
f′(zi)={1,zi>00,zi≤0class ReLU:
def __call__(self, z):
return np.maximum(0, z)
def derivative(self, z):
return (z > 0).astype(float)
Sigmoid
Derivatan av sigmoidaktiveringsfunktionen är följande:
f′(zi)=f(zi)⋅(1−f(zi))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 båda dessa aktiveringsfunktioner tillämpar vi dem på hela vektorn z, och detsamma gäller för deras derivator. NumPy tillämpar internt operationen på varje element i vektorn. Till exempel, om vektorn z innehåller 3 element, är derivatan enligt följande:
f′(z)=f′(z1z2z3)=f′(z1)f′(z2)f′(z3)backward()-metoden
Metoden backward()
ansvarar för beräkning av gradienter med hjälp av formlerna nedan:
a^{l-1} och zl lagras som attributen inputs
respektive outputs
i klassen Layer
. Aktiveringsfunktionen f lagras som attributet activation
.
När alla nödvändiga gradienter har beräknats kan vikter och bias uppdateras eftersom de inte längre behövs för ytterligare beräkningar:
Wlbl=Wl−α⋅dWl=bl−α⋅dblDärför är learning_rate
(α) en annan parameter för denna metod.
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
*
-operatorn utför elementvis multiplikation, medan funktionen np.dot()
utför skalärprodukt i NumPy. Attributet .T
transponerar en array.
Tack för dina kommentarer!
Fråga AI
Fråga AI
Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal
Awesome!
Completion rate improved to 4
Implementering av Backpropagation
Svep för att visa menyn
Allmän metod
Vid framåtriktad spridning tar varje lager l utdata från föregående lager, al−1, som indata och beräknar sina egna utdata. Därför tar metoden forward()
i klassen Layer
vektorn av föregående utdata som sin enda parameter, medan övrig nödvändig information lagras inom klassen.
Vid bakåtriktad spridning behöver varje lager l endast dal för att beräkna respektive gradienter och returnera dal−1, så metoden backward()
tar vektorn dal som sin parameter. Övrig nödvändig information är redan lagrad i klassen Layer
.
Derivator av aktiveringsfunktioner
Eftersom derivator av aktiveringsfunktioner behövs för bakåtriktad spridning, bör aktiveringsfunktioner som ReLU och sigmoid struktureras som klasser istället för fristående funktioner. Detta gör det möjligt att definiera både:
- Själva aktiveringsfunktionen (implementerad via metoden
__call__()
), vilket möjliggör direkt användning i klassenLayer
medself.activation(z)
; - Dess derivata (implementerad via metoden
derivative()
), vilket möjliggör effektiv bakåtriktad spridning och används i klassenLayer
somself.activation.derivative(z)
.
Genom att strukturera aktiveringsfunktioner som objekt kan de enkelt överföras till klassen Layer
och användas dynamiskt.
ReLu
Derivatan av ReLU-aktiveringsfunktionen är följande, där zi är ett element i vektorn av pre-aktiveringar z:
f′(zi)={1,zi>00,zi≤0class ReLU:
def __call__(self, z):
return np.maximum(0, z)
def derivative(self, z):
return (z > 0).astype(float)
Sigmoid
Derivatan av sigmoidaktiveringsfunktionen är följande:
f′(zi)=f(zi)⋅(1−f(zi))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 båda dessa aktiveringsfunktioner tillämpar vi dem på hela vektorn z, och detsamma gäller för deras derivator. NumPy tillämpar internt operationen på varje element i vektorn. Till exempel, om vektorn z innehåller 3 element, är derivatan enligt följande:
f′(z)=f′(z1z2z3)=f′(z1)f′(z2)f′(z3)backward()-metoden
Metoden backward()
ansvarar för beräkning av gradienter med hjälp av formlerna nedan:
a^{l-1} och zl lagras som attributen inputs
respektive outputs
i klassen Layer
. Aktiveringsfunktionen f lagras som attributet activation
.
När alla nödvändiga gradienter har beräknats kan vikter och bias uppdateras eftersom de inte längre behövs för ytterligare beräkningar:
Wlbl=Wl−α⋅dWl=bl−α⋅dblDärför är learning_rate
(α) en annan parameter för denna metod.
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
*
-operatorn utför elementvis multiplikation, medan funktionen np.dot()
utför skalärprodukt i NumPy. Attributet .T
transponerar en array.
Tack för dina kommentarer!