Reti neurali in pratica
by Claudio Fin 4-1-2003

[Il neurone]  [Il computo neurale]  [L'addestramento]  [Rappresentazione software]  [Esempio di apprendimento funzione]


Queste pagine contengono qualche appunto pratico e sintetico sull'uso delle reti neurali di tipo feed forward addestrate con il metodo della 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 complessita' 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 piu' funzioni contemporaneamente, e' quello di richiedere solo semplici somme e moltiplicazioni, piu' l' applicazione di una semplice funzione di trasferimento in uscita uguale per tutte le unita'.

Alcuni link introduttivi:
http://www.steo.it/ici/neuro/neurofuzzy.pdf
http://www.irccsdebellis.it/html/Reti_Neurali/SITO_RetiNeurali.htm
http://lbalzerani.supereva.it/ia/backpropagation.html?p
 
 


IL NEURONE


L'unita' elementare di calcolo di una rete neurale e' il neurone.  Puo' avere uno o piu'ingressi provenienti da altri neuroni e ha una sola uscita eventualmente diretta verso uno o piu' 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 piu' 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'unita'fittizia che genera un segnale sempre pari a 1, e pertanto non e' 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 e' invece chiamato attivita' ed e' 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" e' la base dei logaritmi naturali (2,71828):

L'uscita del nostro neurone si ottiene percio' 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 semplicita' e' 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' attivita' di uscita in funzione di diverse configurazioni dei pesi.

w1 = 6.40
 wb = -5.30
  w1 = -11.20
wb  = 6.00
w1 = -1.50
wb  = 0.80

Come si vede, con un singolo neurone (perceptron) lo spazio del problema puo' essere solo suddiviso da un piano piu' o meno inclinato e/o orientato, e' cioe' possibile lavorare solo con problemi linearmente separabili da un piano, ma non e' possibile ottenere "figure chiuse" o funzioni piu' 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 pero' non entra nel calcolo complessivo,  i suoi neuroni non hanno pesi e rappresentano solo i valori di ingresso. Seguono poi uno o piu' strati detti intermedi o nascosti, ed infine uno strato di uscita Y, formato da uno o piu' neuroni a seconda del compito della rete. Con uno strato intermedio una rete puo' gia'calcolare molte funzioni matematiche (ma il numero di unita' nascoste potrebbe diventare proibitivo), con 2 strati intermedi la sua potenza aumenta considerevolmente e si riduce il numero di unita' necessarie. Questo si comprende intuitivamente considerando che un ulteriore strato permette ai neuroni di uscita di fare la somma di piu' 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 piu' complessa. Il numero minimo di unita' H necessarie per creare una figura chiusa in uno spazio n-dimensionale e' n+1 (in questo caso lo spazio del problema e' a 2 dimensioni e le unita' H devono essere 3), piu' unita' ci sono e piu' la figura (o la funzione) puo' essere dettagliata.
 
 

Per rendere l'idea delle possibilita' insite nel computo neurale basta guardare la figura seguente. E'un esempio di rete gia' abbastanza complessa da poter calcolare le funzioni trascendenti della cinematica inversa, ed e' 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 velocita' 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 quantita' 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 di apprendimento (compreso tra 0,1 e 0,9) scelto a priori. Tanto maggiore e' Epsilon e tanto piu' rapida e' 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 piu' preciso ma il tempo occorrente per esso aumenta notevolmente ed e' 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 e' 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 piu'neuroni, l' errore sarebbe la somma di tutti i singoli delta pesati [figura]. Una volta determinato l'errore di H e' 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, e' 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 impostano i pesi a piccoli valori casuali
2) 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 unita'
   c) Si modificano i pesi
3) Se il massimo errore commesso da una qualsiasi unita'di uscita durante un
   qualsiasi esempio e' maggiore di quello ammesso torna al punto 2
 


RAPPRESENTAZIONE SOFTWARE


Generalmente per compattezza una rete viene rappresentata come nella figura seguente. Ai fini del calcolo automatico e'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 e' 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'e' la struttura dei dati descritta in Pascal. le costanti NX, NH e NY permettono di definire con comodita' 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 piu' il peso di bias (a questo e'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;
 

 

Qui di seguito sono riportate le procedure di "esecuzione" della rete, cioe' 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 e' che per arrivare esattamente ai limiti 0 e 1 occorrono pesi molto grandi, mentre e' relativamente semplice arrivare al 10% o al 90%.

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

Ho scelto questo esempio perche' la funzione matematica e' nota ed e' facile preparare le coppie in/out di addestramento. L'insieme dei campioni non va scelto a caso, anzi, la scelta e' una cosa di fondamentale importanza per il corretto addestramento. Bisogna cioe' 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, cioe' 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 e' terminata un'epoca di apprendimento, il cui errore sara' l'errore massimo commesso dall' unita' di uscita durante la presentazione degli esempi. Se l'errore e' abbastanza basso l'apprendimento e' terminato, con la certezza che l'unita' non sbagliera' piu' 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 puo' 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 e' la rete non addestrata, la seconda e' la risposta dopo 1000 epoche, la terza dopo 10000 epoche e l'ultima dopo 100mila epoche. Il tasso di apprendimento utilizzato e' stato di 0,5. Come si puo' vedere si arriva ad avere un comportamento molto "simile" a quello voluto salvo una difficolta' 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 
 

UNITA' Y
---------------------------------------------
       H1        H2     H3       H4     Bias
Y   -13.1986  6.8320  5.0785  -1.9914  0.5348


Pagina e disegni realizzati da Claudio Fin
Ultimo aggiornamento 8-1-2003