Implementazione della Retropropagazione
Approccio Generale
Nella propagazione in avanti, ogni livello l prende come input le uscite del livello precedente, al−1, e calcola le proprie uscite. Pertanto, il metodo forward() della classe Layer accetta come unico parametro il vettore delle uscite precedenti, mentre le altre informazioni necessarie sono memorizzate all'interno della classe.
Nella propagazione all'indietro, ogni livello l necessita solo di dal per calcolare i rispettivi gradienti e restituire dal−1, quindi il metodo backward() prende come parametro il vettore dal. Il resto delle informazioni richieste è già memorizzato nella classe Layer.
Derivate delle Funzioni di Attivazione
Poiché le derivate delle funzioni di attivazione sono necessarie per la retropropagazione, funzioni di attivazione come ReLU e sigmoide dovrebbero essere implementate come classi invece che come funzioni standalone. Questa struttura consente di definire chiaramente entrambe le componenti:
- La funzione di attivazione stessa — implementata tramite il metodo
__call__(), così da poter essere applicata direttamente nella classeLayerconself.activation(z); - La sua derivata — implementata tramite il metodo
derivative(), permettendo un calcolo efficiente durante la retropropagazione tramiteself.activation.derivative(z).
Rappresentare le funzioni di attivazione come oggetti facilita il loro passaggio ai diversi livelli e la loro applicazione dinamica sia durante la propagazione in avanti che all'indietro.
ReLU
La derivata della funzione di attivazione ReLU è la seguente, dove zi è un elemento del vettore delle pre-attivazioni 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)
Sigmoide
La derivata della funzione di attivazione sigmoide è la seguente:
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)
Per entrambe le funzioni di attivazione, l'operazione viene applicata all'intero vettore z, così come alla sua derivata. NumPy esegue automaticamente il calcolo element-wise, ovvero ogni elemento del vettore viene elaborato indipendentemente.
Ad esempio, se il vettore z contiene tre elementi, la derivata viene calcolata come:
f′(z)=f′z1z2z3=f′(z1)f′(z2)f′(z3)Il metodo backward()
Il metodo backward() è responsabile del calcolo dei gradienti utilizzando le seguenti formule:
a^{l-1} e zl sono memorizzati rispettivamente come attributi inputs e outputs nella classe Layer. La funzione di attivazione f è memorizzata come attributo activation.
Una volta calcolati tutti i gradienti necessari, pesi e bias possono essere aggiornati poiché non sono più necessari per ulteriori calcoli:
Wlbl=Wl−α⋅dWl=bl−α⋅dblPertanto, learning_rate (α) è un altro parametro di questo metodo.
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
L'operatore * esegue la moltiplicazione elemento per elemento, mentre la funzione np.dot() esegue il prodotto scalare in NumPy. L'attributo .T trasporta (traspone) un array.
Grazie per i tuoi commenti!
Chieda ad AI
Chieda ad AI
Chieda pure quello che desidera o provi una delle domande suggerite per iniziare la nostra conversazione
Awesome!
Completion rate improved to 4
Implementazione della Retropropagazione
Scorri per mostrare il menu
Approccio Generale
Nella propagazione in avanti, ogni livello l prende come input le uscite del livello precedente, al−1, e calcola le proprie uscite. Pertanto, il metodo forward() della classe Layer accetta come unico parametro il vettore delle uscite precedenti, mentre le altre informazioni necessarie sono memorizzate all'interno della classe.
Nella propagazione all'indietro, ogni livello l necessita solo di dal per calcolare i rispettivi gradienti e restituire dal−1, quindi il metodo backward() prende come parametro il vettore dal. Il resto delle informazioni richieste è già memorizzato nella classe Layer.
Derivate delle Funzioni di Attivazione
Poiché le derivate delle funzioni di attivazione sono necessarie per la retropropagazione, funzioni di attivazione come ReLU e sigmoide dovrebbero essere implementate come classi invece che come funzioni standalone. Questa struttura consente di definire chiaramente entrambe le componenti:
- La funzione di attivazione stessa — implementata tramite il metodo
__call__(), così da poter essere applicata direttamente nella classeLayerconself.activation(z); - La sua derivata — implementata tramite il metodo
derivative(), permettendo un calcolo efficiente durante la retropropagazione tramiteself.activation.derivative(z).
Rappresentare le funzioni di attivazione come oggetti facilita il loro passaggio ai diversi livelli e la loro applicazione dinamica sia durante la propagazione in avanti che all'indietro.
ReLU
La derivata della funzione di attivazione ReLU è la seguente, dove zi è un elemento del vettore delle pre-attivazioni 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)
Sigmoide
La derivata della funzione di attivazione sigmoide è la seguente:
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)
Per entrambe le funzioni di attivazione, l'operazione viene applicata all'intero vettore z, così come alla sua derivata. NumPy esegue automaticamente il calcolo element-wise, ovvero ogni elemento del vettore viene elaborato indipendentemente.
Ad esempio, se il vettore z contiene tre elementi, la derivata viene calcolata come:
f′(z)=f′z1z2z3=f′(z1)f′(z2)f′(z3)Il metodo backward()
Il metodo backward() è responsabile del calcolo dei gradienti utilizzando le seguenti formule:
a^{l-1} e zl sono memorizzati rispettivamente come attributi inputs e outputs nella classe Layer. La funzione di attivazione f è memorizzata come attributo activation.
Una volta calcolati tutti i gradienti necessari, pesi e bias possono essere aggiornati poiché non sono più necessari per ulteriori calcoli:
Wlbl=Wl−α⋅dWl=bl−α⋅dblPertanto, learning_rate (α) è un altro parametro di questo metodo.
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
L'operatore * esegue la moltiplicazione elemento per elemento, mentre la funzione np.dot() esegue il prodotto scalare in NumPy. L'attributo .T trasporta (traspone) un array.
Grazie per i tuoi commenti!