Neural Network, Backpropagation

Parte (2/3)

Potrebbe interessarti:

Il progetto Python, che comprende gli script mostrati in questo post, e quelli relativi alla creazione dei grafici Matplotlib e Plotly, è disponibile assieme al corso Introduzione al Machine Learning.

Dimmi di Più

Backpropagation

La “Backpropagation” è l’acronimo di “backward propagation of errors” (propagazione all’indietro degli errori), ed è un modo per regolare i parametri di una rete neurale, per minimizzare l’errore del modello, inteso come la differenza tra l’output previsto, e quello effettivo. Nella fase di Forward Propagation, i dati di input passano attraverso la rete, da un layer all’altro. In ogni layer successivo a quello di input, ogni nodo calcola la somma pesata dei suoi input e dei suoi pesi, e applica al valore risultante una funzione di attivazione, come il sigmoide. Considerando l’architettura di una rete con un singolo hidden layer, vista precedentemente, ogni suo nodo $a^h_j$ ritona una funzione base $\phi_j$, che corrisponde ad un asse base di un nuovo spazio delle feature multidimensionale, non-lineare, che “piega e deforma” lo spazio delle feature originale. Nel nuovo spazio risultante, le osservazioni del dataset diventano linearmente separabili. Le diverse funzioni base definite dall’hidden layer vengono linearmente combinate tra loro dall’output node $a^o_1$, che ritorna, tramite l’applicazione della funzione sigmoide, la probabilità che l’osservazione di input appartenga alla classe positiva, “1”. L’output finale della rete viene confrontato con l’output previsto, utilizzando una funzione di costo come la logistic loss, che indica quanto è sbagliata la previsione effettuata dal modello.

A questo punto entra in gioco la fase di Backpropagation. Partendo dall’output layer, calcoliamo quanto ogni parametro della rete abbia contribuito all’errore definito dalla funzione di costo. Matematicamente, questo processo viene fatto utilizzando la chain rule del calcolo, una regola che permette di stimare la derivata di una composizione di funzioni, sotto forma di prodotti e derivazioni concatenate. Essa consente di determinare le derivate parziali della funzione di costo, rispetto a ciascun peso e bias del modello. Questi gradienti vengono poi propagati a ritroso attraverso la rete. Ciò significa che ci muoviamo all’indietro, dall’output layer, fino al layer precedente a quello di input, per calcolare i gradienti di ogni parametro di questi layer. Calcolati tutti i gradienti, utilizziamo tali valori per aggiornare i parametri del modello, con un algoritmo di ottimizzazione come la discesa del gradiente. Ogni gradiente indica la pendenza della funzione di costo rispetto a un certo parametro, e, in relazione a tale parametro, mostra la direzione da seguire per scendere più velocemente verso il minimo di tale funzione.

Semplificando, possiamo pensare ad una rete neurale con un errore di apprendimento1 come ad un apparecchio con problemi di funzionamento. Ciascun gradiente è una “diagnosi” di ogni singolo componente del macchinario, che ci permette di capire come “aggiustare” quella particolare parte. Riparando tutti i suoi pezzi, ritorniamo ad avere l’apparecchio funzionante.

Chain Rule

La Chain Rule ci aiuta a calcolare la derivata di una funzione composta da altre funzioni. Infatti, la Chain Rule afferma che la derivata di una composizione di funzioni è il prodotto delle derivate di tutte le funzioni di questa composizione. Più precisamente, utilizzando la notazione di Leibniz, se le funzioni $f$ e $g$ sono differenziabili, allora:

$$ \require{physics} \begin{align} \dv{f(g(x))}{x} & = \dv{f(g(x))}{g(x)} \cdot \dv{g(x)}{x} \label{chain-1}\tag{1}\\[6pt] \end{align} $$

oppure

$$ \begin{align} \dv{f(g(x))}{x} & = \dv{f}{g} \cdot \dv{g}{x} \label{chain-2}\tag{2}\\[6pt] \end{align} $$

Allo stesso modo, possiamo usare la Chain Rule per una composizione di funzioni arbitrariamente lunga. Ad esempio:

$$ \begin{align} \dv{f(g(h(u(v(x)))))}{x} & = \dv{f}{g} \cdot \dv{g}{h} \cdot \dv{h}{u} \cdot \dv{u}{v} \cdot \dv{v}{x} \label{chain-3}\tag{3}\\[6pt] \end{align} $$

Supponiamo di avere una funzione come:

$$ \begin{align} h(x) & = 3(2x^2)^5\\[6pt] \end{align} $$

Possiamo definire $h(x)$ come la composizione di due funzioni più semplici:

$$ \begin{align} h(x) & = f(g(x))\\[6pt] f(x) & = 3g(x)^5\\[6pt] g(x) & = 2x^2\\[6pt] \end{align} $$

Quindi:

$$ \begin{align} \dv{h(x)}{x} & = \dv{f(g(x))}{x} = \dv{f(g(x))}{g(x)} \cdot \dv{g(x)}{x}\\[6pt] & = \dv{3g(x)^5}{g(x)} \cdot \dv{2x^2}{x}\\[6pt] & = 15g(x)^4 \cdot 4x\\[6pt] \end{align} $$

Chain Rule Multivariabile

Se abbiamo una composizione di funzioni con più variabili, come $g(y, h)$, e $h(x, z)$, applichiamo la Chain Rule multivariabile. Invece di usare le derivate, dobbiamo usare le derivate parziali, perché vogliamo sapere come cambia una data funzione, rispetto a ogni suo singolo parametro, mantenendo tutti gli altri parametri costanti. Tramite la Chain Rule multivariabile, processiamo le derivate parziali, da quella più esterna a quella più interna, includendo solo i percorsi che passano attraverso la variabile indipendente, $x$. Ad esempio:

$$ \begin{align} \pdv{f(g(y, h(x, z)))}{x} & = \pdv{f(g(y, h(x, z)))}{g(y, h(x, z))} \cdot \pdv{g(y, h(x, z))}{h(x, z)} \cdot \pdv{h(x, z)}{x}\\[6pt] \end{align} $$

In questo esempio, quando calcoliamo la derivata parziale di $g(y, h(x, z))$, lo facciamo rispetto a $h(x, z)$ e non a $y$, in quanto $h(x, z)$ è in funzione di $x$, mentre $y$ viene trattata come costante - e il concetto di derivata rispetto ad una costante non ha senso. Lo stesso accade per $h(x, z)$.

Chain Rule e Backpropagation

Nei diagrammi seguenti, mostriamo la composizione di funzioni usata nella fase di forward, e le derivate parziali della stessa, utilizzate nella fase di backpropagation. Per semplicità, per ora consideriamo solo i pesi, $w$, ed escludiamo i parametri bias, $b$. All’interno di ogni nodo della rete, indichiamo le singole funzioni applicate: la somma pesata, $z$, e la funzione di attivazione, $a$. Ripensando alla fase di forward propagation, abbiamo visto come l’output della rete, $\text{out}$, sia definito come una composizione di funzioni. Considerando lo schema di esempio sottostante, abbiamo:

Diagramma della fase di Forward Propagation
Figura 1: Fase di Forward Propagation
$$ \begin{align} \text{out} & = a^o_1\left( z^o_1\left( a^h_1 \left( z^h_1\left(x_1, w^h_{1,1}\right) \right), w^o_{1,1} \right) \right)\\[6pt] \text{loss} & = L\left(y, \text{out}\right)\\[6pt] & = L\left(y, a^o_1\left( z^o_1\left( a^h_1 \left( z^h_1\left(x_1, w^h_{1,1}\right) \right), w^o_{1,1} \right) \right) \right)\\[6pt] \end{align} $$

Quindi, nell’output layer, per calcolare la derivata parziale di $L$ rispetto al parametro $w^o_{1,1}$, possiamo usare la Chain Rule e indicare:

Diagramma della fase di Backpropagation, considerando l'Output Layer
Figura 2: Fase di Backpropagation #1
$$ \begin{align} \pdv{L}{w^o_{1,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{w^o_{1,1}}\\[6pt] \end{align} $$

Nell’hidden layer, per calcolare la derivata parziale di $L$ rispetto al parametro $w^h_{1,1}$, abbiamo:

Diagramma della fase di Backpropagation, considerando l'Output e l'Hidden Layer
Figura 3: Fase di Backpropagation #2
$$ \begin{align} \pdv{L}{w^h_{1,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,1}}\\[6pt] \end{align} $$

Con la chain rule, il calcolo del gradiente per ogni parametro della rete viene suddiviso in derivate locali, più facili da calcolare, rispetto ad un’unica derivata, che può diventare molto complessa (o non risolvibile analiticamente), quando le reti diventano più profonde. Oltre a questo, la backpropagation permette di suddividere il calcolo finale in risultati intermedi, che possono essere riutilizzati per migliorare le performance del modello. Detto questo, vediamo come calcolare il gradiente della funzione di costo nell’output layer e nell’hidden layer.

Backpropagation nell’Output Layer

Calcolo del Gradiente Rispetto ai Pesi

Utilizzando una rete a singolo layer con due nodi per layer, calcoliamo le derivate parziali della funzione di costo, $L$, rispetto ad ogni peso $w^o_{t,s}$ dell’output layer (lo stesso procedimento dovrà essere fatto per i parametri di bias, $b^o_t$). Vedremo poi come esprimere le equazioni risultanti in forma vettorizzata, mediante matrici, e generalizzarle per reti con più hidden layer, con più nodi per layer:

Calcolo della Derivata Parziale di L rispetto a $w^o_{1,1}$
Figura 4: Derivata Parziale di L rispetto a $w^o_{1,1}$
$$ \begin{align} \pdv{L}{w^o_{1,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{w^o_{1,1}}\\[6pt] \end{align} $$


Calcolo della Derivata Parziale di L rispetto a $w^o_{1,2}$
Figura 5: Derivata Parziale di L rispetto a $w^o_{1,2}$
$$ \begin{align} \pdv{L}{w^o_{1,2}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{w^o_{1,2}}\\[6pt] \end{align} $$


Calcolo della Derivata Parziale di L rispetto a $w^o_{2,1}$
Figura 6: Derivata Parziale di L rispetto a $w^o_{2,1}$
$$ \begin{align} \pdv{L}{w^o_{2,1}} & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{w^o_{2,1}}\\[6pt] \end{align} $$


Calcolo della Derivata Parziale di L rispetto a $w^o_{2,2}$
Figura 7: Derivata Parziale di L rispetto a $w^o_{2,2}$
$$ \begin{align} \pdv{L}{w^o_{2,2}} & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{w^o_{2,2}}\\[6pt] \end{align} $$


Riassumendo:

$$ \begin{align} \pdv{L}{w^o_{1,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{w^o_{1,1}}\\[6pt] \pdv{L}{w^o_{1,2}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{w^o_{1,2}}\\[6pt] \pdv{L}{w^o_{2,1}} & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{w^o_{2,1}}\\[6pt] \pdv{L}{w^o_{2,2}} & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{w^o_{2,2}}\\[6pt] \end{align} $$

Possiamo semplificare le precedenti equazioni definendo i termini $d^o_j$, che rappresentano le derivata parziali “di output” dei nodi dell’output layer, $a^o_j$, considerando il verso contrario del processo di backpropagation:

$$ \begin{align} d^o_1 & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1}\\[6pt] d^o_2 & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2}\\[6pt] \end{align} $$

Quindi:

$$ \begin{align} \pdv{L}{w^o_{1,1}} & = d^o_1 \cdot \pdv{z^o_1}{w^o_{1,1}}\\[6pt] \pdv{L}{w^o_{1,2}} & = d^o_1 \cdot \pdv{z^o_1}{w^o_{1,2}}\\[6pt] \pdv{L}{w^o_{2,1}} & = d^o_2 \cdot \pdv{z^o_2}{w^o_{2,1}}\\[6pt] \pdv{L}{w^o_{2,2}} & = d^o_2 \cdot \pdv{z^o_2}{w^o_{2,2}}\\[6pt] \end{align} $$

Notiamo inoltre che:

$$ \begin{align} \pdv{z^o_1}{w^o_{1,1}} & = \pdv{}{w^o_{1,1}}\left(a^h_1 \cdot w^o_{1,1} + a^h_2 \cdot w^o_{1,2} + b^o_1\right) = a^h_1\\[6pt] \pdv{z^o_1}{w^o_{1,2}} & = \pdv{}{w^o_{1,2}}\left(a^h_1 \cdot w^o_{1,1} + a^h_2 \cdot w^o_{1,2} + b^o_1\right) = a^h_2\\[6pt] \pdv{z^o_2}{w^o_{2,1}} & = \pdv{}{w^o_{2,1}}\left(a^h_1 \cdot w^o_{2,1} + a^h_2 \cdot w^o_{2,2} + b^o_2\right) = a^h_1\\[6pt] \pdv{z^o_2}{w^o_{2,2}} & = \pdv{}{w^o_{2,2}}\left(a^h_1 \cdot w^o_{2,1} + a^h_2 \cdot w^o_{2,2} + b^o_2\right) = a^h_2\\[6pt] \end{align} $$

Semplificando ulteriormente:

$$ \begin{align} \pdv{L}{w^o_{1,1}} & = d^o_1 \cdot a^h_1\\[6pt] \pdv{L}{w^o_{1,2}} & = d^o_1 \cdot a^h_2\\[6pt] \pdv{L}{w^o_{2,1}} & = d^o_2 \cdot a^h_1\\[6pt] \pdv{L}{w^o_{2,2}} & = d^o_2 \cdot a^h_2\\[6pt] \end{align} $$

Possiamo esprimere le equazioni risultanti in forma vettorizzata, mediante matrici, in questo modo:

$$ \begin{align} \mathbf{d}^o & = \begin{bmatrix} d^o_1\\[6pt] d^o_2\\[6pt] \end{bmatrix} = \begin{bmatrix} \pdv{L}{a^o_1}\\[6pt] \pdv{L}{a^o_2}\\[6pt] \end{bmatrix} \odot \begin{bmatrix} \pdv{a^o_1}{z^o_1}\\[6pt] \pdv{a^o_2}{z^o_2}\\[6pt] \end{bmatrix}\\[6pt] \pdv{L}{\mathbf{W}^o} & = \begin{bmatrix} d^o_1\\[6pt] d^o_2\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} a^h_1 & a^h_2\\[6pt] \end{bmatrix} \end{align} $$

dove $\odot$ è il prodotto di Hadamard, un’operazione che moltiplica gli elementi corrispondenti tra due matrici o vettori, e restitusice una matrice o un vettore della stessa dimensione.

Generalizzazione

Generalizzando, per una singola osservazione di input, $\mathbf{x}^{(i)}$, per un output layer di $n_o$ nodi (o classi), preceduto da un hidden layer di $n_h$ nodi, abbiamo:

$$ \begin{align} \mathbf{d}^o & = \begin{bmatrix} d^o_1\\[6pt] d^o_2\\[6pt] \vdots\\[6pt] d^o_{n_o}\\[6pt] \end{bmatrix} = \begin{bmatrix} \pdv{L}{a^o_1}\\[6pt] \pdv{L}{a^o_2}\\[6pt] \vdots\\[6pt] \pdv{L}{a^o_{n_o}}\\[6pt] \end{bmatrix} \odot \begin{bmatrix} \pdv{a^o_1}{z^o_1}\\[6pt] \pdv{a^o_2}{z^o_2}\\[6pt] \vdots\\[6pt] \pdv{a^o_{n_o}}{z^o_{n_o}}\\[6pt] \end{bmatrix} = \pdv{L}{\mathbf{a}^o} \odot \pdv{\mathbf{a}^o}{\mathbf{z}^o}\\[12pt] \pdv{L}{\mathbf{W}^o} & = \begin{bmatrix} d^o_1\\[6pt] d^o_2\\[6pt] \vdots\\[6pt] d^o_{n_o} \end{bmatrix} \cdot \begin{bmatrix} a^h_1 & a^h_2 & \cdots & a^h_{n_h}\\[6pt] \end{bmatrix} = \mathbf{d}^o \cdot \left(\mathbf{a}^h\right)^\intercal \end{align} $$

Per osservazioni multiple, consideriamo invece le matrici $\pdv{L}{\mathbf{A}^o}$ e $\pdv{\mathbf{A}^o}{\mathbf{Z}^o}$, entrambe di dimensione $m \times n_o$. Definiamo quindi la matrice $\mathbf{D}^o$ di dimensione $m \times n_o$, come:

$$ \begin{align} \mathbf{D}^o & = \begin{bmatrix} d^{o(1)}_1 & d^{o(1)}_2 & \dots & d^{o(1)}_{n_o}\\[6pt] d^{o(2)}_1 & d^{o(2)}_2 & \dots & d^{o(2)}_{n_o}\\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] d^{o(m)}_1 & d^{o(m)}_2 & \dots & d^{o(m)}_{n_o}\\[6pt] \end{bmatrix} = \pdv{L}{\mathbf{A}^o} \odot \pdv{\mathbf{A}^o}{\mathbf{Z}^o} \end{align} $$

Il gradiente $\pdv{L}{\mathbf{W}^o}$ viene calcolato come la somma dei gradienti per ogni osservazione del dataset, ed è definito da una matrice di dimensione $n_o \times n_h$:

$$ \begin{align} \pdv{L}{\mathbf{W}^o} & = \begin{bmatrix} d^{o(1)}_1 & d^{o(2)}_1 & \cdots & d^{o(m)}_1 \\[6pt] d^{o(1)}_2 & d^{o(2)}_2 & \cdots & d^{o(m)}_2 \\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] d^{o(1)}_{n_o} & d^{o(2)}_{n_o} & \cdots & d^{o(m)}_{n_o}\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} a^{h(1)}_1 & a^{h(1)}_2 & \dots & a^{h(1)}_{n_h}\\[6pt] a^{h(2)}_1 & a^{h(2)}_2 & \dots & a^{h(2)}_{n_h}\\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] a^{h(m)}_1 & a^{h(m)}_2 & \dots & a^{h(m)}_{n_h}\\[6pt] \end{bmatrix} = \left(\mathbf{D}^o\right)^\intercal \cdot \mathbf{A}^h\\[6pt] \end{align} $$

Questo accade in quanto ciascuna osservazione di input contribuisce al costo totale del modello. Quindi, durante la fase di backpropagation, per un certo peso $w^o_{t,s}$, calcoliamo il gradiente di ciascuna delle $m$ osservazioni, e sommiamo tali valori tra di loro. Ad esempio:

$$ \begin{align} \pdv{L}{w^o_{1,1}} & = d^{o(1)}_1 \cdot a^{h(1)}_1 + d^{o(2)}_1 \cdot a^{h(2)}_1 + \cdots + d^{o(m)}_1 \cdot a^{h(m)}_1 \end{align} $$

Calcolo del Gradiente Rispetto ai Bias

Con lo stesso procedimento, calcoliamo il gradiente della funzione di costo rispetto ai bias:

$$ \begin{align} \pdv{L}{b^o_1} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{b^o_1}\\[6pt] \pdv{L}{b^o_2} & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{b^o_2}\\[6pt] \end{align} $$

Possiamo semplificare le precedenti equazioni in questo modo:

$$ \begin{align} d^o_1 & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1}\\[6pt] d^o_2 & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2}\\[6pt] \end{align} $$

Quindi:

$$ \begin{align} \pdv{L}{b^o_1} & = d^o_1 \cdot \pdv{z^o_1}{b^o_1}\\[6pt] \pdv{L}{b^o_2} & = d^o_2 \cdot \pdv{z^o_2}{b^o_2}\\[6pt] \end{align} $$

Notiamo che:

$$ \begin{align} \pdv{z^o_1}{b^o_1} & = \pdv{}{b^o_1}\left(a^h_1 \cdot w^o_{1,1} + a^h_2 \cdot w^o_{1,2} + b^o_1\right) = 1\\[6pt] \pdv{z^o_1}{b^o_2} & = \pdv{}{b^o_2}\left(a^h_1 \cdot w^o_{2,1} + a^h_2 \cdot w^o_{2,2} + b^o_2\right) = 1\\[6pt] \end{align} $$

Semplificando ulteriormente:

$$ \begin{align} \pdv{L}{b^o_1} & = d^o_1 \cdot 1 = d^o_1\\[6pt] \pdv{L}{b^o_2} & = d^o_2 \cdot 1 = d^o_2\\[6pt] \end{align} $$

Generalizzazione

Generalizzando, per una singola osservazione di input, $\mathbf{x}^{(i)}$, per un output layer di $n_o$ nodi (o classi), il gradiente della funzione di costo, $L$, rispetto al vettore bias $b^o$, può essere espresso dal seguente vettore, di dimensione $n_o$:

$$ \begin{align} \pdv{L}{\mathbf{b}^o} & = \begin{bmatrix} d^o_1\\[6pt] d^o_2\\[6pt] \vdots\\[6pt] d^o_{n_o}\\[6pt] \end{bmatrix} = \mathbf{d}^o \end{align} $$

Per osservazioni multiple, $\mathbf{X}$, anche il gradiente $\pdv{L}{\mathbf{b}^o}$ viene calcolato come la somma dei gradienti per ogni osservazione del dataset, ed è definito da una matrice di dimensione $n_o \times 1$:

$$ \begin{align} \pdv{L}{\mathbf{b}^o} & = \begin{bmatrix} d^{o(1)}_1 & d^{o(2)}_1 & \cdots & d^{o(m)}_1 \\[6pt] d^{o(1)}_2 & d^{o(2)}_2 & \cdots & d^{o(m)}_2 \\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] d^{o(1)}_{n_o} & d^{o(2)}_{n_o} & \cdots & d^{o(m)}_{n_o}\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} 1 \\[6pt] 1 \\[6pt] \vdots \\[6pt] 1 \\[6pt] \end{bmatrix} = \left(\mathbf{D}^o\right)^\intercal \cdot \mathbf{1}\\[6pt] \end{align} $$

Ad esempio:

$$ \begin{align} \pdv{L}{b^o_1} & = d^{o(1)}_1 + d^{o(2)}_1 + \cdots + d^{o(m)}_1 \\[6pt] \end{align} $$

Backpropagation nell’Hidden Layer

Calcolo del Gradiente Rispetto ai Pesi

$\require{physics}$ Come già fatto per l’output layer, calcoliamo le derivate parziali della funzione di costo, $L$, rispetto ad ogni peso $w^h_{t,s}$ dell’hidden layer. A differenza di quanto accade con l’output layer, ogni nodo dell’hidden layer riceve in input un valore $\partial z^o_j / \partial a^h_j$, per ciascuno degli $n_o$ nodi dell’output layer. Quindi, ad esempio, volendo calcolare $\partial L / \partial w^h_{1,1}$, dobbiamo sommare i contributi della chain rule applicata a ciascun percorso indicato nel diagramma sottostante, da $a^o_1$ a $w^h_{1,1}$, e da $a^o_2$ a $w^h_{1,1}$:

Calcolo della Derivata Parziale di L rispetto a $w^h_{1,1}$
Figura 8: Derivata Parziale di L rispetto a $w^h_{1,1}$
$$ \begin{align} \pdv{L}{w^h_{1,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,1}}\\[6pt] & + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,1}}\\[6pt] \end{align} $$


Calcolo della Derivata Parziale di L rispetto a $w^h_{1,2}$
Figura 9: Derivata Parziale di L rispetto a $w^h_{1,2}$
$$ \begin{align} \pdv{L}{w^h_{1,2}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,2}}\\[6pt] & + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,2}}\\[6pt] \end{align} $$


Calcolo della Derivata Parziale di L rispetto a $w^h_{2,1}$
Figura 10: Derivata Parziale di L rispetto a $w^h_{2,1}$
$$ \begin{align} \pdv{L}{w^h_{2,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,1}}\\[6pt] & + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,1}}\\[6pt] \end{align} $$


Calcolo della Derivata Parziale di L rispetto a $w^h_{2,2}$
Figura 11: Derivata Parziale di L rispetto a $w^h_{2,2}$
$$ \begin{align} \pdv{L}{w^h_{2,2}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,2}}\\[6pt] & + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,2}}\\[6pt] \end{align} $$


Riassumendo:

$$ \begin{align} \pdv{L}{w^h_{1,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,1}} + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,1}}\\[6pt] \pdv{L}{w^h_{1,2}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,2}} + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,2}}\\[6pt] \pdv{L}{w^h_{2,1}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,1}} + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,1}}\\[6pt] \pdv{L}{w^h_{2,2}} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,2}} + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,2}}\\[6pt] \end{align} $$

Possiamo semplificare le precedenti equazioni definendo i termini $d^o_j$, che rappresentano le derivata parziali di output dei nodi dell’output layer, $a^o_j$, considerando il verso contrario del processo di backpropagation:

$$ \begin{align} d^o_1 & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1}\\[6pt] d^o_2 & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2}\\[6pt] \end{align} $$

Quindi:

$$ \begin{align} \pdv{L}{w^h_{1,1}} & = d^o_1 \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,1}} + d^o_2 \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,1}}\\[6pt] \pdv{L}{w^h_{1,2}} & = d^o_1 \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,2}} + d^o_2 \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{w^h_{1,2}}\\[6pt] \pdv{L}{w^h_{2,1}} & = d^o_1 \cdot \pdv{z^o_1}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,1}} + d^o_2 \cdot \pdv{z^o_2}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,1}}\\[6pt] \pdv{L}{w^h_{2,2}} & = d^o_1 \cdot \pdv{z^o_1}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,2}} + d^o_2 \cdot \pdv{z^o_2}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{w^h_{2,2}}\\[6pt] \end{align} $$

Notiamo inoltre che:

$$ \begin{align} \pdv{z^o_1}{a^h_1} & = \pdv{}{a^h_1}\left(a^h_1 \cdot w^o_{1,1} + a^h_2 \cdot w^o_{1,2} + b^o_1\right) = w^o_{1,1}\\[6pt] \pdv{z^o_1}{a^h_2} & = \pdv{}{a^h_2}\left(a^h_1 \cdot w^o_{1,1} + a^h_2 \cdot w^o_{1,2} + b^o_1\right) = w^o_{1,2}\\[6pt] \pdv{z^o_2}{a^h_1} & = \pdv{}{a^h_1}\left(a^h_1 \cdot w^o_{2,1} + a^h_2 \cdot w^o_{2,2} + b^o_2\right) = w^o_{2,1}\\[6pt] \pdv{z^o_2}{a^h_2} & = \pdv{}{a^h_2}\left(a^h_1 \cdot w^o_{2,1} + a^h_2 \cdot w^o_{2,2} + b^o_2\right) = w^o_{2,2}\\[12pt] \pdv{z^h_1}{w^h_{1,1}} & = \pdv{}{w^h_{1,1}}\left(x_1 \cdot w^h_{1,1} + x_2 \cdot w^h_{1,2} + b^h_1\right) = x_1\\[6pt] \pdv{z^h_1}{w^h_{1,2}} & = \pdv{}{w^h_{1,2}}\left(x_1 \cdot w^h_{1,1} + x_2 \cdot w^h_{1,2} + b^h_1\right) = x_2\\[6pt] \pdv{z^h_2}{w^h_{2,1}} & = \pdv{}{w^h_{2,1}}\left(x_1 \cdot w^h_{2,1} + x_2 \cdot w^h_{2,2} + b^h_2\right) = x_1\\[6pt] \pdv{z^h_2}{w^h_{2,2}} & = \pdv{}{w^h_{2,2}}\left(x_1 \cdot w^h_{2,1} + x_2 \cdot w^h_{2,2} + b^h_2\right) = x_2\\[6pt] \end{align} $$

Semplificando ulteriormente:

$$ \begin{align} \pdv{L}{w^h_{1,1}} & = d^o_1 \cdot w^o_{1,1} \cdot \pdv{a^h_1}{z^h_1} \cdot x_1 + d^o_2 \cdot w^o_{2,1} \cdot \pdv{a^h_1}{z^h_1} \cdot x_1\\[6pt] \pdv{L}{w^h_{1,2}} & = d^o_1 \cdot w^o_{1,1} \cdot \pdv{a^h_1}{z^h_1} \cdot x_2 + d^o_2 \cdot w^o_{2,1} \cdot \pdv{a^h_1}{z^h_1} \cdot x_2\\[6pt] \pdv{L}{w^h_{2,1}} & = d^o_1 \cdot w^o_{1,2} \cdot \pdv{a^h_2}{z^h_2} \cdot x_1 + d^o_2 \cdot w^o_{2,2} \cdot \pdv{a^h_2}{z^h_2} \cdot x_1\\[6pt] \pdv{L}{w^h_{2,2}} & = d^o_1 \cdot w^o_{1,2} \cdot \pdv{a^h_2}{z^h_2} \cdot x_2 + d^o_2 \cdot w^o_{2,2} \cdot \pdv{a^h_2}{z^h_2} \cdot x_2\\[6pt] \end{align} $$

Ora definiamo i termini $d^h_j$, che rappresentano le derivata parziali di output dei nodi dell’hidden layer, $a^h_j$, considerando il verso contrario del processo di backpropagation:

$$ \begin{align} d^h_1 & = d^o_1 \cdot w^o_{1,1} \cdot \pdv{a^h_1}{z^h_1} + d^o_2 \cdot w^o_{2,1} \cdot \pdv{a^h_1}{z^h_1} = \left(d^o_1 \cdot w^o_{1,1} + d^o_2 \cdot w^o_{2,1}\right) \cdot \pdv{a^h_1}{z^h_1}\\[6pt] d^h_2 & = d^o_1 \cdot w^o_{1,2} \cdot \pdv{a^h_2}{z^h_2} + d^o_2 \cdot w^o_{2,2} \cdot \pdv{a^h_2}{z^h_2} = \left(d^o_1 \cdot w^o_{1,2} + d^o_2 \cdot w^o_{2,2}\right) \cdot \pdv{a^h_2}{z^h_2}\\[6pt] \end{align} $$

Possiamo esprimere le equazioni risultanti in forma vettorizzata, mediante matrici, in questo modo:

$$ \begin{align} \mathbf{d}^h & = \begin{bmatrix} d^h_1\\[6pt] d^h_2\\[6pt] \end{bmatrix} = \begin{bmatrix} w^o_{1,1} & w^o_{1,2}\\[6pt] w^o_{2,1} & w^o_{2,2}\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} d^o_1\\[6pt] d^o_2\\[6pt] \end{bmatrix} \odot \begin{bmatrix} \pdv{a^h_1}{z^h_1}\\[6pt] \pdv{a^h_2}{z^h_2}\\[6pt] \end{bmatrix}\\[6pt] \pdv{L}{\mathbf{W}^h} & = \begin{bmatrix} d^h_1\\[6pt] d^h_2\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} x_1 & x_2\\[6pt] \end{bmatrix} \end{align} $$

dove $\odot$ è il prodotto di Hadamard, un’operazione che moltiplica gli elementi corrispondenti tra due matrici o vettori, e restitusice una matrice o un vettore della stessa dimensione.

Generalizzazione

Generalizzando, per una singola osservazione di input, $\mathbf{x}^{(i)}$, per un hidden layer di $n_h$ nodi, preceduto da un input layer di $n$ nodi, la matrice contenente i valori $d^h_j$ può essere calcolata come:

$$ \begin{align} \mathbf{d}^h & = \begin{bmatrix} d^h_1\\[6pt] d^h_2\\[6pt] \vdots\\[6pt] d^h_{n_h}\\[6pt] \end{bmatrix} = \begin{bmatrix} w^o_{1,1} & w^o_{1,2} & \cdots & w^o_{1,{n_h}} \\[6pt] w^o_{2,1} & w^o_{2,2} & \cdots & w^o_{2,{n_h}} \\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] w^o_{{n_o},1} & w^o_{{n_o},2} & \cdots & w^o_{{n_o},{n_h}}\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} d^o_1 \\[6pt] d^o_2 \\[6pt] \vdots \\[6pt] d^o_{n_o}\\[6pt] \end{bmatrix} \odot \begin{bmatrix} \pdv{a^h_1}{z^h_1} \\[6pt] \pdv{a^h_2}{z^h_2} \\[6pt] \vdots \\[6pt] \pdv{a^h_{n_h}}{z^h_{n_h}}\\[6pt] \end{bmatrix} = \mathbf{W}^o \cdot \mathbf{d}^o \odot \pdv{\mathbf{a}^h}{\mathbf{z}^h} \end{align} $$

Il gradiente della funzione di costo, $L$, rispetto ai pesi $w^h_{t,s}$, può essere espresso dalla seguente matrice, di dimensione $n_h \times n$:

$$ \begin{align} \pdv{L}{\mathbf{W}^h} & = \begin{bmatrix} d^h_1\\[6pt] d^h_2\\[6pt] \vdots\\[6pt] d^h_{n_h} \end{bmatrix} \cdot \begin{bmatrix} x_1 & x_2 & \cdots & x_n\\[6pt] \end{bmatrix} = \mathbf{d}^h \cdot \mathbf{x}^\intercal\\[6pt] \end{align} $$

Per osservazioni multiple, riprendiamo la matrice $\mathbf{D}^o$ di dimensione $m \times n_o$, ritornata dall’output layer. Abbiamo poi la matrice dei pesi dell’output layer, $\mathbf{W}^o$, con dimensione $n_o \times n_h$, e la matrice $\pdv{\mathbf{A}^h}{\mathbf{Z}^h}$, con dimensione $m \times n_h$. Quindi, anche $\mathbf{D}^h$ ha dimensione $m \times n_h$:

$$ \begin{align} \mathbf{D}^h & = \begin{bmatrix} d^{h(1)}_1 & d^{h(1)}_2 & \dots & d^{h(1)}_{n_h}\\[6pt] d^{h(2)}_1 & d^{h(2)}_2 & \dots & d^{h(2)}_{n_h}\\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] d^{h(m)}_1 & d^{h(m)}_2 & \dots & d^{h(m)}_{n_h}\\[6pt] \end{bmatrix} = \mathbf{D}^o \cdot \mathbf{W}^o \odot \pdv{\mathbf{A}^h}{\mathbf{Z}^h} \end{align} $$

Similmente a $\pdv{L}{\mathbf{W}^o}$, il gradiente $\pdv{L}{\mathbf{W}^h}$ viene calcolato come la somma dei gradienti per ogni osservazione del dataset, ed è definito da una matrice di dimensione $n_h \times n$:

$$ \begin{align} \pdv{L}{\mathbf{W}^h} & = \begin{bmatrix} d^{h(1)}_1 & d^{h(2)}_1 & \cdots & d^{h(m)}_1 \\[6pt] d^{h(1)}_2 & d^{h(2)}_2 & \cdots & d^{h(m)}_2 \\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] d^{h(1)}_{n_h} & d^{h(2)}_{n_h} & \cdots & d^{h(m)}_{n_h}\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} x^{(1)}_1 & x^{(1)}_2 & \dots & x^{(1)}_n\\[6pt] x^{(2)}_1 & x^{(2)}_2 & \dots & x^{(2)}_n\\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] x^{(m)}_1 & x^{(m)}_2 & \dots & x^{(m)}_n\\[6pt] \end{bmatrix}\\[6pt] & = \left(\mathbf{D}^h\right)^\intercal \cdot \mathbf{X}\\[6pt] \end{align} $$

Calcolo del Gradiente Rispetto ai Bias

Con lo stesso procedimento, calcoliamo il gradiente della funzione di costo rispetto ai bias:

$$ \begin{align} \pdv{L}{b^h_1} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{b^h_1} + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{b^h_1}\\[6pt] \pdv{L}{b^h_2} & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1} \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{b^h_2} + \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2} \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{b^h_2}\\[6pt] \end{align} $$

Semplifichiamo le precedenti equazioni definendo i termini $d^o_j$:

$$ \begin{align} d^o_1 & = \pdv{L}{a^o_1} \cdot \pdv{a^o_1}{z^o_1}\\[6pt] d^o_2 & = \pdv{L}{a^o_2} \cdot \pdv{a^o_2}{z^o_2}\\[6pt] \end{align} $$

Quindi:

$$ \begin{align} \pdv{L}{b^h_1} & = d^o_1 \cdot \pdv{z^o_1}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{b^h_1} + d^o_2 \cdot \pdv{z^o_2}{a^h_1} \cdot \pdv{a^h_1}{z^h_1} \cdot \pdv{z^h_1}{b^h_1}\\[6pt] \pdv{L}{b^h_2} & = d^o_1 \cdot \pdv{z^o_1}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{b^h_2} + d^o_2 \cdot \pdv{z^o_2}{a^h_2} \cdot \pdv{a^h_2}{z^h_2} \cdot \pdv{z^h_2}{b^h_2}\\[6pt] \end{align} $$

Notiamo inoltre che:

$$ \begin{align} \pdv{z^o_1}{a^h_1} & = \pdv{}{a^h_1}\left(a^h_1 \cdot w^o_{1,1} + a^h_2 \cdot w^o_{1,2} + b^o_1\right) = w^o_{1,1}\\[6pt] \pdv{z^o_1}{a^h_2} & = \pdv{}{a^h_2}\left(a^h_1 \cdot w^o_{1,1} + a^h_2 \cdot w^o_{1,2} + b^o_1\right) = w^o_{1,2}\\[6pt] \pdv{z^o_2}{a^h_1} & = \pdv{}{a^h_1}\left(a^h_1 \cdot w^o_{2,1} + a^h_2 \cdot w^o_{2,2} + b^o_2\right) = w^o_{2,1}\\[6pt] \pdv{z^o_2}{a^h_2} & = \pdv{}{a^h_2}\left(a^h_1 \cdot w^o_{2,1} + a^h_2 \cdot w^o_{2,2} + b^o_2\right) = w^o_{2,2}\\[12pt] \pdv{z^h_1}{b^h_1} & = \pdv{}{b^h_1}\left(x_1 \cdot w^h_{1,1} + x_2 \cdot w^h_{1,2} + b^h_1\right) = 1\\[6pt] \pdv{z^h_2}{b^h_2} & = \pdv{}{b^h_2}\left(x_1 \cdot w^h_{2,1} + x_2 \cdot w^h_{2,2} + b^h_2\right) = 1\\[6pt] \end{align} $$

Semplificando ulteriormente:

$$ \begin{align} \pdv{L}{b^h_1} & = d^o_1 \cdot w^o_{1,1} \cdot \pdv{a^h_1}{z^h_1} + d^o_2 \cdot w^o_{2,1} \cdot \pdv{a^h_1}{z^h_1}\\[6pt] \pdv{L}{b^h_2} & = d^o_1 \cdot w^o_{1,2} \cdot \pdv{a^h_2}{z^h_2} + d^o_2 \cdot w^o_{2,2} \cdot \pdv{a^h_2}{z^h_2}\\[6pt] \end{align} $$

Definiamo i termini $d^h_j$, che in questo caso corrispondono con le derivate parziali $\pdv{L}{b^h_j}$:

$$ \begin{align} d^h_1 & = d^o_1 \cdot w^o_{1,1} \cdot \pdv{a^h_1}{z^h_1} + d^o_2 \cdot w^o_{2,1} \cdot \pdv{a^h_1}{z^h_1} = \left(d^o_1 \cdot w^o_{1,1} + d^o_2 \cdot w^o_{2,1}\right) \cdot \pdv{a^h_1}{z^h_1} = \pdv{L}{b^h_1}\\[6pt] d^h_2 & = d^o_1 \cdot w^o_{1,2} \cdot \pdv{a^h_2}{z^h_2} + d^o_2 \cdot w^o_{2,2} \cdot \pdv{a^h_2}{z^h_2} = \left(d^o_1 \cdot w^o_{1,2} + d^o_2 \cdot w^o_{2,2}\right) \cdot \pdv{a^h_2}{z^h_2} = \pdv{L}{b^h_2}\\[6pt] \end{align} $$

Possiamo esprimere le equazioni risultanti in forma vettorizzata, mediante matrici, in questo modo:

$$ \begin{align} \mathbf{d}^h & = \begin{bmatrix} d^h_1\\[6pt] d^h_2\\[6pt] \end{bmatrix} = \begin{bmatrix} w^o_{1,1} & w^o_{1,2}\\[6pt] w^o_{2,1} & w^o_{2,2}\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} d^o_1\\[6pt] d^o_2\\[6pt] \end{bmatrix} \odot \begin{bmatrix} \pdv{a^h_1}{z^h_1}\\[6pt] \pdv{a^h_2}{z^h_2}\\[6pt] \end{bmatrix}\\[6pt] \pdv{L}{\mathbf{b}^h} & = \begin{bmatrix} \pdv{L}{b^h_1} & \pdv{L}{b^h_2}\\[6pt] \end{bmatrix}^\intercal = \begin{bmatrix} d^h_1 & d^h_2\\[6pt] \end{bmatrix}^\intercal \end{align} $$

Generalizzazione

Generalizzando, per una singola osservazione di input, $\mathbf{x}^{(i)}$, per un hidden layer di $n_h$ nodi, il gradiente della funzione di costo, $L$, rispetto ai bias $b^h_j$, può essere espresso dal seguente vettore, di dimensione $n_h$:

$$ \begin{align} \pdv{L}{\mathbf{b}^h} & = \begin{bmatrix} d^h_1\\[6pt] d^h_2\\[6pt] \vdots\\[6pt] d^h_{n_h}\\[6pt] \end{bmatrix} = \mathbf{d}^h \end{align} $$

Per osservazioni multiple, $\mathbf{X}$, anche il gradiente $\pdv{L}{\mathbf{b}^h}$ viene calcolato come la somma dei gradienti per ogni osservazione del dataset, ed è definito da una matrice di dimensione $n_h \times 1$:

$$ \begin{align} \pdv{L}{\mathbf{b}^h} & = \begin{bmatrix} d^{h(1)}_1 & d^{h(2)}_1 & \cdots & d^{h(m)}_1 \\[6pt] d^{h(1)}_2 & d^{h(2)}_2 & \cdots & d^{h(m)}_2 \\[6pt] \vdots & \vdots & \vdots & \vdots \\[6pt] d^{h(1)}_{n_o} & d^{h(2)}_{n_o} & \cdots & d^{h(m)}_{n_o}\\[6pt] \end{bmatrix} \cdot \begin{bmatrix} 1 \\[6pt] 1 \\[6pt] \vdots \\[6pt] 1 \\[6pt] \end{bmatrix} = \left(\mathbf{D}^h\right)^\intercal \cdot \mathbf{1}\\[6pt] \end{align} $$

Ad esempio:

$$ \begin{align} \pdv{L}{b^h_1} & = d^{h(1)}_1 + d^{h(2)}_1 + \cdots + d^{h(m)}_1 \\[6pt] \end{align} $$

Ricapitolando

Per implementare la fase di backpropagation di una rete neurale con un hidden layer, per l’output layer servono le seguenti equazioni:

$$ \begin{align} \mathbf{D}^o & = \pdv{\mathbf{L}}{\mathbf{A}^o} \cdot \pdv{\mathbf{A}^o}{\mathbf{Z}^o}\\[6pt] \pdv{L}{\mathbf{W}^o} & = \left(\mathbf{D}^o\right)^\intercal \cdot \mathbf{A}^h\\[6pt] \pdv{L}{\mathbf{b}^o} & = \left(\mathbf{D}^o\right)^\intercal \cdot \mathbf{1}\\[6pt] \end{align} $$

dove:

  • $\pdv{\mathbf{L}}{\mathbf{A}^o}$ è la derivata della funzione di costo (es.: $\text{MSE}$);
  • $\pdv{\mathbf{A}^o}{\mathbf{Z}^o}$ è la derivata della funzione di attivazione (es.: il sigmoide, $\sigma$).

Nell’input layer abbiamo invece:

$$ \begin{align} \mathbf{D}^o & = \pdv{\mathbf{L}}{\mathbf{A}^o} \cdot \pdv{\mathbf{A}^o}{\mathbf{Z}^o}\\[6pt] \mathbf{D}^h & = \mathbf{D}^o \cdot \mathbf{W}^o \odot \pdv{\mathbf{A}^h}{\mathbf{Z}^h}\\[6pt] \pdv{L}{\mathbf{W}^h} & = \left(\mathbf{D}^h\right)^\intercal \cdot \mathbf{X}\\[6pt] \pdv{L}{\mathbf{b}^h} & = \left(\mathbf{D}^h\right)^\intercal \cdot \mathbf{1}\\[6pt] \end{align} $$

Nel prossimo post vedremo come usare queste equazioni per implementare la classe MLPClassifier.


  1. con il termine “errore di apprendimento” intendiamo l’errore medio ritornato dalla funzione di costo, $L\left(y^{(i)}, \text{out}^{(i)}\right)$, applicata all’output layer, considerando tutti gli esempi del dataset. ↩︎

Caricamento
  • Rendering delle formule LaTeX...