Uno degli aspetti più delicati nella computazione legata a modelli di deep learning è relativa al numero enorme di parametri, dati e calcoli coinvolti, organizzati in modo pratico in vettori e matrici, e al relativo calcolo del gradiente della funzione di costo rispetto a tali parametri.
E' quindi opportuno capire come impostare in modo efficiente i calcoli nel grafo computazionale del modello, applicando correttamente la chain rule e ricavando in modo elegante i gradienti anche rispetto a grandezze di tipo vettoriale e matriciale - passaggio essenziale nello sviluppo della backpropagation e della vettorizzazione del training set per processare batch di dati senza essere costretti ad iterare per ogni singolo campione.
Utilizziamo in seguito una notazione semplificata, indicando con dx il gradiente di una nostra funzione costo J rispetto alla grandezza x della quale conserverà ovviamente le stesse dimensioni per essere utilizzata direttamente negli algoritmi della discesa del gradiente.
Proponiamo subito una pratica tabella riassuntiva di sviluppo di gradienti utili nella backprogation per modelli di reti neurali densamente connesse (Fully Connected), calcolati rispetto a un gradiente noto dz
Per ogni voce è sviluppato in calce il calcolo di dettaglio, sebbene quasi tutti i casi possano essere derivati dal caso generale del calcolo di dW per Z(n×p)=W(n×m)X(m×p)
z(n×1)=W(n×m)x(m×1) | dx(m×1)=W⊤(m×n)dz(n×1) |
z(1×n)=x(1×m)W(m×n) | dx(1×m)=dz(1×n)W⊤(n×m) |
Z=X | dX=dZ |
Zij=f(Zij) | dX=dZ∗f′(X) |
z(n×1)=W(n×m)x(m×1) | dW(n×m)=dz(n×1) x⊤(1×m) |
z(1×n)=x(1×m)W(m×n) | dW(m×n)=x⊤(m×1)dz(1×n) |
Z(n×p)=W(n×m)X(m×p) | dW(n×m)=dZ(n×p) X⊤(p×m) |
Z(n×p)=X(n×m)W(m×p) | dW(m×p)=X⊤(m×n)dZ(n×p) |
Z=softmax(X)J=CE(Z,Y) | dX=(Z−Y) |
Partiamo dalla definizione di jacobiano, che generalizza il concetto di derivata a una funzione Rn→Rm e al quale è possibile applicare la chain rule in modo assolutamente trasparente:
Sia f:Rn→Rm , f(x)=[f1(x1⋯xn),⋯,fm(x1⋯xn)]
Definiamo quindi il jacobiano ∂f∂x=[∂f1∂x1⋯∂f1∂xn⋮⋱⋮∂fm∂x1⋯∂fm∂xn]=[∂f∂x1⋯∂f∂xn]=[∇f⊤1⋮∇f⊤m]
Come detto il jacobiano supporta pienamente la chain rule, per cui è facile verificare che se f:Rn→Rm e g:Rm→Rl allora ∂g(f(x))∂x=∂g∂f∂f∂x
Notiamo che il jacobiano è la trasposta del gradiente, per cui, ogni qualvolta avremo un jacobiano esplicitamente direttamente coinvolto nel calcolo del gradiente, dovremo fare attenzione a verificare che la dimensione del gradiente sia quella effettivamente attesa e nel caso applicare la trasposizione - in particolare quando operiamo con vettori colonna.
In questo caso abbiamo che zi=m∑i=1Wijxj e ∂zi∂xj=Wij , pertanto avremo un jacobiano ∂z∂x=W .
Attraverso la chain rule tra jacobiani ∂J∂x=∂J∂z∂z∂x=∂J∂zW
Vediamo ora per riprova il calcolo del gradiente, che ci attendiamo essere ricavabile dalla trasposta dello jacobiano.
dx=[∂J∂x1⋮∂J∂xm] e dz=[∂J∂z1⋮∂J∂zn] e per la regola della chain rule ∂J∂xj=∑ni=1∂J∂zi∂zi∂xj=(W:j)⊤dz , e quindi concludiamo esplicitando le dimensioni che:
dx(m×1)=[(W:1)⊤dz⋮(W:m)⊤dz]=W⊤(m×n)dz(n×1)
a conferma della relazione di trasposizione tra jacobiano e gradiente.
In questo caso abbiamo che zi=m∑i=1Wjixj e ∂zi∂xj=Wji , pertanto avremo un jacobiano ∂z∂x=W⊤ .
Attraverso la chain rule tra jacobiani ∂J∂x=∂J∂z∂z∂x=∂J∂zW⊤
Vediamo ora per riprova il calcolo del gradiente. Abbiamo:
dx=[∂J∂x1 ⋯ ∂J∂xm] e dz=[∂J∂z1 ⋯ ∂J∂zn] e per la regola della chain rule ∂J∂xj=n∑i=1∂J∂zi∂zi∂xj=dz (Wj:)⊤ , e quindi concludiamo esplicitando le dimensioni che:
dx(1×m)=[dz (W1:)⊤ ⋯ dz (Wm:)⊤]=dz(1×n)W⊤(n×m)
In questo caso ∂zi∂xj={0 se i≠j1 se i=j pertanto ∂z∂x=I
Per quanto riguarda il gradiente è immediato che dx=dz
Ipotizziamo di avere una funzione f:R→R applicata ad ogni componente del vettore x
In questo caso ∂zi∂xj={0 se i≠jf′(xi) se i=j pertanto ∂z∂x=diag(f′(x))
Per quanto riguarda il gradiente, ipotizzando due vettori colonna, abbiamo ∂J∂xj=n∑i=1∂J∂zi∂zi∂xj=dzj f′(xj)
e quindi dx=dz∗f′(x) , dove l'operatore ∗ effettua una moltiplicazione componente per componente delle due grandezze.
Il risultato relativo al gradiente è valido anche se consideriamo Z,X∈Rn×m infatti ∂Zij∂Xkl={0 se i,j≠k,lf′(Xij) se i,j=k,l e quindi
∂J∂Xkl=m∑i=1n∑j=1∂J∂Zij∂Zij∂Xkl=dZklf′(Xkl) che infatti porta ad un gradiente dX=dZ∗f′(X)
In questo caso e nei successivi dove andremo a calcolare il gradiente rispetto a grandezze strutturate in matrici, andremo convenientemente a definire il ns.gradiente con la stessa dimensione della struttra originaria, cosa che ne permetterà anche l'utilizzo in modo diretto negli algoritimi di discesa del gradiente:
dW=[dW11⋯dW1n⋮⋱⋮dWm1⋯dWmn]. Questo tipo di organizzazione tuttavia rende problematica la definizione diretta dello jacobiano ∂z∂Wche si attende invece un vettore di dimensione mn e non una matrice, che darebbe teoricamente origine a un jacobiano in forma di tensore.
Per tale motivo ci focalizziamo direttamente sul calcolo del gradiente dW e delle singole componenti ∂zk∂Wijsenza entrare nella esplicitazione della struttura dello jacobiano.
Abbiamo innanzitutto che zk=m∑l=1Wklxl e quindi ∂zk∂Wij={0 se k≠ixj se k=i che possiamo anche scrivere come
∂z∂Wij=[0xj0]←i-ma riga e applicando la chain rule ∂J∂Wij=∂J∂z∂z∂Wij=n∑k=1∂J∂zk∂zk∂Wij=dzi xj
e quindi abbiamo che il gradiente dW(n×m)=dz(n×1) x⊤(1×m)
In questo caso zk=m∑l=1Wlkxl e quindi ∂zk∂Wij={0 se k≠jxi se k=j che possiamo anche scrivere come
∂z∂Wij=[0xi0]←j-ma riga e applicando la chain rule ∂J∂Wij=∂J∂z∂z∂Wij=n∑k=1∂J∂zk∂zk∂Wij=dzj xi
e otteniamo il gradiente dW(m×n)=x⊤(m×1)dz(1×n)
Questo caso e il successivo generalizzano i 2 casi precedenti con l'utilizzo di matrici al posto di vettori.
Abbiamo Zij=m∑h=1WihXhj e quindi ∂Zij∂Wkl={ 0 se k≠iXlj se k=i
Applicando la chain rule ∂J∂Wkl=n∑i=1p∑j=1∂J∂Zij∂Zij∂Wkl=p∑j=1dZkjXlj=dZk:(Xl:)⊤
E pertanto dW(n×m)=dZ(n×p) X⊤(p×m)
Abbiamo Zij=m∑h=1XihWhj e quindi ∂Zij∂Wkl={ 0 se j≠lXik se j=l
Applicando la chain rule ∂J∂Wkl=n∑i=1p∑j=1∂J∂Zij∂Zij∂Wkl=n∑i=1dZilXik=(X:k)⊤dZ:l
E pertanto dW(m×p)=X⊤(m×n)dZ(n×p)
Un caso di funzione che troviamo frequentemente nelle reti neurali e merita di essere trattata specificamente è la funzione softmax(x(n×1))=[ex1∑nk=1exk⋮exn∑nk=1exk] . Iniziamo a calcolare il jacobiano:
∂zi∂xj={se i≠j⇒ −exiexj(∑nk=1exk)2=−zizjse i=j⇒ exj∑nk=1exk−exjexj(∑nk=1exk)2=zj(1−zj) e quindi ∂z∂x=[z1(1−z1)⋯−z1zn⋮⋱⋮−znz1⋯zn(1−zn)]
La funzione softmax è quasi sempre presente nel livello di uscita, abbinata ad una funzione di costo entropia incrociata (Cross Entropy) J=CE(z,y)=−y⊤logz , nella quale la somma delle componenti del vettore dato y è uguale a 1. Procederemo in questo caso a prendere a esplicitare il jacobiano ∂J∂z=[−y1z1⋯−ynzn]
Applicando la chain rule agli jacobiani abbiamo ∂J∂x=∂J∂z∂z∂x=[⋯−yjzjzj(1−zj)+∑k≠jykzkzjzk⋯]=[⋯−yj+zjyj+zj∑k≠jyk⋯]=[⋯zj−yj⋯]=(z−x)⊤
Per cui trasponendo otteremo il gradiente dx=z−x
Il risultato può essere esteso anche nel caso di matrici, dove con Z(n×m)=softmax(X(n×m)) applichiamo la funzione softmax colonna per colonna, ovvero [z:1⋯z:m]=[softmax(x:1)⋯softmax(x:m)] . La funzione di costo che utilizzeremo in questo caso è estesa alla matrice come J=m∑i=1n∑j=1−Yij logZij e ∂J∂Zij=−YijZij
In questo caso abbiamo:
∂Zij∂Xkl={se j≠l⇒ 0se j=l , i≠k⇒ −eXil eXkl(∑nt=1eXtl)2=−ZilZklse j=l , i=k⇒ eXkl∑nt=1eXtl−eXkl eXkl(∑nt=1eXtl)2=Zkl(1−Zkl)
∂J∂Xkl=m∑i=1n∑j=1∂J∂Zij∂Zij∂Xkl=m∑i=1−YilZil∂Zil∂Xkl=−YklZklZkl(1−Zkl)+∑i≠kYilZilZilZkl=−Ykl+YklZkl+Zkl∑i≠kYil=Zkl−Ykl
Per cui otteniamo dX=(Z−Y)
Nella pratica la funzione di costo viene moltiplicata per un coefficiente 1m per ottenere valori non legati alla numerica delle colonne/campioni in matrice.
Come abbiamo visto precedentemente il metodo della discesa del gradiente presenta alcune problematicità di efficienza nel caso di plateau e di disomogeneità rilevanti del gradiente nelle varie dimensioni.
Per rendere il metodo più efficiente vengono solitamente utilizzate delle versioni più evolute del metodo, in grado di accelerare la ricerca e contrastare i casi patologici.
Un metodo particolarmente efficiente nello smorzare ampie oscillazioni nei passi dovute a disomogeneità forti del gradiente lungo diverse dimensioni, è quello di utilizzare al posto del gradiente ∇f(x(t−1)) la media esponenziale vt sui valori del gradiente stesso:
{vt=βvt−1+(1−β)∇f(x(t−1)),v0=0x(t)=x(t−1)−αvt
dove il coefficiente β<1 indica il peso assegnato nella media ai gradienti precedenti. Generalmente viene utilizzato un β≈0.9 e la media viene calcolata biased come presentato nella formula, ovvero senza correttivo per i primi vt che avranno modulo ridotto.
L'utilizzo del momento smorzerà le oscillazioni e contribuirà ad una discesa verso il minimo con meno passi.
Un'altra variante consiste nell'armonizzare i passi nelle varie dimensioni, smorzando o amplificando le varie componenti del gradiente in ragione della loro media.
In particolare prenderemo in considerazione la radice della media esponenziale biased dei quadrati:
∀ i {s(t)i=βs(t−1)i+(1−β)[∂f∂xi(x(t−1))]2 , s(0)i=0x(t)i=x(t−1)i−α∂f∂xi(x(t−1))√s(t)i+ε
dove il coefficiente β<1 indica il peso assegnato nella media ai coefficienti si precedenti. Generalmente viene utilizzato un β≈0.99 e la media viene calcolata unbiased come presentato nella formula, ovvero senza correttivo per i primi si che avranno modulo ridotto.
Viene anche introdotto un ε≈10−8 al denominatore per evitare errori dovuti a si prossimi a zero.
RMSprop da un lato armonizza lo sviluppo dei passi tra le dimensioni non omogenee del gradiente, smorzando quelle di modulo maggiore e amplificando quelle di modulo minore, dall'altro "accelera" la fuga da zone di plateau, dove le componenti del gradiente diventano prossime allo zero.
L' algoritmo Adam combina la discesa con Momento e RMSprop per integrare in modo efficace i benefici di entrambi gli algoritmi.
A differenza degli algoritmi singoli, Adam utilizza generalmente le medie esponenziali unbiased ovvero normalizzate dividendole per un fattore (1−βt) che riequilibri in particolare i primi valori della media.
Per ogni dimensione avremo quindi:
∀ i {v(t)i=β1v(t−1)i+(1−β1)[∂f∂xi(x(t−1))] , v(0)i=0s(t)i=β2s(t−1)i+(1−β2)[∂f∂xi(x(t−1))]2 , s(0)i=0x(t)i=x(t−1)i−αv(t)i(1−βt1)√s(t)i(1−βt2)+ε
Dove valori tipici dei parametri sono β1=0.9 , β2=0.99 , ε=10−8
Adam è frequentemente utilizzato come algoritmo di discesa del gradiente in ambito di deep learning