570 likes | 765 Views
Anno Accademico 2010/2011. Approssimazione di funzioni mediante tecniche di programmazione genetica. Salvatore Alaimo. 05 maggio 2011. Algoritmi Genetici.
E N D
Anno Accademico 2010/2011 Approssimazione di funzioni mediante tecniche di programmazione genetica. Salvatore Alaimo 05 maggio 2011
Algoritmi Genetici • Un algoritmo genetico è un metodo euristico di ottimizzazione e ricerca, ispirato al principio della selezione naturale di Charles Darwin che regola l’evoluzione biologica. • Gli algoritmi genetici sono applicabili alla risoluzione di un'ampia varietà di problemi d'ottimizzazione non indicati per gli algoritmi classici, compresi quelli in cui la funzione obiettivo è discontinua, non derivabile, stocastica, o fortemente non lineare.
Algoritmi Genetici • Un tipico algoritmo genetico parte da un certo numero di possibili soluzioni (individui) chiamate popolazione. • Si provvede a far evolvere ogni soluzione nel corso dell'esecuzione. • L’evoluzione è ottenuta mediante: • Parziale ricombinazione delle soluzioni: ogni individuo trasmette parte del suo patrimonio genetico ai propri discendenti; • Mutazioni casuali nella popolazione di partenza: sporadicamente nascono individui con caratteristiche diverse dai genitori. • In generale, per ciascuna iterazione (generazione): • Si selezionano alcuni individui della popolazione corrente; • Con essi si generano nuovi elementi della popolazione stessa (riproduzione o crossover, mutazione) • Gli elementi generati sostituiranno un pari numero d'individui già presenti • Si forma così la popolazione per la successiva iterazione.
Algoritmi Genetici • La soluzione del problema è codificata attraverso una struttura (tipicamente stringa) detta Gene. • Per stabilire la «bontà» di un gene, si definisce una funzione, detta Funzione di Fitness.
Algoritmi Genetici • Crossover:è l’operazione che definisce la programmazione di un gene sulla base di altri due geni detti genitori. Cut-Splice Crossover Single-Point Crossover Two-Point Crossover Uniform Crossover
Algoritmi Genetici • Mutazione: è l’operazione che mantiene la diversità genetica da una generazione alla successiva.
Algoritmi Genetici • La successione di iterazioni evolverà verso una soluzione ottimale (locale o globale) del problema. • Finita la fase di evoluzione, sono tenute solo le soluzioni che meglio risolvono il problema. • Alla fine ci si aspetta di trovare una popolazione di soluzioni che risolva adeguatamente il problema posto.
Algoritmi Genetici • Non vi è modo di decidere a priori se l'algoritmo sarà effettivamente in grado di trovare una soluzione accettabile. • Utilizzo: problemi di ottimizzazione per i quali non si conoscono algoritmi di complessità lineare o polinomiale.
Programmazione Genetica • Elaborata fondamentalmente da John R. Koza • È un metodo per la generazione automatica di programmi, a partire da una descrizione ad alto livello del task da svolgere • Basato sul principio darwiniano della selezione naturale. • Si avvale di operazioni capaci di alterare l'architettura di detti programmi e di prendere decisioni sull'uso delle subroutine, dei loop, della ricorsione e della memoria. • Costituisce un'estensione degli algoritmi genetici al caso di popolazioni costituite da programmi di dimensione variabile. • La popolazione risulta composta da un numero di programmi, i quali, mediante operatori genetici, producono, in un certo numero di generazioni, il programma che risolve al meglio un problema.
Programmazione Genetica • + • + • * • 5 • La struttura base è un ad albero, il cui corpo è costituito da funzioni (primitive), mentre i nodi terminali rappresentano variabili o costanti numeriche. • 75 • 5 • 3 • ^ • 5 • 2 • + • + • + • * • 5 • * • 5 • 80 • * • 5 • 3 • 25 • 3 • ^ • 3 • ^ • g • 2 • x • 2 • x
Programmazione Genetica • Struttura generica di un algoritmo: • Costruzione di una popolazione di programmi iniziale a partire dalle primitive disponibili • Finchè non si ottiene una soluzione accettabile: • Eseguire ogni programma e valutarne la «fitness»; • Selezionare i programmi a cui applicare gli operatori genetici; • Applicare gli operatori genetici ai programmi selezionati; • Costruire una nuova popolazione che contiene: • Il miglior programma ottenuto fino ad ora (con alta probabilità) • Alcuni dei programmi aggiornati al passo precedente • Alcuni programmi costruiti casualmente per ottenere una popolazione di dimensione identica a quella iniziale. • Restituire il miglior programma ottenuto.
Programmazione Genetica • Le primitive dipendono dalla natura del problema da risolvere. • Per semplici problemi numerici, esse sono tipicamente le funzioni aritmetiche. ({+, -, *, /}) • Affinché il problema sia risolto correttamente, è, necessario che siano valide le seguenti proprietà per l’insieme di primitive: • Sufficiency: esprimere una soluzione del problema solo in funzione delle primitive. (Es.: {AND, OR, NOT} per i problemi di combinatoria booleana) • Closure: si suddivide in altre due proprietà: • Strong Type Consistency: tutte le primitive devono prendere in input e restituire in output valori dello stesso tipo, indipendentemente dal compito svolto. • Evaluation Safety: ogni primitiva deve essere in grado di gestire eventuali errori e produrre un risultato valido in ogni situazione. (Es.: overflow numerici gestiti come “wraparound”, divisioni per zero gestite come “infinito”)
Programmazione Genetica • La funzione di fitness consente di valutare la bontà del programma in base all’errore commesso nella risoluzione del problema e alla complessità temporale, spaziale e/o computazionale. • Principali operatori genetici: • Crossover o riproduzione: • Sessuata • Asessuata (Imitazione) • Mutazione
Programmazione Genetica • + • Crossover • * • 5 • 3 • ^ • + • x • 2 • * • Exp • 3 • ^ • x • * • x • 2 • + • exp • 9 • x • x
Programmazione Genetica • Imitazione • + • * • * • b • + • exp • 9 • x • x • a • x
Programmazione Genetica • Mutazione • * • * • + • exp • + • exp • 9 • cos • x • 9 • x • x • x
Programmazione Genetica • Problemi nell’approccio di Koza alla programmazione genetica: • Schema troppo generico in cui la manipolazione delle costanti risulta essere troppo oneroso. • Convergenza troppo rapida dell’algoritmo ad una soluzione locale, piuttosto che globale, del problema. • Maggiore complessità delle funzioni usate implica maggiori parametri da aggiustare, quindi, maggiore sensibilità al rumore. • Se la funzione di fitness richiede la pura aderenza ai dati, la convergenza potrebbe non essere mai raggiunta, provocando un aumento della complessità dei programmi.
Approssimare Funzioni • Il problema: data una serie di valori, trovare quell’espressione matematica che meglio rappresenta l’andamento dei dati. • Aspetti problematici: • Complessità della funzione risultato; • Aderenza ai dati e rumore; • Misura della bontà del risultato. • Approcci tradizionali: • Regressione • Interpolazione
Approssimare Funzioni • Per valutare l’aderenza ai dati si è scelto di usare la misura dell’errore basata sullo scarto quadratico medio: • continua al variare della parametrizzazione • non continua al variare della forma della forma di f. • La ricerca della parametrizzazione è una ricerca di un minimo di una funzione continua (o continua a tratti). • La ricerca della forma è più simile ad una ricerca in ampiezza, utilizzando delle euristiche per limitare lo spazio di ricerca.
Rappresentazione di una Funzione • Per implementare l’albero di definizione di una funzione sono utilizzati due vettori: • Vettore «form»: descrive la forma della funzione (dalle foglie alla radice); • Vettore «constants»: contiene le costanti numeriche della funzione. • L’algoritmo di ricerca del minimo (globale e locale) ottimizza i valori del vettore «constants» per minimizzare l’errore. • L’algoritmo di ricerca dell’approssimazione altera il vettore «form» per trovare la migliore famiglia di funzioni che risolve il problema. • Ogni elemento del vettore form contiene tre valori (FormEntry): • Operatore (eType); • Primo Operando (op1): è l’indice, nel vettore form, della radice del sottoalbero sinistro radicato nell’elemento corrente; • Secondo Operando (op2): è l’indice, nel vettore form, della radice del sottoalbero destro radicato nell’elemento corrente. • Nel vettore form, il primo operando è posto prima del secondo operando; la radice di ogni sottoalbero è posta dopo ogni operando.
Rappresentazione di una Funzione • Operatori a due argomenti: • Addizione (0): f(a)+g(b) • Sottrazione (1): f(a)-g(b) • Moltiplicazione (2): f(a)*g(b) • Divisione (3): f(a)/g(b) • Potenza (4): f(a)k • Operatori a un argomento: • Ripetizione (20): serve a rappresentare funzioni del tipo f(g(x)) senza ripetere più volte la funzione g(x) • Esponenziale (21): ef(x) • Seno (22): sen(f(x)) • Coseno (23): cos(f(x)) • Costante (100): rappresenta una costante del vettore «constants» • Variabile (101): rappresenta una variabile da sostituire durante la valutazione della funzione
Rappresentazione di una Funzione • Per calcolare f(x) si utilizza un vettore di comodo «tempCalc» della stessa dimensione di «forms». • Il calcolo avviene mediante il seguente algoritmo: • Sia x il vettore dei dati • For i := 1 to size(tempCalc) • Iftipo(forms[i])is «costante» then • tempCalc[i] := constants[op1(forms[i])] • ElseIftipo(forms[i])is «variabile» then • tempCalc[i] := x[op1(forms[i])] • Else • Applica l’operazione tipo(forms[i]) ai valori tempCalc[op1(forms[i])] e, se necessario, tempCalc[op2(forms[i])] e poni il risultato in tempCalc[i] • End • End • If errore di calcolo thenreturn+∞ • Return tempCalc[size(tempCalc)]
Esempio: f(x)=3x+2 «constants» «forms» Calcolo f(4) «tempCalc»
Calcolo del minimo • È un algoritmo che data una funzione f(x,c) calcola la parametrizzazione «c» che minimizza l’errore • Composto da due algoritmi genetici: • Algoritmo del minimo locale: sfrutta una piccola popolazione di parametrizzazioni per trovare un minimo locale della funzione errore; • per velocizzare la convergenza esegue una analisi di sensibilità al fine di stabilire l’incremento e la direzione di incremento • Algoritmo del minimo globale: sfrutta una popolazione di «minimi locali» per trovare il minimo globale dell’errore; • Una popolazione di «minimi locali» è una parametrizzazione c1 della funzione f(x, c1) calcolata mediante l’algoritmo del minimo locale.
Minimi Locali • Data una funzione f(x, c) e una parametrizzazione iniziale, l’algoritmo dei «minimi locali» cerca di migliorare la parametrizzazione per minimizzare localmente la funzione errore. • La velocità di convergenza dipende da: • numero di parametri presenti; • posizione dei parametri; • probabilità che scelta una parametrizzazione a caso, essa sia la migliore. • Per migliorare la convergenza si utilizzano due operatori realizzati appositamente, piuttosto che le tecniche tipiche degli algoritmi genetici: • Mutazione gaussiana; • Ricerca nella direzione. • Per migliorare le prestazioni, ad ogni iterazione, è mantenuta solo la miglior parametrizzazione, e le altre sono scartate.
Minimi Locali • Mutazione gaussiana: • Genera una nuova parametrizzazione in un intorno di quella di partenza, la cui distanza è funzione dell’errore. (a maggior errore corrisponde maggior distanza, e viceversa) • Per fare ciò si utilizza una distribuzione di probabilità gaussiana nello spazio dei parametri centrata nel punto corrispondente alla vecchia parametrizzazione. • Per calcolare la varianza della distribuzione si esegue una analisi di sensibilità. • Si calcola una piccola variazione della parametrizzazione e si valuta il rapporto tra la distanza degli errori e la distanza delle parametrizzazioni. • Numeri casuali distribuiti come descritto precedentemente forniscono la variazione casuale della parametrizzazione.
Minimi Locali • Ricerca nella direzione: • Si costruiscono nuove parametrizzazioni nella direzione in cui l’errore diminuisce, fino a trovare il punto in cui l’errore inizia ad aumentare o si raggiunge il numero massimo di iterazioni. • Velocizza la convergenza quando le parametrizzazioni sono troppo lontane dal punto di minimo errore. • Difetto: La parametrizzazione inizia ad oscillare attorno alla posizione del minimo ma non lo raggiunge mai. a f(x) = ax+b Parametrizzazione:c=(a,b) b
Minimi Locali • Sia • f(x,c) una funzione con parametrizzazione c (casuale o trovata precedentemente) • e(f, P) una stima dell’errore di f sui punti del datasetP • n il numero di iterazioni • oldC := c, oldE := e(f(x, oldC), P) • For i := 1 to n • c’ := gaussianMutation(oldC) • e’:= e(f(x, c’), P) • IfoldE > e’then • d := c’ - oldC • bestC := exploreDirection(d, c’) • oldC := bestC, oldE := e(f(x, bestC), p) • End • End • Return oldC
Minimo Globale • Data una funzione f(x) trovare la parametrizzazione «c» che minimizza l’errore sui punti del dataset P. • Gli operatori genetici definiti per l’algoritmo sono: • Crossover • Mutazione • L’algoritmo del minimo globale è utilizzato nell’algoritmo di ricerca dell’approssimazione, come unico operatore che lavora sui parametri della funzione. • Si ottengono buoni risultati anche con popolazioni di piccole dimensioni (Es. 12 individui e 6 sopravvissuti).
Minimo Globale • Crossover: • Date due parametrizzazione (genitori), si costruisce una nuova parametrizzazione (figlio) che, nello spazio dei parametri, risulta essere compresa tra i due. • Accelera la convergenza: • Date due parametrizzazioni che stanno convergendo allo stesso minimo locale. • L’algoritmo riesce a produrre, con un singolo passo ,una parametrizzazione molto più vicina al minimo rispetto alle due precedenti. • Rende l’algoritmo meno sensibile ai minimi locali nel caso in cui il minimo globale è circondato da tanti minimi locali. • Importante l’inizializzazione perché non cerca nell’intero spazio dei parametri. • Mutazione: • Si esegue l’algoritmo dei «minimi locali» per costruire una parametrizzazione che si avvicini il più possibile ai minimi dell’errore.
Minimo Globale • Sia • f(x) una funzione con valutazione dell’errore e(f,P) • n il numero di individui della popolazione • k il numero di sopravvissuti per generazione • m il numero di iterazioni dell’algoritmo dei «minimi globali» • t il numero di iterazioni dell’algoritmo dei «minimi locali» • Poni nel vettore «pop» una n parametrizzazioni casuali. • For i := 1 to m • For p in pop • Aggiorna p con il risultato di localFinder( f(x,p), e(f,P), t) • End • Best := Elemento p di pop tale che e(f(x, pop), P) è minimo • Survivor := scegli a caso k elementi di pop dando priorità a quelli con errore più piccolo • Children := combina con l’operatore crossover gli elementi di Survivorscegliendoli a caso • Aggiorna «pop» con la nuova popolazione composta da: • Best • Le parametrizzazioni contenute in Children • n-(1+k/2) parametrizzazioni casuali. • End • Return Elemento p di pop tale che e(f(x, pop), P) è minimo
Algoritmo Principale • Mutazione: • Presa una funzione, od un sottoalbero del suo primo operatore, la combina ad una generata casualmente utilizzando un operatore di somma o prodotto. • Rende possibile la risoluzione di problemi più complessi, ma rende anche molto più instabile la convergenza. (Problema: a maggiore complessità equivale minor crescita della fitness) • Imitazione: • L’operatore costruisce una nuova funzione con le seguenti caratteristiche rispetto a quella di partenza: • Profondità dell’albero di definizione uguale o maggiore di una unità; • Numero di costanti e variabili scelte casualmente; • Numero di funzioni trascendenti al più uguale a quello della funzione di partenza. • Aumenta la probabilità di trovare la forma giusta della funzione con piccoli incrementi della complessità.
Algoritmo Principale • Sia • P un insieme di punti • e una valutazione dell’errore di una qualsiasi funzione f sull’insieme dei punti • n il numero di iterazioni • m il numero di funzioni per generazione • k il numero di sopravvissuti per generazione • Costruisci il vettore «pop» con m funzioni generate casualmente • For i := 1 to n • Aggiorna gli elementi di «pop» tramite l’algoritmo dei minimi globali • Best := L’elemento di «pop» per cui l’errore e risulta minimo • Survivors := SelectSurvivors(pop, k) • pop := CreateNewPopulation(Best, Survivors, n, k) • End • Return L’elemento di «pop» per cui l’errore e risulta minimo
Algoritmo Principale • SelectSurvivors(pop, k) • Survivors := vettore contenente i k migliori elementi di «pop» • For j := 1 to k • p1 = rand(), p2=rand() • Ifp1 < 0,7 and p2 < 0,5then • Survivors[j] = mutate(Survivors[j]) • ElseIfp1 < 0,7 and p2 >= 0,5then • Survivors[j] = imitate(Survivors[j]) • End • End • Return Survivors
Algoritmo Principale • CreateNewPopulation(Best, Survivors, n, k) • Random := costruisci (n-k-1) funzioni casuali • p = rand() • Ifp < 0,98then • pop := <Best> + Survivors + Random • Else • pop := Survivors + Random • End • Return pop
Algoritmo Principale • generateRandomFunction(n, k, t) • Sia • nla profondità dell’albero di definizione della funzione • k il numero massimo di operazioni trascendenti • t il numero di variabili indipendenti • p=rand() • Ifn == 1 and p <0.5then • Return f(x)=1.0 • ElseIfn == 1 and p >= 0.5then • Return f(x)=x(rand()*t) • End • If rand() < 0.5 then • Scegli a caso una operazione trascendente r(x) • Return f(x) = r(generateRandomFunction(n-1,k-1,t)) • Else • Scegli a caso una operazione binaria b(f1, f2) • f1 = generateRandomFunction((1+rand()*(n-1)), k, t) • f2 = generateRandomFunction(n-1, k-1, t) • Return f(x) = b(f1, f2) • End
Test dell’algoritmo • Per provare il funzionamento dell’algoritmo sono state selezionate 11 funzioni per le quali è stato estratto un campione di 100 elementi nell’intervallo [-10;10). • Per rendere più verosimili i test, si è scelto di aggiungere al campione un rumore casuale distribuito secondo una normale gaussiana standardizzata. • L’iterazione principale dell’algoritmo è stata eseguita al più 250 volte, con una popolazione di 30 individui e 6 sopravvissuti per generazione. • Al fine di controllare la solidità dell’algoritmo si è scelto di ripeterlo 20 volte in modo da verificare quanto la convergenza sia dovuta ad una particolare catena di eventi, o a proprietà dell’algoritmo. • Per verificare l’efficienza del metodo si è misurato il tempo di esecuzione di ogni iterazione (minimo, massimo e medio), e l’utilizzo di memoria. Non è stato scelto come parametro l’utilizzo della CPU in quanto l’algoritmo è stato ottimizzato per saturare al massimo la risorsa in modo da ridurre i tempi di calcolo.
Test dell’algoritmo • Le funzioni scelte sono:
Test dell’algoritmo • Generazioni: 7 • Funzioni testate: 274.587 • Tempo: • Medio: 9s • Minimo: 3s • Massimo: 23s • Errore medio: 0,57 • Solidità: 20 su 20 • Utilizzo memoria: 0,01Gb
Test dell’algoritmo • Generazioni: 31 • Funzioni testate: 875.647 • Tempo: • Medio: 23s • Minimo: 4s • Massimo: 137s • Errore medio: 0,57 • Solidità: 20 su 20 • Utilizzo memoria: 0,02Gb
Test dell’algoritmo • Generazioni: 2 • Funzioni testate: 137.955 • Tempo: • Medio: 3s • Minimo: 2,5s • Massimo: 11,4s • Errore medio: 0,57 • Solidità: 20 su 20 • Utilizzo memoria: 0,01Gb
Test dell’algoritmo • Generazioni: 39 • Funzioni testate: 1.062.675 • Tempo: • Medio: 26s • Minimo: 3s • Massimo: 82s • Errore medio: 0,59 • Solidità: 20 su 20 • Utilizzo memoria: 0,08Gb
Test dell’algoritmo • Generazioni: 10 • Funzioni testate: 356.871 • Tempo: • Medio: 9s • Minimo: 3s • Massimo: 22s • Errore medio: 0,55 • Solidità: 20 su 20 • Utilizzo memoria: 0,04Gb
Test dell’algoritmo • Generazioni: 61 • Funzioni testate: 1.605.394 • Tempo: • Medio: 45s • Minimo: 2s • Massimo: 160s • Errore medio: 0,53 • Solidità: 19 su 20 • Utilizzo memoria: 0,15Gb
Test dell’algoritmo • Generazioni: 142 • Funzioni testate: 3.689.075 • Tempo: • Medio: 118s • Minimo: 1s • Massimo: 141s • Errore medio: 0,55 • Solidità: 5 su 20 • Utilizzo memoria: 0,06Gb
Test dell’algoritmo • Generazioni: 142 • Funzioni testate: 3.689.075 • Tempo: • Medio: 118s • Minimo: 1s • Massimo: 141s • Errore medio: 0,55 • Solidità: 5 su 20 • Utilizzo memoria: 0,06Gb
Test dell’algoritmo • Test con funzione probabilistica:
Applicazione pratica:Analisi del «Afterglow» di un Gamma RayBurst (GRB)
Gamma RayBurst • È un fenomeno astronomico che consiste in un lampo di radiazione gamma che avviene per: • Esplosione di una Supernova • Quasar • Altre cause legate alla morte di una stella • Dura al più qualche centinaio di secondi per cui l’unico modo per studiare il fenomeno è analizzare l’afterglow. (la luminosità residua in conseguenza al fenomeno) • L’andamento dell’afterglow nel tempo permette di identificare il tipo di GRB.