LO SCAFFALE DEGLI HOBBY

Appunti On Line

AVVERTENZE da leggere attentamente


Reti neurali in pratica

Questo testo contiene qualche appunto pratico e sintetico sull'uso delle reti neurali di tipo feed forward addestrate con il metodo back propagation. Le reti neurali di cui si parla qui non sono un modello stretto di quelle naturali, ma funzionano come un potente sistema matematico di interpolazione "addestrabile" per calcolare funzioni non lineari di qualsiasi complessità a partire da esempi di ingressi/uscite noti. Un altro grosso vantaggio, oltre a quello di poter "apprendere" funzioni complesse e poter calcolare in parallelo più funzioni contemporaneamente, è quello di richiedere solo semplici somme e moltiplicazioni, più l' applicazione di una funzione di trasferimento in uscita uguale per tutte le unità.


Alcuni link introduttivi:



IL NEURONE

L'unità elementare di calcolo di una rete neurale è il neurone. Può avere uno o più ingressi provenienti da altri neuroni e ha una sola uscita eventualmente diretta verso uno o più neuroni successivi. I segnali, sia in ingresso che in uscita possono assumere un qualsiasi valore continuo compreso tra 0 e 1.

In questa figura il neurone Y ha 4 ingressi (sinapsi o connessioni) a cui arrivano i segnali H1..H4 ciascuno associato ad un peso (w1..w4). I pesi sono un fattore moltiplicativo applicato al segnale di ingresso, possono essere positivi o negativi (sinapsi eccitatoria o inibitoria), maggiori o minori di 1 (sinapsi amplificatrice o attenuatrice). In più ogni neurone ha un peso di bias (wb) che serve per regolare il punto di lavoro del neurone stesso. Questa sinapsi si considera collegata ad un'unità fittizia che genera un segnale sempre pari a 1, e pertanto non è necessario rappresentarla nel disegno.

Si definisce attivazione interna del neurone (chiamata A) la somma pesata di tutti i segnali in ingresso:

A = H1*w1 + H2*w2 + H3*w3 + H4*w4 + wb

Il segnale in uscita dal neurone è invece chiamato attività ed è calcolato applicando una funzione di trasferimento di forma sigmoidale che ha dato buoni risultati pratici e semplifica la trattazione matematica. Nella formula seguente X rappresenta l'attivazione interna ed "e" è la base dei logaritmi naturali (2,71828):



L'uscita del nostro neurone si ottiene perciò con:
Y = 1 / (1 + e^(-A))


IL COMPUTO NEURALE

A seconda del valore dei pesi, al variare dei valori in ingresso l'uscita del neurone riproduce una diversa funzione matematica. Per semplicità è possibile considerare il caso di un singolo neurone con uno o due ingressi (problema a 1 o 2 dimensioni). I grafici seguenti mostrano alcuni possibili andamenti dell' attività di uscita in funzione di diverse configurazioni dei pesi.









Come si vede, con un singolo neurone (perceptron) lo spazio del problema può essere solo suddiviso da un piano più o meno inclinato e/o orientato, è cioè possibile lavorare solo con problemi linearmente separabili da un piano, ma non è possibile ottenere "figure chiuse" o funzioni più complesse.

Per fare questo le reti neurali devono essere formate da diversi strati interconnessi tra loro. In genere si considera uno strato di ingresso X che però non entra nel calcolo complessivo, i suoi neuroni non hanno pesi e rappresentano solo i valori di ingresso. Seguono poi uno o più strati detti intermedi o nascosti, ed infine uno strato di uscita Y, formato da uno o più neuroni a seconda del compito della rete. Con uno strato intermedio una rete può già calcolare molte funzioni matematiche (ma il numero di unità nascoste potrebbe diventare proibitivo), con 2 strati intermedi la sua potenza aumenta considerevolmente e si riduce il numero di unità necessarie. Questo si comprende intuitivamente considerando che un ulteriore strato permette ai neuroni di uscita di fare la somma di più funzioni complesse provenienti dallo strato precedente. La figura seguente chiarisce il concetto: i neuroni H suddividono semplicemente lo spazio in tre piani diversi e il neurone Y effettua la somma globale di questi piani ottenendo una la funzione di uscita molto più complessa. Il numero minimo di unità H necessarie per creare una figura chiusa in uno spazio n-dimensionale è n+1 (in questo caso lo spazio del problema è a 2 dimensioni e le unità H devono essere 3), più unità ci sono e più la figura (o la funzione) può essere dettagliata.




Per rendere l'idea delle possibilità insite nel computo neurale basta guardare la figura seguente. È un esempio di rete già abbastanza complessa da poter calcolare le funzioni trascendenti della cinematica inversa, ed è in grado di controllare il movimento di due snodi di un braccio robotico partendo dai loro angoli attuali e dalle coordinate polari del punto da raggiungere...





L'ADDESTRAMENTO

Per essere utile una rete neurale va addestrata. Si parte con i pesi impostati a piccoli valori casuali e si sottopongono ad essa degli esempi di ingressi e uscite corretti, si applica un procedimento di correzione dei pesi per piccoli passi fino ad ottenere un'uscita effettiva che per ogni esempio non si discosti oltre una certa percentuale dall' uscita campione usata per l'addestramento. Per fare questo si usa la regola delta generalizzata, in sostanza per ogni esempio fornito in ingresso si valuta l'errore in uscita rispetto al valore desiderato, e si calcola un delta del neurone che serve poi per modificare i diversi pesi.

In questa figura si suppone che il neurone Y sia l'uscita della nostra rete, pertanto per determinare il suo errore possiamo semplicemente fare la differenza tra l'uscita desiderata (D) e quella effettiva (Y). Il delta del neurone si calcola moltiplicando l'errore per la derivata della funzione di uscita (Y*(1-Y)), in questo modo il delta rappresenta in un certo senso la velocità di variazione dell'errore del neurone al variare complessivo dell'attivazione interna. I pesi possono poi essere modificati come da formula. Ogni peso viene modificato di una quantità pari al delta del neurone per il segnale in arrivo su quella connessione e il tutto ancora moltiplicato per un fattore Epsilon (Eps) detto fattore (o tasso) di apprendimento (compreso tra 0,1 e 0,9) scelto a priori. Tanto maggiore è Epsilon e tanto più rapida è la variazione dei pesi durante l'addestramento, ma questo puo portare ad errori eccessivi e oscillazioni nell'apprendimento. Viceversa un Epsilon basso permette un addestramento più preciso ma il tempo occorrente per esso aumenta notevolmente ed è possibile che l'apprendimento si blocchi in un minimo locale della funzione di errore.

Nel caso in cui il neurone da addestrare appartenga ad uno strato intermedio non è possibile determinare il suo errore come differenza tra l'uscita voluta e quella effettiva, in questo caso si usa "retropropagare" l'errore che era stato calcolato sull'uscita effettiva attraverso il delta. In questa figura si vede che l'errore del neurone H viene considerato pari al delta del neurone successivo moltiplicato per il peso della connessione che unisce i due neuroni. Nel caso in cui la sua uscita andasse verso più neuroni, l' errore è la somma di tutti i singoli delta pesati come calcolato nella seguente figura:





Una volta determinato l'errore di H è possibile calcolare il DeltaH ed effettuare le variazioni dei pesi nello stesso modo di prima. Come si nota nel calcolo dell'errore si parte dall'uscita e si procede verso gli ingressi, è importantissimo calcolare il delta di tutti i neuroni della rete PRIMA di iniziare a modificare i pesi.

Per l'addestramento globale di una rete si procede nel seguente modo:

1) Si sceglie un epsilon iniziale grande maggiore di 0.6
2) Si impostano i pesi a piccoli valori casuali
3) Per ogni esempio
    a) Si presenta l'esempio alla rete e la si
       esegue per determinarne l'uscita
    b) Si calcolano i delta di tutte le unità 
    c) Si modificano i pesi
4) Se il massimo errore commesso da una qualsiasi unità
   di uscita durante un qualsiasi esempio è maggiore di
   quello ammesso tornare al punto 3
5) Se continuando l'addestramento l'errore non diminuisce,
   allora diminuire epsilon e tornare al punto 3


RAPPRESENTAZIONE SOFTWARE

Generalmente per compattezza una rete viene rappresentata come in questa figura. Ai fini del calcolo automatico è comodo considerare i vari neuroni di uno strato come elementi di un array, e i vari pesi di quello strato come una matrice bidimensionale. Nella figura è rappresentata una rete con 2 ingressi, 2 uscite e uno strato intermedio. i,k e j sono gli indici che servono a identificare un neurone all'interno dello strato. wh e wy sono le matrici dei pesi degli strati. A destra c'è la struttura dei dati descritta in Pascal. Le costanti NX, NH e NY permettono di definire con comodità quanti neuroni devono esserci in ogni strato. Nel caso delle matrici dei pesi, per ogni neurone sono presenti tutti i pesi verso lo strato precedente più il peso di bias (a questo è dovuto il NX+1 e NH+1).




STRUTTURA DATI

const NX = 2; 
const NH = 4;
const NY = 2;
var A: real;
var i, k, j: integer;
var X:  array[1..NX] of real;
var H:  array[1..NH] of real;
var Y:  array[1..NY] of real;
var wh: array[1..NH, 1..NX+1] of real;
var wy: array[1..NY, 1..NH+1] of real;

Di seguito sono riportate le procedure di "esecuzione" della rete, cioè il procedimento per ottenere i valori di uscita Y[j] a partire dagli ingressi X[i], la struttura dati aggiuntiva per l'apprendimento (l'array D[j] contiene le uscite desiderate) e la procedura di retropropagazione dell'errore e modifica dei pesi.



ESECUZIONE

//Calcola strato H
for k := 1 to NH do begin
  A := 0.0;
  for i := 1 to NX do A := A + (wh[k,i] * X[i]);
  A := A + wh[k, NX+1];
  H[k] := 1.0 / (1.0 + EXP(-A));
end;
//Calcola strato Y
for j := 1 to NY do begin
  A := 0.0;
  for k := 1 to NH do A := A + (wy[j,k] * H[k]);
  A := A + wy[j, NH+1];
  Y[j] := 1.0 / (1.0 + EXP(-A));
end;


STRUTTURA DATI AGGIUNTIVA PER APPRENDIMENTO

const Eps = 0.3
var Err: real;
var D array[1..NY] of real;
var DeltaY array[1..NY] of real; 
var DeltaH array[1..NH] of real;


BACK PROPAGATION

//Calcolo errore strato Y
for j := 1 to NY do begin
  Err := D[j] - Y[j];
  DeltaY[j] := Err * Y[j] * (1 - Y[j]);
end;
//Calcolo errore strato H
for k := 1 to NH do begin
  Err := 0.0;
  for j := 1 to NY do Err := Err + (DeltaY[j] * wy[j, k]);
  DeltaH[k] := Err * H[k] * (1 - H[k]);
end;
//Modifica pesi strato Y
for j := 1 to NY do begin
  for k := 1 to NH do wy[j, k] := wy[j, k] + (Eps * DeltaY[j] * H[k]);
  wy[j, NH+1] := wy[j, NH+1] + (Eps * DeltaY[j]);
end;
//Modifica pesi strato H
for k := 1 to NH do begin
  for i := 1 to NX do wh[k, i] := wh[k, i] + (Eps * DeltaH[k] * X[i]);
  wh[k, NX+1] := wh[k, NX+1] + (Eps * DeltaH[k]);
end;


ESPERIMENTO DI APPRENDIMENTO FUNZIONE

Come primo esperimento con una rete semplice ho voluto provare ad addestrarla al calcolo di una sinusoide. In pratica in ingresso voglio fornire un valore compreso tra 0 e 1 che rappresenta l'angolo tra 0 e 360 gradi, e in uscita mi aspetto di ottenere il seno dell'angolo nel range 0,1..0,9 (il valore da 0,1 a 0,9 in uscita deve rappresentare il seno da -1 a +1).

Il motivo per cui ho scelto un range in uscita da 0,1 a 0,9 è che per arrivare esattamente ai limiti 0 e 1 occorrono pesi molto grandi, mentre è relativamente semplice arrivare al 10% o al 90%.

Il numero di unità intermedie dipende dalle caratteristiche del problema da risolvere, empiricamente un buon valore può essere 2,5 volte le unità di ingresso. Poche unità intermedie non permettono alla rete di apprendere una configurazione di pesi valida, troppe aumentano oltre il necessario il già consistente tempo di addestramento. Oltre a questa regola bisognerebbe però tenere anche conto della complessità della funzione da calcolare. In fondo le unità del livello H creano tanti "segmenti" o suddivisioni semplici dello spazio del problema, ed è compito dell'unità Y sommare tutte queste suddivisioni elementari per ottenere la funzione complessiva. Se non ci sono sufficienti unità intermedie per descrivere tutte le caratteristiche elementari della funzione non si riesce a ricostruirla.

Ho scelto questo esempio perché la funzione matematica è nota ed è facile preparare le coppie in/out di addestramento. L'insieme dei campioni non va scelto a caso, anzi, la scelta è una cosa di fondamentale importanza per il corretto addestramento. Bisogna cioè prendere per quanto possibile campioni distribuiti omogeneamente in tutto lo spazio del problema, e devono anche essere abbastanza fitti da seguire e descrivere tutte le caratteristiche della funzione voluta (e possibilmente includere i suoi punti estremi), altrimenti si rischia di avere una rete che fornisce risultati corretti solo per i valori campione, ma al di fuori di quelli sbaglia completamente (si specializza su quei valori e non generalizza).

La tabella seguente mostra 17 campioni del valore del seno presi nell'intero range 0..360 gradi. La colonna Ingresso X rappresenta l'ingresso della rete, cioè i gradi traslati nel range 0..1 tramite la formula:

X = gradi / 360

La colonna uscita D rappresenta invece i valori desiderati di sen(X) traslati nel range 0,1..0,9 tramite la formula:

D = 0,1 + (0,8 * (seno + 1) / 2)
Campione   Gradi     Seno      Ingresso X   Uscita D
 1           0.0    0.0000      0.0000      0.5000
 2          22.5    0.3827      0.0625      0.6531
 3          45.0    0.7071      0.1250      0.7828
 4          67.5    0.9239      0.1875      0.8696
 5          90.0    1.0000      0.2500      0.9000
 6         112.5    0.9239      0.3125      0.8696
 7         135.0    0.7071      0.3750      0.7828
 8         157.5    0.3827      0.4375      0.6531
 9         180.0    0.0000      0.5000      0.5000
10         202.5   -0.3827      0.5625      0.3469
11         225.0   -0.7071      0.6250      0.2172
12         247.5   -0.9239      0.6875      0.1304
13         270.0   -1.0000      0.7500      0.1000
14         292.5   -0.9239      0.8125      0.1304
15         315.0   -0.7071      0.8750      0.2172
16         337.5   -0.3827      0.9375      0.3469
17         360.0    0.0000      1.0000      0.5000

A questo punto l'apprendimento consiste nel presentare uno alla volta i valori di X e determinare l'errore di uscita rispetto al valore desiderato D. Una volta conosciuto l'errore si modificano i pesi con la regola delta retropropagando l'errore anche allo strato intermedio H. Una volta terminati i 17 esempi è terminata un'epoca di apprendimento, il cui errore sarà l'errore massimo commesso dall' unità di uscita durante la presentazione degli esempi. Se l'errore è abbastanza basso l'apprendimento è terminato, con la certezza che l'unità non sbaglierà più di quel valore su ciascun esempio, altrimenti si ricomincia con una nuova epoca ripresentando di nuovo gli esempi e aggiustando i pesi. L'errore dell'epoca può essere tenuto sotto controllo per valutare l'avanzamento dell'apprendimento della rete.

Le immagini seguenti mostrano l'uscita della rete (in rosso) rispetto alla curva campione (verde) su cui sono riportati i punti di addestramento. La prima immagine è la rete non addestrata, la seconda è la risposta dopo 1000 epoche, la terza dopo 10000 epoche e l'ultima dopo 100mila epoche. Il tasso di apprendimento utilizzato è stato di 0,5. Come si può vedere si arriva ad avere un comportamento molto "simile" a quello voluto salvo una difficoltà a raggiungere i punti estremi della curva.





PESI DOPO L'ADDESTRAMENTO:

STRATO H
----------------------
        X        Bias 
H1    3.7558   -2.1814 
H2   12.2071  -10.9423 
H3   14.5007   -1.5133 
H4   -2.0168   -2.9522 
 

UNITÀ Y
---------------------------------------------
       H1        H2     H3       H4     Bias
Y   -13.1986  6.8320  5.0785  -1.9914  0.5348





Simulazione singolo neurone con singolo ingresso.



Codice Python: DOWNLOAD



Simulazione singolo neurone con due ingressi.



Codice Python: DOWNLOAD

Parlano di noi...

youtube.com/watch?v=q7aJOmlsVBw



All'indice principale | Al vecchio sito