Introduzione alle reti neurali artificiali
-
Upload
matteo-tosato -
Category
Documents
-
view
242 -
download
11
description
Transcript of Introduzione alle reti neurali artificiali
INTRODUZIONE ALLE RETI NEURALI ARTIFICIALI
Matteo Tosato 2010/2011
Revisione 3.0
2
Matteo Tosato - Introduzione alle reti neurali artificiali
Sommario Introduzione storica...................................................... 4
- Ciò che l’occhio della rana comunica al cervello della rana, da Kant alle reti
neurali artificiali. .................................................... 4
- Anni 40’: il sogno booleano ............................................. 4
- Anni 50’: l’età dell’oro del sogno booleano ............................. 5
- Anni 80’: Il risveglio del sogno di Boole ............................... 8
- Ringraziamenti .......................................................... 9
Aspetti biologici........................................................ 10
Il neurone artificiale................................................... 13
- Considerazioni principali .............................................. 13
- Interpretazione vettoriale ............................................. 19
Apprendimento del perceptron............................................. 20
- La regola di Hebb ...................................................... 21
- La regola postsinaptica ................................................ 22
- La regola presinaptica ................................................. 22
- La regola delta ........................................................ 22
- Valutazione delle disuguaglianze ....................................... 27
Reti neurali MLP (Multi layer perceptron)................................ 29
- Reti neurali a due strati (M-Adeline) .................................. 30
- Architetture Feed-forward .............................................. 32
- Feed-forward ricorrenti ................................................ 34
- Error back-propagation (EBP) ........................................... 35
- Migliorie per l’algoritmo EBP .......................................... 42
- Algoritmo Resilient back-propagation (RPROP) ........................... 46
- Reti di Hopfield ....................................................... 48
Reti neurali auto-organizzanti........................................... 51
- Mappe di Kohonen ....................................................... 51
Esempio di rete SOM ................................................. 56
- Competitive learning reale ............................................. 63
Problemi e strategie..................................................... 67
- Neuro-fuzzy ............................................................ 67
- Reti ART ............................................................... 69
Metodologie di progettazione............................................. 70
- Il problema dei dati in ingresso ....................................... 73
Esempi di applicazioni pratiche.......................................... 74
- Intrusion detection .................................................... 74
- Previsione di fenomeni complessi ....................................... 84
3
Matteo Tosato - Introduzione alle reti neurali artificiali
- Analisi di segnale ..................................................... 86
Reti di reti neurali..................................................... 88
Conclusione e ringraziamenti............................................. 89
Appendice A – basi matematiche........................................... 90
Appendice B – Riferimenti................................................ 98
Appendice C – Aneuro32................................................... 99
4
Matteo Tosato - Introduzione alle reti neurali artificiali
Introduzione storica a cura di Andres Reyes
Ciò che l’occhio della rana comunica al cervello della rana, da Kant alle reti neurali
artificiali.
Figura 1: Walter Pitts
Walter Pitts nacque a Detroit il 23 aprile del 1923 e all'età di 15 anni scappò di casa
perché il padre voleva abbandonasse gli studi per il lavoro. Da qui la storia prosegue
con un aneddoto che amava raccontare il neuro-fisiologo Warren McCulloch (1898-1969) .
Il giovane Pitts arrivato a Chicago passò le sue ore nel parco vicino all'università
conversando di filosofia e logica con Bert.
Ignaro in realtà che fosse il famoso matematico Bertrand Russell (1872-1970) ospite
alla University of Chicago nell'anno accademico 1938-39 per un seminario. Sempre
secondo McCulloch, Russell consigliò a Pitts di leggere “La costituzione logica del
mondo” (1928) del logico Rudolf Carnap (1891-1970) membro del circolo di Vienna, che si
trovava a Chicago per il seminario di Russell. Pitts si accorse che il libro presentava
un errore ed andò a trovare Carnap in ufficio all'università, ma non essendosi
presentato solo mesi dopo Carnap seppe chi era il giovane e per aiutarlo gli trovò un
lavoro presso l'università.
Anni 40’: il sogno booleano
Nel 1943 il giovane Pitts e McCulloch proposero uno studio pionieristico "A logical
calculus of the ideas immanent in nervous activity" sulle reti neurali artificiali
(ANN) dimostrando che l'algebra di Boole poteva essere applicata allo studio delle reti
neurali biologiche , studiando come 1 (eccitato) e 0 (inibito) l'attività del neurone.
5
Matteo Tosato - Introduzione alle reti neurali artificiali
Inserendosi così negli intenti, già definiti dal matematico inglese George Boole fin
dal 1854, “di ricercare le leggi fondamentali di quelle operazioni dello spirito
mediante le quali si attua il ragionamento, dare loro un'espressione nel linguaggio
simbolico del calcolo, e costruire su questo fondamento la scienza della logica e il
suo metodo”.
Boole (1815-1864) riteneva che le sue ricerche fossero più un contributo alla
psicologia che alla matematica e che leggi da lui scoperte fossero realmente quelle del
pensiero perché dimostravano che la logica proposizionale e quella sillogistica
aristotelica erano due aspetti della stessa realtà. Bastava infatti sostituire "1 =
vero" e "0 = falso" come due insiemi che rappresentano il Tutto ed il Nulla.
Infine l'ingegnere Claude Shannon (1916-2001) nella sua tesi del 1937 “A Symbolic
Analysis of relay and Switching Circuits” evidenziò come l'algebra di Boole poteva
rappresentarsi anche come un interruttore aperto (0) o chiuso (1) mettendo così le basi
per la costruzione dei computers.
L'analogia tra circuiti elettrici e neuronali permetteva quindi di pensare
metaforicamente al cervello come a un computer biologico (wetware) e al computer come
un cervello elettronico permettendo così di risolvere il dualismo cartesiano in chiave
materialista.
Inoltre trasformava le reti neuronali in una macchina di Turing (TM) portando
all'identificazione dei processi cognitivi con quelli formali algoritmici di una
macchina dando così la possibilità di riprodurre meccanicamente la coscienza come
auspicato dalla nascente ricerca sull'intelligenza artificiale .
Posizione che sarebbe stata criticata negli anni '80 dal filosofo americano John Searle
con l'esperimento mentale della stanza cinese (“Menti, cervelli e programmi”,1980) e da
Thomas Nagel con la celeberrima frase:
”Che cosa si prova ad essere un pipistrello?”.
Per Searle,l'approccio computazionale fornisce solo un una dottrina formale del
funzionamento della mente,parla di operazioni mentali e di processi, ma solo raramente
di contenuti. Mentre sembra che l'intenzionalità sia una caratteristica della
coscienza, cioè la sua necessità di pensare qualcosa, vedere qualcosa, immaginare
qualcosa.
Con questa metodologia dunque non è possibile spiegare la questione dei qualia, le
qualità soggettive degli stati di coscienza, ciò che il filosofo americano Thomas Nagel
ha definito come l'effetto che fa essere un determinato tipo di essere.
Il modello proposto da McCulloch e Pitts mancava però di una caratteristica
fondamentale: la possibilità di apprendere.
Contributo che giunse nel 1949 dallo psicologo canadese Donald Hebb (1904-1985) che
propose nella sua opera “L'organizzazione del comportamento” un semplice meccanismo di
apprendimento: “quando un assone della cellula A prende parte ripetitivamente nel
processo di eccitamento della cellula B, qualche cambiamento strutturale o metabolico
subentra in una o entrambe le cellule in modo che l'efficienza di A, come cellula
eccitatrice di B, aumenti”.
Anni 50’: l’età dell’oro del sogno booleano
6
Matteo Tosato - Introduzione alle reti neurali artificiali
Alla fine degli anni '50 vennero pubblicate tre opere che incentivarono ulteriori
sviluppi delle reti neurali artificiali : “Pandemonium: A paradigm for learning” (1958)
di Selfridge, Il Perceptron (1958) di Rosenblatt e l'Adaline di Windrow e Hoff.
L'idea di Pandemonium, termine coniato dal poeta inglese John Milton nel “Paradiso
perduto”(1667), secondo Oliver Selfridge “era quella di avere un gruppo di demoni che
davano la voce a quelli del livello superiore, e questi a quelli di un livello ancora
superiore” cioè di disporre di diverse reti neurali , appunto di demoni, semi-
indipendenti che comunicavano il loro output per ogni singola proprietà per esempio di
un volto o di una parola (Pattern Recognition).
Figura 2: Modello del perceptron
L'idea dei demoni venne ripresa nel 1985 da Marvin Minsky come modello della mente come
società di multi-agenti (“La società della mente”,1985).
Nel 1958 lo psicologo Frank Rosenblatt scrisse “The Perceptron, a Probabilistic Model
for Information Storage and Organization in the Brain” rifiutando l'uso della logica
simbolica di Pitts e McCulloch a favore di metodi probabilistici. Il perceptron
risultava quindi un classificatore e riconoscitore di schemi che simulava la visione
umana.
Nel loro saggio “Adaptive Switching Circuits” (1960) Bernard Windrow e Marcian Hoff
introdussero una rete simile al perceptron, chiamata Adaline (Adaptive Linear Element)
ed in seguito la Madaline (Multiple Adaline) la prima rete ad essere applicata nel
mondo reale per la riduzione dell'eco nelle linee telefoniche.
La principale differenza con il modello di Rosenblatt era l'algoritmo di apprendimento
basato sulla minimizzazione della somma dei quadrati degli errori nelle sinapsi (delta
rule) e sulla somministrazione di esempi per ottenere l'output desiderato
(apprendimento supervisionato).
In questo contesto ritroviamo anche l'esperimento del 1959 condotto da Jerome Lettvin
(1920-2011), dal neuroscienziato cileno Humberto Maturana, da McCulloch e Pitts sulla
percezione visiva della rana:
“Ciò che l'occhio della rana comunica al cervello della rana”.
7
Matteo Tosato - Introduzione alle reti neurali artificiali
Figura 3: Pitts e Lettvin osservando una rana
Il rapporto fra vista e percezione, fra il vedere ed il decodificare un' immagine, è da
sempre uno degli argomenti alla base delle questioni legate all'esperienza cosciente.
Lo scopo dell'esperimento, richiamandosi alla “Critica della ragion pura” (1787) del
filosofo tedesco Immanuel Kant (1724-1804), era di dimostrare sperimentalmente le "basi
fisiologiche del sintetico a priori" cioè all'esistenza di filtri naturali che
selezionano i contenuti dell'esperienza.
Se ad esempio una mosca passasse davanti all'occhio della rana questa verrebbe
percepita e di riflesso mangiata però se dinanzi alla rana poniamo un oggetto statico,
anche una mosca uccisa dallo sperimentatore, non se la mangerebbe, non perché lo
decida, ma perché non la vede!
L'immagine della mosca si forma nella retina della rana però l'informazione non viene
elaborata dal cervello.
Le opere di Rosenblatt, Windrow e Hoff stimolarono numerose ricerche tuttavia
l‟entusiasmo cessò nel 1969 con il saggio “Perceptrons: An Introduction to
Computational Geometry” di Marvin Minsky e Seymour Papert in cui si dimostravano i
limiti del perceptron come l'impossibilità di realizzare funzioni linearmente
separabili come la Xor. Infatti ciò avrebbe richiesto l'addestramento dei neuroni
nascosti (Hidden Layer).
8
Matteo Tosato - Introduzione alle reti neurali artificiali
Termina così per più di un decennio ciò che il matematico Douglas Hofstadter , autore
di “Godel, Escher e Bach”, aveva definito come l'età dell'oro del sogno booleano
dell'intelligenza artificiale.
Figura 4: Marvin Minsky e Seymour Papert
Anni 80’: Il risveglio del sogno di Boole
Nel 1982 il finlandese Teuvo Kohonen, ispirandosi alla topologia della corteccia del
cervello, introdusse un nuovo tipo di ANN le SOM (self-organizing map) in grado di
sviluppare un comportamento auto-organizzante senza l‟addestramento da parte di un
supervisore, attraverso l‟eccitazione di neuroni vicini e l'inibizione di quelli
lontani.
Nel 1986 venne introdotto, grazie alle pubblicazioni degli psicologi David Rumelhart,
Geoffrey Hinton e Ronald Williams, l‟algoritmo di retro-propagazione (Error
BackPropagation EBP), capace di addestrare anche il livello di neuroni nascosti (hidden
layer) attraverso una modifica sistematica degli errori tra i nodi, superando così le
critiche degli anni 60'.
Bisogna però ricordare che tale algoritmo era già stato pensato nel 1974 da P. Werbos
nella sua tesi di dottorato.
Inoltre David Rumelhart (1942-2011) ed il suo collega James McClennand pubblicarono in
due volumi “Parallel Distributed Processing” (PDP) rilanciando così il programma
connessionista.
Proponevano quindi tre elementi predominanti nella riproduzione dell'attività cognitiva
attraverso le ANN: il processamento in parallelo, memoria distribuita ed adattabilità.
Al contrario di come avveniva nell'intelligenza artificiale: processamento sequenziale,
memoria localizzata ed istruzioni imperative.
Il connessionismo definiva l'intelligenza come apprendimento e non più come mera
elaborazione e programmazione di simboli infine come nel cervello i dati venivano
“evocati” e non “cercati”.
9
Matteo Tosato - Introduzione alle reti neurali artificiali
Ulteriore successo del connessionismo fu che Rumelhart e McClennand resero disponibili
per anni i sorgenti dei loro programmi agli studenti delle università dove insegnavano
esortandoli a testarli e a modificarli.
Ringraziamenti
Vorrei ringraziare il filosofo e neuro-psicologo Marco Mozzoni , direttore della
rivista di neuroscienze BrainFactor, per l'aiuto datomi nella stesura di questo breve
articolo introduttivo alle reti neurali.
Andres Reyes.
10
Matteo Tosato - Introduzione alle reti neurali artificiali
Aspetti biologici
Il cervello,
È l‟oggetto più complesso e misterioso che si conosca: 1.300-1.500 grammi di tessuto
gelatinoso composto da 100 miliardi di cellule (i neuroni), ognuna delle quali sviluppa
in media 10 mila connessioni con le cellule vicine. Durante la vita fetale l‟organismo
produce non meno di 250 mila neuroni il minuto. Ma 15-30 giorni prima della nascita, la
produzione si blocca e per il cervello comincia una seconda fase che durerà per tutta
la vita: la creazione di connessioni tra le cellule.
In questo processo, le cellule che falliscono le connessioni vengono eliminate, tanto
che al momento della nascita sono già dimezzate. Il cervello umano (più correttamente
"encefalo") è il risultato della sovrapposizione dei tre tipi di cervello apparsi nel
corso dell‟evoluzione dei vertebrati.
Dal basso (alla base del cranio), il cervello più antico, o romboencefalo,
specializzato nel controllo di funzioni involontarie come vigilanza, respirazione,
circolazione e tono muscolare. Comprende il cervelletto e le parti del midollo spinale
che si allungano nel cervello.
Salendo, c‟è il mesencefalo: una piccola porzione di tessuto nervoso costituita dai
cosiddetti peduncoli cerebrali e dalla lamina quadrigemina. Infine c‟è il prosencefalo,
la parte più "moderna", suddiviso in diencefalo e telencefalo. Il primo, chiamato anche
"sistema limbico", contiene strutture come talamo, ipotalamo, ipofisi e ippocampo, da
cui provengono sensazioni come fame, sete o desiderio sessuale. Infine, la parte più
recente in assoluto: la corteccia, dove hanno sede le funzioni intelligenza e
linguaggio.
Ma veniamo ai mattoni del cervello, i neuroni: cellule specializzate nel raccogliere,
elaborare e trasferire impulsi nervosi. Dal loro corpo cellulare si diramano vari
rametti, i dendriti, e un ramo più grosso, l‟assone.
I primi ricevono i segnali in arrivo, il secondo conduce i messaggi in uscita. Grazie a
dendriti e assoni, il numero totale delle connessioni che i neuroni di un cervello
umano riescono a stabilire supera il numero di tutti i corpi celesti presenti
nell‟universo.
L‟esistenza di queste connessioni, o sinapsi, fu scoperta alla fine del XIX secolo dal
fisiologo inglese Charles Scott Shemngton, anche se non si tratta di connessioni
fisiche perché tra due neuroni s‟interpone sempre una microscopica fessura.
Per superare questo varco, i segnali cambiano faccia: da elettrici, diventano chimici.
La terminazione dell‟assone rilascia sostanze, dette neurotrasmettitori, che sono
raccolte dagli appositi recettori presenti sulla membrana della cellula-obiettivo.
Catturato il neurotrasmettitore, il messaggio chimico viene riconvertito in impulso
elettrico.
Per rendere il viaggio più veloce, sull‟assone l‟impulso procede a balzi.
L‟assone, infatti, è ricoperto da un materiale isolante chiamato guaina mielinica, che
però lascia scoperti alcuni punti: i nodi di Ranvier. E saltando da un nodo all‟altro,
l‟impulso raggiunge i 400 km/h.
11
Matteo Tosato - Introduzione alle reti neurali artificiali
"Il cervello ha alcuni punti di contatto con i computer, ma anche una differenza
essenziale: è "plastico" Che cosa significa? Che ogni volta che lo usiamo, si
modifica".
Proprio qui volevo arrivare dove l'informatica di distrae e cambiando direzione
incontra la neurologia. Abbiamo già visto che due neuroni, per comunicare, si scambiano
sostanze chimiche che li inducono a generare particolari impulsi elettrici. Immaginate
di ripetere questo processo milioni, miliardi di volte e avrete descritto, anche se in
maniera semplificata, il trasferimento di un‟informazione (visiva, acustica...)
all‟interno di un circuito neuronale del cervello umano. Vediamo un caso semplice.
immaginiamo per esempio di cogliere un fiore mai visto prima e caratterizzato da un
profumo piacevolissimo. Questo tipo di informazione viaggerà dalla mucosa olfattiva (la
parte interna del naso che "sente" gli odori), lungo il nervo olfattivo, fino alla
parte della corteccia cerebrale organizzata per analizzare e comprendere i profumi. Nel
fare ciò, l‟informazione attraverserà un numero enorme di sinapsi creando l‟equivalente
di un "sentiero" neuronale. Al ripetersi dell‟esperienza, l‟informazione viaggerà
nuovamente lungo lo stesso percorso rinforzandolo ancora di più, proprio come il
passaggio di molte persone in un bosco crea un sentiero.
Una cosa però è certa: alla base della memoria c‟è la plasticità neuronale.
Con queste parole si definisce l‟abilità del cervello di plasmare se stesso attraverso
il continuo rimodellamento delle sinapsi vecchie e la creazione di sinapsi nuove. Il
cervello è infatti in costante rimodellamento, ed è proprio per questo che si deve
mantenerlo sempre in esercizio per garantirne l‟efficienza. Certo, è legittimo pensare
che l‟apprendimento sia qualcosa di più della ristrutturazione di un certo numero di
sinapsi... ma esiste una prova concreta che senza la plasticità neuronale non saremmo
più capaci di apprendere.
Concentriamoci su quella che è la struttura del neurone biologico, che abbiamo visto
essere struttura fondamentale.
Figura 5: Neurone
Le sinapsi quindi comprendono sia l'assone che i dentriti, possono essere eccitatorie
oppure inibitorie a seconda della loro capacità di trasporto del segnale.
Il neurone, dato che può emettere o meno un segnale elettrico avrà anche una soglia di
attivazione. Fin quando la membrana del neurone resta indisturbata non si origina alcun
potenziale d‟azione, ma se un qualsiasi evento provoca un sufficiente aumento del
potenziale del livello di -90mV verso il livello zero, è lo stesso voltaggio in aumento
12
Matteo Tosato - Introduzione alle reti neurali artificiali
che fa si che molti canali del sodio voltaggio dipendenti comincino ad aprirsi. Ciò
permette un rapido ingresso di ioni sodio, che provoca ancora un nuovo aumento del
potenziale di membrana, che fa aprire un numero ancora maggiore di canali del sodio
accrescendo il flusso di ioni sodio che entrano nella cellula. Il processo si
autoalimenta con un circolo vizioso di feedback positivo fino a che tutti i canali del
sodio non risultano totalmente aperti. Ma a questo punto in una successiva frazione di
millisecondo il potenziale di membrana in aumento provoca una chiusura dei canali del
sodio e una apertura di quelli del potassio, dopodiché il potenziale d‟azione termina.
Perché si inneschi il potenziale d‟azione è necessario che il potenziale di membrana
aumenti di 15/30mV, portando quest‟ultimo a circa -65mV (soglia di eccitazione). Quindi
non sempre è detto che la soglia di attivazione viene raggiunta, dipende proprio dalla
velocità del processo suddetto.
Figura 6: Attivazione neurone
Questo potenziale è diffuso lungo tutta la struttura neuronale, anche alle estremità
delle sinapsi la dove il segnale elettrico diventa chimico per passare al neurone
interconnesso. Se questo si verifica la sinapsi sarà quindi di eccitazione, altrimenti
di inibizione.
questo è quanto ci conviene sapere per comprendere come funziona il neurone, esistono
poi altre importanti questioni che si potrebbe citare per quanto riguarda tutta la
parte chimica, il neurone è in effetti un sistema pompa sodio-potassio.
I neuroni interconnessi formano una rete neurale, questa nel corso del tempo e delle
esperienze si modifica adattandosi alla nuova necessità di risolvere sempre problemi
differenti e prendere decisioni diverse. Le ricerche riguardo il funzionamento del
cervello hanno fatto grandi passi in avanti negli ultimi anni, diversi sono i progetti
interessanti ai quali attualmente si sta lavorando in tutto il mondo; c‟è chi ha come
obiettivo quello di costruire un cervello artificiale e chi mette a punto tecniche
sempre più sofisticate per l‟analisi del suo funzionamento. La seguente immagine mostra
una mappa del cervello ricostruita al computer.
13
Matteo Tosato - Introduzione alle reti neurali artificiali
Figura 7: Mappa 3D del cervello (non completa)
Il neurone artificiale
Considerazioni principali
Che cosa ha fatto l‟informatica dunque? Bè nulla di speciale se posso esprimere un
parere personale, ha spudoratamente copiato dalla Natura il principio di funzionamento
trovato nel neurone biologico, le equazioni che descrivono i neuroni come dei
generatori di elettricità furono scoperte da due premi Nobel di Cambridge.
Per applicare tale principio, il neurone è stato di molto
semplificato e adattato. Nonostante questo le sue proprietà
fondamentali sono state conservate.
La struttura base è costituita da „i‟ ingressi, una funzione
di attivazione „Ө‟, una uscita „y‟, un peso „w‟ per ogni
sinapsi ed un valore soglia „ט‟ il quale servirà eventualmente
per normalizzare gli input.
14
Matteo Tosato - Introduzione alle reti neurali artificiali
P
W1
W2
X1
X2
Wi
Xi
Ө(P) Y.
.
.
Figura 8: Neurone artificiale schematizzato
Il numero degli ingressi può variare da un minimo di 1 ad un valore positivo intero
qualunque. In figura, ciò che ho indicato con la lettera P all‟interno del neurone è il
suo potenziale. Questo potenziale si ottiene dalla sommatoria dei valori in input
tenendo conto del peso sinaptico ad essi associata.
Definiamo quindi la seguente formula per il potenziale P:
∑( )
Questo potenziale non è il valore trasferito al neurone successivo ma solo un valore
intermedio che verrà utilizzato della funzione al momento del trasferimento. La variabile „n‟ rappresenta ovviamente il numero di input presenti. La variabile
soglia , che viene sottratta ogni volta che l‟input viene moltiplicato al peso sinaptico, ha lo scopo di normalizzare tale input in modo che rientri in un valore
compreso tra -1 e 1. Ma questo non sempre viene fatto, spesso i dati sono normalizzati
prima di essere inseriti in ingresso.
Difficilmente una rete neurale può lavorare con input molto grandi e nello scopo
dell‟utilizzo avrebbe poco senso. Pensiamo a una immagine la quale ridotta in pixel
viene analizzata attraverso una rete neurale, ogni pixel può benissimo avere valore 0 o
1, ad indicare colore o bianco.
Il trasferimento, in questo caso, coincide anche con il valore di uscita Y definito
dalla formula seguente:
( ∑( )
)
Ci resta ora da definire la funzione di trasferimento . Essa dipende strettamente con quello che la rete neurale dovrà fare e dal tipo di
architettura scelta.
Di seguito presento le funzioni di utilizzo più comune. (Riporto grafico e sintassi di
matlab).
La prima che vediamo è chiamata funzione a gradino o binaria. Vi è solo una lieve
differenza fra le due. Questa è utilizzata nelle configurazioni semplici quando si ha
un solo elettrone ed un solo strato.
15
Matteo Tosato - Introduzione alle reti neurali artificiali
{
e {
Questa funzione viene utilizzata quando è prevista un‟uscita con valore zero oppure
eccitatoria, quindi quando input e output sono booleani. quella a gradino naturalmente
varia per il caso con x minore o uguale a zero dove il valore di y è -1.
Un‟altra funzione di uso comune è quella lineare anche chiamata identità, la bisettrice
del primo e terzo quadrante.
*
Per valori di y crescenti possiamo invece ricorrere alla funzione a saturazione
lineare.
{
La funzione sigmoidale è una delle più importanti, specie nelle reti dove viene
utilizzato l‟apprendimento back-propagation. Viene chiamata anche funzione logistica.
L‟equazione che la descrive è:
16
Matteo Tosato - Introduzione alle reti neurali artificiali
Essa è sempre crescente, è continua su tutto l‟asse dei reali ed è derivabile, vale 1 a
+∞ e 0 a -∞, questa funzione è la più utilizzata nelle reti multistrato dove è importante avere risultati nel continuo, però presenta un “problema”, essendoci un
esponenziale risulta piuttosto gravosa in termini di calcoli (considerate che ogni
neurone ha una funzione di attivazione e le uscite vanno calcolate miliardi di volte).
Quando si ha necessità di avere spesso valori in uscita inibitori possiamo utilizzare
la tangente iperbolica. La cui equazione è:
In ultimo le “radial basis functions”, simile alla funzione di Gauss:
Ora che conosciamo il neurone artificiale siamo in grado di affrontare le principali
configurazioni.
I neuroni possono essere combinati in tantissimi modi per ottenere la rete neurale dal
comportamento voluto. Nelle reti i neuroni si stimolano reciprocamente, quindi l‟uscita
y che abbiamo visto prima diventa l‟input di un altro neurone e via dicendo fino ad
arrivare ad una uscita non connessa che rappresenta l‟output dell‟intera rete. La rete
come per quelle biologiche, va a modificare i propri pesi sinaptici dei neuroni
attraverso algoritmi di apprendimento dipendenti dalla configurazione, in questo modo
si possono ottenere comportamenti diversi.
L‟output della rete potrà convergere, crescere oppure oscillare. Solitamente una rete
utile ha una uscita che converge verso il valore desiderato. Una NN con uscita sempre
17
Matteo Tosato - Introduzione alle reti neurali artificiali
crescente si dice che “esplode”, proprio perché la sua uscita diventerà presto
intrattabile. Una NN con uscita oscillatoria significa che compie un ciclo ripetitivo,
come vizioso.
Riassumendo, possiamo dire che una NN è composta da neuroni e che corregge i propri
pesi sinaptici ad ogni attivazione di questi.
La rete appena creata sarà inservibile per il suo scopo finale, perché avrà pesi
sinaptici non corretti. (e questo vale per le configurazioni più utilizzate). Dobbiamo
sottoporre tale rete ad un periodo di “training”. Durante questa fase dovremo fornire
in input un set di valori e il corretto output, in modo da correggere i pesi in maniera
opportuna. La rete in questo modo raggiunge il comportamento desiderato per tutta la
classe di input. Una volta che è stata raggiunta la precisione desiderata, i pesi
sinaptici vengono congelati e la NN è pronta all‟uso.
Le configurazioni più comuni sono NN non ricorrenti, totalmente connesse, a livelli,
simmetriche, auto associative, stocastiche e asincrone. Di seguito mostro alcuni
modelli.
Rete non ricorrente:
output
input In questo tipo di reti le connessioni vanno in un solo senso, dall‟input all‟output. E‟
esattamente il contrario delle reti chiamate “cicliche”.
Rete totalmente connessa:
In questo tipo di rete ogni neurone che la compone è connesso con tutti gli altri,
escluso se stesso. Si noti che un peso sinaptico con valore nullo corrisponde
all‟assenza di connessione, abbiamo visto prima l‟equazione del potenziale dove input
viene moltiplicato al peso, quindi con w = 0, l‟input non viene trasferito. Solitamente
in queste reti alcuni pesi vengono inizializzati a zero.
Rete a più livelli: (totalmente connessa a più livelli)
18
Matteo Tosato - Introduzione alle reti neurali artificiali
input
output
Reti in cui le unità sono organizzate in insiemi separati e disgiunti di cui
generalmente uno è detto di input, un altro di output e gli altri vengono detti
“nascosti” oppure “intermedi”.
Rete simmetrica:
Nelle reti simmetriche ogni connessione fra due qualsiasi neuroni è uguale in entrambi
i sensi: Wij = Wji
Rete auto associativa:
Quest‟ultimo tipo è utilizzato proprio per l‟intelligenza artificiale. Queste hanno il
compito di ricevere un segnale in input e farlo evolvere restituendo un output
leggermente modificato, proprio quelle che avviene nel cervello umano.
Per gli scopi più applicativi, vengono utilizzate quelle a più livelli interamente
interconnesse tra questi. A questa poi si dovrebbe aggiungere anche un ulteriore
configurazione, ovvero quelle a più livelli ricorrenti. Queste possono avere anche
sinapsi che collegano neuroni di uno stesso livello.
19
Matteo Tosato - Introduzione alle reti neurali artificiali
Ma la configurazione più semplice è quella che fa uso di un solo neurone. Essa trova
impiego oltre ai fini didattici, anche in diversi campi di applicazione. È infatti già
in grado di fare alcuni tipi di classificazioni, partiremo da questa e proseguendo,
vedremo i suoi limiti rispetto alle configurazioni più avanzate.
Interpretazione vettoriale
In questo paragrafo interpretiamo il comportamento del neurone artificiale in chiave
vettoriale.
Possiamo considerare i valori di input come componenti del vettore , e i valori dei
pesi sinaptici componenti del vettore .
Tale che:
* + e * +
La sommatoria eseguita dal neurone, corrisponde al prodotto scalare dei due vettori:
∑( )
Dove è l‟angolo formato dai due vettori.
X
W α
Secondo le considerazioni appena fatte, il prodotto interno dei due vettori corrisponde
alla risposta del neurone. Se immaginiamo di muovere i due vettori, il prodotto interno
sarà proporzionale al coseno dell‟angolo .
Immaginiamo la situazione seguente:
W2 = 0,8W1 = 0,3
X2 = 0,3X1 = 0,7
Con pesi normalizzati si ha:
20
Matteo Tosato - Introduzione alle reti neurali artificiali
|| |||| ||
|| |||| ||
La norma del vettore corrisponde alla sua lunghezza:
|| || √ √
Il prodotto interno sarà tanto maggiore quanto è minore la distanza dei due vettori
all‟interno dello stesso quadrante. Quando la risposta è uguale a 0 i due vettori sono
ortogonali fra di loro; quando è maggiore di 90° la situazione è simmetrica e l‟unità
assume valori negativi.
Prendendo come esempio il neurone con funzione di attivazione binaria, avremo che
l‟output può assumere valore attivo (1, vettori con distanza < 90°) o rimanere silente
(0, vettori con distanza > 90°).
In una rete di molti neuroni è possibile determinare quale neurone possiede valori
sinaptici più simili all‟input dato il suo valore di attivazione solo se i valori sono
normalizzati, ovvero se la loro somma risulta uguale all‟unità.
Apprendimento del perceptron
Il punto di forza assoluto delle ANN (Artificial neural networks) è l‟apprendimento.
Secondo Donald Hebb, a livello biologico un collegamento fra due neuroni subisce un
rinforzo nel momento in cui si ha una attivazione del rispettivo neurone postsinaptico.
Allo stesso modo, nelle reti artificiali avremo un aggiustamento in positivo del valore
sinaptico secondo un determinato algoritmo di addestramento.
1 0 0
1 0 1 0
Generalizzando, il processo di addestramento per una ANN si suddivide in 5 fasi, queste
sono valide in quasi ogni scenario di addestramento:
- Si crea la struttura dati necessaria; si può lavorare ad oggetti o con matrici,
quest‟ultimo prevede uno sforzo in più ma è altamente più efficiente e sintetico.
- I pesi vengono inizializzati, ad esempio con un valore casuale compreso tra -1 e 1.
- Viene eseguita la fase di training. Dovremo fornire alla rete neurale due input: gli
ingressi e le uscite (target, ovvero quello che la rete dovrebbe dare in uscita) Si
esegue la computazione secondo il principio di attivazione del neurone visto prima e
viene confrontato il risultato ottenuto con il desiderato.
21
Matteo Tosato - Introduzione alle reti neurali artificiali
- A questo punto vengono calcolate le variazioni dei pesi quindi aggiornati di
conseguenza. La fase di training viene ripetuta fino a che la rete non converge al
risultato desiderato.
- A questo punto la rete è pronta per l‟utilizzo.
Ogni ciclo a cui la rete è sottoposta durante la fase di training è detto un‟epoca.
Durante un‟epoca vengono presentati tutti gli input del training set. Ad esempio, per
un problema come l‟OR logico ne occorreranno davvero poche. L‟algoritmo di
apprendimento è quindi iterativo e viene eseguito per ogni esempio.
Notare che, in termini più generali, esistono due modalità con le quali correggere i
valori sinaptici. La prima, denominata addestramento „batch‟, consiste nell‟aggiornarne
i valori dopo la presentazione dell‟intero pattern set, ovvero dopo aver proposto alla
rete tutti gli esempi. L‟errore della rete per il pattern set è l‟errore quadratico
medio che analizzeremo in seguito.
Un‟altra modalità è detta „on-line‟. In questo caso la correzione dei pesi viene
eseguita ad ogni iterazione su singolo esempio.
La regola di Hebb
Donald Hebb, studioso originale e unico nel panorama della psicologia del „900, fu un
precursore di molte teorie e scoperte successive, e fu uno dei primi scienziati ad
approfondire il legame tra il sistema nervoso e comportamento.
Come abbiamo detto in precedenza, una connessione subisce un rinforzo quando si ha
un‟attivazione del suo neurone postsinaptico. Quando si utilizza questo metodo, il
valore di inizializzazione per i neuroni è 0.
La variazione sinaptica è definita dall‟equazione:
Dove è il tasso di apprendimento (learning rate), questo valore specifica la capacità di apprendimento della rete, può avere un valore compreso tra 0 e 1. Più
questo valore è alto più la rete apprenderà velocemente, ma sarà anche meno precisa, è
in definitiva, un parametro dinamico per risolvere eventuali problemi di prestazione e
precisione in fase di apprendimento.
Per ciascuna coppia di pattern si ha:
∑
Questo metodo rappresenta la base su cui tutti o quasi i successivi metodi di
addestramento si sono sviluppati. Nonostante questo essa possiede molti limiti. Ad
esempio, data lo sola possibilità di aumentare il valore delle sinapsi, i pattern di
input non dovrebbero avere elementi in comune, perché questo causerebbe l‟attivazione
di tutti i corrispondenti neuroni attivati in precedenza per qual particolare input.
Questo effetto viene definito come “interferenza”. Pertanto la regola di Hebb permette
di apprendere solo pattern ortogonali, ovvero pattern la cui somma dei prodotti dei
singoli componenti è zero.
22
Matteo Tosato - Introduzione alle reti neurali artificiali
La regola postsinaptica
Stent (1987) e Singer (1973), viste le grosse limitazione della regola di Hebb misero a
punto un metodo chiamato regola postsinaptica che ha come obiettivo ridurre l‟effetto
di “interferenza” prima definito, quando si lavora con input parzialmente sovrapposti.
L‟idea sta nell‟aggiunta di una regola oltre quella di Hebb, la condizione permette di
diminuire il valore delle sinapsi quando l‟unità postsinaptica è attiva e l‟unità
presinaptica è inattiva:
( ( ) )
Nonostante l‟introduzione di questa regola riduca l‟effetto interferenza, essa tende a
creare sinapsi inibitorie quindi non è in grado di apprendere correttamente in caso di
input sovrapposti parzialmente.
La regola presinaptica
La regola presinaptica prevede una condizione simmetricamente opposta alla regola di
Stent-Singer. Il valore della sinapsi viene diminuito quando l‟unità postsinaptica è
inattiva e quella presinaptica è attiva:
( ( ) )
Questa funzione meglio della precedente quando molti pattern di input diversi
parzialmente sovrapposti debbono essere classificati con lo stesso pattern.
La regola delta
Ritornando ad una rappresentazione più astratta dei vettori sinaptici e di input,
prendiamo in esame un problema come quello dell‟operazione logica OR.
Tale operazione prevede due input che possono assumere valore 0 oppure 1. E prevede per
l‟uscita medesimi possibili valori. Si ha quindi una tabella di verità del tipo
seguente:
X1 X2 Y
0 0 0
0 1 1
1 0 1
1 1 1
Tabella 1: Tabella di verità OR logico
La rappresentazione n-dimensionale del problema OR è la seguente:
23
Matteo Tosato - Introduzione alle reti neurali artificiali
(1,1)
(1,0)(0,0)
(0,1)
X1
X2
Quando si parte con pesi sinaptici casuali, equivale ad avere in partenza una retta che
non separerà i punti in modo corretto. (sarà una retta con inclinazione e
posizionamento casuale)
Cambiando l‟inclinazione della retta, ovvero modificando il valore dei pesi sinaptici,
possiamo arrivare a separare gli input correttamente.
E‟ evidente anche la necessità di utilizzare anche delle soglie, chiamate „bias‟ per
poter traslare oltre che ruotare la retta.
Uno degli algoritmi notevoli che consente di effettuare questa operazione è appunto la
regola delta, anche chiamato algoritmo di addestramento specifico del perceptron.
Il principio è semplice, si basa sul calcolo dell‟errore in output.
Poi, su questo, si aggiornano i pesi in modo tale da convergere verso il risultato
corretto.
Definiamo l‟errore con la seguente equazione:
Il delta è l‟errore commesso della rete neurale per l‟esempio k-esimo, „Exp‟ è il
valore atteso mentre Y è l‟output dato dalla rete.
Da cui troviamo il “delta weight”, ovvero la variazione da applicare al peso:
Dove η è il “learning rate”, X è l‟input k-esimo della rete.
Dunque, l‟aggiornamento del peso sinaptico avviene seguendo la regola seguente:
( )
Quando il “delta error” raggiunge il valore desiderato, i pesi possono essere
“congelati”. E la rete è pronta per svolgere il suo lavoro.
Esempio addestramento perceptron tramite delta rule
Vediamo una rete a percettrone a livello di programmazione, con mio rammarico molti
libri trattano le reti neurali solo in modo teorico, senza fornire sorgenti in
linguaggio o pseudo-linguaggio di esempio nemmeno per le più semplici configurazioni.
Per questo motivo cerco dove possibile di fornire anche un minimo di materiale
esemplificativo.
24
Matteo Tosato - Introduzione alle reti neurali artificiali
All‟interno del sorgente, la prima cosa di cui occuparci è definire le strutture dati
che compongono la rete neurale. Qui sono possibili approcci diversi. Seguendo un metodo
prettamente logico, possiamo definire delle strutture dati o classi che descrivono ogni
parte della rete. Ad esempio ragionando ad oggetti, definiremo la classe neurone ed i
suoi metodi. Una classe neurone è adatta ad contenere già tutte le possibili funzioni
di trasferimento. Poi una classe sinapsi, una classe livello per le reti multilivello e
via discorrendo…
Oppure, possiamo utilizzare un approccio un po‟ meno ordinato ed utilizzare in modo
intelligente le matrici. Utilizzando le matrici si ha un notevole risparmio di risorse
e maggiore velocità di elaborazione.
Per la fase di training dobbiamo definire un metodo per fornire input e target alla
rete. Di norma sono utilizzati file .xml. Infatti la stessa rete neurale è utile per
scopi differenti, il file xml prepara questa al lavoro desiderato. Per semplicità noi
cominceremo da un file .dat che contiene i dati disposti semplicemente in righe. Per
l‟operazione OR ci basterà definire gli input. L‟output possiamo calcolarlo con
l‟operazione che fornisce il linguaggio. Se vi state chiedendo che utilità ha un rete
neurale che fa un‟operazione come l‟OR, già fornita dalla comodissima operazione C “|”,
vi rispondo che non serve a nulla, la presento al sol scopo di capire come sia
possibile impartire al calcolatore istruzioni sequenziali per descrivere una logica, in
comprensivo, non sequenziale.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// Uncomment follow line to avoid debug messages
#define _DEBUG_
#define FAILURE 1
#define SUCCESS 0
// Define neurons
#define INPUT_N 2
#define OUTPUT_N 1
// Set precision
#define PRECISION double
// Define Learning rate
#define _L_RATE 0.5
// Define network desired accuracy
#define ACCEPTABLE_DELTA 0.05
// Training file
#define FTRAINING_PATH
"H:\\AI_sources\\Windows\\Learning\\test_nn01\\bin\\Debug\\training.dat"
// Perform training
int __n_network_training(const char*,unsigned int);
// Neural network weights
PRECISION weights[INPUT_N][OUTPUT_N];
PRECISION pot;
int input[INPUT_N];
PRECISION output[OUTPUT_N];
La matrice weights rappresenta tutti i pesi del percettrone che saranno solamente due
dati i soli due input. Come vedete ho definito anche il file training.dat il quale
25
Matteo Tosato - Introduzione alle reti neurali artificiali
contiene gli input 0 e 1 nelle loro combinazioni. La funzione __n_training() si occupa
dell‟addestramento della rete. La funzione è la seguente:
int __n_network_training(const char* path,unsigned int epochs) {
// Checks...
if(epochs <= 0) return FAILURE;
if(path <= 0) return FAILURE;
int input[2];
PRECISION exp_output,netout,pot,delta_err,delta[INPUT_N];
char*n = malloc(16);
char*nptr = n;
unsigned int k = 0, persistant_accuracy = 0;
input[0] = -1;
input[1] = -1;
// Get training set from file
FILE* fp = fopen(path,"r");
if(fp == NULL)return FAILURE;
char c = 0;
while(c != EOF || epochs > 0) {
while(input[0] == -1 || input[1] == -1)
{
c = (char)fgetc(fp);
if(c == ';') {
input[k] = atoi(n);
(k == 1) ? k = 0 : k++;
n = nptr;
} else {
sprintf(++n,"%c",c);
}
}
// Learn OR operation
exp_output = input[0] | input[1];
// Potential of output neurons
pot = weights[0][0] * input[0];
pot += weights[1][0] * input[1];
// Net output (with linear transfer function)
netout = (pot > 0.0) ? 1.0 : 0.0;
// Compute delta error
delta_err = exp_output - netout;
// Compute delta
delta[0] = delta_err * _L_RATE * input[0];
delta[1] = delta_err * _L_RATE * input[1];
// Update weigths
weights[0][0] += delta[0];
weights[1][0] += delta[1];
// Check neural network accuracy
if(persistant_accuracy >= 10) {
break;
} else {
if(delta_err < ACCEPTABLE_DELTA) {
persistant_accuracy++;
} else persistant_accuracy = 0;
}
#ifdef _DEBUG_
26
Matteo Tosato - Introduzione alle reti neurali artificiali
printf("in: %d - %d out: %lf\n",input[0],input[1],netout);
#endif
// Restore
input[0] = -1;
input[1] = -1;
// Decrement epochs
epochs--;
}
fclose(fp);
free(n);
return SUCCESS;
}
Dopo le inizializzazioni, un ciclo while() su occupa dell‟addestramento, vengono
prelevati i dati dal file di training. Questi sono memorizzati in questo modo:
0;0;0;1;1;0;1;1;0;0;0;1;1;0... E‟ una serie che si ripete. Il risultato target viene
calcolato con l‟OR canonico, poi viene calcolato il potenziale, subito dopo la funzione
di attivazione restituisce 1 se il potenziale è maggiore di 0, infine viene calcolato
il delta error e la variazione post-sinaptica che viene utilizzata poi per
l‟aggiornamento dei pesi.
La funzione main() è così definita:
int main()
{
char answer[16];
// Init
int x,y;
for(x=0;x<INPUT_N;x++) {
for(y=0;y<OUTPUT_N;y++) {
weights[x][y] = ((rand()%2000)/(PRECISION)(1000.0)-(PRECISION)1.0);
}
}
if(__n_network_training(FTRAINING_PATH,-1) == FAILURE) {
fprintf(stderr,"[+] FATAL! - Training failure... or epochs not
sufficient");
return FAILURE;
} else {
printf("[+] - Neural network trained!\n");
}
while(1) {
printf(" - Type first input: ");
scanf("%d",&input[0]);
printf(" - Type second input: ");
scanf("%d",&input[1]);
// Calculate potential of output neuron
pot = weights[0][0] * (PRECISION)input[0];
pot += weights[1][0] * (PRECISION)input[1];
// Net output (with linear transfer function)
output[0] = (pot > 0.0) ? 1.0 : 0.0;
printf(" - Network output: %f\n",output[0]);
printf("continue s/n?");
scanf("%16s",answer);
27
Matteo Tosato - Introduzione alle reti neurali artificiali
if(strcmp(answer,"s")) {
break;
}
}
return SUCCESS;
}
Prima vengono iniziati i pesi ad un valore casuale nel range -1:1.
Poi viene chiamata la funzione di addestramento.
A seguito viene chiesto all‟utente di inserire gli input, la rete calcola il risultato
correttamente.
La rete neurale è inoltre in grado di restituire valori corretti anche in presenza di
input non pulito (rumore in input). Ad esempio provate ad inserire 0.90 al posto di 1
oppure 0.20 al posto di 0. La rete restituisce comunque output coerenti, dato che la
funzione di attivazione fornisce una certa “tolleranza” d‟errore, Le reti neurali fanno
quindi parte delle tecnologie dette a “logica fuzzy”.
Più utilizziamo un learning rate basso, più tempo la rete ci metterà ad apprendere, più
sarà in grado di restituire output corretti anche in presenza di rumore.
Valutazione delle disuguaglianze
Il metodo che vedremo di seguito viene chiamato “valutazione delle disuguaglianze”.
Lo scopo di questo metodo sta nel poter valutare a priori, la dove è possibile, se
stiamo affrontando un problema che possiede delle soluzioni “linearmente separabili”.
Ovvero se esiste un retta in grado di separare gli input. Come è avvenuto nell‟esempio
OR oppure no.
Partiamo da un esempio, la tabella che segue mostra input ed output del “problema di
parità”. Qui abbiamo 3 input, quindi un neurone tridimensionale. L‟output dipende dal
numero di ingressi posti ad uno. Quando essi sono dispari l‟output del neurone deve
dare uno, quando sono pari 0.
X1 X2 X3 Y
0 0 0 0
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
1 1 1 1
Tabella 2: Tabella di verità del problema di parità
Abbiamo quindi due classi A e B.
*( ) ( ) ( ) ( )+
*( ) ( ) ( ) ( )+
Siccome non abbiamo un numero di input eccessivo, possiamo ancora rappresentare
graficamente le soluzioni:
28
Matteo Tosato - Introduzione alle reti neurali artificiali
X2
X1
X3
(1,0,0)
(1,1,0)(0,1,0)
(0,1,1)
(0,0,1)
(0,0,0)
(1,1,1)
(1,0,1)
I pallini bianchi sono l‟output pari a 0.
Ora partendo dall‟equazione utilizzata per trovare l‟output della rete Y:
( ∑( )
)
Possiamo considerare il valore soglia ט come un ulteriore peso “-W0”. Da questo deriva che:
( )
A questo punto per ogni serie di argomenti possiamo scrivere la relativa
disuguaglianza:
1) - (0,0,0) 2) – (0,0,1) 3) – (0,1,0) 4) – (0,1,1) 5) – (1,0,0) 6) – (1,0,1) 7) – (1,1,0) 8) – (1,1,1)
Ora qui è sufficiente trovare le contraddizioni per capire che il problema non è
risolvibile linearmente. Ne basta una, ad esempio la quarta si contraddice con la
numero 2 e 3. Dati n input sono presenti disuguaglianze.
Tornando alle due classi A e B e alle loro definizioni, possiamo dire che la prima
avrà:
E per la seconda:
29
Matteo Tosato - Introduzione alle reti neurali artificiali
Allora la serie di punti per i quali rappresentano un iperpiano bidimensionale in uno spazio tridimensionale che separa le soluzioni del
problema se questo è separabile linearmente.
Un altro principio molto importante è il teorema di Cover del 1965, di cui non sto a
riportare la dimostrazione. Esso afferma che dato un numero di input per
l‟addestramento non linearmente separabili, uno può probabilmente trasformare questo in
un set linearmente separabile proiettandolo in uno spazio multidimensionale attraverso
alcune trasformazioni non lineari.
La seguente equazione definisce C come il numero di funzioni a soglia lineari per un
problema ad n dimensioni. (n input):
( ) ∑(
)
La funzione parziale , viene sostituita dal numero di esempi, serie di valori per il
training di un‟epoca.
Reti neurali MLP (Multi layer perceptron)
Nei capitoli precedenti abbiamo descritto ampiamente il perceptron e capito cosa si
intende per separazione lineare degli input.
Nell‟esempio „OR‟ sono presenti i passaggi minimi necessari per avere una rete neurale
minimale, con un solo neurone, che simula la porta logica OR.
In questo capitolo inizieremo con il descrivere alcuni dei limiti di cui questa
configurazione soffre, e in seguito, vedremo che partendo dal perceptron è possibile
comporre reti più ampie componendole in più livelli.
Tornado alla rappresentazione n-dimensionale del problema OR, dove „n‟ corrisponde al
numero degli input del neurone:
(1,1)
(1,0)(0,0)
(0,1)
X1
X2
La combinazione di input 0,0 è l‟unica che fornisce 0 in output. Si dice quindi che
questo problema (l‟OR) ha soluzioni linearmente separabili.
Ora cercheremo di addestrare la rete per eseguire l‟operazione booleana Exclusive-
Or,(XOR). La seguente è la tabella di verità:
30
Matteo Tosato - Introduzione alle reti neurali artificiali
X1 X2 Y
0 0 0
0 1 1
1 0 1
1 1 0
Tabella 3: Tabella di verità XOR
Il grafico delle soluzioni sarà identico al precedente a parte la disposizione della
retta di colore rosso. O meglio, non si tratterà più di una retta.
Non riusciremo mai a separare le soluzioni con l‟ausilio una retta. Questo significa
che il percettrone bidimensionale non è in grado di risolvere problemi che hanno
soluzioni separabili non linearmente. Come in questo caso, il percettrone non può
risolvere il problema XOR.
Le soluzioni dell‟XOR non sono linearmente separabili.
Ci occorre un altro tipo di configurazione, il seguente grafico mostra come le
soluzioni vengono divise da una rete neurale completamente connessa tra i suoi 3
livelli:
(1,1)
(1,0)(0,0)
X1
X2
(0,1)
Reti neurali a due strati (M-Adeline)
Aggiungendo al percettrone un livello in più si ottiene una rete “M-Adeline” costituita
da 2 livelli distinti. Questa non consente ancora di risolvere il problema XOR, ma si
presta per introdurre un nuovo genere di algoritmi di addestramento, più complessi.
Metodi adeguati anche per reti con più di due livelli.
31
Matteo Tosato - Introduzione alle reti neurali artificiali
W3
W2
Wi
.
.
.
X1
X2
Xi
Y
Figura 9: M-Adeline
In questo caso, i neuroni di output devono avere una funzione di attivazione
derivabile, i neuroni di input una funzione binaria o continua. Questa configurazione è
in grado di distinguere gli input e suddividerli in classi diverse, l‟importante è che
ognuna sia linearmente separabile dall‟altra. E‟ sufficiente che ogni neurone di output
j rappresenti la corrispondente classe j e che, presentando input della classe j, si
abbia: ∑ ( ) ∑ ( ) per tutti gli indici k diversi da un determinato j.
La reti M-ADALINE possono essere addestrate tramite l‟algoritmo di “Windrow-Hoff”.
In modalità on-line viene riassunto nelle fasi seguenti:
- Si presentano sequenzialmente gli esempi del training set. Per ogni esempio k, ogni
neurone j fornirà generalmente un output diverso da quello target , con un
errore. Quindi avremo che l‟errore della rete è dato da ( ) e un errore quadratico medio E su tutti gli esempi dato da:
∑∑( )
- L‟errore ottenuto deve essere minimizzato aggiornando il valore dei pesi, questa
variazione delta è definita come: (ottenuta tramite la regola del gradiente da
):
∑[( ) ]
Qui a seconda della funzione di attivazione utilizzata avremo casi differenti, ad
esempio:
Funzione di trasferimento sigmoide:
( )
( ) ( )
∑[( ) ( ) ]
Funzione di trasferimento tangente iperbolica:
( )
( )
32
Matteo Tosato - Introduzione alle reti neurali artificiali
∑[( )( ) ]
Funzione di trasferimento lineare:
( ) ( )
∑[( ) ]
- Infine la correzione dei pesi sinaptici avviene sempre tramite la formula:
( ) ( ) .
- A questo punto viene valutato l‟errore e se ancora non soddisfacente viene ripetuto
il procedimento.
L‟algoritmo descritto viene eseguito effettuando le correzioni dei pesi sinaptici ad
ogni singolo esempio sottoposto:
[( ) ]
Architetture Feed-forward
Una rete MLP (Multi layer perceptron) è una rete i cui neuroni compongono più livelli
e, tra loro, sono completamente interconnessi. I livelli sono minimo 3, fra input,
output e nascosto.
Questi ultimi possono variare a qualsiasi numero.
Questa configurazione è una delle più utilizzate in assoluto ed è in grado di risolvere
molti problemi, quindi anche quelli che non hanno soluzioni separabili linearmente.
Si parla di configurazioni feed-forward perché gli input seguono una sola direzione,
dai neuroni di input a quelli di uscita, senza mai tornare indietro o passare a un
neurone vicino.
Se supponiamo di avere una rete con 3 input, ed un problema con soluzioni non
separabili, ora i neuroni facente parte del layer nascosto inseriscono piani aggiuntivi
consentendo la separazione dei vertici di classe A da quelli di classe B. Quindi per un
generico problema tridimensionale la rappresentazione grafica delle sue soluzioni
appare come la seguente:
33
Matteo Tosato - Introduzione alle reti neurali artificiali
X2
X1
X3
Figura 10: Piano bidimensionale di separazione in uno spazio tridimensionale
La struttura della rete è dunque come la seguente:
X1 X2 X3
Figura 11: Esempio di ANN feed-forward
Più layer nascosti inseriamo più siamo in grado di effettuare separazioni complesse.
I neuroni degli strati nascosti non possono avere funzioni di trasferimento lineare
altrimenti la rete sarebbe equivalente ad una a due strati e non potrebbe separare le
soluzioni in modo non lineare.
Per fissare il concetto, immaginiamo la seguente situazione di lavoro; due input ,
due numeri nascosti con pesi sinaptici rispettivi e un neurone
output O, con pesi sinaptici e .
X1
X2
N1
N2
OW21
W22
W12
W11
V1
V2
34
Matteo Tosato - Introduzione alle reti neurali artificiali
( ) ( ) ( ) ( )
Date le equazioni che abbiamo ricavato possiamo considerare
tutto come due input , un output O e pesi sinaptici .
A differenza dei livelli input ed output il cui numero di
neuroni è definibile, non c‟è un metodo altrettanto rigoroso
per definire il numero di livelli nascosti necessari e nemmeno
il numero dei neuroni necessari per ognuno di questi livelli.
La definizione del numero di livelli avviene per via di
osservazioni ripetute sull‟allenamento e tramite l‟esperienza
accumulata su problemi simili.
Feed-forward ricorrenti
Una configurazione particolare delle reti feed-forward è la cosiddetta “rete di Elman”.
Questa possiede oltre al primo strato di neuroni nascosti, anche un layer „contesto‟ in
cui vengono memorizzati gli stati di attivazione precedenti.
Questo ha lo stesso comportamento degli altri strati, in partenza il valore di
attivazione di questi neuroni sarà pari ad 1. Poi conterrà sempre il valore di uscita
del primo layer nascosto all‟istante .
Le connessioni sinaptiche dallo strato intermedio a quello di contesto valgono 1,
mentre quelle in direzione inversa sono inizializzate casualmente e soggette al
processo di addestramento in modo analogo a tutte le altre.
Questa configurazione permette alla rete di ricordarsi di ciò che è successo in
precedenza. E‟ un‟ottima soluzione quando si utilizza una rete per la previsione di
funzioni complesse.
I1
I2
I3
In
H1(t)
H2(t)
Hn(t)
yj
H1(t-1)
H2(t-1)
Hn(t-1)
Figura 12: Rete feed-forward con connessioni ricorrenti
35
Matteo Tosato - Introduzione alle reti neurali artificiali
Le connessioni segnate in rosso sono quelle di valore unitario che riportano le uscite
dei neuroni all‟ingresso del ciclo successivo.
Error back-propagation (EBP)
Uno degli algoritmi con cui è possibile addestrare reti di questo tipo è denominato
“Error back-propagation”.
Questo nome è dovuto al fatto che l‟errore calcolato su ciascun layer da partire
dall‟ultimo viene consegnato al layer precedente e così via.
La definizione matematica dell‟algoritmo è la seguente:
Partendo dall‟equazione dell‟errore quadratico medio, e applicando a questo la regola
del gradiente, ricaviamo l‟equazione per il calcolo della variazione dei pesi, riporto
tutti i passaggi:
( ) ( )
( )
( )
(∑ )
( ) ( ) (A)
Ponendo:
( ) ( ) (B) Si ottiene la seguente:
(C)
Questa regola viene utilizzata per aggiornare i pesi dei livelli output e nascosto.
Analogamente, per quanto riguarda le connessioni tra stato di input e strato nascosto:
( )
Se confrontiamo questa formula con la precedente formula A, al posto degli errori noti
( ) troviamo le derivate
, che dobbiamo ora calcolare retropropagando l‟errore
dallo strato output a ogni neurone nascosto:
∑(
) ∑( ) ( )
O anche applicando la formula B:
∑
36
Matteo Tosato - Introduzione alle reti neurali artificiali
Ottenendo:
( )(∑ ) (D)
Che ponendo:
( ) .∑ / (E)
Assume anche la forma della C:
(F)
Le formule D,E,F sono valide per aggiornare i pesi dei livelli nascosto, input e anche,
in reti più generali, per le connessioni tra due strati nascosti consecutive. Ad
esempio se adottiamo la funzione sigmoide, è:
( )
( ) ( ) ( )
Dove k è proporzionale alla pendenza della sigmoide nel suo punto di flessione:
Normalmente si pone k = 1, altre volte k=1/T dove T è denominata temperatura per motivi
che vedremo in seguito. In ogni caso le formule A e D diventano rispettivamente:
( ) ( ) (A‟)
( )(∑ ) (D‟)
I pesi sinattici vengono aggiornati, ad ogni tempo t dell‟intervallo 1,2...,(t-
1),t,(t+1),...etc.
( ) ( ) (G)
( ) ( ) (H)
Per comprendere in modo completo le nuove nozioni, ricorriamo per esempio al problema
dell‟XOR.
In precedenza avevamo visto come la configurazione a singola unità è incapace di
risolvere il problema. Ora invece utilizzeremo una rete che abbia due input, due
neuroni nello strato nascosto ed un neurone come uscita. Introduciamo nella rete
neurale un peso fittizio. Il bias.
Questo corrisponde alla soglia vista per le funzioni di trasferimento binarie a soglia,
con la differenza che questa avrà la particolarità di essere variabile.
Il bias è rappresentabile nella rete come un neurone aggiuntivo nel layer precedente a
quelli che hanno funzioni sigmoidali. Nel nostro caso strati nascosti e di output
avranno funzioni a sigmoide, quindi il neurone bias lo introdurremo nei layer di input
e nascosto. Questo neurone trasferirà sempre il valore 1, mentre la sinapsi che collega
questo ai neuroni dello strato successivo ha un peso variabile come per gli altri casi.
La nostra rete:
37
Matteo Tosato - Introduzione alle reti neurali artificiali
ΣE
BIAS
WEIGHT
Figura 13: Esempio di rete MLP addestrata con EBP
In questo modo saremo in grado di inserire più livelli di separazione, quindi di
addestrare la nostra rete per eseguire l‟operazione XOR correttamente per tutte le
casistiche.
L‟errore commesso dallo strato di output sarà propagato all‟indietro. Faccio notare che
il numero di neuroni che compone il layer nascosto è variabile, più questo cresce più
il numero di iterazioni necessarie per l‟apprendimento sarà basso. Il numero minimo
necessario è naturalmente 2.
La regola di back-propagation presenta anche qualche controindicazione. In primis si
tratta di un processo molto oneroso in termini di impegno CPU, La funzione di
apprendimento può assumere un andamento molto complesso data la presenza di diverse
sequenze di operazioni non-lineari. I minimi locali rappresentano le zone più
pericolose perché l‟algoritmo può rimanerci intrappolato; Pericolose sono anche le zone
pianeggianti, ad esempio XOR ne possiede parecchie, queste sono zone ove i pesi sono
modificati in modo minimo rallentando la convergenza. Mentre valli troppo strette
potrebbero far saltare l‟algoritmo lontano dalla soluzione.
Esempio addestramento tramite EBP
Ci preoccuperemo poi di come migliorare l‟algoritmo per rendere la convergenza più
veloce. Nel seguente esempio addestriamo la rete in modalità batch.
#pragma once
#include "targetver.h"
#include <iostream>
#include <tchar.h>
#include <stdlib.h>
#include <cmath>
#include <time.h>
using namespace std;
#define u_int unsigned int
// Comment to avoid logger procedure
// #define LOG
/* NEURAL LEGEND
INPUT: Xi
HIDDEN: Zk
OUTPUT: Yj
38
Matteo Tosato - Introduzione alle reti neurali artificiali
WEIGHTS:
- HIDDEN: Wik (Bias: Wbik)
- OUTPUT: Wkj (Bias: Wbkj)
DELTA WEIGHTS:
- HIDDEN: DWik
- OUTPUT: DWkj
SUMMATION: SUM
FUNCTION: f() / derivate: f'()
ERRORS:
- HIDDEN: Ek
- OUTPUT: Ej
LEARNING RATE: N
EXPECTED VALUE: EXP
BIAS: B
*/
#include "stdafx.h"
/* MLP with 3 layers - back-propagation learning algorithm - XOR test*/
#ifdef LOG
FILE* log_file;
#endif
#define PRECISION double
#define MAX_PATH 256
#define DBG_LEN 256
const PRECISION __l_rate = 0.2;
const u_int INPUT_N = 2;
const u_int HIDDEN_N = 2;
const u_int OUTPUT_N = 1;
const u_int DEFAULT_EPOCHS = 200000;
const PRECISION M_E = 2.71828182845904523536;
const PRECISION accuracy_target = 0.1;
// ----------------------------------------
// Allocates neural network structures in data section
// ----------------------------------------
// ----- COMPONENT --------------------------------- SYMBOL ---
// Weights matrices
PRECISION W_hidden_in[HIDDEN_N][INPUT_N]; // Wik
PRECISION W_out_hidden[OUTPUT_N][HIDDEN_N]; // Wkj
// Weight vector on hidden layer
PRECISION Bias_hidden[HIDDEN_N]; // Wbik
// Weight vector on output layer
PRECISION Bias_out[OUTPUT_N]; // Wbkj
const PRECISION bias = 1.0; // B
// Errors vectors
PRECISION Error_hidden[HIDDEN_N]; // Ek
PRECISION Error_out[OUTPUT_N]; // Ej
// Delta weight matrices
PRECISION Delta_W_hidden[HIDDEN_N][INPUT_N]; // DWik
PRECISION Delta_W_output[OUTPUT_N][HIDDEN_N]; // DWkj
// Output vectors
PRECISION Out_hidden[HIDDEN_N]; // Zk
PRECISION Out_output[OUTPUT_N]; // Yj
PRECISION Net_out[OUTPUT_N]; // = Yj
// ------------------------------------------------------------
//Prototypes:
void Init_weights(void); // Weights initialization
PRECISION transf(PRECISION input); // Sigmoid function
bool Training(const char* training_path_file, u_int* epochs); // Training session
#ifdef LOG
void Init_logger(void); // Logger initialization
void Tolog(char*string); // Log routines
#endif
// -------------------------------------------------------------
// --- PROGRAM ENTRY POINT ---
// -------------------------------------------------------------
int main(int argc, char* argv[])
39
Matteo Tosato - Introduzione alle reti neurali artificiali
{
u_int epochs = 0;
char*pathfile = NULL;
if(argc > 1) {
pathfile = new(char[MAX_PATH]);
strncpy(pathfile,argv[1],MAX_PATH);
}
#ifdef LOG
Init_logger();
#endif
Init_weights();
if(Training(pathfile,&epochs) != true) {
cerr << "[+] WARNING - Neural network training failure" << endl;
} else cout << "[+] SUCCESS - Neural network MLP trained in " << epochs << " epochs!" << endl;
#ifdef LOG
fclose(log_file);
#endif
PRECISION input[2];
// Network simulation
while(1) {
cout << " First input <0|1>:";
cin >> input[0];
cout << " Second input <0|1>:";
cin >> input[1];
if(input[0] < 0 || input[0] > 1 ||
input[1] < 0 || input[1] > 1) {
cerr << "Input not valid. Retry." << endl;
continue;
}
// Propagate into layers...
for(int i = 0; i<HIDDEN_N; i++) {
// Propagate into hidden layer
Out_hidden[i] = transf(
input[0]*W_hidden_in[i][0]+
input[1]*W_hidden_in[i][1]+
bias*Bias_hidden[i]);
// Propagate into output layer
Out_output[0] += W_out_hidden[0][i]*Out_hidden[i];
}
Out_output[0] += Bias_out[0]*bias;
// Calculate net output
for(int i = 0; i<OUTPUT_N; i++) {
Net_out[i] = transf(Out_output[0]);
Out_output[0] = 0.0;
}
cout << "Network output: " << Net_out[0] << endl;
}
return 0;
}
// -------------------------------------------------------------
// --- TRAINING SESSION --- BACK-PROPAGATION ALGORITHM ---
// -------------------------------------------------------------
bool Training(const char* training_path_file, u_int* epochs) {
FILE* fp = NULL;
if(training_path_file != NULL) {
fp = fopen(training_path_file,"r");
if(!fp) {
cerr<<"[+] FATAL ERROR - Training file "<< training_path_file<<" not found!"<<endl;
return false;
}
}
char*n = new(char[16]);
char*nptr = n;
40
Matteo Tosato - Introduzione alle reti neurali artificiali
u_int k = 0, accuracy = 0;
char c = 0;
int set = 0;
u_int input[2]; // Xi
PRECISION Expected; // EXP
input[0] = -1;
input[1] = -1;
while(*epochs < DEFAULT_EPOCHS) {
// For training file
if(fp != NULL) {
while(input[0] == -1 || input[1] == -1) {
c = (char)fgetc(fp);
if(c == ';') {
input[k] = atoi(n);
(k == 1) ? k = 0 : k++;
n = nptr;
} else {
sprintf(++n,"%c",c);
}
}
} else {
// Otherwise generate appropriate training set
switch(set) {
case 0:
input[0] = 0;input[1] = 0;break;
case 1:
input[0] = 0;input[1] = 1;break;
case 2:
input[0] = 1;input[1] = 0;break;
case 3:
input[0] = 1;input[1] = 1;break;
default:
set = 0; continue;
}
set++;
}
// XOR
Expected = (PRECISION)(input[0] ^ input[1]);
// Propagate into layers...
//---------------------------------------//
// --- Zk = FhT(SUM(Xi*Wik)+(B*Wbik)) ---//
// --------------------------------------//
for(int i = 0; i<HIDDEN_N; i++) {
// Propagate into hidden layer
Out_hidden[i] = transf(
input[0]*W_hidden_in[i][0]+
input[1]*W_hidden_in[i][1]+
bias*Bias_hidden[i]);
// Propagate into output layer
//---------------------------------------//
// --- Yj = FhT(SUM(Wkj*Zk)+(B*Wbkj)) ---//
// --------------------------------------//
Out_output[0] += W_out_hidden[0][i]*Out_hidden[i];
}
Out_output[0] += Bias_out[0]*bias;
// Calculate net output
for(int i = 0; i<OUTPUT_N; i++) {
Net_out[i] = transf(Out_output[i]);
Out_output[i] = 0.0;
}
// Calculate error on output layer
//---------------------------------//
// --- Ej = (EXP - Yj)*Yj(1-Yj) ---//
// --------------------------------//
for(int i = 0; i<OUTPUT_N; i++)
41
Matteo Tosato - Introduzione alle reti neurali artificiali
Error_out[i] = (Expected - Net_out[i])*Net_out[i]*(1-Net_out[i]);
// Calculate delta weights of output layer
//-----------------------------//
// --- DWkj = (Wkj+N*Ej*Yj) ---//
// ----------------------------//
for(int i = 0; i<HIDDEN_N; i++)
Delta_W_output[0][i] = W_out_hidden[0][i]+__l_rate*Error_out[0]*Net_out[0];
// Calculate bias delta weight of output layer
//-----------------------------//
// --- Wbkj = (Wbkj+N*Ej*B) ---//
// ----------------------------//
for(int i = 0; i<OUTPUT_N; i++)
Bias_out[i] = Bias_out[i] + __l_rate*Error_out[i]*bias;
// Calculate error on hidden layer
//-------------------------------//
// --- Ek = (Zk*(1-Zk)*Ej*Wkj ---//
// ------------------------------//
for(int i = 0; i<HIDDEN_N; i++)
Error_hidden[i] = Out_hidden[i]*(1-Out_hidden[i])*Out_hidden[i]*W_out_hidden[0][i];
// Calculate delta weights of hidden layer
//-----------------------------//
// --- DWik = (Wik+N*Ek*Xi) ---//
// ----------------------------//
for(int i = 0; i<HIDDEN_N; i++)
Delta_W_hidden[i][0] = W_hidden_in[i][0]+__l_rate*Error_hidden[i]*input[0];
for(int i = 0; i<HIDDEN_N; i++) {
Delta_W_hidden[i][1] = W_hidden_in[i][1]+__l_rate*Error_hidden[i]*input[1];
Bias_hidden[i] = Bias_hidden[i]+__l_rate*Error_hidden[i]*bias;
}
// Update weights
//-------------------//
// --- Wik = DWik ---//
// ------------------//
for(int j = 0; j<INPUT_N; j++) {
for(int i = 0; i<HIDDEN_N; i++)
W_hidden_in[i][j] = Delta_W_hidden[i][j];
}
//-------------------//
// --- Wkj = DWkj ---//
// ------------------//
for(int j = 0; j<OUTPUT_N; j++) {
for(int i = 0; i<HIDDEN_N; i++)
W_out_hidden[j][i] = Delta_W_output[j][i];
}
(*epochs)++;
if(fabs(Net_out[0] - Expected) < accuracy_target)
accuracy++;
else
accuracy = 0;
if(accuracy == 25) {
delete n;
if(fp)fclose(fp);
return true;
}
// Uncomment for debug on prompt
/*
printf("[%u] IN: %d,%d OUT: %f EXP: %f ERR: %f\n",
*epochs,input[0],input[1],Net_out[0],Expected,fabs(Net_out[0] - Expected));
*/
#ifdef LOG
char*debug_str = new(char[DBG_LEN]);
sprintf(debug_str,"%u;%d;%d;%f;%f;%f\n",epochs,input[0],input[1],Expected,Net_out[0],fabs(Ne
t_out[0] - Expected));
Tolog(debug_str);
delete debug_str;
#endif
input[0] = -1;
42
Matteo Tosato - Introduzione alle reti neurali artificiali
input[1] = -1;
}
delete n;
if(fp)fclose(fp);
return false;
}
// -------------------------------------------------------------
// - TRANSFER FUNCTION FOR HIDDEN AND OUTPUT LAYER, SIGMOIDAL---
// -------------------------------------------------------------
PRECISION transf(PRECISION n) {
return(1/(1+pow(M_E,-n)));
}
// -------------------------------------------------------------
// --- WEIGHTS INITIALIZATION ---
// -------------------------------------------------------------
void Init_weights(void) {
srand((unsigned int)time(NULL));
for(int i = 0; i<INPUT_N; i++)
for(int j = 0; j<HIDDEN_N; j++)
W_hidden_in[j][i] = ((rand()%20000/10000.0)-1.0)+(rand()%10000/100000000.0f);
for(int i = 0; i<OUTPUT_N; i++)
for(int j = 0; j<HIDDEN_N; j++)
W_out_hidden[i][j] = ((rand()%20000/10000.0)-1.0)+(rand()%10000/100000000.0f);
for(int i = 0; i<HIDDEN_N; i ++)
Bias_hidden[i] = ((rand()%20000/10000.0)-1.0)+(rand()%10000/100000000.0f);
for(int i = 0; i<OUTPUT_N; i++)
Bias_out[i] = ((rand()%20000/10000.0)-1.0)+(rand()%10000/100000000.0f);
for(int i = 0; i<OUTPUT_N; i++)
Out_output[i] = 0.0;
}
// -------------------------------------------------------------
// --- LOG ROUTINES ---
// -------------------------------------------------------------
#ifdef LOG
void Init_logger(void) {
log_file = fopen("NN_log_file.dat","w");
fprintf(log_file,"N°;IN;OUT;EXPECTED;NET_OUTPUT;ERROR\n");
}
void Tolog(char*string) {
fprintf(log_file,string);
}
#endif
Migliorie per l’algoritmo EBP
Come abbiamo accennato, ci sono però due problemi fondamentali che rendono imperfetto
questo algoritmo:
- Il problema dei minimi locali.
Il minimo locale può essere rappresentato in una depressione nella funzione di training
in cui possiamo incappare e rimanervi bloccati.
Ecco come può essere raffigurato graficamente:
43
Matteo Tosato - Introduzione alle reti neurali artificiali
Nell‟esempio riportato abbiamo sperimentato quanto questa affermazione è vera. Difatti
il programma che addestra la rete FF per eseguire l‟operazione XOR soffre di blocchi
frequenti. Ovvero come nel grafico, l‟algoritmo rimane intrappolato in una depressione
che sembra essere la migliore soluzione che minimizza l‟errore, mentre in realtà non lo
è.
- Scarse performance.
EBP è uno dei più dispendiosi algoritmi di addestramento in termini di tempo CPU.
Questo perché le variazioni sinaptiche sono davvero minime, quindi servono molte
iterazioni per convergere al valore desiderato. Infatti ecco come l‟errore potrebbe
oscillare facendo crescere in maniera esponenziale il numero di epoche necessarie
all‟apprendimento del comportamento voluto:
Dovremmo essere in grado ora di fare considerazioni più complesse e più generali sui
problemi e soluzioni con cui abbiamo a che fare.
Se eseguite un buon numero di test sull‟esempio che abbiamo appena visto, vi capiterà
senz‟altro di accorgervi delle problematiche citate nel capitolo precedente.
Esistono un buon numero di migliorie che sono state introdotte con lo scopo di
migliorare l‟algoritmo. Ora ne vedremo alcune.
Il coefficiente “momentum”
- La prima è l‟introduzione di una variabile costante da moltiplicare alla variazione
delta dei pesi al tempo (t-1), ogni volta che un peso viene aggiornato, dunque la
funzione diventa ora:
( ) ( ) ( ) ( )
è un coefficiente come , anche esso compreso tra 0 ed 1. Il termine aggiuntivo rappresenta un “ricordo” dell‟aggiornamento avvenuti in precedenza.
Questa tecnica è implementabile nel codice di esempio visto prima, semplicemente
aggiungendo delle matrici di ugual grandezza a quelle utilizzate per immagazzinare i
valori delta dei pesi, ed utilizzarle per salvare la variazione all‟istante t-1.
44
Matteo Tosato - Introduzione alle reti neurali artificiali
Learning rate adattativo
- Un‟altra tecnica utilizzata (in aggiunta) è l‟introduzione del learning rate
“adattativo”. Questo significa che quando l‟algoritmo di addestramento rimane bloccato,
il learnig rate assume un valore più utile ad uscire del problema. Questa operazione
può essere fatta con diversi metodi:
Una prima versione utilizza metodi euristici, rappresentati da regole del tipo: “se
l‟errore è alto e la sua variazione delta è grande, allora occorre diminuire un po‟ il
learning rate”. Le regole possono essere applicate in modo autonomo, da un sistema
“espero” fuzzy, che assiste la rete neuronale durante l‟apprendimento.
Una seconda variante propone la modifica del learning rate non solo ad ogni ciclo t del
processo, ma anche per ogni connessione di peso. Indicando con ( ) il learning rate
relativo al tempo t e alla connessione di peso (t), la regola suggerita, che ha
consentito di accelerare la convergenza dell‟apprendimento, è:
( ) ( )
Dove il coefficiente u deve essere leggermente inferiore a 1 (tipicamente u = 0.7) o
leggermente superiore a 1 (u = 1.05) a seconda che siano dello stesso segno o meno le
due derivate:
( )
( )
Il coefficiente di momentum viene invece lasciato invariato nel tempo.
- Un‟altra variante propone la seguente legge per calcolare sia il valore del learning
rate che quello del momentum:
( ) ( ), - Dove, con riferimento ai pesi e al vettore di cui essi sono componenti, è
l‟angolo tra il vettore ( ) e il vettore gradiente dell‟errore grad E(t).
Parametri di libertà aggiuntivi
- Un‟altra ancora apporta una generalizzazione dell‟algoritmo BP, introducendo nuovi
gradi di libertà della rete. Per ogni neurone i viene usata la seguente funzione di
trasferimento di tipo sigmoidale:
(∑ )
Dove i parametri k, possono variare nel tempo nel corso dell‟apprendimento. Nel
BP classico le regole d‟apprendimento riguardano solo i pesi W e la soglia ,
assimilata generalmente ai pesi mediante bias. Indicheremo questo con: ( ). Le regole sono quelle già viste, del tipo:
Possiamo generalizzare l‟algoritmo BP, facendo variare tutti i parametri della sigmoide
prima introdotta: BP(W, ) aggiungendo alle regole precedenti le seguenti, ad esse analoghe:
45
Matteo Tosato - Introduzione alle reti neurali artificiali
Dove SIGMA, LAMBDA, KAPPA sono opportuni coefficienti di learning rate, compresi tra 0
e 1.
Modifica della funzione sigmoidale
In ultimo, segnalo una intelligente soluzione per il problema delle performance che mi
è capitato di trovare in rete. L‟idea verte a sostituire la funzione di trasferimento
dei neuroni con una equivalente o quasi dal punto di vista delle caratteristiche, ma
che sia meno impegnativa per quanto riguarda i calcoli.
La funzione sigmoide standard è:
Questa funzione presenta caratteristiche importantissime per noi. E‟ sempre crescente,
a vale 0 e a 1, è derivabile e continua su tutto l‟asse dei reali. E‟ la più
utilizzata di tutte proprio per questa particolarità. Essa ha solo un problema, al
denominatore è presente un esponenziale. Questo è molto dispendioso in termini di
impegno CPU. Dobbiamo tenere presente che ogni neurone della rete avrà una funzione di
trasferimento di questo tipo, e che questi valori vengono calcolati migliaia di volte
per ogni epoca. Ad ogni modo una soluzione è utilizzare funzioni di trasferimento
alternative. Ecco un esempio:
(
| |)
Questa funzione è del tutto simile in caratteristiche alla sigmoidale ma non ha
l‟esponenziale, questa è in grado di ridurre notevolmente il tempo impiegato dalla rete
per l‟addestramento. Non intendo il numero di epoche naturalmente ma il tempo CPU
dedicato. I seguenti sono i due grafici delle funzioni. Quello in verde è relativo a
quest‟ultima versione.
Ci sono altre migliorie possibili da applicare all‟algoritmo di addestramento back-
46
Matteo Tosato - Introduzione alle reti neurali artificiali
propagation, in generale però è possibile anche crearsi una propria regola di
miglioramento a quanto già fa BP secondo le proprie esigenze.
Algoritmo Resilient back-propagation (RPROP)
L‟algoritmo EBP che abbiamo affrontato, consente di addestrare una rete feed-forward.
Abbiamo visto che esso soffre di alcuni inconvenienti come i minimi locali e i problemi
legati alle prestazioni i quali poi dipendono dal tipo e potenza della CPU che deve
eseguire l‟addestramento.
RPROP sta per “Resilient propagation” ed è un nuovo sistema per l‟apprendimento
supervisionato. Ideato nel 1993 da Martin Riedmiller. Esso attua un adattamento diretto
sul peso in questione basandosi sul valore del gradiente locale. Il suo principio è
eliminare l‟influenza della dimensione (il valore assoluto che assumono) delle derivate
parziali sugli aggiornamenti dei pesi. Conseguenza di ciò, solo il segno di queste
viene valutato. Viene introdotta di fatto una nuova regola, la quale determina
l‟evoluzione del valore di aggiornamento ( ). La stima si basa appunto
sull‟osservazione del comportamento della derivata parziale durante i successivi due
step:
( )
{
( )
( )
( )
( )
( )
( )
( )
Dove
Ogni volta che la derivata parziale del peso corrispondente cambia il suo segno,
fatto che indica che l‟ultimo aggiornamento fatto è stato molto importante e che
l‟algoritmo ha saltato sopra un minimo locale, il valore di aggiornamento ( ) viene
diminuito dal fattore Se la derivata mantiene il suo segno, il valore di
aggiornamento è debolmente incrementato in modo da accelerare la convergenza nella
regione superficiale. Questo per ogni peso.
Una volta che il delta è stato adattato per ogni peso, il valore di aggiornamento segue
una semplice regola: se la derivata è positiva (incremento di errore), il peso viene
decrementato dal suo valore di aggiornamento, se la derivata è negativa, il valore di
aggiornamento viene aggiunto:
{
( )
( )
( )
( )
Quindi come al solito:
( ) ( ) ( )
Esiste anche una eccezione per le regole viste; se la derivata parziale cambia di segno
significa che lo step di aggiornamento precedente era troppo importante e il minimo è
andato perso, allora il precedente valore di aggiornamento viene invertito:
47
Matteo Tosato - Introduzione alle reti neurali artificiali
( ) ( )
( )
( )
A causa di questa regola, la derivata può cambiare il suo segno più di una volta. Per
evitare una doppia correzione del valore di aggiornamento, non ci sarà adattamento del
valore nello step successivo al cambiamento di segno. In pratica questo può essere
fatto settando la regola di aggiornamento nel modo seguente:
( )
La derivata parziale dell‟errore totale è resa da:
( )
∑
( )
Quindi, la derivata parziale degli errori deve essere accumulata per tutti i patterns
di addestramento.
Se volessimo fare un confronto con l‟algoritmo classico visto in precedenza, diremmo
che la differenza sostanziale è espressa dalla seguente formula, ovvero quella che
determina il valore delta per l‟aggiornamento dei pesi sinaptici:
(
) [EBP]
(
) [RPROP]
gioca quindi un ruolo determinante nell‟aggiornamento dei pesi sinaptici.
I seguenti sono i valori più comuni da assegnare al fattore di incremento e decremento:
e
Per evitare che questi due valori crescano o diminuiscano senza controllo, vengono
solitamente impostati anche due limiti, uno inferiore ed uno superiore:
e
Mentre il valore iniziale di questi è solitamente posto a 0.1. ( )
Di seguito propongo infine lo “pseudo-codice” del nuovo algoritmo di training: [Martin
Riedmiller, Heinrich Braun; Institut fur Logik, Komplexitat und Deduktionssyteme -
University of Karlsruhe]
( )
( )
( )
*
48
Matteo Tosato - Introduzione alle reti neurali artificiali
(
( )
( ) ) *
( ) ( ( ) )
( ) (
( )) ( )
( ) ( ) ( )
( )
( )
+
(
( )
( ) ) *
( ) ( ( ) )
( )
+
(
( )
( ) ) *
( ) (
( )) ( )
( ) ( ) ( )
( )
( )
+
+
( )
La dimensione della derivata diminuisce esponenzialmente con la distanza tra il vettore
dei pesi e quello dei valori neurali del layer di output. Usando RPROP la dimensione
del valore di aggiornamento dei pesi dipende solo dalla sequenza dei segni assunti dal
gradiente locale calcolato.
Le reti neurali offrono un tipo di fuzzy logic estremamente adattabile, l‟importante è
averne appreso il funzionamento base, per poi procedere con le proprie configurazioni.
Quelle che abbiamo affrontato fino ad ora sono le configurazioni più utilizzate e più
utili nelle moderne applicazioni come pattern-recognition, classificazione di dati,
risoluzione di problemi di controllo automatico, sistemi adattativi ed altre faccende.
Reti di Hopfield
Nelle reti appena viste, generalmente chiamate “feed-forward”, i segnali in ingresso
andavano in una sola direzione, da qui i layer di input ed output. Naturalmente di reti
ce ne sono di altri tipi e le abbiamo visto nella prima parte del testo. Un tipo di
rete importante sono quelle che hanno neuroni con collegamenti, oltre che con quelli
del livello successivo, anche con neuroni dello stesso livello.
49
Matteo Tosato - Introduzione alle reti neurali artificiali
3 1 2
S1
S2S3
W2W3
Figura 14: Rete caotica semplice
La complessità di queste reti stà nel fatto che le sue unità rimangono attive anche
all‟istante successivo dalla ricevuta di input. La rete rimane perciò attivata per un
periodo limitato (transitorio) di tempo. Possono verificarsi diversi casi, la rete può
oscillare attraverso un numero finito T di stati, per poi ricominciare il ciclo. Oppure
oscillare attraverso un numeri infinito di stati, senza mai riconseguire uno stato già
visitato (Chaos deterministico).
La rete in figura può avere un comportamento assai complesso. Si consideri che ogni
neurone ha la seguente funzione di attivazione per ogni neurone:
( )
( )
I cui stati ( ) cambiano nel tempo t con le solite regole ( sono i pesi sinaptici):
( ) ( ( ) ( )) ( ) ( ( )) ( ) ( ( )) Se si definiscono i valori delle costanti nelle funzione di attivazione, lo stato
cambia nel tempo in modo complesso, al variare del parametro . Le variazioni di tale
parametro conferiscono alla rete comportamenti stabili, oscillatori oppure caotici. Le
versione discreta (DH Discrete Hopfield) ha N neuroni con stati bipolari ( ) ( ), funzione di trasferimento a gradino (detta anche signum, abbreviato generalmente in
sign o sgn) e connessioni simmetriche tra un neurone e qualsiasi altro, escludendo solo
le connessioni di un neurone con se stesso. Si hanno quindi N(N-1) connessioni e N(N-
1)/2 pesi sinaptici diversi. Indicando con il peso sinattico della connessione j->i
tra i due neuroni i,j si ha:
Per ogni neurone i, il potenziale si calcola:
( ) ∑( ( ))
Dato che ogni neurone hanno una funzione a gradino e che per ( ) , si mantiene lo stato precedente, la rete ha una funzione E, denominata “energia” per un‟analogia
formale con la energia meccanica:
∑∑( )
La quale diminuisce nel tempo:
50
Matteo Tosato - Introduzione alle reti neurali artificiali
,∑( ) -
Quindi l‟energia non cresce ma diminuisce, per
L‟attivazione dei neuroni può essere per via iterativa, in modo deterministico oppure
stocastico, sincrono o asincrono.
Restando sulla modalità deterministica, se i neuroni vengono attivati in parallelo
(sincronia), oltre a stati finali stabili si possono conseguire attrattori a ciclo
limite T = 2. Esaminiamo la rete:
S1
S2 S3
1,5
-2
1
I neuroni sono bipolari a soglia zero e per un totale di 6 connessioni.
Si può notare che con una attivazione asincrona si hanno due stati stabili (+1,-1,+1) e
(-1,+1,-1). Si ha infatti partendo dal primo stato e attivando sequenzialmente un
neurone per volta, la situazione seguente:
Tempo Stato rete (S1,S2,S3) Neurone
attivato
Potenziale neurone
attivato
Stato futuro del
neurone attivato
t (+1,-1,+1) S1 +0.5 +1
t+1 (+1,-1,+1) S2 -1 -1
t+2 (+1,-1,+1) S3 +3.5 +1
La sequenza viene ripetuta, quindi lo stato della rete si ripete ad oltranza e rimane
invariato. Lo stato (+1,-1,+1) è detto attrattore assieme allo stato (-1,+1,-1). La
rete evolve sempre verso questi stati. Naturalmente a seconda della modalità il
comportamento della rete di Hopfield cambia di conseguenza. Senza vedere tutti gli
altri casi preferisco soffermarmi su quelli che sono i possibili utilizzi delle reti di
Hopfield. I due principali sono come memoria associativa e come ottimizzatore.
L‟ottimizzazione è un problema particolarmente adatto alle reti di Hopfield proprio
perché queste convergono verso uno stato stabile. Un esempio classico è il problema del
commesso viaggiatore. Date N città e conoscendo le distanze tra due qualunque di
esse, si tratta di determinare un percorso di visite che soddisfa i vincoli e minimizza
il percorso globale, con ritorno alla città iniziale. Il problema TSP può inoltre
essere simmetrico o asimmetrico. Generalmente questi problemi vengono risolti con i
metodi della ricerca operativa, che spesso offrono prestazioni accettabili, conseguite
polinomiali. Tuttavia la programmazione lineare a numeri interi e la programmazione
dinamica possono solo trattare problemi con Molto più efficienti sono
alcuni moderni metodi come quello denominato “Branch and cut” e l‟algoritmo Lin-
Kerningham. L‟uso delle reti neuronali per risolvere problemi di questo tipo è stato
proposto inizialmente da Hopfield, con una versione analogica della sua rete. Questa
rete ha la proprietà di avere, come epifenomeno del normale funzionamento, una energia:
∑∑( )
51
Matteo Tosato - Introduzione alle reti neurali artificiali
La quale, come abbiamo visto, diminuisce monotonicamente nel tempo. L‟energia è
funzione quadratica degli stati e lineare dei pesi sinaptici . Se si riuscisse a
costruire una funzione costo F che fosse funzione quadratica delle variabili del
problema e ne soddisfacesse i vincoli, dall‟eguaglianza ( ) ( ) si potrebbero
ricavare i pesi che consentirebbero alla rete, partendo da valori casuali, di evolvere
verso uno stato finale che coincide con la soluzione ottimale (costo minimo e vincoli
soddisfatti). La funzione F dipende perciò dal problema e, per quanto di disegno
laborioso, non presenta difficoltà insormontabili.
Reti neurali auto-organizzanti
Mappe di Kohonen
Teuvo Kohonen (1934) è un ricercatore, ed è attualmente professore emerito
nell‟accademia Finlandese. Uno dei suoi più famosi contributi fu quello sulle reti
auto-organizzanti “SOM”.
Le reti SOM (Self-organizing maps) sono un particolare tipo di ANN che creano una forte
ed interessante analogia con le reti biologiche che compongono la corteccia celebrale.
Questa corteccia può essere paragonata al cappello di un fungo che avvolge il suo
gambo, i nuclei sottocorticali e il midollo spinale. Alla corteccia affluiscono le
informazioni visive, acustiche, olfattive e le sensazioni tattili e dolorose: ogni
sensazione è mappata e viene letta da una specifica area della corteccia. (area di
differenza sensoriale).
Insieme a quest‟area sensoriale, vi si trovano le aree motorie, che controllano la
funzione dei muscoli volontari. E‟ stato possibile tracciare una mappa dei neuroni
responsabili dei movimenti delle dita, della mano, delle braccia e di tutti gli altri
muscoli volontari. Siccome non tutte le aree muscolari sono uguali, c‟è una differenza
di sensibilità fra le diverse parti del corpo. La mappa dei movimenti, come quella
delle sensazioni viene definita con il termine di “omuncolo” che indica la
rappresentazione proporzionale delle funzioni motorie e sensoriali.
Figura 15: Omuncolo sensoriale e motorio
Le aree motorie si occupano di generare impulsi atti a contrarre le rispettive parti
del corpo formate da muscoli volontari, mentre le aree sensoriali raccolgono
informazioni dai vari organi recettori, più un‟area sensoriale è ampia più la
sensazione è ricca di dettagli.
52
Matteo Tosato - Introduzione alle reti neurali artificiali
Nelle reti SOM, i neuroni proiettano l‟input multidimensionale su una superfice di
neuroni artificiali, rappresentandolo in due dimensioni ed effettuandone quindi una
notevole compressione, pur conservando le similarità originarie. Inoltre la capacità di
scoprire, in modo autonomo, proprietà interessanti di un input multidimensionale
accomuna le reti SOM alla capacità degli organismi viventi di adattarsi all‟ambiente
senza la necessità di una guida esterna.
Le reti SOM sono in grado imparare in modo autonomo come classificare una serie di
input attraverso la competizione fra i suoi neuroni che compongono la superficie. Il
seguente schema mostra questo sistema di “Competitive learning” con „n‟ input e „m‟
output:
Xi -1X1 Xi Xi +1 Xn
Yj -1Y1 Yj Yj +1 Ym
WjnWjiWj1
Figura 16: Schema di rete "Competitive learning"
Dove m neuroni j (con attivazione ) sono connessi a n input , tramite pesi sinaptici
. Inoltre, ogni neurone j è connesso con tutti i neuroni k del suo strato (incluso
se stesso) tramite pesi sinaptici . I neuroni k vicini al neurone j lo eccitano
( ), mentre quelli lontani lo inibiscono( ). La seguente è la dinamica della rete:
( ) [∑( ) ∑( ( ))
]
Dove, se v è il vicinato, (i + k) varia tra (j - v) e (j + v); F è una funzione di
trasferimento non lineare con saturazione (per limitare il valore di ) e è un fattore di feed-back, compreso tra 0 e 1.
Presentando in input un vettore X, di n componenti , verrà attivato maggiormente un
certo neurone j( ( ) ( ) ),in base alla prima sommatoria dell‟equazione precedente. Nei tempi successivi entra in azione la seconda sommatoria e i neuroni in
un intorno di j si rafforzano mutualmente e indeboliscono i neuroni lontani. In questo
modo le uscite Y dei neuroni vanno a creare quella che viene chiamata “bolla di
attivazione”, centrata su j, con una certa estensione “orizzontale” e una certa
ampiezza “verticale”.
L‟estensione dipende dal rapporto tra feed-back positivi e negativi, la prevalenza dei
primi allargando la bolla e viceversa.
L‟ampiezza dipende dal fattore di feed-back e cresce con esso. Quindi, ogni input attiverà la sua bolla ed input simili attiveranno le bolle dei
neuroni limitrofi, mentre input differenti attivano bolle più lontane.
Il seguente è il grafico di distribuzione dei pesi “a capello messicano” in un intorno
del neurone di uscita Y.
53
Matteo Tosato - Introduzione alle reti neurali artificiali
Figura 17: Distribuzione dei pesi del tipo: "a cappello messicano" in un intorno del neurone Yk
E‟ possibile semplificare notevolmente la struttura della rete eliminando le
connessioni ricorrenti laterali “a cappello messicano”, se si definisce un vicinato di neuroni contemporaneamente attivi.
In tal caso la bolla si forma per definizione, dato che l‟attivazione iniziale di un
neurone j trascina quella dei neuroni vicini.
La struttura finale di una rete SOM utilizzata nelle applicazioni è quindi senza queste
connessioni laterali, costituita da m neuroni j, ciascuno collegato a n input i tramite
dei pesi sinaptici . Tutte le connessioni laterali vengono invece simulate
utilizzando un vicinato topologico. Normalmente questo è un quadrato. Ad esempio gli 8
neuroni adiacenti.
L‟apprendimento senza supervisione è piuttosto semplice, si istruisce la rete con m * n
pesi sinaptici, si presenta in input il generico vettore ( ) e si
determina quel vettore che rende massimo il prodotto scalare: ∑ ( ) . I
neuroni competono ed uno solo di essi vincerà. Questo, assieme a tutto il suo vicinato,
avvicina il relativo vettore a X:
( ) ( ) ( )
Dove è il coefficiente learning rate che già conosciamo, compreso tra i valori 0 ed 1. Questo
viene fatto diminuire nel tempo, partendo da 1.
Notate che il vettore dei pesi è quello relativo al
neurone vincente.
Queste reti sono state applicate con successo per
risolvere questioni riguardanti la classificazione
e la valutazioni di parametri. Ad esempio in
Germania, è stata sviluppata una rete di questo
tipo per la valutazione di circuiti integrati,
composta da 2500 neuroni con 10 input, ogni input
rappresenta un parametro del circuito da
analizzare. Come la quantità ed altri parametri di
fabbricazione.
Questa rete crea quindi diverse “bolle”, ognuna
delle quali attrarrà gli input simili.
Una rete di questo tipo viene quindi addestrata in
modo tale da avvicinare il vettore dei pesi appartenenti al neurone vincente, verso il
vettore degli input. (Immaginate di rappresentare graficamente i due vettori iscritti
in una circonferenza di raggio 1).
Aggiungendo la supervisione all‟algoritmo di addestramento si ottiene una rete
sicuramente più adatta alla classificazione. Pilotando il tipo di vettore di input è
possibile ottenere le bolle di attivazione desiderate. Il funzionamento della rete sarà
quindi quello di inserire gli input ricevuti in certe aree neurali in modo da compiere
54
Matteo Tosato - Introduzione alle reti neurali artificiali
delle classificazioni. Una rete SOM di grosse dimensioni riesce ad emulare almeno
parzialmente ciò che avviene nel cervello umano.
La rete di Kohonen lavora come una mappa e come un mappa viene costruita. Su questa
mappa andranno a formarsi le nostre aree di attivazione che corrispondono a certi tipi
di input esterni.
Il disegno è semplificato, ma ogni neurone è in realtà connesso ad ogni uscita tramite
sinapsi di peso differente. I neuroni di output assieme formano una mappa. Questa mappa
si attiverà in una certa zona e si indebolirà nelle altre visto il comportamento dei
neuroni dello strato di output a formare “il cappello messicano”.
L‟implementazione di questo tipo di rete non è molto più complesso del caso MLP. Sempre
con matrici multidimensionali è possibile rappresentare ogni parte fisica della rete:
neuroni e sinapsi. Riassumiamo qui di seguito quali sono le operazioni da compiere per
lavorare con SOM:
- Si inizializza un vettore per gli input ed uno per gli output.
- Si inizializza un vettore multidimensionale per i pesi tra input ed output.
- Una funzione learn() dovrà passare i valori di input normalizzati al vettore di
input.
- Una funzione exec() chiamata da learn() dovrà calcolare il valore per ogni neurone
dello strato di output.
- Un‟altra funzione dovrà scansionare il vettore di output in cerca del neurone
vincente.
- Questo viene passato ad una funzione che ha il compito di aggiornare il vettore dei
pesi per il neuronodo.
- Qui è possibile inserire una funzione adjust() di normalizzazione degli altri pesi
dei neuroni del vicinato.
- Una funzione test() si preoccuperà di testare la rete una volta che questa è arrivata
ad attivare diverse aree.
Tale configurazione è anche denominata “mappa di Kohonen”. Infatti rappresentando i
neuroni di output in righe e colonne a formare una matrice ad esempio 100x100, si
ottiene una mappa. I base a come i pesi sono stati inizializzati, la rete durante la
fase di apprendimento, si auto-organizzerà in aree. Una per ogni classe di input.
Un tipico esempio per comprendere come lavora questa configurazione è il riconoscimento
di profili altimetrici. Un profilo può essere rappresentato anche da pochi input. Ad
esempio 5.
Valori: 0,3 – 0,2 – 0,3 – 0,3 – 0,4
55
Matteo Tosato - Introduzione alle reti neurali artificiali
Valori: 0,1 – 0,2 – 0,5 – 0,4 – 0,2
Valori: 0,4 – 0,1 – 0,0 – 0,2 – 0,6
La mappa di Kohonen è rappresentata invece in questo modo:
O
Il pallino nella rete rappresenta il neurone vincente. Durante la classificazione degli
input possono verificarsi dei problemi. Ad esempio, il profilo piano si pone in una
situazione neutrale rispetto alle altre tipologie. Così facendo può essere inserito
all‟interno di altre classi.
Per evitare questo problema, legato a questo particolare caso, si può ricorrere a due
operazioni:
- la normalizzazione degli input, o “stretching” dei profili; questa avviene sottraendo
il valore di input più basso a ogni input, poi portare il valore più alto ad 1 e
dividere tutti gli altri input con questo valore massimo.
- L‟altra norma consiste nel tipo di funzione di trasferimento; invece di fare una
moltiplicazione tra valore input e peso, si può ricorrere alla differenza vettoriale
tra le due grandezze. Quindi la formula di trasferimento diventa:
00.000
00.001
1 2 3 4 5
00.000
00.001
00.001
1 2 3 4 5
00.000
00.001
00.001
1 2 3 4 5
56
Matteo Tosato - Introduzione alle reti neurali artificiali
∑[
(|
| )
]
Dove “e” vale 0.01.
Implementiamo una rete SOM per il riconoscimento dei profili altimetrici.
Dovremo anche predisporre una serie di set per il training e una serie di set per la
verifica. Possibilmente diversi, in modo da poter poi osservare la capacità di
generalizzazione della rete. I set possono essere inseriti uno per riga in un file, in
modo tale da poterli leggere con fscanf(). E saranno come quelli visti negli esempi
sopra.
Esempio di rete SOM
Il seguente è il codice della rete di Kohonen a scopo esemplificativo che utilizza già
la due ottimizzazioni di funzionalità che abbiamo descritto.
/*
* SOM [Self organizing map]
* by Matteo Tosato
* header file
*/
#ifndef _HSOM_H
#define _HSOM_H
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#define neuron_state_t double
#define BYTE char
#define DUMP 0
#define MAP 1
#define MAX_PATH 256
// Initial learning rate
const double __l_rate = 0.1;
// Uncomment to create log file with network results in append mode
// #define LOG
const unsigned int NUM_INPUT_N = 100; // GRAPHIC MAP 100 x 100
const unsigned int NUM_OUTPUT_N = 100; // Maximum size of input patterns
// Parameters structure:
struct param {
char* lrn_file;
char* val_file;
FILE* lrn;
FILE* val;
unsigned int iterations;
unsigned int pattrn_size;
double K;
BYTE print_mode;
unsigned int winner;
};
// Neural network structure:
struct SOM {
57
Matteo Tosato - Introduzione alle reti neurali artificiali
neuron_state_t IN[NUM_INPUT_N];
neuron_state_t OUT[NUM_OUTPUT_N];
neuron_state_t WEIGHTS[NUM_INPUT_N][NUM_OUTPUT_N];
};
#endif /* _HSOM_H */
Questo è il file di implementazione principale:
/*
* SOM [Self organizing map]
* by Matteo Tosato
*
* Kohonen neural networks, reproduces the "pseudo-biological networks behavior".
* Parameters:
* pattern dimension - training file - validation file - number of iterations (epoch) - [-d] Dump
results | [-g] MAP
*
* tosatz{at}tiscali{dot}it
*/
#include "hsom.h"
// Prototypes:
struct param* parameters_parser(int argc, char**argv);
void learn(struct param*,struct SOM*);
void exec(struct param*,struct SOM*);
void adjust(struct param*,struct SOM*);
void Init_weights(struct param*, struct SOM*);
void Test(struct param*, struct SOM*);
void dump(struct param*, struct SOM*);
void map(struct param*, struct SOM*);
void stretching(struct param*, struct SOM*);
/*****************************************
* Entry Point
******************************************/
int main(int argc, char** argv) {
struct SOM nn;
struct param *param;
if((param = parameters_parser(argc,argv)) == NULL) {
fprintf(stderr,"[+] FATAL - Arguments parsing failure.\n");
printf("Usage:\n %s <pattern dimension> <path training file> "
"<path validation file (test)> <number of iterations (epochs)>\n",argv[0]);
printf("\ntosatz{at}tiscali{dot}it\n");
return 1;
}
param->lrn = fopen(param->lrn_file,"r");
param->val = fopen(param->val_file,"r");
if(param->lrn == NULL || param->val == NULL) {
fprintf(stderr,"[+] FATAL - File not found\n");
return 1;
}
param->K = __l_rate;
Init_weights(param,&nn);
printf("[+] Learning ...");
learn(param, &nn);
printf(" Done!\n");
printf("[+] Testing ... \n\n");
Test(param,&nn);
fclose(param->lrn);
fclose(param->val);
delete param, &nn;
return 0;
}
/*****************************************
* Input stretching, (input normalization)
******************************************/
void stretching(struct param* p, struct SOM* nn) {
neuron_state_t MIN = 10;
neuron_state_t MAX = 0;
u_int max_index = 0;
58
Matteo Tosato - Introduzione alle reti neurali artificiali
// Search for minimum and maximum values:
for(u_int j = 0; j < p->pattrn_size; j++) {
if(nn->IN[j] < MIN) {
MIN = nn->IN[j];
}
if(nn->IN[j] > MAX) {
MAX = nn->IN[j];
max_index = j;
}
}
// Perform input normalization:
for(u_int j = 0; j < p->pattrn_size; j++) {
nn->IN[j] -= MIN;
}
nn->IN[max_index] = 1.0f;
for(u_int j = 0; j < p->pattrn_size; j++) {
if(j == max_index) continue;
nn->IN[j] = nn->IN[j] / MAX;
}
}
/*****************************************
* Network in learning step
******************************************/
void learn(struct param* p, struct SOM* nn) {
unsigned int j, c = 0;
// Begin
while(c < p->iterations) {
while(1) {
j = 0;
// Get input
while(j < p->pattrn_size) {
fscanf(p->lrn,"%lf",&nn->IN[j++]); // To input neurons
}
if(feof(p->lrn)) break;
exec(p,nn);
adjust(p,nn);
}
p->K = p->K/1.3;
fseek(p->lrn,0,0);
c++;
}
return;
}
/*****************************************
* Elaboration of inputs
******************************************/
void exec(struct param *p, struct SOM *nn) {
// Input normalization:
stretching(p,nn);
// For each output neuron calculate rispective value:
for(unsigned int k = 0; k < NUM_OUTPUT_N; k++)
nn->OUT[k] = 0;
for(unsigned int k = 0; k < NUM_OUTPUT_N; k++) {
for(unsigned int j = 0; j < p->pattrn_size; j++) {
//nn->OUT[k] += (nn->IN[j] * nn->WEIGHTS[j][k]); <-- normal
nn->OUT[k] += 1/(fabs(nn->IN[j] - nn->WEIGHTS[j][k]/100) + 0.01);
}
}
// Neighbourhood simulation, "Mexican bonnet weights":
for(unsigned int j = 0; j < NUM_OUTPUT_N; j++)
nn->OUT[j] += 0.1*(nn->OUT[j-1]+nn->OUT[j+1]-nn->OUT[j-2]-nn->OUT[j+2]);
// Search for winner neuron:
u_int winner = 0;
neuron_state_t winner_value = 0.0f;
59
Matteo Tosato - Introduzione alle reti neurali artificiali
for(unsigned int i = 0; i < NUM_OUTPUT_N; i++) {
if(nn->OUT[i] > winner_value) {
winner_value = nn->OUT[i];
winner = i;
}
}
p->winner = winner;
}
/*****************************************
* Simulation of the neighborhood
******************************************/
void adjust(struct param *p, struct SOM *nn) {
// Updating weights of winner neuron and and nearest neighbors:
for(unsigned int i = 0; i < p->pattrn_size; i++) {
nn->WEIGHTS[i][p->winner] =
nn->WEIGHTS[i][p->winner] + p->K * (nn->IN[i] - nn->WEIGHTS[i][p->winner]);
nn->WEIGHTS[i][p->winner - 1] =
nn->WEIGHTS[i][p->winner - 1] + p->K * (nn->IN[i] - nn->WEIGHTS[i][p->winner - 1]);
nn->WEIGHTS[i][p->winner - 2] =
nn->WEIGHTS[i][p->winner - 2] + p->K * (nn->IN[i] - nn->WEIGHTS[i][p->winner - 2]);
nn->WEIGHTS[i][p->winner + 1] =
nn->WEIGHTS[i][p->winner + 1] + p->K * (nn->IN[i] - nn->WEIGHTS[i][p->winner + 1]);
nn->WEIGHTS[i][p->winner + 2] =
nn->WEIGHTS[i][p->winner + 2] + p->K * (nn->IN[i] - nn->WEIGHTS[i][p->winner + 2]);
}
return;
}
/*****************************************
* Function for Test
******************************************/
void Test(struct param *p, struct SOM *nn) {
unsigned int k = 0;
char answer[8];
while(1)
{
endfile:
for(unsigned int j = 0; j < p->pattrn_size; j++) {
fscanf(p->val,"%lf",&nn->IN[j]);
}
if(feof(p->lrn)) {
rewind(p->val);
k = 0;
goto endfile;
}
k++;
exec(p,nn);
printf("[+] Test n° %u\n",k);
switch(p->print_mode) {
case DUMP: dump(p,nn); break;
case MAP: map(p,nn); break;
}
printf("[+] Continue? <y/n> ");
scanf("%s",answer);
if( (!strncmp(answer,"n",1)) || (!strncmp(answer,"N",1)) ) return;
else system("clear");
}
}
/*****************************************
* Collect parameters
******************************************/
struct param* parameters_parser(int argc, char**argv) {
if(argc < 4) return NULL;
struct param *p = new(struct param);
p->pattrn_size = atoi(argv[1]);
if(!(p->lrn_file = new(char[MAX_PATH]))) return NULL;
strncpy(p->lrn_file,argv[2],MAX_PATH - 1);
if(!(p->val_file = new(char[MAX_PATH]))) return NULL;
strncpy(p->val_file,argv[3],MAX_PATH - 1);
p->iterations = atoi(argv[4]);
60
Matteo Tosato - Introduzione alle reti neurali artificiali
if(!strcmp(argv[5],"-d")) {
p->print_mode = DUMP;
} else if(!strcmp(argv[5],"-g")) {
p->print_mode = MAP;
} else p->print_mode = 0;
return p;
}
/*****************************************
* Weights initialization
******************************************/
void Init_weights(struct param *p, struct SOM *nn) {
srand((unsigned int) time(NULL));
for(unsigned int i = 0; i < NUM_OUTPUT_N; i++) {
for(unsigned int k = 0; k < p->pattrn_size; k++) {
nn->WEIGHTS[k][i] =
fabs(((rand()%20000/10000.0)-1.0)+(rand()%10000/100000000.0f));
}
}
}
/*****************************************
* Dump values of input and output neurons
******************************************/
void dump(struct param* p, struct SOM* nn) {
printf("[+] Neural networks simulation results:\n");
printf("\n\n[+] INPUT NEURONS:");
for(unsigned int i = 0; i < p->pattrn_size; i++) {
printf("%lf ",nn->IN[i]);
}
printf("\n\n[+] OUTPUT NEURONS:");
for(unsigned int k = 0; k < NUM_OUTPUT_N; k++) {
printf("%lf ",nn->OUT[k]);
}
printf("\n\n");
// Send network results to log file
#ifdef LOG
u_int j = 0;
FILE* log_file = fopen("Results.txt","a");
fprintf(log_file," --- SON results: --- \n");
fprintf(log_file,"Input:\n");
while(nn->IN[j] > 0) {
fprintf(log_file,"%lf;",nn->IN[j++]);
}
fprintf(log_file,"\nOutput:\n");
for(j=0;j < NUM_OUTPUT_N;j++)
fprintf(log_file,"%lf;",nn->OUT[j]);
fclose(log_file);
#endif
}
/*****************************************
* Build a simple graphic Kohonen map
******************************************/
void map(struct param* p, struct SOM* nn) {
int c = 0, r = 0;
printf("\n\n\n");
printf("INPUTS:\n");
for(u_int j = 0; j < p->pattrn_size; j++) {
printf("%lf\n",nn->IN[j]);
}
printf("\n\n");
printf("0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9\n");
for(u_int j = 0; j < NUM_OUTPUT_N; j++) {
if(nn->OUT[j] == nn->OUT[p->winner])
printf("*");
else
printf("-");
if(++c == 10) {
printf(" %d\n",r++);
c = 0;
} else {
61
Matteo Tosato - Introduzione alle reti neurali artificiali
printf("---");
}
}
printf("Winner neuron: %d",p->winner);
printf("\n-----------------------------------------\n");
}
Di seguito sono mostrati i valori in input, il loro valore durante e al termine del
processo di stretching.
1° SET
0,34 0,24 0,34
0,50 0,40 0,57
0,80 0,70 1,00
0,41 0,31 0,44
0,10 0,00 0,00
2° SET
0,23 0,00 0,00
0,56 0,33 0,44
0,98 0,75 1,00
0,62 0,39 0,52
0,23 0,00 0,00
3° SET
0,20 0,00 0,00
0,20 0,00 0,00
0,30 0,10 1,00
0,20 0,00 0,00
0,20 0,00 0,00
4° SET
0,45 0,44 0,49
0,16 0,15 0,17
0,01 0,00 0,00
0,45 0,44 0,49
0,90 0,89 1,00
5° SET
0,90 0,89 1,00
0,70 0,69 0,78
0,30 0,29 0,33
0,12 0,11 0,12
0,01 0,00 0,00
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
62
Matteo Tosato - Introduzione alle reti neurali artificiali
6° SET
0,23 0,00 0,00
0,40 0,17 0,24
0,76 0,53 0,74
0,90 0,67 0,93
0,95 0,72 1,00
7° SET
0,01 0,00 0,00
0,30 0,29 0,42
0,70 0,69 1,00
0,40 0,39 0,57
0,10 0,09 0,13
8° SET
0,80 0,40 0,70
0,50 0,10 0,18
0,40 0,00 0,00
0,70 0,30 0,53
0,97 0,57 1,00
9° SET
0,40 0,00 0,00
0,40 0,00 0,00
0,40 0,00 0,00
0,50 0,10 1,00
0,40 0,00 0,00
10° SET
0,90 0,80 1,00
0,60 0,50 0,63
0,30 0,20 0,25
0,30 0,20 0,25
0,10 0,00 0,00
11° SET
0,20 0,00 0,00
0,20 0,00 0,00
0,30 0,10 0,17
0,50 0,30 0,50
0,80 0,60 1,00
La seguente è la mappa di Kohonen con i risultati, questi sono relativi ai vari set di
verifica qui sopra con il colore uguale.
0 1 2 3 4 5 6 7 8 9
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
000
001
001
1 2 3 4 5
Input
str 1°
Dopo stretching
63
Matteo Tosato - Introduzione alle reti neurali artificiali
11 0
1
2
3
4
1 , 5 , 10 6 , 7 5
6
7
4 , 8 2 , 3 8
9 9
Come è evidente dagli input rappresentati nei grafici, la fase di stretching è
importante per diminuire l‟influenza dei valori assoluti dei dati in input e rendere
importante l‟andamento del profilo altimetrico.
Se analizzate i valori di pendenza, possiamo concludere che la rete ha classificato i
set in modo abbastanza corretto.
Partendo dal codice e dal modello visto, è facile aggiungere l‟apprendimento
supervisionato. Questo si fa andando a verificare se la classificazione della rete è
corretta o meno. In caso affermativo, i pesi del neuro-nodo vincente e di tutto il suo
vicinato vengono aumentati, nel caso opposto i pesi andranno indeboliti.
Competitive learning reale
Il codice esemplificativo mostrato nel capitolo precedente prevede una notevole
semplificazione che viene fatta nelle configurazioni SOM.
Rivediamo invece l‟architettura di una rete SOM reale;
La parte principale di questa configurazione è costituita da una mappa, o comunque da
un vettore di neuroni che sono, tra loro, completamente interconnessi. Questa
caratteristica mette già in conto una certa difficoltà realizzativa.
Infatti dati 2000 neuroni avremmo sinapsi da tenere in considerazione
nei calcoli. Nell‟esempio evitavo questo problema simulando un vicinato virtuale ogni
volta che dovevo effettuare l‟aggiornamento dei pesi. Il disegno seguente mostra invece
una architettura completa:
64
Matteo Tosato - Introduzione alle reti neurali artificiali
Y0 Ys...
...
Ys*s
Ys+1
Layer di input
Layer di output
(mappa di Kohonen)
Figura 18: Apprendimento competitivo per il neurone Y0
Sono presenti tutte le connessioni sinaptiche che vanno dal layer di input alla mappa
di Kohonen e anche tutte le connessioni laterali di uno dei neuroni topologici.
Topologico perché il layer di output è disposto su un piano, la mappa appunto. L‟indice
s è pari al lato della mappa.
Oltre che essere connesso con tutti gli altri neuroni del piano, ogni neurone possiede
una connessioni anche con se stesso. Il funzionamento della rete tenendo in
considerazione tutte queste caratteristiche aumenta l‟impegno computazionale richiesto.
Di seguito rivedo tutti i calcoli e le considerazioni fatte precedentemente riguardo le
som, cercando di attenermi a questo modello reale. Comunque non dimentichiamo che molte
volte non è necessario questo approccio complesso, ma è sufficiente attenersi alla
versione semplificata.
- Per prima cosa occorre inizializzare i pesi delle sinapsi, a differenza delle sinapsi
tra input ed output che si inizializzano nel solito modo con valori casuali tra 0 e 1,
le connessioni laterali avranno inizialmente tutte un valore uguale dato dalla
relazione:
dove NY è il numero dei neuroni che compongono la mappa. Per costruire
la mappa ricorro a 400 neuroni (mappa di 20*20 neuroni).
- Vengono inizializzati i valori di uscita dei neuroni di input. Per quanto riguarda il
nostro problema dei profili altimetrici abbiamo bisogno di 5 neuroni in ingresso.
(nelle applicazioni pratiche in genere si hanno un numero di neuroni in ingresso e in
uscita molto più elevato rispetto ai numeri citati nel nostro esempio.)
- Il primo calcolo da affrontare è quello della distanza tra la generica unità e
l‟input. L‟equazione seguente esprime il calcolo della distanza:
√∑( )
(
)
In questa formula, gamma è il “fattore di coscienza del neurone”. Questo è una
variabile locale del neurone, quindi ogni neurone avrà il suo fattore di coscienza
inizializzato a priori, in genere in modo casuale. Non cambierà durante l‟esecuzione.
Delta invece dipende dall‟epoca corrente, varia secondo la relazione seguente:
65
Matteo Tosato - Introduzione alle reti neurali artificiali
esprime la frequenza di vincita del neurone, quini più esso vince, più è probabile
accada ancora per input simili, innalzando e quindi definendo, l‟area di attivazione.
L‟uscita finale del neurone di output è data da:
- Dopo che ogni neurone ha il suo valore di uscita, essi cominceranno a competere tra
loro (come nelle reti biologiche). La competizione neuronale nello strato di uscita ha
come obiettivo eleggere un vincitore e un “vicinato”. Il vicinato può essere più o meno
esteso, relativamente alle dimensioni della rete. Nel caso della nostra rete 20*20 un
vicinato iniziale di 2 o 3 neuroni (caselle nella mappa) è sufficiente.
- A questo punto ogni neurone di uscita prima di tutto rinforzerà se stesso secondo
l‟equazione:
Mentre verrà inibito da tutti gli altri secondo quest‟altra relazione:
( )
Dove rappresenta tutti gli altri neuroni. “A” rappresenta un certo potenziale
responsabile del valore finale del neurone, dato generalmente da una funzione a rampa.
La funzione rampa che ci occorre è molto semplice:
( ) 2
Quindi:
( )
Dove è definito come “primo” perché deve essere confrontato con il valore di uscita
attuale del neurone, finche essi saranno molto diversi l‟iterazione viene ripetuta per
ogni neurone nuovamente (ultimo punto). (Nella libreria realizzata ho evitato di
attendere una uguaglianza esatta tra il vecchio e il nuovo valore, perché genera un
enorme numero di cicli da compiere. Ho preferito usare invece un‟espressione del tipo
66
Matteo Tosato - Introduzione alle reti neurali artificiali
seguente:
if (Math.Abs(t - OutputValue) >= 0.01). Questo mi ha evitato un eccessivo rallentamento di tutto il processo di apprendimento senza causare difetti nel funzionamento.)
Quando la richiesta viene soddisfatta il valore del neurone viene impostato con
- Una volta che la mappa di Kohonen raggiunge lo stato “stabile” un altro algoritmo ha
il compito di ricercare attraverso la mappa il neurone vincente, ovvero quello con il
valore più alto. Questo, assieme al suo vicinato, verrà “premiato” rinforzando le loro
connessioni sinaptiche verso il layer di input.
Il vicinato non rimane sempre al suo valore prestabilito inizialmente, ma diminuisce
nel tempo, in modo da accentuare la punta della collina attivata nella mappa. La regola
che stabilisce la sua evoluzione è:
( )
Dove il valore delta riferisce sempre a quello citato prima.
Quindi per ogni unità “vicina”. Compreso il neurone vincente vengono aggiornati i pesi
sinaptici, ma solo delle sinapsi tra input ed output, quelle laterali non mutano:
( ) Dove epsilon è il learning rate, ancora non citato. Questo è una costante globale nella
maggior parte dei casi. Nella mia libreria, applicata alla classificazione dei profili
altimetrici, ho ottenuto risultati soddisfacenti quando questo è impostato a 0.5 /
0.65.
- Una volta aggiornati i valori sinaptici del neurone vincente e del suo vicinato,
manca l‟ultima operazione, ovvero l‟aggiornamento della frequenza di vincita. Per tutta
l‟area vincente avremo:
( ) Mentre per tutti gli altri neuroni avremo un leggera diminuzione della costante, che
però avrà limite inferiore maggiore o uguale a 0. (per non avere frequenze negative.
Inoltre specifico che la frequenza di vittoria iniziale per tutti i neuroni è 0).
Reti SOM di grosse dimensioni sono piuttosto lente se addestrate con algoritmi di
questo tipo.
Esse mostrano in questo caso, una analogia più completa verso le cugine biologiche.
Anche in questo caso la rete neurale ha come scopo principale la classificazione di
pattern.
67
Matteo Tosato - Introduzione alle reti neurali artificiali
Problemi e strategie
Neuro-fuzzy
Le reti neurali, sono utilizzate nel campo della ricerca scientifica nel tentativo di
riprodurre almeno in parte il funzionamento del cervello dell‟uomo. In campo
applicativo o se volgiamo industriale, le reti hanno assunto nell‟ultimo decennio una
posizione di rilievo, ed il loro utilizzo e potenzialità diventa sempre più presente
nelle aziende tecnologiche.
Molte volte le reti vengono affiancate a sistemi fuzzy, magari proprio dove questi
falliscono, negli esempi trattati abbiamo avuto a che fare con problemi molto semplici,
dove in realtà il problema poteva essere risolto anche senza una rete neurale. Molto
spesso i sistemi fuzzy implementati nel modo classico presentano in molti punti del
loro funzionamento varie criticità. Il numero dei controlli sui parametri può crescere
di molto, peggiorando le performance. In questi casi la rete neurale trova
applicazione. Pensate ad un complesso algoritmo di classificazione, questo può
presentare in alcuni suoi punti di funzionamento delle criticità anche mai identificate
durante la fase di test del sistema. Queste criticità possono presentarsi durante
l‟utilizzo del prodotto da parte di un cliente finale. La rete neurale diminuisce
questo rischio dato che non avrà nessun bisogno di sapere come trattare i dati in
input. La rete neurale può, come abbiamo visto oramai piuttosto bene, imparare la
soluzione corretta per quel problema, inoltre rimanendo una struttura dati “semplice”,
non può generare titubanze nel suo algoritmo che rimarrà sempre lo stesso.
La prima combinazione tra reti neurali e sistemi fuzzy logic di cui parleremo,
definisce la NN come struttura dominante. E il sistema fuzzy come assistente al sistema
di addestramento. Un sistema fuzzy può ad esempio intervenire sull‟aggiornamento dei
vari coefficienti di training di una Error Back Propagation, come il learning rate o
momentum, ad ogni presentazione di input. Il sistema fuzzy si servirà allora di
algoritmi euristici per determinare il tipo di variazione a cui sottoporre i
coefficienti.
Lo stesso procedimento può essere applicato alle reti di Kohonen.
In altre situazioni si parla di “equivalenza neuro-fuzzy”. Facciamo un esempio, abbiamo
due input e e un output Y. Ciascuno dei due punti ha tre funzioni di membership,
rispettivamente: , e l‟output sia a singleton. Il seguente è lo schema funzionale:
68
Matteo Tosato - Introduzione alle reti neurali artificiali
X1 X2
FUZZY 1 FUZZY 2
M11 M12 M13 M21 M22 M23
R1 R9R2
U9
U1
...
U2
R9 = M13 M23R1 = M11 M21
Z1 = 1 / ƩRk Z2 = Ʃ(Uk Rk)
Y = Z1 Z2
Il sistema ha 6 strati,
- Lo strato di input con e .
- Il secondo strato ha due sezioni chiamate “pseudo-reti”, queste possono essere delle
reti neurali o neuro-fuzzy a loro volta non definite ma atte a generare le 6 funzioni
membership „M‟ citate prima.
- Il terzo strato sono proprio le 6 funzioni membership - Questi definiscono le 9 regole secondo le seguenti equazioni:
…
Queste secondo le seguenti regole formano e .
∑
∑( )
Con k = 1,2,..,9 come avete visto dalle formule, in questo caso adottiamo anche i pesi
„U‟. Mentre nel caso delle regole precedenti abbiamo adottato solamente la
moltiplicazione.
- Infine abbiamo il neurone di output „Y‟ che esegue il prodotto tra i due valori „Z‟.
Questo esempio ha gli strati uno, due e tre che eseguono la “fuzzificazione”, il quarto
strato esegue le inferenze e gli ultimi 2 strati effettuano la defuzzificazione.
69
Matteo Tosato - Introduzione alle reti neurali artificiali
Questo tipo di configurazioni possono arrivare ad essere molto molto complesse, forse
perdendo un po‟ della praticità e semplicità delle reti neurali pure. Invece è
frequente vedere configurazioni neurali dove gli input di una rete sono output di
un‟altra rete neurale. Sfruttando le diverse configurazioni e caratteristiche delle
reti, è possibile risolvere molti tipi di problemi. Una rete neurale, una volta che il
suo funzionamento è stato testato e addestrata per un certo compito è definibile come
una “black box”. Quindi, come è frequente fare nella progettazione software, una rete
viene trattata come oggetto e utilizzata per comporre un sistema più grande che ha
bisogno di sfumare i suoi valori. Per il sistema precedente si applica l‟algoritmo EBP
per trovare i valori con cui aggiornare i pesi.
( ) e ( ) ( ) ( ) ( )
Reti ART
Questo tipo di rete neurale è interessante circa la capacità di apprendere
continuamente e auto-modificarsi all‟occorrenza.
Questa categoria di reti si suddividono a loro volta in ART1, le quali trattano solo
input binari, ART2, con input analogici, Fuzzy-ART che usa le operazioni logiche fuzzy
ed infine HART che esegue classificazioni e gerarchie. Le reti ART hanno comunque
complessità minore rispetto le precedenti, ma sono molto utilizzate per risolvere
problemi in cui si deve applicare la logica fuzzy. Sono caratterizzate da un buon
compromesso stabilità-plasticità.
Per stabilità si intende la capacità di non dimenticare quello che è già stato appreso
dagli input precedenti. Infatti normalmente le comuni configurazioni si modificano
secondo gli input che ricevono senza tenere traccia degli stati sinaptici passati.
Per plasticità si intende invece la capacità di auto-modifica in funzione ai nuovi
input o alla necessità di saper fare nuove classificazioni sui dati. Vedremo anche che
queste reti possono aumentare o diminuire il numero dei neuroni nei suoi strati.
Queste reti sono nate con lo scopo di riprodurre una caratteristica importante delle
reti neurali biologiche. Ovvero la capacità di apprendere senza dimenticare i modelli
precedenti. Si può ad esempio pensare alla capacità del cervello, questo ricorda volti
visti non recentemente anche dopo averne acquisiti molti altri nuovi nel frattempo.
Nelle reti invece abbiamo visto che i nuovi modelli imparati sostituiscono quelli
precedenti. Questa rete riproduce il sistema biologico di memoria a breve termine e
lungo termine. Questi meccanismi sono siglati rispettivamente STM e LTM. La prima
apporta cambiamenti graduali nella seconda.
La rete è costituita in due strati, ed . Questi sono interconnessi da pesi
sinaptici top-down e botton-up. Essi costituiscono la STM. Il sistema di apprendimento
è semplice; i pesi sono inizializzati ad uno, = . Mentre l‟opposta sinapsi
dove N è il numero di neuroni dello strato . Gli input sono presentati allo strato .
Vengono calcolate le funzioni di scelta:
( ) | |
| |
Dove è il parametro di scelta il vettore dei pesi sinaptici, il simbolo
|A| denota la norma del vettore A, cioè la sommatoria dei suoi componenti scalari: |A|
= ∑ , l‟operatore logico fuzzy: equivale a MIN(X,W), cioè:
| | ∑ ( ) .
Le classificazioni quindi avranno luogo nel secondo livello . Il nodo di questo
70
Matteo Tosato - Introduzione alle reti neurali artificiali
livello che ha il maggior valore viene prescelto come categoria di X, purché venga soddisfatto il criterio: (di vigilanza)
| |
| |
Dove p è il parametro di vigilanza < 1.
Lo schema della rete:
j. . .
i. . .
M neuroni
N neuroni
LTM, WbLTM, Wf
F1
F2
Se il criterio di vigilanza viene soddisfatto i pesi sinaptici vengono aggiornati:
(
) ( )
Nel caso in cui il criterio di vigilanza non è soddisfatto si crea un nuovo nodo,
ovvero un nuovo neurone. Il suo peso sinattico verrà inizializzato con l‟equazione
appena mostrata. Quindi viene ripresentato l‟input nuovamente fino a che la stabilità
non viene raggiunta.
Concludendo questa panoramica sulle ART, abbiamo appreso che in ogni caso il lavoro di
queste è molto simile a quello delle MLP con EBP come algoritmo di apprendimento.
Inoltre queste ultime abbiamo visto essere molto utili quando il numero di classi
possibili non è predeterminato. Di conseguenza le reti ART risolvono questo particolare
problema.
Metodologie di progettazione
Siamo arrivati a trattare alcune tra le più utilizzate configurazioni di reti neurali.
Tra queste abbiamo parlato, dandone buona importanza, il percettrone, il quale ricordo
nonostante le limitate capacità di separazione, può essere impiegato largamente in
problemi di classificazione, le reti multilivello MLP con algoritmo di apprendimento
EBP, molto onerose in risorse hardware e più complesse dal punto di vista matematico,
le reti di Kohonen con la loro capacità auto-organizzante. Infine abbiamo speso un po‟
di parole anche nel fare una analogia tra le reti neurali e la logica fuzzy. Queste due
tecnologie abbiamo visto essere integrabili e in grado di dare entrambi risultati
“sfumati”.
In questa parte invece faremo un discorso meno tecnico che verte a definire i criteri
di progettazione e di scelta che oramai dovrebbero essere divenuti intuibili. Faremo
riferimento in particolare alle reti MLP, essendo quelle più utilizzate in ambito
pratico. Definibili in punti, i seguenti sono gli argomenti da trattare:
1. Scelta dell‟applicazione. 2. Analisi. 3. Pianificazione delle risorse. 4. Definizione di un criterio per le performance della rete che si desidera.
71
Matteo Tosato - Introduzione alle reti neurali artificiali
5. Progetto della rete neurale. 6. Preparazione degli esempi. 7. Processo di apprendimento. 8. Valutazione finale ed applicazione.
1) Le reti neurali sono convenienti quando l‟algoritmo non si conosce, oppure quando
pensare ad una soluzione algoritmica tradizionale è troppo complesso e dispendioso.
Quindi non vengono applicate quando esistono già algoritmi noti. Ad esempio, negli
esempi fatti per l‟OR ed XOR, la rete neurale non era affatto necessaria dato che la
procedura per eseguire un OR oppure un OR esclusivo è ben nota. Più utile invece nel
caso del riconoscimento dei profili altimetrici.
Riepilogando, una rete neurale è conveniente quando l‟applicazione è “a intensità dei
dati”. Piuttosto che a “intensità di calcoli” e i dati sono prevalentemente
qualitativi, imprecisi e disturbati.
Ai risultati di una rete neurale è consentito essere imprecisi ed in un certo range.
L‟applicazione implementata a reti neurali non può essere “mission critical”. Dato che
queste possono dare risultati imprecisi e parziali. Non devono avere potere
decisionale. Una rete fornisce un dato qualitativo, un andamento previsto, oppure un
dato certo in percentuale. Ciò nonostante una rete può svolgere compiti impossibili per
programmi sequenziali. Come per esempio imparare a fare nuovi tipi di operazioni per
cui non erano state programmate. Adattarsi alla nuova situazione, correggere gli
errori, ricostruire un pattern danneggiato senza sapere la sua forma originale. Ciò che
fa il cervello umano.
2) Come abbiamo visto, una applicazione solitamente non è interamente realizzabile con
un rete neurale. Une applicazione viene solitamente organizzata con moduli in cascata.
Una parte chiamata “ragionatore” può essere costituita da un algoritmo esperto fuzzy, e
da una parte a rete neurale che da al sistema la facoltà di “percepire” informazioni
nuove dall‟ambiente. Consideriamo un esempio reale; il “Phonetic Typewriter” è un
sistema ideato dallo stesso Kohonen. Si tratta di una macchina da scrivere comandata a
voce. Essa comprende 3 moduli in cascata; il primo si basa su algoritmi standard ed
esegue la conversione analogico / digitale e poi l‟analisi di Fourier del segnale
vocale in input (FFT = Fast Fourier Transform); il secondo modulo è una rete auto-
organizzante di Kohonen, questo ha il compito di classificare i fenomeni in input. Il
terzo ed ultimo modulo raffina i risultati ottenuti dalla SOM, ovvero verifica i
risultati dal punto di vista grammaticale.
L‟accoppiamento in cascata di un elemento “ragionatore” ed una rete neurale si presta
molto bene nelle applicazioni dove sono necessarie due parti di sistema, una per
dedurre, da un suono o immagine, ed una per ottenere un dato preciso basato su questa
deduzione. Questa composizione a cascata può essere estesa anche agli stessi moduli di
reti neurali, molte volte composti da più reti in cascata. Come abbiamo già detto,
output di alcune reti possono divenire input di altre.
3) Questo punto parla unicamente delle risorse umane vere e proprie, nel caso lavoriamo
in un team. In questo momento non ci interessa.
4) Anche il quarto punto lo possiamo tralasciare, riguarda la definizione di un
criterio di performance. Nel senso che la rete neurale da creare deve apportare un
reale beneficio. Questo deve essere noto a priori. Lo tralascio perché mi sembra troppo
ovvio, ritengo che da capire il discorso spese/guadagno sia semplice.
5) Il progetto della rete è invece parte fondamentale. Richiede innanzi tutto la
definizione degli input e degli output e degli attributi degli input. Se venissero
trascurati questi fattori durante la progettazione di una rete neurale, si può ottenere
un risultato insufficiente. Ovvero la rete non funzionerà. Una cosa molto importante da
tenere sempre a mente è che per una rete, la presentazione e la qualità degli input
durante il training è fondamentale. Molto spesso gli input hanno bisogno di essere
“normalizzati” per essere adatti a divenire input della rete neurale. Gli input, se
sono ad esempio simboli, possono essere codificati in numeri attraverso una semplice
codifica binaria. Qui è bene precisare che non si tratta della consueta codifica
72
Matteo Tosato - Introduzione alle reti neurali artificiali
binaria che siamo portati a pensare. La codifica seguente non andrebbe bene:
questo perché la rete neurale tenderebbe a “raggruppare” i
valori come simili più di quanto farebbe con ad esempio. In questo caso
bisogna adottare un codifica detta “binaria estesa”. Ad esempio:
In questo modo i valori sono “distanti” uguali. Nel caso delle reti possiamo pensare che si attivi solo un input, sempre in una diversa posizione per ogni simbolo.
La decodifica può avvenire ad esempio nel modo seguente, noti e :
V =
e
( )( )
Poi c‟è da pensare al numero degli strati nascosti da utilizzare nel caso delle reti
MLP e dal numero di neuroni per ognuno di questi livelli. Per determinare il numero
degli strati ci viene incontro un metodo abbastanza rigoroso. Ricordate quando abbiamo
parlato della proiezione degli input nello spazio n-dimensionale? Solitamente quando la
separabilità ha una iper-superficie convessa, basta un solo strato; in caso di
separabilità con iper-superficie concava saranno necessari due strati. Tuttavia non
esiste nessuna certezza matematica di questo, è comunque preferibile avere un solo
strato di neuroni nascosti, dato che con il crescere di questi, il numero dei pesi
sinaptici da aggiornare cresce anch‟esso, aumentando il costo in termini di risorse
hardware necessarie. E‟ anche vero che esiste un metodo, applicabile all‟algoritmo di
addestramento EBP che valuta durante questo, la possibilità, necessità di aumentare o
diminuire il numero dei neuroni. Questo metodo prende il nome di “Structural Learning”.
Esistono due varianti, nella si ha una rete inizialmente con poche neuroni e neuroni
intermedi vengono aggiunti secondo necessità, questo metodo è utile anche per
aggiornare una rete neurale esistente. La seconda variante elimina neuroni, partendo
ovviamente da una situazione di eccesso. Per questa esistono poi molte sotto varianti
che non vedremo, uno può anche, una volta nel contesto della sua applicazione,
inventare nuovi sistemi di adattamento strutturale automatici.
Un altro elemento da scegliere con attenzione riguarda il tipo di funzioni di
trasferimento da utilizzare. Noi abbiamo in precedenza visto ed anche utilizzato le più
diffuse. E‟ possibile comunque applicare qualsiasi tipo di funzione. L‟importante è che
siano continue, monotone e derivabili. Abbiamo già visto che non possono essere tutte
lineari. Come nel caso delle reti MLP. Negli strati intermedi le funzioni non hanno
scopo di essere lineari, come abbiamo visto per la rete XOR.
6) Siamo arrivati alla progettazione del training set, o degli esempi. Quando
l‟apprendimento della rete è supervisionato, abbiamo bisogno di preparare un efficiente
training set. Gli esempi devono essere preparati tenendo conto di fattori precisi. Nel
caso si parte da dati esistenti, prima di inserirli come input, dobbiamo eliminare gli
estranei e omogenizzare quelli necessari all‟applicazione, controllando le omonime
(dati diversi con lo stesso nome), e le sinonime (dati uguali ma con nome diverso),
controllare la congruenza delle unità di misura e la compresenza di dati gerarchici.
Inoltre il numero di esempi deve essere dimensionato alla complessità del problema.
Esistono regole più o meno corrette per fare una stima del numero di esempi necessari.
Una di questi è la seguente:
Un altro fattore estremamente importante è fornire alla rete neurale input rumorosi.
Ovvero non del tutto esatti. Ad esempio se l‟output corretto della rete per un
determinata iterazione del training set è 0.5, noi possiamo fornire alla rete come
valore atteso anche 0.48. In questo modo la rete addestrata è in grado di fare delle
generalizzazioni più efficaci. In questo procedimento non bisogna però esagerare,
dipende da quanto la generalizzazione è importante per la nostra applicazione, una
grande capacità di generalizzare è accompagnata naturalmente anche ad una minore
precisione.
7) Abbiamo già accennato in precedenza ai coefficienti di apprendimento, che come nel
caso dell‟esempio del capitolo sulle reti MLP essi sono determinanti. Nelle reti MLP
viene applicato l‟algoritmo BP in una delle sue varianti, la scelta del valore per
learning rate e momentum non sono dettate da metodi rigorosi, sono comunque valori
solitamente bassi, inferiori allo 0.5. Esiste poi la possibilità di implementare il
comportamento del learning rate come “adattativo”. Quando l‟algoritmo rimane bloccato
in un minimo locale, il learning rate viene aumentato / diminuito per dare il giusto
73
Matteo Tosato - Introduzione alle reti neurali artificiali
apporto di precisione alla rete senza prolungare eccessivamente la durata
dell‟addestramento.
In conclusione il problema / caratteristica delle reti neurali è che non ci sono metodi
precisi ne di progettazione ne di validazione, ci sono reti neurali adatte solo a
determinati compiti, non riutilizzabili, è bene salvare le varie configurazioni che
durante l‟utilizzo nelle applicazioni vengono aggiornate o cambiate, questo per poter
ritornare nello stato precedente nelle eventualità che anche i fattori esterni
ritornino ad uno dei loro stati passati.
Una buona idea è secondo me inserire tra le routine di chiamata delle librerie /
applicazioni neurali anche funzione per il salvataggio e ripristino dei pesi, o anche
del numero di neuroni correnti per ogni strato.
Il problema dei dati in ingresso
Forse il compito dove le reti neurali trovano maggior successo è quello che concerne la
visione artificiale. Esiste da più di una dozzina d‟anni una libreria open source
dedicata alla visione. OpenCV. Questa libreria permette la realizzazione di programmi
in grado di riconoscere oggetti tramite una periferica, tipo una telecamera. Nel campo
della videosorveglianza queste vengono pesantemente utilizzate. Si pensi ad esempio al
problema del riconoscimento di una figura umana in una scena dinamica. Un compito
assolutamente impossibile per un normale programma sequenziale. Oppure un sistema di
riconoscimento targhe, oppure ancora un sistema per riconoscere i visi all‟ingresso di
un ufficio.
Dato che sarebbe una pazzia partire a progettare un sistema del genere dal singolo
neurone (anche se qui non nego di aver parlato con persone potenzialmente in grado di
farlo) dobbiamo ricorrere a queste librerie, che più che fornirci il sistema neurale,
ci danno dei moduli già composti per trattare i dati che otteniamo dalle periferiche.
Infatti uno dei maggiori problemi che incontriamo quando lavoriamo con le reti neurali
consiste nel modo in cui trattare i dati in ingresso alla rete. Rimanendo sull‟esempio
della visione artificiale, possiamo pensare alla qualità delle immagini in arrivo da
una telecamera, esse possono arrivare con molteplici problemi e situazioni variabili;
immagini buie, sfocate, disturbate etc... A questo problema occorre rispondere con
faticose operazioni di correzione e revisione delle immagini in arrivo. Data una
immagine devono esserne evidenziate le caratteristiche salienti che ci interessano. Se
il nostro compito è quello di individuare all‟interno di un video una figura umana
dobbiamo cercare di mettere in evidenzia proprio le caratteristiche che ci interessano.
Ad esempio i contorni delle figure saranno di maggior importanza rispetto alla qualità
dei colori.
A questo proposito esistono filtri che ricalcano complesse e dispendiose operazioni
matematiche sulle immagini, che sono ovviamente trattate come matrici di pixel.
Questo problema del trattamento dei dati in ingresso esiste anche in tutti gli altri
ambiti di impiego.
Un‟altra questione è relativa a come codificare i dati in input. Ne abbiamo già
accennato; non sempre i dati da analizzare hanno un formato adatto per costituire
l‟input di una rete neurale. Le normalizzazioni o lo streching di questi valori spesso
non è sufficiente o è comunque impossibile da eseguire. Immaginiamo di dover
classificare delle forme di figure piane. Quello che è necessario è trovare un codifica
adatta. Oltre rappresentarne la caratteristica, occorre mantenere anche i fattori di
proporzione che le figure hanno tra loro, se questo non viene garantito, i risultati
74
Matteo Tosato - Introduzione alle reti neurali artificiali
generati saranno scorretti. Consideriamo una rete con tre input e le seguenti codifiche
dei dati;
001
001
010
010
011
100
L‟esempio sopra mostra sulla prima riga una codifica errata, mentre sulla seconda una
alternativa migliore. La prima codifica indicherebbe alla rete neurale un valore più
pesante per la figura a stella, quindi nella computazione totale, essa tenderebbe ad
avere molto più peso rispetto le altre.
La seconda codifica invece si limita a evidenziare la caratteristica senza influire sul
peso di essa.
Esempi di applicazioni pratiche
Intrusion detection
Presentiamo ora una serie di concetti strettamente legati alle conoscenze nel campo
delle telecomunicazioni, dei protocolli di rete e della sicurezza informatica. Cercherò
comunque di indicare delle linee generali applicabili anche ad altri ambiti, ma è
sicuramente ideale avere la conoscenza informatica di base almeno per quanto riguarda
reti e naturalmente, programmazione. Sarebbe stato forse peggio trattare degli esempi
come l‟applicazione delle reti neurali nell‟analisi finanziaria, lì occorrerebbe
davvero studiare molti concetti che riguardano l‟economia e la statistica per poi
applicare le reti nella progettazione di sistemi che effettuano delle previsioni su
tassi e tendenze.
Questo dimostra l‟incredibile varietà di campi disponibili in cui questa tecnologia può
essere impiegata. Recenti successi sono stati ottenuti nel campo medico grazie a reti
neurali per il riconoscimento di tumori nelle radiografie, piuttosto che reti neurali
impiegate nel campo delle biotecnologie.
Due parole su cosa significa analizzare il traffico di rete;
internet e le reti più in generale si basano su una serie di protocolli. I “protocolli”
sono una convenzione che i programmatori devono utilizzare nella scrittura delle parti
dei loro programmi che devono comunicare con altri computer nella rete. In questo modo
è possibile garantire una adeguata “compatibilità” tra tutti i tipi di sistemi che
devono poter comunicare indipendentemente dal tipo di piattaforma.
Prima di proseguire raccomando di approfondire questo aspetto se non lo si conosce di
già. Di seguito lascio alcuni spunti introduttivi. Saremo malgrado costretti ad
affrontare questioni molto tecniche e specifiche della progettazione di questi
protocolli, dato che noi dovremo monitorarne il
transito, occorre averne una profonda conoscenza.
http://it.wikipedia.org/wiki/Protocollo_di_rete
http://it.wikipedia.org/wiki/Modello_OSI
75
Matteo Tosato - Introduzione alle reti neurali artificiali
Alcuni cenni sulla programmazione di rete:
http://scuola.linux.it/docs/altre_scuole/planck/socket/progr-socket4.html
Dunque il problema che ci troviamo a dover risolvere non è poi dei più semplici. I
seguenti punti mostrano le più comuni situazioni in cui il traffico di rete è
considerato certamente anomalo:
- Flusso in entrata di un elevato numero di richieste di connessione.
- Flusso di un elevato numero di reply ARP senza precedenti richieste.
- Pacchetti con MTU superiore alla norma.
- Flusso elevato di richieste di ping.
- Pacchetti TCP desincronizzati.
Da queste semplici osservazioni è piuttosto complicato tentare di riconoscere se si
tratta di pacchetti legittimi, errori o tentativi di attacco. Un grande flusso di nuove
connessioni in entrata non è detto rappresenti sempre il tentativo di provocare
l‟interruzione dei servizi. Potrebbe essere che l‟host è in effetti in un momento di
grande utilizzo da parte dei client, oppure si potrebbe trattare di tentativo di
profiling verso l‟host.
La valutazione di questi aspetti può essere fatta con regole piuttosto semplici, non ci
occorre utilizzare metodi fuzzy. Il nostro obiettivo è capire, a prescindere dalle
informazioni inviate (cose difficile da fare senza rischiare di bloccare
accidentalmente connessioni legittime) se si tratta di una connessione instaurata da
un‟attaccante o da un regolare client. Almeno per quanto riguarda tutto il traffico
TCP, che è anche la tipologia di pacchetti più abbondante che transita sulle reti.
Sono necessarie delle osservazioni fatte sulle tempistiche di invio – ricezione.
Dobbiamo tener presente che nella maggior parte dei casi gli attacchi vengono
effettuati attraverso host “intermediari”. Chiamati anche bot. L‟attaccante infatti,
prima viola altri server meno controllati e ne acquisisce il controllo. Poi da questi
lancia il suo reale attacco. In questo modo esso aumenta la sua speranza di rimanere
nell‟anonimato. Più host intermediari usa più è probabile che la sua identità rimanga
non conosciuta.
Molti tipi di approcci sono stati utilizzati nel corso degli anni per sfruttare la
differenza che si ha nelle connessioni di questi attaccanti e quelle degli utenti
normali. L‟elemento che andremo a prendere in considerazione ora è il “Round trip time”
(RTT).
Di cosa si tratta? Per capirlo dobbiamo tenere ben presente il funzionamento del
protocollo TCP. Questo implementa un sistema di controllo per l‟affidabilità della
trasmissione dei dati. Esso si basa su una conferma di ricezione da parte del
ricevente. Il protocollo contiene difatti un campo “acknowledgement” atto a contenere
il numero di sequenza del prossimo pacchetto che egli si aspetta di ricevere. In questo
modo, i due host sono sincronizzati. E accetteranno pacchetti solo se essi risultano
attinenti al range (la finestra di TCP) aspettato. Si veda un adeguato approfondimento
all‟argomento.
L‟RTT corrisponde al tempo di andata e ritorno di un pacchetto dati da un client al
server. Ogni host tiene in memoria un tempo RTT previsto entro il quale l‟altro capo
della connessione dovrà rispondere. Se la conferma di ricezione non arriva nel tempo
previsto l‟host ritrasmetterà le informazioni.
L‟RTT previsto viene calcolato nel modo seguente:
( ) ( ( )) (( ) )
corrisponde al tempo RTT appena campionato. Tcp è così in grado di adattarsi alla
larghezza di banda e al traffico di rete, ed elimina il problema dei percorsi
differenti che vari pacchetti TCP della medesima connessione possono prendere. Quando
un pacchetto viene perso, non potendo il destinatario riceverlo esso non invierà
conferma e il timeout scadrà, a questo punto il mittente rispedisce i dati, quando
arriverà la conferma di ricezione, il mittente non ha modo di sapere se questa
76
Matteo Tosato - Introduzione alle reti neurali artificiali
riferisce al primo o al secondo pacchetto inviato, comunque incrementerà l‟RTT perché
considererà il primo pacchetto spedito. Tale fenomeno viene chiamato “ambiguità della
conferma di ricezione” e le conferme di ricezione di TCP sono dette “ambigue”.
Volendo si potrebbe fare in modo che TCP calcoli l‟RTT non dal pacchetto originale ma
dalla ritrasmissione, ma in questo modo si avrebbe un problema ancora maggiore dato che
l‟RTT finirebbe per diventare troppo breve a tal punto che TCP invierebbe ogni
pacchetto almeno due volte generando il doppio del traffico. Quindi nonostante il
problema dell‟ambiguità, TCP tende a tenere un tempo RTT “pessimista” come valore di
timeout.
Il seguente grafico mostra l‟andamento dell‟RTT durante un tipica connessione tra due
host di una rete LAN:
Questo grafico non mostra il valore timeout RTT di TCP, mostra il valore RTT campionato
sulla base dei pacchetti ricevuti.
Vediamo di capire come possiamo utilizzare questi dati per i nostri scopi.
Il calcolo del valore RTT permette di stimare il numero di host (quindi di
elaborazioni) presenti sul tratto “downstream” della connessione. Determinando una
certa “lunghezza” di connessione, possiamo capire se si tratta di una intrusione o
meno. Il nostro “sensore” viene posizionato nel modo seguente:
77
Matteo Tosato - Introduzione alle reti neurali artificiali
Host1 Host2 Host3 Victim
Attacker
Normal clientC1
Ci Cn-1Cn
Sensor
Figura 19: Schema attacco informatico mediante host intermediari
Possiamo considerare ogni pacchetto TCP “outcoming” e il rispettivo “echo”, quindi
calcolare la differenza temporale RTT del pacchetto in andata e ritorno. Questo tempo
può essere influenzato da molteplici fattori.
Dobbiamo considerare il tempo di propagazione ( ), quindi dipendente dalla distanza
fisica, il tempo impiegato dal calcolatore per processare il pacchetto ( ), il tempo di
accodamento che il pacchetto può avere nello stack TCP/IP ( ), e il tempo di
trasmissione ( ). Quindi possiamo riassumere il calcolo del RTT nel modo seguente:
( )
Generalmente è piuttosto costante per molti pacchetti. Quindi raggruppando il
calcolo può essere inteso anche come:
Dove è il ritardo non variabile o costante e è il ritardo variabile definito da
( ). Se ci sono K connessioni, (o k hosts) tra l‟attaccante e la vittima,
allora il valore rappresentato da rappresenta la parte di variazione di tutti i
ritardi lungo la catena di connessioni tra questi hosts:
∑
Per poter calcolare questo valore dobbiamo iterare su ogni pacchetto in arrivo e se si
tratta di un pacchetto echo, confrontare questo con il relativo pacchetto di invio, se
non si tratta di un echo ma di un pacchetto outcoming, lo si accoda per essere
“matchato” dopo. Lo pseudo-codice:
(Han-Ching Wu And Shou-Hsuan Stephen Huang, Department of Computer Science, University
of Houston)
Initialize send queue;
while(there are some packets) {
read next packet P; {
if P is a send packet {
calculate TimeGap;
if TimeGap > threshold
reset Send queue;
else
insert packet P to Send queue;
78
Matteo Tosato - Introduzione alle reti neurali artificiali
}
else if P is an echo packet {
if (P.size is large) do nothing;
else {
S = dequeue(Send);
if((S.ack = P.seq) and (S.seq < P.ack)) {
Match P and S;
Compute RTT between P and S;
}
}
}
}
}
Sicuramente è una osservazione acuta il fatto di specificare che non tutti i valori RTT
della connessione saranno uguali. Questo dipende dalla fluttuazione del traffico di
rete. E‟ anche vero però che analizzando intervalli ristretti di tempo questo problema
scompare e tutti gli RTT saranno più o meno simili. Sulla base di questo è possibile
riconoscere, o meglio definire vari livelli del valore RTT e di conseguenza, stimare il
numero di “stepping-stones” (gli host presenti lungo la connessione).
I vantaggi di usare l‟intelligenza artificiale (NN, neural networks) invece di
algoritmi esperti fuzzy sono innanzi tutto una notevole flessibilità; questa è
importante perché le situazioni nelle quali un host si può trovare sono molto varie. Le
nn possiedono anche la capacità di analizzare dati non-lineari con multi-variabilità.
Non dovremo considerare connessione per connessione ma solo i pacchetti in se. Quando
vedremo una serie di valori RTT assolutamente fuori scala sapremo che quella
connessione è ipoteticamente una intrusione che sta utilizzando vari host intermediari
per nascondere la sua identità. Un messaggio sarà reso all‟amministratore che
effettuerà il dovuto controllo approfondito. Date le diverse situazioni possibili in
cui gli host si possono trovare, la rete neurale è la soluzione migliore circa
l‟adattabilità del sistema.
Vediamo per step le operazioni da compiere:
1 Per prima cosa occorre creare il sistema per il capture dei pacchetti ed il
filtraggio. Tramite una call-back i pacchetti TCP send o echo devono essere inseriti in
una coda pronti per essere processati.
2 Poi, secondo l‟algoritmo presentato prima, occorre calcolare il valore RTT
campionato, dobbiamo poi raggruppare questi in righe di n valori, dove n corrisponde al
numero di neuroni della rete neurale nel layer di input. Se per esempio abbiamo 500
valori RTT e 10 neuroni in ingresso, organizzeremo gli RTT in 50 righe, ovvero 50 set
per la rete. Ognuna di queste righe viene valutata dalla rete.
3 Una volta che la rete ha elaborato i set in input è in grado di valutare il numero di
“stepping-stone” presenti e confrontando questo valore con una media su tutti i
pacchetti è in grado di individuare le connessioni che stanno molto probabilmente
utilizzando sistemi intermediari per accedere. Poi queste possono essere ulteriormente
filtrate in base a criteri che eliminano evidenti falsi allarmi.
Ma la cosa interessante che occorre focalizzare è l‟estrema adattabilità del sistema
senza effettuare la ricompilazione, sarà sufficiente addestrare la rete in modo
diverso, per avere un comportamento differente.
Il tipo di rete neurale che può essere impiegato non è restrittivo al patto che sia una
feed-forward, dato il compito di “classificazione” che gli spetta. I neuroni nascosti e
il neurone di uscita devono avere una funzione non lineare. Può andare bene la
79
Matteo Tosato - Introduzione alle reti neurali artificiali
tangente, la sigmoide o anche la funzione seno. Un esempio di configurazione con 10
neuroni di input:
x1
x2
x3
x4
x5
X6
X7
X8
X9
x0
Y(Ʃ(x*w))
Y(Ʃ(x*w))
Y(Ʃ(x*w))
Y(Ʃ(x*w))
NetOut =
Y(Ʃ(Y(Ʃ(x*w1)*w2)))
Figura 20: Rete MLP per la valutazione degli RTTs
Scendiamo nel dettaglio della progettazione di un sistema di questo tipo. Nella maggior
parte dei casi, le spiegazioni teoriche di una cosa nascondono una miriade di questioni
pratiche che solitamente vengono tralasciate.
Di seguito vediamo come realizzare i vari moduli del nostro programma. Diamo per
assunto che la cosa può essere fatta sia come programma munito di interfaccia utente
grafica, (come ho fatto io per provare il sistema), o come modulo kernel. Detto questo
cambia poco per i moduli principali eccetto forse il modulo di cattura che a livello
kernel viene fatto in modo differente.
Appunto il processo di cattura dei pacchetti è la prima cosa che dobbiamo affrontare.
Un sistema di cattura è di fatto un driver in grado di passarci, tramite una funzione
callback, ogni pacchetto che transita sulla scheda di rete o attraverso il nostro host
in generale. Le modalità di esecuzione sono generalmente due, normale e promiscua. In
modalità normale il traffico acquisito sarà relativo ad una particolare scheda di rete,
tutti gli altri pacchetti che non sono indirizzati o non escono dall‟interfaccia non
sono considerati. La modalità promiscua invece opera nel modo inverso, tutti i
pacchetti vengono acquisiti indipendentemente dalla loro origine o dalla loro
destinazione.
Il pacchetto ci viene consegnato nella sua integrità, ovvero avremo un puntatore che
punta al primo byte dello strato di collegamento, generalmente ethernet.
Ethernet IP Data ...
Anche se lavoriamo a livello kernel avremo lo stesso risultato, ma non lo faremo
utilizzando dei driver di terze parti, nel caso di linux occorrerà utilizzare
l‟interfaccia “netfilter” per ricevere in modo seriale assieme agli altri moduli di
80
Matteo Tosato - Introduzione alle reti neurali artificiali
rete i puntatori ai pacchetti da analizzare. Inoltre lavorando a questo livello è
possibile bloccare i pacchetti prima che essi transitino nella scheda. Per esempio, se
il nostro modulo viene assemblato assieme ad un canonico firewall potremmo scegliere se
fornire un semplice sistema di segnalazione o permettere al nostro modulo di
intervenire in “real-time” sul traffico.
Ho utilizzato i driver libpcap per realizzare il modulo. Ho inserito tutte le procedure
in una classe appoggiandomi al framework Qt. Le funzioni native pcap da utilizzare sono
in ordine:
pcap_findalldevs(), per acquisire la lista di interfacce di rete disponibili.
pcap_lookupnet(), per acquisire informazioni addizionali sull‟interfaccia.
pcap_open_live(), per ottenere un handle di sessione.
pcap_datalink(), per verificare il livello di collegamento.
pcap_next_ex(), restituisce il prossimo pacchetto presente in stack.
Tutte le funzioni sono descritte all‟interno della documentazione che viene fornita
all‟interno dei sorgenti, oppure direttamente sul WEB all‟indirizzo seguente:
http://www.winpcap.org/docs/docs_412/html/main.html
Ogni pacchetto acquisito dovrà essere analizzato dall‟algoritmo proposto prima.
Ricordo che comunque l‟analisi che andremo a fare è bene farla non su tutte le porte
contemporaneamente, ovvero, è necessario filtrare i pacchetti in modo da non
considerare tutto il traffico delle altre applicazioni che non siano i vari client di
accesso remoto utilizzati dagli attaccanti, questi sono generalmente telnet, Open-ssh,
Putty e pochi altri. E‟ assolutamente inutile acquisire tutto il traffico TCP riferito
alla porta 80. Produrrebbe solo dei risultati confusionari dato che il traffico WEB
produce migliaia di pacchetti al minuto. Ed è anche inutile perché non è possibile
utilizzare quella porta da lato client se impegnata già a fare un altro tipo di
servizio, sia da parte dell‟utente legittimo che dall‟attaccante. A meno che l‟exploit
si trova nel web server, ma anche in questo caso, gli exploit aprono connessioni non di
certo dalla stessa porta di servizio.
L‟algoritmo lo abbiamo visto, qui vediamo come implementarlo in modo pratico. Innanzi
tutto vediamo di definire che cosa si intende per “pacchetto Send e Echo”. Un pacchetto
Send è definito come segmento in uscita dall‟interfaccia di rete dell‟host monitorato,
o come in questo caso, dall‟host su cui il nostro programma stà girando, esso contiene
dati. Questo pacchetto ha il flag ACK e PSH settato. Non ci interesseremo a quale
connessione appartiene, abbiamo detto che non ci importa di avere anche questa
variabile. Ci limiteremo a “match-are” tutti i pacchetti send ed echo.
Recuperiamo il flusso di una comune sessione TCP nella quale due host si sono scambiati
un certo numero di dati. Vi evidenzio i pacchetti Send ed Echo con i colori rosso e blu
rispettivamente.
|Time | 192.168.0.2 |
| | | 91.203.96.252 |
|11,995 | SYN | |Seq = 0
| |(6206) ------------------> (443) |
|12,090 | SYN, ACK | |Seq = 0 Ack = 1
| |(6206) <------------------ (443) |
|12,091 | ACK | |Seq = 1 Ack = 1
| |(6206) ------------------> (443) |
|12,091 | PSH, ACK - Len: 180 |Seq = 1 Ack = 1
| |(6206) ------------------> (443) |
|12,191 | ACK | |Seq = 1 Ack = 181
| |(6206) <------------------ (443) |
|12,193 | ACK - Len: 1360 |Seq = 1 Ack = 181
81
Matteo Tosato - Introduzione alle reti neurali artificiali
| |(6206) <------------------ (443) |
|12,196 | ACK - Len: 1360 |Seq = 1361 Ack = 181
| |(6206) <------------------ (443) |
|12,196 | ACK | |Seq = 181 Ack = 2721
| |(6206) ------------------> (443) |
|12,295 | ACK - Len: 1360 |Seq = 2721 Ack = 181
| |(6206) <------------------ (443) |
|12,295 | PSH, ACK - Len: 509 |Seq = 4081 Ack = 181
| |(6206) <------------------ (443) |
|12,295 | ACK | |Seq = 181 Ack = 4590
| |(6206) ------------------> (443) |
|12,328 | PSH, ACK - Len: 267 |Seq = 181 Ack = 4590
| |(6206) ------------------> (443) |
|12,469 | ACK | |Seq = 4590 Ack = 448
| |(6206) <------------------ (443) |
|12,469 | PSH, ACK - Len: 59 |Seq = 448 Ack = 4590
| |(6206) ------------------> (443) |
|12,565 | ACK | |Seq = 4590 Ack = 507
| |(6206) <------------------ (443) |
|12,565 | PSH, ACK - Len: 59 |Seq = 4590 Ack = 507
| |(6206) <------------------ (443) |
|12,572 | PSH, ACK - Len: 901 |Seq = 507 Ack = 4649
| |(6206) ------------------> (443) |
|12,722 | ACK | |Seq = 4649 Ack = 1408
| |(6206) <------------------ (443) |
|12,722 | PSH, ACK - Len: 517 |Seq = 1408 Ack = 4649
| |(6206) ------------------> (443) |
|12,827 | ACK | |Seq = 4649 Ack = 1925
| |(6206) <------------------ (443) |
|12,837 | PSH, ACK - Len: 229 |Seq = 4649 Ack = 1925
| |(6206) <------------------ (443) |
|12,838 | PSH, ACK - Len: 261 |Seq = 4878 Ack = 1925
| |(6206) <------------------ (443) |
|12,838 | ACK | |Seq = 1925 Ack = 5139
| |(6206) ------------------> (443) |
|12,838 | FIN, ACK | |Seq = 5139 Ack = 1925
| |(6206) <------------------ (443) |
|12,838 | ACK | |Seq = 1925 Ack = 5140
| |(6206) ------------------> (443) |
|12,938 | FIN, ACK | |Seq = 1925 Ack = 5140
| |(6206) ------------------> (443) |
|13,033 | ACK | |Seq = 5140 Ack = 1926
| |(6206) <------------------ (443) |
Abbiamo 3 valori RTT campionati.
0.204 s., 0.237 e 0.265.
Nell‟algoritmo utilizziamo la regola:
“if((S.ack = P.seq) and (S.seq < P.ack))”
questa ci impedisce di sbagliare la corrispondenza dei due pacchetti.
Riprendendo direttamente il mio codice avrò alcune routine che provvedono al
riconoscimento degli strati e all‟accesso a questi tramite un sistema di puntatori e
casting. Fino ad arrivare al riconoscimento del pacchetto Send, ovvero:
if(ip->saddr == localip && (tcp->flags & 0x10) && (tcp->flags & 0x18)) {
I flag che vado a controllare sono l‟ACK e PSH e naturalmente l‟indirizzo di origine,
che deve essere il mio. Queste regole classificano il pacchetto come “Send”. A questo
82
Matteo Tosato - Introduzione alle reti neurali artificiali
punto può essere inserito in un struttura FIFO come una coda. Infatti è il primo
pacchetto send a dover essere abbinato al primo pacchetto echo che rispetta le seguenti
regole:
}else if((ip->daddr == localip) && (tcp->flags & 0x10) && (tcp->flags & 0x18)) {
...
if((s_tcp->ack_n == tcp->seq_n) && (s_tcp->seq_n < tcp->ack_n)) {
Soltanto a questo punto possiamo calcolare il valore RTT della coppia di pacchetti.
I risultati dei campionamenti devono essere organizzati in “set” per la rete neurale.
Ovvero dato il numero N di neuroni che abbiamo scelto per lo strato di input della rete
dovremo organizzare i valori in array di N elementi e sottoporli alla rete. Se mi è
concesso di generalizzare la struttura della rete, possiamo riassumere con questo
schema:
∑ f.
.
.
RTT1
RTT2
RTTN
Il valore di uscita della rete da un‟idea del numero di “stepping-stones” rilevati
dalla serie di RTTs.
Ci sono comunque delle note da fare su questo sistema.
Non rappresenta una soluzione completamente sicura e applicabile in ogni circostanza.
Immaginiamo un server che offre un servizio di accesso remoto con SSH, (anche se questo
è abbastanza improbabile come servizio) ed esso sia pesantemente utilizzato. E‟
possibile che un attaccante si mischi nella folla sfruttando tutto il timeout di TCP
prima di inviare il pacchetto successivo. Questo potrebbe indurre al fallimento il
nostro sistema, dato che considererebbe i tempi RTT alti rilevati come “eccezioni”
dovute ad anomalie; e proprio il punto di forza delle reti neurali rischierebbe di
essere causa del fallimento del sistema di rilevamento. Pertanto in questi casi
occorrerebbe anche tenere come riferimento la connessione in se e andare a analizzare
gli RTT campionati solo relativi ad essa, questo per ogni connessione. Questo complica
le cose e più che altro, aumenta notevolmente il costo in potenza di calcolo necessario
per il sistema.
Generalmente possiamo tenere monitorate le porte di servizio. Ad esempio, abbiamo un
server web che può essere gestito da remoto tramite SSH, (questa è una situazione
piuttosto comune per la maggior parte dei server di servizi internet) quindi il numero
di connessioni previste sulla porta 22 sarà pari ad uno. Così, oltre a stabilire un
numero massimo di sessioni SSH, il sistema sarebbe in grado di valutare se l‟accesso è
tenuto da un client standard, oppure se esso sta utilizzando una lunga catena di
connessioni per nascondere la sua identità. In questo ultimo caso la connessione può
essere interrotta. L‟attaccante sarebbe così obbligato ad utilizzare una connessine
diretta per l‟accesso e così facendo, sarebbe velocemente smascherato tramite i sistemi
per la localizzazione dell‟IP utilizzabili dagli stessi provider proprietari delle
linee. Dal punto di vista dell‟utente è sufficiente segnalare l‟IP registrato nei log
che risulta autore di azioni sospette per far scattare tutta la questione.
83
Matteo Tosato - Introduzione alle reti neurali artificiali
Un sistema del genere è comunque supplementare ai sistemi anti-intrusione tradizionali.
Si tratta di tecniche nuove e piuttosto diverse dalle solite ma non le sostituiscono,
aggiungono solamente un certo grado di intelligenza.
I seguenti sono i tempi RTT che ho rilevato per connessioni dirette in Rete LAN,
ipotizzando di utilizzare una rete neurale a 6 neuroni di input, avremmo:
RTT set n°1
0.140795s. 0.700669s. 0.093393s. 0.123039s. 0.121076s. 0.10092s.
RTT set n°2
0.092423s. 0.092714s. 0.100824s. 0.094254s. 0.09343s. 0.764306s.
RTT set n°3
0.099924s. 0.099725s. 0.092682s. 0.100902s. 0.100548s. 0.492595s.
RTT set n°4
0.095503s. 0.099248s. 0.095705s. 0.095733s. 0.095373s. 0.094035s.
RTT set n°5
0.097204s. 0.096408s. 0.099615s. 0.799309s. 0.651773s. 0.095147s.
RTT set n°6
0.282706s. 0.099976s. 0.119879s. 0.199972s. 0.200492s. 0.100925s.
RTT set n°7
0.099749s. 0.099919s. 0.101313s. 0.100984s. 0.100547s. 0.099287s.
I valori sono tutti più o meno simili e, salvo casi particolari, non sono superiori ai
200 ms. (una media di 100 ms.) Per questo motivo sarebbe meglio utilizzare più neuroni
di input, magari tra 15 e 20. Per le connessioni provenienti da internet avremo valori
leggermente più alti.
Non c‟è un sistema univoco per effettuare la giusta valutazione (ovvero il tipo di
addestramento da fare), perché le situazione può essere davvero varia. Per questo
motivo la rete neurale risulta molto comoda, è sufficiente un riaddestramento per
modificare il criterio di valutazione. Potremmo anche insegnare alla rete ad
identificare solo le connessioni fidate.
Nel programma dovrò pensare ad un pannello dove questi parametri possono essere
settati. Dobbiamo rendere il sistema il più personalizzabile possibile. Ad esempio:
La schema di funzionamento del mio programma esemplificativo è infine il seguente:
84
Matteo Tosato - Introduzione alle reti neurali artificiali
Main
Packet capture
~
User Interface
~
IA pre-processor
~
General statistics
IA config
dialog
Capture
module
config
FIFO
Packets
Puntatori
pacchetti
Packet analyzer
and dumpFIFO
Il modulo IA è quello che gestisce la rete neurale e si preoccupa di eseguire il
rilevamento dei valori RTT anomali. In più si preoccupa di loggare tutta l‟attività su
file. I thread principali sono 3. E‟ bene infatti sfruttare, la dove possibile, le
architetture multi-core, dato che solo l‟elaborazione della rete neurale può arrivare
ad essere dispendiosa se sono presenti molti neuroni nel livello nascosto.
Previsione di fenomeni complessi
Le reti neurali possono essere utilizzate anche per prevedere il valore di una
(previsione uni-variata) o più (previsione multi-variata) variabili sulla base di dati
storici. Questa capacità è sfruttata molto nell‟ambito finanziario e statistico. Data
una funzione ( ), solitamente ne si esegue l‟analisi per mezzo della scomposizione in
componenti armoniche ideata dal celebre Fourier. Con le reti neurali è possibile fare a
meno di questa tecnica effettuando un addestramento mirato a prevedere (o classificare
se il nostro obiettivo non è la previsione), il comportamento della variabile nel tempo
futuro.
Nel caso della previsione multi-variata anche con serie di input differenti, è
l‟insieme di valori delle sequenze storiche di tutte le variabili di input che concorre
alla determinazione dell‟output di ognuna delle variabili su cui si vuole fare la
previsione. Per questo motivo è possibile avere bisogno di un numero enorme di neuroni
di input, rendendo difficile tutta l‟applicazione.
Si preferisce, in questi casi, utilizzare le reti neurali ricorrenti. Queste, come
abbiamo visto, hanno connessioni anche tra neuroni dello stesso livello, quindi la loro
memoria sarà estesa anche agli input precedenti.
Supponiamo di dover prevedere il comportamento di una singola variabile.
L‟addestramento consisterà nell‟inserire in input alla rete una serie di valori assunti
da x. In output la serie di valori che x assumerà. E così via per più serie, finché il
85
Matteo Tosato - Introduzione alle reti neurali artificiali
target di precisione della rete non viene raggiunto. A questo punto la rete sarà in
grado di prevedere valori successivi che x assumerà.
Dobbiamo anche considerare che la rete non imparerà solamente la relazione che esiste
tra i valori di input e quelli di uscita, ma anche quella esistente tra input
consecutivi. e . Questo è un indice della derivata in quel punto della funzione.
Di seguito lo schema ipotetico di una rete per la previsione uni-variata:
x107
x108
x109
x110
x111
x112
x113
x100
x101
x102
x103
x104
x105
x106R
ete
ne
ura
le
x114
x115
x116
x117
x118
x119
x120
Un davvero banale esempio può essere fatto con un segnale periodico. Naturalmente una
cosa di questo tipo a senso solo per il fine didattico. Ma nella realtà possiamo
applicare questa tecnica a qualsiasi segnale variabile difficilmente prevedibile. I
maggiori tipi di analisi che vengono fatti attualmente, oltre essere complessi da un
punto di vista realizzativo, incappano molto spesso in errori, dato che sistemi di
analisi che si basano su algoritmi sequenziali non hanno la capacità di
generalizzazione di una struttura neurale. Quindi all‟arrivo di dati in ingresso
affetti da un disturbo molto spesso questi sistemi non sono in grado di funzionare
correttamente.
Un esempio di risultato potrebbe essere il seguente:
86
Matteo Tosato - Introduzione alle reti neurali artificiali
Il numero di neuroni in input, in uscita e la struttura del training set sono variabili
che possono essere decise seguendo l‟equazione di convenienza seguente:
( )
Un altro aspetto importante è la normalizzazione. Non è infatti detto che i valori da
analizzare rimangano all‟interno di un range adatto alla nostra rete. Per questo motivo
deve essere fatta, anche in questo caso, una operazione di stretching sui valori.
Analisi di segnale
Tipicamente l‟analisi di una qualsiasi segnale aperiodico viene fatta attraverso la
trasformata di Fourier per suddividere la forma d‟onda in varie componenti. Attraverso
l‟analisi in frequenza è possibile fare delle considerazioni sulle caratteristiche che
ci interessano.
Anche se, la rete neurale non avrà bisogno necessariamente di scomporre il segnale in
più componenti, essa sarà comunque in grado di estrapolare le caratteristiche che
desideriamo dal segnale proprio come lo possiamo fare noi con la nostra testa. Tutto
dipende dall‟addestramento a cui la sottoponiamo preventivamente. Quando noi osserviamo
la forma d‟onda e tiriamo le conclusioni su “che cosa rappresentava” il segnale in quel
momento, facciamo anche noi delle associazioni come le fa la rete neurale. Una rete
neurale per quanto semplice, ricalca quello che può fare il cervello.
La lettura di un testo è un‟utile analogia, quando leggiamo non andiamo a valutare ogni
lettera, ogni sillaba, suono, punteggiatura, sintassi presente etc… ma sappiamo già che
suoni emettere per esprimere ciò che c‟è scritto. Questo perché siamo “abituati” a
farlo, la conoscenza necessaria è già diffusa tra le connessioni neurali.
(connessionismo) Lo stesso discorso vale per i sistemi basati su intelligenza
artificiale, non abbiamo più bisogno di implementare enormi e complessi sistemi di
analisi, che in molti casi sono anche irrealizzabili.
Ciò non obbliga comunque a bypassare Fourier, in certi casi rimane molto utile isolare
le caratteristiche del segnale per poi, in seguito, analizzarle con una rete. Le varie
componenti ricavate della trasformata possono divenire input di una rete neurale feed-
forward o di altra configurazione. Molte volte è sufficiente un percettrone per avere
già una certa possibilità di classificazione.
0
1
2
3
4
5
6
7
0 10 20 30 40 50 60
Futuro Sorico
87
Matteo Tosato - Introduzione alle reti neurali artificiali
Un esempio può essere il seguente, dato il segnale di origine:
Con l‟ausilio della trasformata di Fourier lo si scompone nelle sue componenti,
La FFT ha il compito di amplificare e di isolarne “le caratteristiche”.
Ogni caratteristica viene normalizzata e inserita nello strato di input.
i
h
k
y
.
.
.
.
.
.
.
.
.
.
.
.
ComponentiNeuroni di
Input
FFT
Neuroni
nascosti
Neurone
di outputSegnale
AD
converter
+
freq. divisor
Figura 21: Analisi di segnale tramite rete feed-forward
I due blocchi grigi, che rappresentano il convertitore analogico-digitale e il modulo
per la trasformata di Fourier veloce, possono anche essere realizzati via hardware.
Come anche la rete stessa del resto.
Lo schema illustrato si comporta da analizzatore del segnale. Stabilisce che cosa il
segnale rappresenta in base all‟addestramento cui è stata sottoposta.
88
Matteo Tosato - Introduzione alle reti neurali artificiali
Solitamente si insegna a riconoscere certi pattern che rappresentano fenomeni esterni.
Immaginiamo ad esempio, un dispositivo ricevitore con antenna.
La cosa più complicata da fare non è tanto realizzare il sistema, ma scegliere gli
esempi da sottoporre alla rete.
Reti di reti neurali
Utilizzando un approccio ingegneristico, possiamo pensare ad una rete neurale come un
blocco. Il famoso “black-block”. Con input ed output. Quando il funzionamento di un
blocco è stato puntualizzato, possiamo utilizzarlo dimenticandoci delle sue
caratteristiche interne, per produrre altri blocchi. Questo è quello che viene
solitamente fatto nell‟ingegneria, partendo dal blocco più piccolo e crescendo verso
quello più grande.
Allora nulla ci vieta di estendere questo approccio anche alle reti neurali. Quello che
otteniamo è la dispersione ulteriore del funzionamento. Incrementando le capacità di
generalizzazione del sistema.
Recenti studi hanno mostrato come questo approccio risulta valido anche nello studio di
patologie come la schizofrenia.
Un modello di questo tipo è il seguente:
... ...
...
Block 3
Block 2
Block 1
Dove il blocco 1 è una ulteriore “fuzzificazione” di 3 input originali. Pertanto il
blocco 2 si ritroverà a lavorare con una classe e altri input.
Nessuna complicazione dal punto di vista computazionale, dato che il blocco 2, utilizza
la classe in uscita dal blocco 1 al pari degli altri input.
89
Matteo Tosato - Introduzione alle reti neurali artificiali
Le cose possono divenire anche molto complicate e si possono mischiare anche più tipi
di configurazioni. Reti che utilizzano al loro interno reti auto-associative come
memorie, oppure reti auto-organizzanti che hanno input generati da altre reti, e via
dicendo...
... ...
...
Fuzzy - system
In base ai tipi di dati di cui si dispone si decide quali raggruppare in gruppi e
processare separatamente, oppure quali di questi vanno prima trattati da una ulteriore
rete, oppure quali devono essere normalizzati.
Non ci sono regole per decidere quale configurazione sia la migliore per ogni
problematica, molte decisioni vanno prese in base all‟esperienza che si accumula
durante i test.
Conclusione e ringraziamenti
Naturalmente le possibilità delle reti non si fermano a quello che abbiamo visto,
esistono molte altre varianti che meritano di essere prese in considerazione.
In questo testo ho cercato solo di fare una adeguata introduzione per i tipi e per le
applicazioni più diffuse oggi.
Di seguito, nei riferimenti, elenco le risorse utilizzate per lo studio e dove è
possibile trovare altre informazioni e tutti gli approfondimenti necessari.
Le reti neurali sono oggetti utili ed interessanti anche dal punto di vista delle
neuroscienze e sono il punto di partenza per la realizzazione di una intelligenza non
biologica. (vedi il progetto “Blue Brain”).
Ci sono anche importanti implicazioni nella filosofia. Sul tema della coscienza e della
fenomenologia.
Ringraziamenti particolari:
90
Matteo Tosato - Introduzione alle reti neurali artificiali
- Flavio Bernardotti, fonte di informazioni e risorse.
- Andres Reyes, introduzione storica.
Appendice A – basi matematiche
Quando si lavora con le reti neurali è utile usare alcuni costrutti matematici. Questi
sono quelli di norma utilizzati nella risoluzione di molti problemi in ambiti
scientifici. Nelle ANN è infatti possibile incappare in questioni, che dal punto di
vista matematico, possono divenire anche abbastanza complesse.
In configurazioni semplici, dove i neuroni avranno al massimo funzioni di trasferimento
binarie non avremo molta necessità di ricorrere alla matematica. Diversa è la questione
quando utilizziamo algoritmi più complessi con back-propagation o una delle sue
varianti. Inoltre, alcune operazioni sui pesi possono divenire molto più veloci quando
utilizziamo alcune delle regole offerte dall‟algebra lineare per quanto riguarda le
operazioni sulle matrici. Abbiamo visto infatti che il miglior modo di lavorare con le
reti, è di definirle come matrici, ciò rende meno dispendioso il processo dal punto di
vista dell‟impiego di tempo CPU e memoria, rispetto all‟approccio ad oggetti.
Partendo proprio da questo ultimo punto, vediamo alcuni concetti di algebra lineare che
possono risultare molto utili nel lavoro con le reti.
- Cenni sui vettori
Ogni parte della rete può in effetti essere intesa come un vettore di elementi, negli
esempi riportati nella prima parte, ho sempre preferito utilizzare proprio degli array
C per contenere i valori potenziali dei neuroni, il valore dei pesi, etc... tutti
questi oggetti possono essere considerati come vettori e matrici. Possiamo descrivere
un vettore nel seguente modo:
(
)
Una prima cosa che si può vedere riguardo al semplice vettore è la trasposizione. Il
seguente è il vettore trasposto di x:
( )
Gli elementi del vettore sono chiamati “componenti”. Un vettore può essere
rappresentato graficamente come una freccia in uno spazio di n dimensioni, dove n è la
dimensione del vettore.
Due vettori possono essere moltiplicati, moltiplicando fra loro ogni elemento. Molto
semplicemente nel modo seguente:
(
)
(
)
(
)
91
Matteo Tosato - Introduzione alle reti neurali artificiali
E‟ chiaro che graficamente questa operazione corrisponde ad un allungamento del
vettore, in questo caso doppio. Oppure in caso fosse stato un vettore composto da
componenti il cui valore era 0,5 sarebbe stata una riduzione.
Stessa cosa vale per l‟addizione, con la differenza che dal punto di vista geometrico
questa corrisponde alla diagonale del parallelogramma con due lati individuati dai due
vettori.
- Prodotto interno
Un caso più interessante è invece il prodotto interno. Questo corrisponde esattamente
al calcolo del potenziale del neurone.
(
)
(
)
∑( )
- Norma
La norma di un vettore corrisponde alla sua lunghezza.
‖ ‖ √ √
La normalizzazione di un vettore consiste nel dividere il vettore per la propria norma.
Cosa significa? A volte gli input di una rete neurale possono arrivare da dispositivi,
che per loro natura, possono essere affetti da oscillazioni. Pensate ad esempio a dei
sensori esterni che hanno una qualche funzione di trasduzione, questi possono fornire
input scorretti come intensità che potrebbero portare la rete neurale a errori. Per
questo motivo gli input vengono in certi casi normalizzati. Questo processo avviene
dividendo ogni componente per la norma vettoriale:
√∑
Il seguente grafico mostra il processo di normalizzazione su due input, i quali vengono
normalizzati per rientrare tra i valori 0 e 1:
92
Matteo Tosato - Introduzione alle reti neurali artificiali
2.0
2.00.5
0.5
1.0 1.5
1.5
1.0
x1
x2
x1
x2
Nel campo delle reti, la norma viene utilizzata per calcolare la distanza di due
vettori. Ad esempio la distanza del vettore degli input al vettore dei pesi, oppure il
vettore di output rispetto quello della risposta desiderata. Per questo si ricorre alla
norma della differenza:
‖ ‖ √( ) ( ) ( )
Questo calcolo nel caso di vettori binari, ovvero con componenti * +, da in output la
distanza di Hamming tra i due vettori. La distanza di Hamming può essere utile in
alcuni casi. Essa è definita come il numero di componenti corrispondenti differenti tra
due vettori. Invece per un solo vettore binario tale distanza può essere intesa come la
distanza tra questo e il vettore nullo, un vettore ove tutti i componenti sono posti a
0.
- Disuguaglianza di Cauchy-Schwartz
Questa dice che il valore assoluto del prodotto interno di due vettori X,W è minore o
uguale al prodotto tra le norme dei due vettori.
| | || || || ||
Quindi esisterà un angolo tra i due vettori:
|| || || ||
Quindi il prodotto interno dei due vettori è anche definibile con:
|| || || ||
Questo ci indica che il prodotto interno dei due vettori sarà proporzionale al coseno
dell‟angolo che viene a formarsi. Siccome:
93
Matteo Tosato - Introduzione alle reti neurali artificiali
Il prodotto interno, quindi la risposta del neurone, sarà tanto maggiore quanto minore
è la distanza tra il vettore di input e il vettore dei pesi.
- Cenni sulle matrici
Una matrice è definibile come una raccolta di M righe per N colonne di numeri reali.
[
]
Solitamente i suoi componenti si indicano con in modo da identificare un componente
nella matrice utilizzando due indici, rispettivamente per la riga e la colonna.
L‟addizione tra due matrici è possibile solo se le due hanno numero di righe e colonne
uguali.
Invece è possibile moltiplicare una matrice per un vettore. Ad esempio data la matrice
W seguente:
[
]
E un vettore X:
[
]
Che deve avere stesso numero di componenti del numero di colonne della matrice W, è
possibile definire un nuovo vettore Wx moltiplicando ogni componente della matrice con
il componente del vettore corrispondente di colonna. Questo per ogni riga:
[
] [
] [( ) ( ) ( )( ) ( ) ( )
] 0
1
Se consideriamo che la matrice W può corrispondere benissimo a due vettori di pesi
sinaptici, quindi per due neuroni, e il vettore X al vettore di input, questo calcolo
consente di calcolare in un solo passo tutti i nuovi valori per i neuroni di output.
Infatti abbiamo due prodotti interni nel vettore finale Wx.
La moltiplicazione tra due matrici A*B è possibile solo se la matrice A ha numero di
colonne uguale alle righe della matrice B, in questo caso il prodotto finale ij
corrisponde al prodotto del vettore della riga i della prima matrice con il vettore
della colonna j della seconda matrice. Ad esempio:
0
1 [
]
[,( ) ( ) ( )- ,( ) ( ) ( )-
,( ) ( ) ( )- ,( ) ( ) ( )-] 0
1
Naturalmente la moltiplicazione tra matrici non è commutativa, ovvero ,
perché il risultato dei due prodotti sarebbe molto diverso.
94
Matteo Tosato - Introduzione alle reti neurali artificiali
La matrice unitaria I è una matrice quadrata in cui ciascun componente ij è dato dal
delta di “Kronecker” ( )
( ) {
Per cui:
[
]
Il prodotto tra una matrice A e la matrice I corrispondente restituisce sempre la
matrice originaria:
Come per il vettore trasposto anche per la matrice è possibile fare lo stesso
ragionamento.
[
] e 0
1
E‟ facilmente intuibile che è possibile calcolare anche i prodotti I risultati
però sono diversi.
- Metodo di eliminazione di Gauss (rango della matrice)
Il metodo di eliminazione di Gauss permette di ottenere una matrice equivalente che
possiede un numero crescente di zero iniziali sulle righe.
[
] [
]
Dove il simbolo * rappresenta qualsiasi valore risultato da altre operazioni. Vi sono
solo tre operazioni che è possibile fare sulla matrice:
1. La moltiplicazione di una riga per uno scalare diverso da 0, ad esempio:
2. Scambio di righe:
3. Addizione del multiplo di una riga a un‟altra riga:
Operando in serie in questo modo e ripetendo da capo il procedimento si arriva ad
ottenere una matrice che non può essere più ridotta. Arrivati a questo punto il numero
delle righe che non hanno componenti uguali a zero viene detto rango della matrice.
Questo procedimento possiede un grosso numero di applicazioni, tra cui la soluzione di
un sistema di equazioni lineari omogenee a N incognite disposte in forma matriciale.
Un esempio:
95
Matteo Tosato - Introduzione alle reti neurali artificiali
[
] [
] [
] [
] [
]
- Derivata
Solitamente quando si lavora con le reti neurali si può arrivare ad utilizzare concetti
di analisi matematica abbastanza ricorrentemente. La derivata in primis è molto
utilizzata, dato che è necessaria per l‟algoritmo di apprendimento supervisionato back-
propagation “EBP”. Qui vediamo di riassumere brevemente che cosa è la derivata e come
si calcola.
Dal punto di vista matematico la derivata si definisce come limite del rapporto
incrementale fra la variazione dei valori della funzione e quella della variabile
indipendente, al tendere a zero di quest‟ultima.
Ammettiamo di voler descrivere il movimento di un soggetto che si muove lungo una guida
rettilinea; diciamo la posizione (rispetto ad un punto fissato) dell‟auto al tempo t.
Il tachimetro dell‟auto segna, al tempo , una certa velocità, che chiamiamo ( ). La
velocità media nell‟intervallo [ - è data dal rapporto fra lo spazio percorso ed il
tempo impiegato a percorrerlo, quindi:
, - ( ) ( )
Quindi la velocità al tempo 0 segnata sul tachimetro è il limite della velocità media
quando l‟ampiezza dell‟intervallo tende a zero:
( )
( ) ( )
Graficamente la derivata è una secante di una qualsiasi funzione,
Il tutto si può sintetizzare come segue: abbiamo una funzione ( ) , ed un punto
fissato ( ). Consideriamo una piccola variazione e definiamo il rapporto
incrementale della funzione nel punto con incremento h come:
96
Matteo Tosato - Introduzione alle reti neurali artificiali
( ) ( )
( ) ( )
Il rapporto incrementale rappresenta una velocità media, il coefficiente angolare di
una retta secante, un tasso medio di crescita, e così via.
Ci interessa studiare il limite per h che tende a zero:
( )
( ) ( )
Se il limite esiste è derivabile in .
La derivata consente di trovare nella funzione eventuali minimi,
Noi nell‟algoritmo Error back-propagation avremo bisogno di calcolarci la derivata
della funzione di trasferimento che sceglieremo di utilizzare, dato che la impiegheremo
per calcolare l‟errore del singolo nodo dello strato di output e nascosto.
E‟ importante anche il concetto di gradiente. Il gradiente di una funzione f(x)
vettoriale (ovvero che produce un numero in uscita) può essere inteso come un vettore
composto dalle derivate dei suoi componenti. Lo abbiamo incontrato nell‟algoritmo EBP.
- Integrale
Potremmo anche incappare nel calcolo integrale. Ma a parte il suo utilizzo nelle reti
neurali, la definizione di integrale è bene saperla, dato il suo impiego nella maggior
parte dei campi scientifici. Si pensi solo all‟analisi di Fourier.
Il concetto di integrale è piuttosto semplice in se.
Si consideri la relazione tra velocità e tempo. Se poi il moto è anche uniformemente
accelerato avremo un grafico come il seguente:
Trovare lo spazio percorso non è complicato dato che , ci basta trovare l‟area
del trapezio che si forma. Ma come possiamo fare in caso avessimo un moto non uniforme?
0
1
2
3
4
5
0 1 2 3
Ve
loci
tà
Tempo
Velocità-tempo
97
Matteo Tosato - Introduzione alle reti neurali artificiali
In questo caso calcolare l‟area che c‟è tra la funzione l‟asse x non può essere fatta
con una semplice moltiplicazione, si può pensare allora di costruire nel grafico una
serie di rettangoli aventi per base un segmento ricavato sull‟asse delle x e come
valore massimo un valore del tratto di funzione y rispettivo. In questo modo tentiamo
di avvicinarci all‟area reale facendo la somma di tutte le aree dei rettangoli.
Graficamente;
Naturalmente non riusciamo a riprodurre esattamente l‟area. Possiamo solo avere una
delle due situazioni:
∑ ( ) ( )
oppure,
∑ ( ) ( )
Dove ( ) definisce un segmento sull‟asse delle x, ovvero la base del rettangolo;
f() identifica il punto minore della funzione nell‟intervallo; F() identifica invece il
maggiore.
Il trucco per trovare l‟area giusta sta nel scegliere dei rettangoli dalla base molto
piccola. Se facciamo tendere il numero di rettangoli ad infinito otteniamo l‟area
corretta. Quindi:
∑ ( ) ( )
∑ ( ) ( )
0
1
2
3
4
0 1 2 3 4V
elo
cità
Tempo
Velocità-tempo
0
2
4
6
8
10
0 1 2 3 4 5 6 7 8 9 10
Ve
loci
tà
Tempo
Velocità-tempo
98
Matteo Tosato - Introduzione alle reti neurali artificiali
La notazione degli integrali definisce con la „s‟ medioevale la sommatoria e con il
termine dx, l‟infinitesimo, ovvero il segmento che costituisce la base dei rettangoli.
∑ ( ) ( )
∫ ( )
∑ ( ) ( )
Detto questo è facile definire la funzione integrale e quindi l‟integrale definito.
L‟integrale è detto definito quando sarà considerato entro un certo range, di
conseguenza se rendiamo variabile uno degli estremi abbiamo un funzione. Al variare
dell‟estremo x, il valore integrale si avvicina o si allontana dall‟ipotetica area
vista prima.
( ) ∫ ( )
Questa è una funzione crescente, dato che x è un punto sull‟asse compreso fra a e b.
Il teorema fondamentale del calcolo integrale dice che la derivata della funzione è
uguale alla funzione di partenza. Indicando la derivata rispetto ad x con D avremo:
( ) ,∫ ( ) - ( )
Appendice B – Riferimenti
- Analysis and Applications of Artificial Neural Networks 1Ed, Prentice Hall
- Process Neural Networks, Xingui He e Shaohua Xu, advanced topics in science and
technologiy in cina
- Veelenturf L.P.J. Analysis and Applications of Artificial Neural Networks (1Ed,
Prentice Hall, 1995)
- Artificial Intelligence Structures and Strategies for Complex Problem Solving
Third Edition, George F. Luger, William A. Stubblefield
- A Direct Adaptive Method for Faster Backpropagation Learning: The RPROP Algorithm
, Martin Riedmiller and Heinrich Braun, Institut fur Logik, Komplexitat und
Deduktionssyteme.
- Novel Algorithms and Techniques in Telecommunications, Automation and Industrial
Electronics
- Novel Algorithms and Techniques in Telecommunications and Networking
- Pratical Neural Network Recipes in C++
- Reti neurali e fuzzy logic su personal computer – Luca Marchese
- An Improved Backpropagation Method with Adaptive Learning Rate V.P. Plagianakos,
D.G. Sotiropoulos, and M.N. Vrahatis University of Patras, Department of
Mathematics, Division of Computational Mathematics & Informatics
- Neural Networks, (Neural Networks & Artificial Intelligence), Università Italiana
Cracking – Italian University of Cracking
- http://it.wikipedia.org/wiki/Rete_neurale
99
Matteo Tosato - Introduzione alle reti neurali artificiali
- http://www.willamette.edu/~gorr/classes/cs449/intro.html
- http://www.semeion.it/
- http://www.synaptics.org/synaptics/research.htm
- http://www.ra.cs.uni-tuebingen.de/SNNS/ (Software)
- http://www.heatonresearch.com/encog (Framework, Java e C#)
- http://www.bernardotti.it/portal/ (Forum CV e AI)
- AI framework in C#, Aneuro32
Appendice C – Aneuro32
Di seguito presento alcuni esempi di semplici programmi in C# che utilizzano il
framework „aneuro32‟ (https://github.com/Matteo87/Aneuro32) che ho sviluppato a fronte
di integrare varie configurazioni di reti neurali artificiali e altri paradigmi del
natural computing in un unico SDK.
Addestramento M-Adeline tramite algoritmo Windrow-Hoff per operatore AND:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using aneuro32.Nn.Structure.FeedForward; using aneuro32.Functions; using aneuro32.Learning.Supervised.Propagation; using aneuro32.Misc; namespace M_Adeline_testApp { class Program { static void Main(string[] args) { // input set double[][] input = { new double[] {0,0}, new double[] {0,1}, new double[] {1,0}, new double[] {1,1} }; // target set double[][] target = { new double[] {0}, new double[] {0}, new double[] {0}, new double[] {1} }; // Creating neural network: MAdeline MyNet = new MAdeline(2); // Add bias: MyNet.AddBiasWeight(); // Connects units: MyNet.Build(); // Creating training object: WindrowHoff trainingAlg = new WindrowHoff( ref MyNet, // Network input, // input set target, // target set activation_mode.sigmoid, // Transfer function 0.001, // Target MSE
100
Matteo Tosato - Introduzione alle reti neurali artificiali
0.5 // Learning rate ); bool retVal; // Training loop: do { retVal = trainingAlg.iteration(); if (retVal != true) { Console.WriteLine("Training error: " + trainingAlg.NetworkError); // Check for error break; } } while (!trainingAlg.isTrained); // Testing network: int j = 0; Console.WriteLine("Net test:"); foreach (double[] _in in input) { MyNet.SetInput(input[j]); MyNet.Exec(); Console.WriteLine("\nPattern n° "+j); Console.WriteLine("Input: " + input[j][0] + " " + input[j][1]); Console.WriteLine("Output: " + MyNet.output.OutputValue.ToString("0.00") + " Ideal: " + target[j][0]); j++; } Console.WriteLine("\nNet final error: "+trainingAlg.CurrentMeanSquareError.ToString("0.######")); Console.WriteLine("Total epoch: "+trainingAlg.CurrentEpoch); List<double> weights = MyNet.SaveWeights(); Console.WriteLine("\nNet final weights: "); foreach (double d in weights) { Console.WriteLine(d.ToString("0.######")); } Console.ReadLine(); } } }
Ouput:
Net test:
Pattern n° 0
Input: 0 0
Output: 0,00 Ideal: 0
Pattern n° 1
Input: 0 1
Output: 0,02 Ideal: 0
Pattern n° 2
Input: 1 0
Output: 0,02 Ideal: 0
Pattern n° 3
Input: 1 1
Output: 0,97 Ideal: 1
Net final error: 0,001
Total epoch: 8217
Net final weights:
6,305019
6,304662
-9,533159
101
Matteo Tosato - Introduzione alle reti neurali artificiali
Addestramento MLP tramite algoritmo Error back-propagation con learning rate adattativo
per operatore XOR:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using aneuro32; using aneuro32.Nn.Structure.FeedForward; using aneuro32.Learning.Supervised.Propagation; namespace DebugProp0 { class Program { static void Main() { double[][] xorInput = { new double[] {0.0,0.0}, new double[] {0.0,1.0}, new double[] {1.0,0.0}, new double[] {1.0,1.0} }; double[][] xorOutput = { new double[] {0.0}, new double[] {1.0}, new double[] {1.0}, new double[] {0.0} }; IFFNeuralNetwork MyNet; PropagationBase MyTrainingAlg; TextWriter outStrm = Console.Out; TextReader inStrm = Console.In; // Build ANN MyNet = new ffnetwork(); // Adding Layers MyNet.AddNewLayer(2); MyNet.AddNewLayer(4); MyNet.AddNewLayer(1); // Adding bias neurons MyNet.AddBiasWeight(); // Connects all MyNet.Build(); // Training instance MyTrainingAlg = new ShiffmanVariantBackpropagation( ref MyNet, xorInput, xorOutput ); // Training process ... do { if (MyTrainingAlg.iteration() != true) break; } while (MyTrainingAlg.isTrained != true); // Exit training, check result and run an example outStrm.WriteLine("Testing... "); outStrm.WriteLine(); double[] res; int j = 0; foreach (double[] pattern in xorInput) { outStrm.WriteLine(); outStrm.WriteLine("Pattern 1°: " + pattern[0] + " " + pattern[1]); MyNet.SetInput(pattern); MyNet.Exec(); res = MyNet.GetOutput(); outStrm.WriteLine("NetOutput: " + res[0] + " Ideal output: " + xorOutput[j++][0]); } outStrm.WriteLine("Total Epochs: " + MyTrainingAlg.CurrentEpoch + ", Final error: " + MyTrainingAlg.GetMeanSquareError()); inStrm.ReadLine(); // Wait for user input } } }
102
Matteo Tosato - Introduzione alle reti neurali artificiali
Output:
Testing...
Pattern 1°: 0 0
NetOutput: 0,0215273578662015 Ideal output: 0
Pattern 1°: 0 1
NetOutput: 0,977569795574149 Ideal output: 1
Pattern 1°: 1 0
NetOutput: 0,977554230396672 Ideal output: 1
Pattern 1°: 1 1
NetOutput: 0,0229820784372725 Ideal output: 0
Total Epochs: 5003, Final error: 0,000999927837006829