Gli algoritmi genetici Un altro importante metodo di calcolo, e di simulazione, molto recente, ma molto potente e versatile è rappresentato da quella famiglia di tecniche di ottimizzazione che vanno sotto il nome di algoritmi genetici, il cui inventore è considerato John Holland, che nel 1975 pubblicò il volume Adaptation in Natural and Artificial Sistems, dove per la prima volta vengono descritti. La peculiarità di queste tecniche deriva dal fatto che si ispirano all’evoluzione naturale e sono quindi fondate sui principi darwinisti della selezione e dell’adattamento, nonché, naturalmente, su meccanismi di riproduzione e di mutazione. Nel corso dei vari paragrafi prenderemo in considerazioni gli svariati modi in cui è possibile implementare ed utilizzare gli algoritmi genetici, oltre a mettere in risalto come l’integrazione di questi con le reti neurali del connessionismo abbia dato luogo a notevoli ed interessanti risvolti nell’ambito di svariate ricerche, non ultima quella che più ci interessa, la psicologia, permettendo un nuovo approccio ai fenomeni psicologici teso a sottolineare soprattutto l’importante ruolo svolto dall’interazione fra l’individuo ed il suo ambiente fisico durante il processo di formazione delle capacità sensomotorie e cognitive. In particolare, questo genere di ricerche, a cui ci rivolgeremo anche noi per la parte sperimentale, si svolgono nel già accennato ambito della Vita artificiale (definito anche con il nome di Psicologia sintetica o Neuroetologia computazionale), che, quindi, verrà diffusamente trattato. Evoluzione naturale e artificiale I sistemi biologici presentano molte caratteristiche che li rendono estremamente adatti all’ambiente in cui vivono, infatti, capacità di adattamento e robustezza nella conservazione delle caratteristiche positive sono i tratti salienti di questi ultimi, ma, come sappiamo, essi non sono il frutto di un progetto determinato a priori, ma il risultato di un processo evolutivo della durata di millenni e basato sulla riproduzione selettiva degli individui migliori. Nel fondamentale libro L’origine delle specie [1859] Darwin, nel cercare di spiegare come si siano “potuti sviluppare e perfezionare tutti i finissimi adattamenti di una parte dell’organismo rispetto ad un’altra e alle condizioni di vita, e di un organismo rispetto ad una altro organismo”, introduce il concetto di lotta per la vita, grazie alla quale “qualsiasi variazione, anche se lieve, qualunque ne sia l’origine, purché risulti in qualsiasi grado utile ad un individuo appartenente a qualsiasi specie, nei suoi rapporti infinitamente complessi con gli altri viventi e col mondo esterno, contribuirà alla conservazione di quell’individuo e, in genere, sarà ereditata dai suoi discendenti. Quindi, anche i discendenti avranno migliori possibilità di sopravvivere…” ed è proprio alla conservazione delle variazioni favorevoli e all’eliminazione di quelle nocive che Darwin da il nome di selezione naturale. Il principio della selezione naturale, quindi, è quello che ha determinato negli organismi biologici l’adattamento a nuovi ambienti e la differenziazione fra le varie specie, ma su quali siano gli effettivi meccanismi dell’evoluzione il dibattito è ancora aperto, anche se vi è un generale accordo su alcuni principi di base quali, ad esempio: • L’evoluzione naturale agisce sul materiale genetico (genotipo) di un individuo e non sulle sue caratteristiche fisiche, il fenotipo, quindi ogni variazione che rende un individuo più efficiente di un altro emerge solo dal patrimonio genetico, ed in questo non influirà affatto ciò che i genitori avranno eventualmente appreso nella loro vita. • Il processo di selezione naturale favorisce la riproduzione di quegli individui che hanno delle caratteristiche che migliorano l’adattabilità all’ambiente, eliminando attraverso una minore potenzialità riproduttiva, quelle che, al contrario, risultano penalizzanti. Quindi, dal punto di vista genetico possiamo dire che la selezione naturale favorisce, attraverso la riproduzione degli individui migliori, quelle particolari combinazioni genetiche che danno vita ad un organismo più efficiente. Ciò che viene selezionato, quindi, è principalmente il genotipo di un individuo e non il fenotipo. In questo senso il fenotipo è solo il vettore di una configurazione genetica grazie al quale è possibile la perpetrazione delle migliori tra queste ultime. • Il nucleo centrale del processo evolutivo è costituito dai meccanismi biologici della riproduzione, infatti, la variabilità generazionale di una specie (in altre parole, le costanti e determinanti differenze che caratterizzano tutti gli individui di una specie fra di loro lungo le varie generazioni) è determinata dalla ricombinazione genetica che avviene nel momento della riproduzione e dalle piccole mutazioni casuali che possono intervenire a carico del codice genetico. Saranno proprio questi meccanismi a stabilire le differenze e le uguaglianze fra un individuo ed i suoi genitori. • L’evoluzione naturale opera su intere popolazioni di individui attraverso processi ciclici e generazionali determinati esclusivamente dalle contingenze ambientali e dalle interazioni fra i vari organismi. A partire da queste considerazioni passiamo ad esaminare cosa c’è in comune fra l’evoluzione dei sistemi biologici e gli algoritmi genetici. E’ stato detto che questi ultimi si ispirano all’evoluzione naturale ed in effetti gli elementi fondamentali degli algoritmi genetici sono riconducibili ai principi di base che sono stati elencati riguardo all’evoluzione naturale: gli algoritmi genetici operano su popolazioni di cromosomi artificiali che vengono fatti riprodurre selettivamente sulla base delle prestazioni dei loro fenotipi rispetto ad un problema da risolvere, quindi, anche per l’evoluzione artificiale valgono i principi della riproduzione selettiva degli individui migliori, della ricombinazione genetica, che i biologi chiamano crossover, e delle piccole mutazioni casuali dei cromosomi. Naturalmente i cromosomi artificiali degli algoritmi genetici sono delle semplificazioni di ciò che è realmente il genoma di un organismo biologico, ma la logica che sta alla base li comprende entrambi. Tanto in natura quanto in ambiente artificiale il codice genetico è un tipo di codifica che permette di contenere e trasmettere in maniera semplice e robusta una grandissima quantità di informazioni. Le lunghe sequenze nucleotidiche che costituiscono la molecola di acido deossiribonucleico, comunemente detto DNA, costituiscono l’intera e sola informazione che permette ad una singola cellula di generare nel tempo quel complesso di strutture, a volte di notevole complessità, che abbiamo chiamato fenotipo. La funzione dei cromosomi artificiali è esattamente la stessa, infatti essi contengono l’informazione per generare un fenotipo che, nel caso degli algoritmi genetici è una proposta di soluzione ad un problema, ma ,quando si applicano alle reti neurali, divengono i registi di complesse operazioni matematiche che portano a risultati sorprendenti. In ultima analisi, un cromosoma è semplicemente una sequenza di simboli, ciò che è importante è il tipo di codificazione, che dipende in larga parte dal problema che dobbiamo risolvere e quindi dal genere di risposte che ci aspettiamo di ottenere. Un tipo di codificazione molto frequente è il codice binario ed in questo caso il cromosoma di un individuo risulta una stringa di lunghezza finita composta di zero e di uno, ma i simboli potrebbero essere di qualsiasi genere. Negli algoritmi genetici, inoltre, al di là del tipo di codifica scelto per il genotipo, svolge un ruolo di fondamentale importanza la cosiddetta funzione di fitness, o funzione di valutazione, che serve per giudicare le prestazioni di ciascun fenotipo rispetto al problema da risolvere e che nel caso degli algoritmi genetici prende il posto dell’ambiente esterno, che sarebbe il suo corrispettivo biologico, infatti, così come in natura l’efficienza di un individuo si misura sulla base delle sue capacità di adattamento all’ambiente, i cromosomi artificiali vengono selezionati in base alla loro capacità di sviluppare un fenotipo che sia il più adatto a fornire una risposta adeguata al problema. Quindi, per affrontare un problema attraverso gli algoritmi genetici bisogna innanzitutto stabilire il tipo di rappresentazione genetica e la funzione di fitness e, successivamente, si passa a creare la popolazione vera e propria, che consiste in un certo numero di stringhe genetiche scelte a caso. In seguito ciascuna stringa di questa generazione iniziale verrà a turno decodificata e valutata in base alla funzione di fitness: naturalmente, data la scelta casuale delle stringhe genetiche, i rispettivi fenotipi saranno tutti diversi fra loro e di conseguenza ciascuna stringa avrà un valore di fitness differente. A questo punto entra in gioco la selezione, che premia con la riproduzione solo le stringhe che hanno sviluppato i fenotipi migliori rispetto alla media di tutte le fitness della popolazione, quindi l’operatore della riproduzione selettiva svolge un ruolo analogo alla legge di sopravvivenza del più forte in natura. I modi per realizzare la riproduzione selettiva sono diversi, ma generalmente si fa ricorso ad un particolare metodo detto della ruota della fortuna truccata(fig.1). Esso consiste nell’assegnare ad ogni individuo della generazione una casella su questa ipotetica ruota della fortuna, quest’ultima avrà, quindi, tante caselle quanti sono gli individui della generazione, ma la dimensione di ciascuna casella sarà proporzionale ai valori di fitness ottenuti dai rispettivi individui. La riproduzione selettiva consiste nel girare la ruota tante volte quanti sono gli individui della popolazione e nel creare ogni volta una copia della stringa genetica dell’individuo corrispondente alla casella prescelta, in questo modo, tanto più grande sarà il valore di fitness, e quindi l’ampiezza della casella, tanto maggiore sarà la probabilità che questa venga sorteggiata. Le nuove stringhe così create vengono poi accoppiate fra di loro ed elaborate dall’operatore predisposto alla ricombinazione genetica: il crossover. Per ciascuna delle coppie così create viene scelto a caso un punto di incrocio attorno al quale avviene lo scambio del materiale genetico (fig.2). Al termine della ricombinazione ogni nuovo individuo così ottenuto subisce un processo di mutazione casuale con cui vengono scelti casualmente alcuni componenti del genoma che vengono sostituiti da altri. Nel caso di un genoma codificato in sistema binario viene scelto casualmente un componente (ma possono anche essere di più), un 1 ad esempio, e viene sostituito con uno 0. Al termine di questo laborioso processo riproduttivo si otterranno un certo numero di stringhe genetiche, direttamente discendenti dalla generazione precedente, della quale avranno conservato pregi e difetti (più spesso difetti), ma variamente ricombinati fra di loro, dando luogo ad una nuova generazione che subirà dal principio il processo che a cui erano stati sottoposti i loro genitori: quindi, codifica del materiale genetico, valutazione della fitness, riproduzione e così via. Questo ciclo generazionale viene ripetuto per un certo numero di volte, finché uno degli individui della generazione più recente rappresenterà una soluzione soddisfacente al problema che ci eravamo posti di risolvere. Fitness=20 Fitness=10 Fitness=2 Fig.1 Esempio di un operatore di riproduzione selettiva realizzato attraverso una ruota della fortuna truccata. Ogni casella della ruota corrisponde ad un individuo e l’ampiezza delle caselle è direttamente proporzionale alla fitness dello stesso. Punto di crossover figlio 1 genitore 1 figlio 2 genitore 2 Fig.2 Esemplificazione di una ricombinazione genetica fra due stringhe. Esempi concreti Per dare una dimensione concreta a quanto è stato detto in precedenza, passeremo alla discussione di due tipi differenti di algoritmi genetici: il primo, molto semplice, si applica completamente alla descrizione che abbiamo fatto poc’anzi, mentre il secondo, più complesso e affascinante, se vogliamo, presenterà un altro modo di utilizzare e codificare gli algoritmi genetici. Massimizzare una funzione1 In questo esempio vedremo come opera un programma di algoritmi genetici nell’affrontare un problema consistente nel trovare valori di x che massimizzino la funzione f(x) = x2 , dove x può variare tra 0 e 31. Per prima cosa bisogna scegliere che tipo di codifica utilizzare per creare la rappresentazione genetica: in questo caso si è optato per una codifica binaria con stringhe genetiche della lunghezza di 5 unità ciascuna, in modo tale da codificare i numeri da 0, che corrisponde allo 00000 in sistema binario, al 31 (11111 in sistema binario)2. A questo punto generiamo una piccola popolazione composta di sole quattro stringhe genetiche prese a caso. Ogni stringa viene codificata, ovvero si converte dal sistema binario a quello decimale, e si valuta la sua fitness applicando la funzione potenza al numero decimale ottenuto. Al termine di tale valutazione ogni stringa riceve una probabilità di riproduzione proporzionale alla propria fitness e, a partire da questa, vengono generate un certo numero di copie per ogni stringa. Queste nuove stringhe vengono poi accoppiate e passate all’operatore di ricombinazione genetica che sceglierà un punto di incrocio, in questo caso la probabilità di crossover è Pc = 1, cioè tutte le coppie. Infine ciascun elemento generato dalla ricombinazione genetica viene mutato dall’operatore di mutazione casuale con una probabilità Pm = 0,001 ( i risultati prodotti dalle prime due generazioni sono riportati nella Tav.1). Già dalla prima attivazione possiamo notare due indici evolutivi molto importanti: il valore massimo e quello medio della fitness, infatti la popolazione è costituita da diversi individui che hanno prestazioni diverse e, di conseguenza, diversi valori di fitness, quindi il valore medio è sempre inferiore a quello massimo, che è l’espressione del migliore individuo della popolazione. Questo risultato, da un punto di vista evolutivo, è molto interessante poiché mette in evidenza come le capacità di adattamento esibite da una specie in generale, anche in natura, non sono mai le migliori in assoluto, ma solo quelle che garantiscono un rapporto favorevole fra nascita e morte degli individui e, di conseguenza, la sopravvivenza della specie. Sotto questo aspetto gli algoritmi genetici ci danno anche una conferma di quanto faceva notare Jacques Monod in Il caso e la necessità [1970] quando afferma che uno dei meriti del neo-darwinismo del primo 1 2 Esempio trato da D. Floreano, Manuale sulle reti neurali. La trasformazione da numero binario a numero decimale è dato dalla formula: N −1 x = ∑ i2 p p =0 dove p indica la posizione del numero intero binario a partire dalla ultima cifra, la numero 0, N è il numero di cifre e i è il valore binario dell’intero corrispondetnte, 0 o 1. Per esempio: 10011 = 1 . 24 + 0 . 23 + 0 . 22 + 1 . 21 + 1 . 20 = 16 + 2 + 1 = 19 novecento è stato quello di sottolineare che “…il fattore decisivo della selezione non è costituito dalla lotta per la vita, ma dal tasso differenziale di riproduzione in seno ad una specie”, infatti ciò che è importante per una specie è la presenza di individui capaci di riprodursi e di perpetuarla, mentre l’adattamento ambientale diviene una sorta di conseguenza imposta da finalità riproduttive. Tav.1 Risultati prodotti dall’algoritmo genetico descritto nel paragrafo. Stringa numero Popolaz. Iniziale Decodificazione x Valuta– zione funzione Probabilità riproduz. Numero di figli Numero di figli effettivo 1 2 3 4 01101 11000 01000 10011 13 24 8 19 169 576 64 361 0,14 0,49 0,06 0,31 0,58 1,97 0,22 1,23 1 2 0 1 1170 293 576 1,00 0,25 0,49 4,00 1,00 1,97 4 1 2 Decodificazione x Valutazione funzione 12 25 27 16 144 625 729 256 Somma Media Massimo Coppie con crossover (!) Incrocio Pc=1,0 0110!1 1100!0 11!000 10!011 01100 11001 11011 10000 Mutazioni Nuova Pm=0,00 popoloz. 1 01100 11001 11011 10000 Somma Media Massimo 01100 11001 11011 10000 1754 439 729 Algoritmi genetici e reti neurali Tanto gli algoritmi genetici quanto le reti neurali sono tecnologie che prendono ispirazione dalla biologia, in particolare, ai processi biologici di adattamento, e la loro peculiarità sta nel fatto che si svolgono su scale temporali molto diverse. Infatti, l’evoluzione filogenetica ha luogo attraverso il succedersi di numerose generazioni di individui, mentre il sistema nervoso si sviluppa in un arco di tempo ben più ristretto e compreso fra il concepimento3 e la morte di uno stesso individuo. Solo di recente alcuni ricercatori si sono rivolti all’integrazione di queste due tecnologie “cercando di creare dei sistemi di calcolo che possiedano una potenza adattiva maggiore di quella fornita singolarmente da ciascuno dei due approcci” (Floreano, Manuale sulle reti neurali). Queste ricerche, oltre a suscitare un notevole interesse dal punto di vista ingegneristico, sono anche un utile e potente strumento per l’investigazione computazionale di tematiche inerenti la psicologia, la biologia, l’etologia e le neuroscienze. Le domande che sorgono nel momento in cui ci accingiamo a studiare il sistema nervoso sono numerose e siamo spesso privi degli strumenti utili a fare chiarezza. Sappiamo che il sistema nervoso degli organismi viventi è determinato nella sua struttura, in gran parte, dal codice genetico e sappiamo pure che questa struttura viene poi sviluppata e raffinata dai processi di apprendimento: qual è il vantaggio apportato da questa combinazione? Quali sono i livelli di interazione fra i due processi nello sviluppo del sistema nervoso? Queste sono solo alcune delle domande che ci si propone di investigare attraverso questi nuovi metodi di ricerca, che hanno il vantaggio di metterci difronte a generazioni e generazioni di organismi dei quali conosciamo perfettamente struttura e funzionamento del sistema nervoso e del codice genetico. Tutte condizioni precluse alla biologia classica, così come a tutte le altre scienze che abbiamo citato poc’anzi. Per quanto riguarda gli indirizzi di ricerca che sono attivi in questo campo, nonostante la novità del settore e la poca sistematicità che in questo momento lo caratterizza, ne possiamo comunque individuare alcuni che approssimativamente raggruppano gli orientamenti principali della disciplina e le differenze si ritrovano in ciò che si decide di fare evolvere: in particolare, ricerche improntate sull’evoluzione dei pesi sinaptici, sull’evoluzione dell’architettura della rete neurale oppure sull’evoluzione delle regole di apprendimento. Vediamo ora come funzionano questi nuovi sistemi. Rappresentazione genetica di una rete neurale4 Se vogliamo combinare gli algoritmi genetici alle reti neurali la prima cosa da fare è scegliere una rappresentazione genetica per la rete neurale. Nella maggior parte delle ricerche, per la rappresentazione dei pesi sinaptici si utilizzano codici binari o direttamente numeri reali. Nel primo caso la codifica del codice genetico è un po’ più complessa rispetto al secondo, infatti in quest’ultimo il genoma di ciascun individuo è costituito semplicemente dai valori numerici dei pesi sinaptici che costituiscono la rete, mentre nel primo è necessario un passaggio in più che permetta la codifica dei numeri reali dei pesi sinaptici in sistema binario e poi costituisca il genoma sulla base di tale 3 Utilizziamo il termine “concepimento” e non “nascita” in quanto numerose ricerche nel campo della neurobiologia e della psicobiologia, alla quali noi stessi facciamo riferimento, sottolineano il determinante ruolo svolto da tutti quei processi di sviluppo embrionale, e quindi di carattere prettamente genetico, che sottendono allo sviluppo di un sistema nervoso efficiente. 4 Nell’affrontare questo e gli altri temi a seguire faremo riferimento in modo pressocché esclusivo ad alcune ricerche nell’ambito della vita artificiale, che è il settore di nostro primario interesse, svolte principalmente dai componenti, effettivi o associati, del gruppo di ricerca sulla vita artificiale del C.N.R. (Istituto di psicologia). codifica, quindi, il rapporto fra fenotipo (la rete neurale) e genotipo in questo caso è più complesso. In effetti, già dalla scelta del tipo di rappresentazione per il materiale genetico siamo indirizzati verso l’uno o l’altro degli indirizzi di ricerca che abbiamo citato prima. Se scegliamo di rappresentare il genoma semplicemente attraverso la sequenza dei pesi sinaptici non possiamo pensare di fare evolvere la rete neurale anche nella sua architettura, poiché, per potere estrarre i pesi sinaptici in maniera da poter ricostituire la rete neurale a partire da essi, la rete deve avere una architettura già determinata. E’ come se, trovandoci davanti ad un archivio dai cassetti numerati, volessimo prendere le schede contenute nei cassetti e modificarle, ricostituendo poi l’archivio con le schede modificate. Sulla base delle sole schede non possiamo modificare la struttura di tutto l’archivio, infatti, l’unica libertà che abbiamo è quella di prendere una scheda e modificarla o riporla in un cassetto differente da quello da cui l’avevamo prelevata, ma in questo caso, al limite, aumentiamo solo il disordine dello schedario, ma non la sua struttura classificatoria. Allo stesso modo, le connessioni di una rete neurale sono un po’ come le caselle numerate dello schedario e se noi preleviamo solo i pesi sinaptici connessi ad esse (le schede dello schedario) l’unica cosa che possiamo fare è modificarli o scambiarli fra di loro, ma per ricostituire una rete funzionale a partire da essi dovremo nuovamente associarli alle stesse connessioni da cui li avevamo estratti. Diversamente, attraverso una rappresentazione genetica in codi ce binario abbiamo molta più libertà nel decidere cosa associare alla varie stringhe di numeri che compongono il genoma. Possiamo codificare non solo i pesi sinaptici della rete, ma anche molte cose in più come la posizione dei neuroni attivi all’interno della rete, la lunghezza delle loro connessioni e la loro soglia. In questo modo, nel codice genetico riusciamo a contenere quel quantitativo di informazioni necessarie a fare evolvere oltre che i pesi sinaptici anche l’architettura della stessa rete. Ritornando all’esempio dell’archivio: con una codifica binaria avremmo la possibilità di creare una sorta di genoma dell’archivio stesso nel quale, oltre alle schede contenute nei cassetti, potremmo inserire altre informazioni che ci permetterebbero di generare, a partire da esso, un nuovo schedario sulla base del precedente e diverso da questo non solo per il contenuto delle schede o per la loro disposizione, ma anche per il numero e la disposizione (l’ordine) dei cassetti. Valutazione, riproduzione e mutazioni Quando, nei paragrafi precedenti, parlammo degli elementi funzionali degli algoritmi genetici, oltre al tipo di codifica scelto per il genoma, descrivemmo anche la funzione selettiva svolta dalla valutazione della fitness del fenotipo e dei metodi riproduttivi e di mutazione. Naturalmente, anche per gli algoritmi genetici associati alle reti neurali valgono gli stessi principi. Negli algoritmi genetici, per valutare la fitness dei vari individui che costituiscono la popolazione bisogna innanzitutto generare il fenotipo a partire dal genotipo, essendo proprio questo a fornire la prestazione che verrà valutata e nel nostro caso, come abbiamo già avuto modo di notare, il fenotipo è costituito da una rete neurale alla quale vengono sottoposti alcuni problemi da risolvere, quindi la popolazione sarà costituita da una serie di reti neurali tutte diverse fra di loro sotto qualche aspetto, che può andare dalla semplice differenza dei pesi sinaptici alla differenza nell’architettura. In base ai risultati ottenuti dai vari fenotipi vengono selezionate le stringhe genetiche migliori ed avviene la riproduzione. Anche in questo caso la riproduzione può essere sessuata o asessuata: nel caso della riproduzione sessuata il metodo di accoppiamento fra le varie stringhe genetiche e la riproduzione è lo stesso che abbiamo descritto in precedenza ed il prodotto della riproduzione sarà, naturalmente, un’altra rete neurale differente dai genitori sotto qualche aspetto. Nel caso della riproduzione asessuata invece agisce il solo operatore di mutazione che modifica il genoma in maniera casuale: nel caso della codifica binaria la mutazione avviene nella maniera consueta, mentre, nel caso in cui il genoma sia costituito dalla sequenza dei pesi sinaptici, l’operatore generalmente agisce sommando o sottraendo un piccolo numero preso a caso ad alcuni pesi del genoma, anch’essi scelti a caso. Come si può notare, in questo genere di esperimenti è preponderante la presenza di variabili casuali, quindi, l’evoluzione di questi oggetti è in gran parte governata dal caso e ciò che li rende estremamente interessanti e che, nonostante il caso, o forse proprio grazie ad esso, riescono a migliorare continuamente le loro prestazioni e a raggiungere delle soluzioni veramente interessanti, e spesso inaspettate, per i problemi che devono risolvere. Il principio, teoricamente poco chiaro, ma in pratica molto efficace, che sta alla base di tutto questo era stato già individuato più di un secolo fa: “…qualsiasi modificazione – che comparisse casualmente nel corso delle età, e che fosse tale da favorire in qualsiasi modo gli individui di una specie qualunque, rendendoli meglio adatti alle nuove condizioni – tenderebbe a conservarsi e, quindi, la selezione naturale potrebbe esercitare liberamente il suo lavoro di perfezionamento”5. Le parole sono di Charles Darwin, presenti ne L’origine della specie [1859]. Prima di continuare vorrei spendere qualche parola sulla frase appena riportata. Le parole “casualmente” e “in qualsiasi modo” sono state messe in risalto proprio per rilevare l’estrema parentela che lega i principi dell’evoluzione naturale con quelli dell’evoluzione artificiale. Sulla casualità dei fattori che determinano le variazioni in natura la letteratura è vasta: sostituzione di una singola coppia di nucleotidi ad un’altra, sostituzione di una o più coppie di nucleotidi, nonché svariate alterazioni a carico del testo genetico che provocano l’inversione o la ripetizione di segmenti del DNA, sono solo alcune delle cause, non prevedibili, dell’estrema variabilità presente in natura. Ugualmente, il significato di “in qualsiasi modo”, sta ad intendere che non esiste una direzione determinata verso la quale si debba orientare l’evoluzione, il principio che sta alla base dell’evoluzione non è, quindi, teleonomico, ma ogni novità generata dal caso si confronta l’ambiente in maniera del tutto paritetica alle altre e sarà solo l’ambiente, inteso in senso molto generico, a stabilire quali novità sono favorevoli e quali no. Allo stesso modo, il principio di evoluzione che regola il funzionamento degli algoritmi genetici non solo è casuale, come abbiamo già visto, ma non è neppure orientato, infatti, le variazioni evolutive che si riscontriamo negli organismi artificiali sono sorprendenti tanto quanto quelle naturali, restando pur sempre nei limiti del paragone. Quando vediamo degli organismi artificiali in azione ci rendiamo conto di come, anche in una realtà tanto semplificata, le possibilità di variazione comportamentale siano enormi. Sarebbe addirittura possibile associare delle “personalità” a questi organismi, che nella ricerca di una soluzione ad un problema percorrono tante strade ed alcune di esse, non necessariamente uguali, risultano vincenti sulle altre, dando luogo a generazioni molto varie di organismi che, pur dinanzi allo stesso problema, lo affrontano e lo risolvono in modo del tutto differente. Simulazioni di vita artificiale 5 Le parole in corsivo non sono presenti nel testo originale. Avendo più volte accennato agli organismi artificiali, è giunto il momento di calarci nella realtà di quelle che sono le simulazioni di vita artificiale6 e lo faremo attraverso alcuni esempi.. Nell’introduzione, e poi più volte nel corso della nostra discussione, abbiamo detto che le simulazioni vita artificiale sono uno dei metodi che ci permettono di studiare le complesse interazioni fra le varie componenti di una sistema naturale dal punto di vista ecologico. Vediamo in concreto in cosa consiste una simulazione di questo genere. Gli strumenti utilizzati per compiere tali simulazioni, oltre all’indispensabile computer, sono gli algoritmi genetici applicati alle reti neurali. Come abbiamo già detto, il primo passo che dobbiamo compiere è la scelta della rappresentazione genetica per la rete neurale che dovremo usare: in questo primo esempio sceglieremo di rappresentare la rete attraverso la sequenza dei suoi pesi sinaptici, quindi il genoma di ciascun individuo della popolazione sarà costituito da una serie di numeri reali che rappresentano i pesi sinaptici: ciò che vogliamo fare evolvere sono proprio tali pesi. Adesso dobbiamo assegnare un compito ai nostri individui, in modo da avere un parametro per valutare la fitness di ciascuno di essi: decidiamo di generare un ambiente di ampiezza definita (una griglia bidimensionale formata da 10 x 10 celle) all’interno del quale disporremo casualmente degli elementi di cibo. Il compito degli organismi è quello di trovare gli elementi di cibo sparsi nell’ambiente e mangiarli (Fig. 6). Ogni elemento mangiato farà aumentare la fitness di una unità. Ora che sappiamo il compito da svolgere bisogna mettere il nostro organismo in gradi di poterlo compiere, dobbiamo quindi dotarlo di un sistema sensoriale che gli permetta di “vedere” dove si trovano i pezzetti di cibo e di un sistema motorio, che lo faccia materialmente muovere all’interno dell’ambiente, per andare a mangiarli. Tutto questo lo otteniamo grazie alla rete neurale, che sta alla base del sistema nervoso dell’organismo (in effetti, l’organismo, essendo un sistema computazionale, è costituito dalla sola rete neurale). Nel caso del nostro esempio la rete è composta: - da un sistema sensoriale composto da due neuroni di input che registrano rispettivamente l’angolo (misurato in senso orario a partire dalla direzione verso cui è rivolto l’organismo) e la distanza euclidea dell’elemento di cibo più vicino; - da quattro neuroni nello strato nascosto; - da un sistema motorio costituito da due neuroni di output con valore di attivazione binario: 0,0 “stai fermo”; 0,1 “gira a destra di 90°”; 1,0 “gira a sinistra di 90°”; 1,1 “un passo avanti”. Lo schema della rete neurale è rappresentato nella figura 7. 6 Per una trattazione più esauriente rispetto a questo genere di ricerche rimando a Intervista sulle reti neurali [1991] e Mente [in corso di pubblicazione] entrambi di D. Parisi, all’interno dei quali sono contenuti, tra l’altro, molti e più significativi esempi sulle simulazioni di vita artificiale. Fig. 6 Schema dell’ambiente all’interno del quale “vive” il nostro organismo artificiale (rappresentato dal cerchietto nero). Le celle colorate in nero sono quelle che contengono il cibo. Neuroni motori Interneuroni Neuroni sensoriali Fig.7 Rappresentazione schematica della rete neurale usata nella simulazione. La vita di ogni individuo della popolazione è di 5000 cicli, ovvero, dopo 5000 attivazioni della rete, corrispondenti ad altrettante azioni dell’individuo stesso, esso muore ed è a questo punto che entrano in azione gli operatori di selezione e di mutazione per effettuare la riproduzione. La riproduzione è asessuata e premia solo il 20% degli organismi della popolazione. Questo significa che dei 100 individui della generazione iniziale, sulla base della valutazione della fitness di ciascuno, vengono selezionati solo i primi venti (i venti che hanno mangiato più elementi di cibo degli altri, per intenderci) ed ognuno di essi darà luogo a 5 figli, che saranno materialmente generati dall’operatore di mutazione, attraverso una casuale modificazione dei pesi sinaptici della rete neurale del genitore. In questo modo, se i primi 20 organismi generano 5 figli ciascuno, avremo 20 x 5 = 100, ovvero ricostituiremo la popolazione nello stesso numero di individui della generazione precedente. Questo ciclo di attivazione, selezione e riproduzione viene reiterato per 100 volte, generando, quindi, 100 generazioni successive. Riassumendo, la situazione sperimentale è questa: abbiamo una popolazione di 100 organismi artificiali, ognuno dei quali viene posto in un ambiente di grandezza definita nel quale sono presenti degli elementi di cibo ed il loro compito è quello di mangiare il maggior numero possibile di questi elementi. Ognuno degli organismi ha a disposizione un totale di 5000 passi per portare a termine il compito. Al raggiungimento di questo tetto verranno selezionati i venti individui che avranno mangiato più cibo e si faranno riprodurre. Questo ciclo viene reiterato per 100 volte. Cosa osserviamo a mano a mano che le generazioni si succedono? Qual è il risultato di queste operazioni? Una volta lanciato il programma di simulazione notiamo che gli organismi delle generazioni iniziali hanno la tendenza a muoversi nell’ambiente in maniera del tutto disordinata e solo casualmente si imbattono negli elementi di cibo. Le fitness individuali di questi organismi, nella maggior parte dei casi, sono molto basse ed il valore medio lo è ancora di più, ma, con il susseguirsi delle generazioni, le fitness individuali crescono piuttosto rapidamente, così come la media, fino a raggiungere valori che indicano l’individuazione della quasi totalità degli elementi di cibo presenti nell’ambiente. La conclusione che possiamo trarre da questa semplice simulazione è che i meccanismi di selezione e di mutazione casuale effettivamente agiscono nel senso dell’ottimizzazione delle prestazioni di una popolazione. Infatti, il sistema selettivo che abbiamo utilizzato premia solo i migliori, garantendo ad essi la trasmissione del loro patrimonio genetico alle generazioni successive. Il principio della mutazione, poi, proprio per la sua casualità non è indirizzato al miglioramento: una dimostrazione di ciò è la comparsa, nel corso delle varie generazioni, di individui che peggiorano, anche molto sensibilmente, le prestazioni ottenute dai rispettivi genitori, e questa è un’altra piccola conferma della bontà del principio di selezione naturale, quanto meno inteso in senso negativo. Se le capacità adattive globali di una specie non migliorano in maniera apprezzabile, quanto meno viene garantito il mantenimento delle condizioni attuali attraverso l’eliminazione di quei fattori che risultano svantaggiosi. Un altro modo per sviluppare una simulazione di vita artificiale consiste nel fare evolvere l’intera architettura di una rete neurale e non solo i suoi pesi sinaptici. In questo caso la situazione è parecchio più complessa di quella precedente, a partire dalla scelta della rappresentazione genetica: non possiamo più accontentarci di un genoma costituito dai soli pesi sinaptici, ma dobbiamo rivolgerci ad un tipo di rappresentazione che permetta operazioni del genere che ci proponiamo. Di questo abbiamo già detto, quindi passeremo subito ad una descrizione pratica di come funzioni un sistema del genere. Il nostro scopo è sempre quello di generare degli organismi artificiali che debbano svolgere un determinato compito7. Questa volta i nostri organismi artificiali vivono in un ambiente formato da uno spazio bidimensionale diviso in celle (20 x 20), al centro del quale si trova un’area specifica (target area) che deve essere raggiunta da ciascun individuo della popolazione (formata da 100 individui), mentre in due dei quattro angoli del quadrato sono situati due fari (in inglese landmark). Ogni volta che un organismo raggiunge l’area target la sua fitness viene incrementata di una unità. Ogni organismo è dotato anche questa volta di un sistema sensoriale che gli permette di conoscere l’angolo (sempre rispetto alla direzione verso cui è rivolto) e la distanza dai due landmark presenti nell’ambiente. Inoltre, è dotato di un sistema motorio uguale a quello che abbiamo descritto in precedenza (quindi formato da due neuroni), che gli permette di andare avanti, girare a destra e a sinistra e di stare fermo. Quello che cambia 7 Questo esempio è tratto da una simulazione realmente eseguita da Orazio Miglino, Stefano Nolfi e Domenico Parisi e riportata, insieme alla discussione sul relativo esperimento, nell’articolo Discontinuity in evolution: how different levels of organisation imply pre-adaptation. completamente è il genotipo degli organismi, che questa volta è rappresentato da una stringa di 0 e di 1 (lunga 1600 bit) ed è diviso in blocchi, in modo tale che ogni blocco corrisponde ad un singolo neurone che può essere espresso nel processo di sviluppo. Ciascun blocco contiene le istruzioni che determinano le proprietà di sviluppo del neurone corrispondente (fig.8). Come abbiamo visto ci sono, dunque, vari tipi neuroni, per l’esattezza tre: neuroni sensoriali, interneuroni (che corrispondono alle unità nascoste) e neuroni motori. Il genotipo è costituito da 40 blocchi, ciò significa che il sistema nervoso di ogni organismo può essere costituito da 40 neuroni al massimo. I primi 8 blocchi corrispondono ai neuroni sensoriali, i seguenti 27 blocchi corrispondono agli interneuroni e gli ultimi 5 ai neuroni motori. Ciascuno dei 40 blocchi specifica le seguenti istruzioni: - gene che determina l’espressione del neurone: il gene che decide sulla esecuzione o meno delle altre istruzioni contenute nel blocco. - gene che stabilisce la posizione fisica del neurone: specifica le coordinate cartesiane del neurone all’interno del sistema nervoso. - geni che determinano la struttura dell’assone: stabiliscono la lunghezza e l’angolo dei vari segmenti che costituiscono l’assone del neurone. - geni dei pesi sinaptici: assegnano il peso sinaptico corrispondente all’assone. - geni della soglia: determinano la soglia di attivazione del neurone. - gene del tipo di neurone: stabilisce che tipo di codifica deve svolgere il neurone. Nel caso dei neuroni sensoriali determina se il neurone codificherà l’angolo o la distanza dai due landmarks, mentre, nel caso dei neuroni motori, stabilisce in quale delle due posizioni richieste dal sistema motorio dovrà operare. Genotipo Geni espress. neurone posizione fisica x posizione fisica y angolazione assonale lunghezza assonale soglia neurone . . . peso sinaptico tipo di neurone Fig.8 Rappresentazione del genotipo che contiene le istruzioni per lo sviluppo di una rete neurale. I blocchi inattivi, corrispondenti a neuroni inespressi, sono neri, quelli attivi sono bianchi. Il risultato delle istruzioni dettate dal genotipo è una rete neurale costituita da quei neuroni che sono stati geneticamente attivati e sviluppati e che hanno stabilito delle connessioni fra di loro. Si possono osservare la fase di sviluppo assonale e la rete neurale che ne consegue nelle figure 8 e 9. Questi tipo di codifica genetica permette, quindi, di fare evolvere l’architettura delle reti neurali e non solo i pesi sinaptici e questo ci mette nelle condizioni di esplorare in maniera ancora più approfondita i rapporti intercorrenti fra genotipo, fenotipo e comportamento. L’esperimento in questione, ad esempio, ha messo in luce l’importanza della variabilità genetica e del materiale non funzionale allo sviluppo del fenotipo nell’adattamento, infatti, affinché si presenti una mutazione vantaggiosa è necessario che si creino le condizioni adatte, tanto dal punto di vista genetico quanto da quello fenotipico, e questo è possibile solo quando i meccanismi di riproduzione e di sviluppo di una specie hanno ha disposizione un grande numero di possibilità espressive differenti. Proprio l’analisi dei risultati della simulazione appena descritta ha permesso di notare come le piccole variazioni strutturali di una rete neurale fossero spesso ininfluenti ai fini di un immediato miglioramento delle prestazioni, ma col passare delle generazioni le prestazioni miglioravano solo in quelle reti che avevano sviluppato un’architettura tale da permettere la comparsa delle variazioni vantaggiose. Questo significa che, sebbene le piccole variazioni nell’architettura di una rete neurale non siano utili nel breve periodo, lo diventano nel lungo periodo, ponendo le basi per la comparsa di mutazioni capaci di migliorare le capacità adattive della specie. Fig.9 Sviluppo dei neuroni e ramificazione degli assoni in base alle istruzioni della stringa genetica. Fig.10 Schema della rete neurale derivante dalle connessioni stabilite durante il processo di sviluppo dei neuroni e di ramificazione degli assoni. Lo strato in basso contiene i neuroni sensoriali, mentre quello più in alto contiene i neuroni motori. Conclusione Ora che conosciamo cosa sono gli algoritmi genetici e la vita artificiale in generale, ed i loro rapporti con l’evoluzionismo e la biologia, è bene ricordare che, in merito a queste ricerche, le opinioni della comunità scientifica sono contrastanti. Se, da un lato, c’è chi accoglie con favore la possibilità, offerta dalla vita artificiale, di studiare l’emergere di comportamenti intelligenti a partire da una semplice organizzazione autonoma della materia, da un altro c’è chi non è convinto del carattere altamente riduzionistico implicito in tali modelli di simulazione. Le critiche, a tal proposito, giungono da più parti, tanto nell’ambito psicologico, quanto da quello filosofico, e sono di varia natura. C’è chi resta perplesso difronte ai riferimenti darwinistici, sostenedo, ad esempio, che l’interazione fra organismo e ambiente, riscontrabile in natura, è molto più complessa di quella che è possibile riprodurre nelle simulazioni, che, effettivamente, non tengono conto di molti fattori, a cominciare dalla competizione riproduttiva presente tra gli individui di una stessa specie, fino alle mutevoli ed inafferrabili influenze reciproche operate dalle numerosissime specie viventi che condividono, a vari livelli, lo stesso habitat ecologico, oppure chi ritiene semplicistico ridurre il comportamento ad una interazioni di elementi materiali, ritenendo più opportuno continuare a studiarlo attraverso i metodi classici della psicologia sperimentale. In ultima analisi, però, queste critiche (come altre dello stesso genere) ne sottendono una assai più generale, che accusa la vita artificiale di eccessivo riduzionismo nella sua ricerca delle basi evolutive e neurobiologiche del comportamento, rifiutando, in generale, l’accostamento di sistemi tanto diversi (quali il sistema nervoso biologico e le reti neurali, ad esempio) sotto il comune denominatore dei sistemi complessi. A partire da questa considerazione, si conclude affermando la sostanziale ininfluenza dei risultati delle simulazioni nei confronti dei sistemi biologici, restringendo, di fatto, il campo delle ricerche al solo ambito delle scienze dell’artificiale, senza attribuire ad esse un valore conoscitivo più generale. In altre parole, non sarebbe possibile estendere i risultati delle simulazioni nell’ambito più generale della psicobiologia (a cui farebbero riferimento) a causa dell’incapacità di questi modelli di cogliere il reale nesso fra le varie componenti dei sistemi che pretenderebbero di simulare e perché, soprattutto per gli psicologi, risulta semplicistico cercare nella biologia le radici del comportamento. Da parte nostra riconosciamo il valore e la consistenza di queste critiche, ma riteniamo altresì che sia proprio il ricorso alla teoria dei sistemi complessi che ne permetta, almeno parzialmente, il superamento, infatti grazie ad essi abbiamo la possibilità di interpretare la realtà in una nuova maniera, secondo cui, “il comportamento e la vita mentale emergono dalle interazioni fra numerosissimi elementi che sono le singole cellule del sistema nervoso, le diverse componenti del corpo (molecole, cellule, organi, sistemi), i segmenti di meteriale genetico che costituiscono i geni. Lo studio di queste componenti e delle loro interazioni è essenziale per capire la natura delle proprietà globali di un individuo che chiamiamo comportamento e vita mentale. Nello stesso tempo, però, il comportamento e la vita mentale non possono essere “ridotte” alle cellule nervose, alle componenti del corpo e ai geni, in quanto il comportamento e la vita mentale sono proprietà emergenti di sistemi complessi di cui le cellule nervose, le singole parti del corpo e i geni sono le componenti. Come nel caso di tutti i sistemi complessi, non è possibile prevedere o dedurre le caratteristiche del comportamento e della vita mentale conoscendo queste componenti e le loro interazioni”8. 8 Parisi, in corso di stampa, pag. 46