Loading [MathJax]/jax/output/HTML-CSS/jax.js

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=dZf(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=(ZY)

 

Jacobiano

Partiamo dalla definizione di jacobiano, che generalizza il concetto di derivata a una funzione RnRm e al quale è possibile applicare la chain rule in modo assolutamente trasparente:

Sia f:RnRm  ,  f(x)=[f1(x1xn),,fm(x1xn)]

Definiamo quindi il jacobiano  fx=[f1x1f1xnfmx1fmxn]=[fx1fxn]=[f1fm]

Come detto il jacobiano supporta pienamente la chain rule, per cui è facile verificare che se f:RnRm  e  g:RmRl  allora g(f(x))x=gffx

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.

 

z(n×1)=W(n×m)x(m×1) : jacobiano zx e gradiente dx

In questo caso abbiamo che zi=mi=1Wijxj  e zixj=Wij , pertanto avremo un jacobiano zx=W .

Attraverso la chain rule tra jacobiani Jx=Jzzx=JzW 

Vediamo ora per riprova il calcolo del gradiente, che ci attendiamo essere ricavabile dalla trasposta dello jacobiano. 
 

dx=[Jx1Jxm] e  dz=[Jz1Jzn]  e per la regola della chain rule Jxj=ni=1Jzizixj=(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.

 

z(1×n)=x(1×m)W(m×n) : jacobiano zx e gradiente dx

In questo caso abbiamo che zi=mi=1Wjixj  e zixj=Wji , pertanto avremo un jacobiano zx=W .

Attraverso la chain rule tra jacobiani Jx=Jzzx=JzW 

Vediamo ora per riprova il calcolo del gradiente. Abbiamo:
dx=[Jx1  Jxm] e  dz=[Jz1  Jzn]  e per la regola della chain rule Jxj=ni=1Jzizixj=dz (Wj:) , e quindi concludiamo esplicitando le dimensioni che:

dx(1×m)=[dz (W1:)  dz (Wm:)]=dz(1×n)W(n×m)

 

z=x : jacobiano zx e gradiente dx

In questo caso zixj={0 se ij1 se i=j pertanto zx=I 

Per quanto riguarda il gradiente è immediato che dx=dz 

 

zi=f(xi) : jacobiano zx e gradiente dx

Ipotizziamo di avere una funzione f:RR applicata ad ogni componente del vettore x

In questo caso zixj={0 se ijf(xi) se i=j pertanto zx=diag(f(x))

Per quanto riguarda il gradiente, ipotizzando due vettori colonna, abbiamo Jxj=ni=1Jzizixj=dzj f(xj) 

e quindi dx=dzf(x)  , dove l'operatore  effettua una moltiplicazione componente per componente delle due grandezze.

Il risultato relativo al gradiente è valido anche se consideriamo Z,XRn×m infatti ZijXkl={0 se i,jk,lf(Xij) se i,j=k,l e quindi

JXkl=mi=1nj=1JZijZijXkl=dZklf(Xkl)   che infatti porta ad un gradiente dX=dZf(X)

 

z(n×1)=W(n×m)x(m×1) : jacobiano zW e gradiente dW

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=[dW11dW1ndWm1dWmn]. Questo tipo di organizzazione tuttavia rende problematica la definizione diretta dello jacobiano zWche 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 zkWijsenza entrare nella esplicitazione della struttura dello jacobiano.

Abbiamo innanzitutto che zk=ml=1Wklxl  e quindi  zkWij={0  se  kixj se  k=i che possiamo anche scrivere come

zWij=[0xj0]i-ma riga    e applicando la chain rule JWij=JzzWij=nk=1JzkzkWij=dzi xj 

e quindi abbiamo che il gradiente dW(n×m)=dz(n×1) x(1×m)

 

z(1×n)=x(1×m)W(m×n) : jacobiano zW e gradiente dW

In questo caso zk=ml=1Wlkxl  e quindi  zkWij={0  se  kjxi se  k=j che possiamo anche scrivere come

zWij=[0xi0]j-ma riga e applicando la chain rule JWij=JzzWij=nk=1JzkzkWij=dzj xi 

e otteniamo il gradiente dW(m×n)=x(m×1)dz(1×n)

 

Z(n×p)=W(n×m)X(m×p) : jacobiano ZW e gradiente dW

Questo caso e il successivo generalizzano i 2 casi precedenti con l'utilizzo di matrici al posto di vettori.

Abbiamo Zij=mh=1WihXhj e quindi ZijWkl={ 0  se  kiXlj se k=i

Applicando la chain rule JWkl=ni=1pj=1JZijZijWkl=pj=1dZkjXlj=dZk:(Xl:)

E pertanto dW(n×m)=dZ(n×p) X(p×m)

 

Z(n×p)=X(n×m)W(m×p) : jacobiano ZW e gradiente dW

Abbiamo Zij=mh=1XihWhj e quindi ZijWkl={ 0  se  jlXik se j=l

Applicando la chain rule JWkl=ni=1pj=1JZijZijWkl=ni=1dZilXik=(X:k)dZ:l

E pertanto dW(m×p)=X(m×n)dZ(n×p) 

 

z(n×1)=softmax(x(n×1)) , J=CE(z,y) : jacobiano zx e gradiente dx

Un caso di funzione che troviamo frequentemente nelle reti neurali e merita di essere trattata specificamente è la funzione softmax(x(n×1))=[ex1nk=1exkexnnk=1exk] .     Iniziamo a calcolare il jacobiano:

zixj={se ij exiexj(nk=1exk)2=zizjse i=j exjnk=1exkexjexj(nk=1exk)2=zj(1zj)  e quindi zx=[z1(1z1)z1znznz1zn(1zn)]

La funzione softmax è quasi sempre presente nel livello di uscita, abbinata ad una funzione di costo entropia incrociata (Cross Entropy)   J=CE(z,y)=ylogz  , nella quale la somma delle componenti del vettore dato y è uguale a 1. Procederemo in questo caso a prendere a esplicitare il jacobiano Jz=[y1z1ynzn]

Applicando la chain rule agli jacobiani  abbiamo Jx=Jzzx=[yjzjzj(1zj)+kjykzkzjzk]=[yj+zjyj+zjkjyk]=[zjyj]=(zx)

Per cui trasponendo otteremo il gradiente  dx=zx

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:1z:m]=[softmax(x:1)softmax(x:m)] .  La funzione di costo che utilizzeremo in questo caso è estesa alla matrice come J=mi=1nj=1Yij logZij   e   JZij=YijZij

In questo caso abbiamo:

 ZijXkl={se jl 0se j=l , ik eXil eXkl(nt=1eXtl)2=ZilZklse j=l , i=k eXklnt=1eXtleXkl eXkl(nt=1eXtl)2=Zkl(1Zkl)

JXkl=mi=1nj=1JZijZijXkl=mi=1YilZilZilXkl=YklZklZkl(1Zkl)+ikYilZilZilZkl=Ykl+YklZkl+ZklikYil=ZklYkl

Per cui otteniamo dX=(ZY)

Nella pratica la funzione di costo viene moltiplicata per un coefficiente 1m per ottenere valori non legati alla numerica delle colonne/campioni in matrice.

 

©2023 - me@enricogiannini.com -