L’idea del progetto di questa tesi è applicare all’addestramento di reti neurali artificiali le funzionalità di uno strumento di gestione di progetti software, in questo caso Maven, per rendere configurabili e componibili in modo dichiarativo, e possibilmente estendibili, sia l’algoritmo di addestramento che le componenti di supporto, come la persistenza della rete neurale e la gestione dei dati dell’insieme di addestramento. Tale idea è nata dall’analogia tra progetti software e addestramento di reti neurali artificiali. Prima dell’introduzione di strumenti di gestione, ciascun progetto software possedeva una propria organizzazione del processo di compilazione, test, deploy, di versionamento e di gestione delle dipendenze. Maven introduce un’interfaccia comune ed un insieme di convenzioni che, oltre a rendere portabile il progetto, ne semplifica il processo di build. Le reti neurali vengono costruite e addestrate usando strumenti di calcolo matematico o scrivendo un eseguibile che utilizzi una libreria dedicata. Il codice per l’addestramento è sviluppato per lo specifico problema, talvolta scartato una volta terminato il suo compito. Nonostante l’addestramento di reti neurali non sia deterministico come un processo di compilazione, ma adotti una serie di tecniche ed euristiche per trovare soluzioni non ottime, sono state cercate delle caratteristiche comuni ai due processi. Si vuole quindi introdurre Maven per definire un prototipo di interfaccia comune all’addestramento di reti neurali artificiali, tenendo conto delle problematiche di questo tipo di processo. Il meccanismo sviluppato per consentire configurabilità e componibilità delle componenti introduce il concetto di servizi: tipologie di oggetti a ciascuna delle quali è associata una factory col compito di configurare le istanze create. Nella configurazione da iniettare attraverso una factory sono tenuti distinti i puri dati, come parametri numerici o stringhe, e servizi collaboratori dotati di comportamento. Attraverso questa distinzione è possibile rappresentare in formato puramente testuale la gerarchia di composizione di un qualunque servizio. Le responsabilità del gestore di progetti sono importare le factory da librerie dichiarate come dipendenze, costruire i servizi in base alla struttura gerarchica specificata nel descrittore di progetto ed utilizzarli per effettuare l’addestramento.
Public Light Manager - Una GUI per la gestione remota di un impianto di illum...
Implementazione in Java di plugin Maven per algoritmi di addestramento per reti neurali artificiali
1. Universit`a degli Studi di Trieste
Facolt`a di Ingegneria
Dipartimento di Elettrotecnica, Elettronica ed Informatica
Corso di Laurea in
Ingegneria dell’Informazione – curriculum Informatica
Tesi di Laurea in
Sistemi Operativi
IMPLEMENTAZIONE IN JAVA
DI PLUGIN MAVEN PER
ALGORITMI DI
ADDESTRAMENTO PER RETI
NEURALI ARTIFICIALI
Laureando: Relatore:
Francesco Komauli Prof. Ing. Enzo Mumolo
Anno Accademico 2012-2013
5. Ringraziamenti
Desidero ringraziare la mia famiglia per il sostegno datomi in questi mesi di
duro lavoro. Ringrazio il professor Enzo Mumolo per avermi dato l’opportunit`a
di approfondire un argomento interessante come le reti neurali artificiali. Vorrei
ringraziare i miei amici per essermi stati sempre accanto ed avermi consigliato.
Infine ringrazio i miei colleghi senza i quali non avrei sviluppato un approccio
critico all’architettura e al design del software.
5
6. 1 Introduzione
L’idea del progetto di questa tesi `e applicare all’addestramento di reti neurali
artificiali le funzionalit`a di uno strumento di gestione di progetti software, in
questo caso Maven, per rendere configurabili e componibili in modo dichiarativo,
e possibilmente estendibili, sia l’algoritmo di addestramento che le componen-
ti di supporto, come la persistenza della rete neurale e la gestione dei dati
dell’insieme di addestramento.
Tale idea `e nata dall’analogia tra progetti software e addestramento di re-
ti neurali artificiali. Prima dell’introduzione di strumenti di gestione, ciascun
progetto software possedeva una propria organizzazione del processo di compi-
lazione, test, deploy, di versionamento e di gestione delle dipendenze. Maven
introduce un’interfaccia comune ed un insieme di convenzioni che, oltre a rendere
portabile il progetto, ne semplifica il processo di build.
Le reti neurali vengono costruite e addestrate usando strumenti di calcolo
matematico o scrivendo un eseguibile che utilizzi una libreria dedicata. Il codice
per l’addestramento `e sviluppato per lo specifico problema, talvolta scartato una
volta terminato il suo compito. Nonostante l’addestramento di reti neurali non
sia deterministico come un processo di compilazione, ma adotti una serie di
tecniche ed euristiche per trovare soluzioni non ottime, sono state cercate delle
caratteristiche comuni ai due processi.
Si vuole quindi introdurre Maven per definire un prototipo di interfaccia
comune all’addestramento di reti neurali artificiali, tenendo conto delle proble-
matiche di questo tipo di processo.
Il meccanismo sviluppato per consentire configurabilit`a e componibilit`a delle
componenti introduce il concetto di servizi: tipologie di oggetti a ciascuna delle
quali `e associata una factory col compito di configurare le istanze create. Nel-
la configurazione da iniettare attraverso una factory sono tenuti distinti i puri
dati, come parametri numerici o stringhe, e servizi collaboratori dotati di com-
portamento. Attraverso questa distinzione `e possibile rappresentare in formato
puramente testuale la gerarchia di composizioe di un qualunque servizio.
Le responsabilit`a del gestore di progetti sono importare le factory da li-
brerie dichiarate come dipendenze, costruire i servizi in base alla struttura
gerarchica specificata nel descrittore di progetto ed utilizzarli per effettuare
l’addestramento.
Il progetto `e inserito nel contesto di un esperimento che vede confrontate tra
loro tre tipologie di classificatori: Multilayer Perceptron, Hidden Markov Model
e Serie di Volterra. Nello specifico caso del riconoscimento di lettere pronunciate
dell’alfabeto inglese, vengono analizzate le diverse capacit`a di generalizzazione
di ciascun modello.
1.1 Obiettivi della tesi
L’obiettivo principale della tesi `e fornire un’implementazione di plugin Maven
per ciascuna tipologia di classificatori. Ciascun plugin deve poter compiere
l’addestramento di classificatori, sviluppato in modo tale da rendere ogni com-
ponente configurabile e componibile, con un livello di dettaglio che consenta di
affrontare problemi specifici come quello particolare del riconoscimento di lette-
re pronunciate. Allo stesso tempo si cerca di minimizzare la quantit`a di codice
dedicata esclusivamente alla sua risoluzione.
6
7. Si intende quindi fare uso dei plugin sviluppati per confrontare le capacit`a
di generalizzazione delle tipologie di classificatori sopra menzionati.
1.2 Organizzazione della tesi
Nella Sezione 2 viene descritto cosa sia Maven, quale sia il suo funzionamento ed
i vantaggi che ha portato alla gestione di progetti software grazie all’introduzione
di un modello di progetto.
La Sezione 3 introduce il modello teorico del multilayer perceptron. Inoltre
viene presentato uno degli algoritmi adatti al suo addestramento, quello di batch
back propagation.
La sezione 4 presenta il plugin Maven per multilayer perceptron, descrivendo
le fasi di addestramento e test e fornendo esempi sul suo utilizzo, tra cui come
strutturare la configurazione e come rappresentare un multilayer perceptron.
Il meccanismo dei servizi che sta alla base del funzionamento del plugin `e
presentato nella Sezione 5. Viene spiegato come i servizi possano essere utilizzati
programmaticamente, in che modo ne vengano definiti di nuovi e come renderli
disponibili attraverso i repository Maven.
Nella Sezione 6 viene descritto come il plugin sia stato utilizzato per l’ad-
destramento di un multilayer perceptron il cui compito `e classificare le lettere
pronunciate dell’alfabeto inglese. Sono dati i parametri della rete neurale e del-
l’algoritmo di back propagation, e una descrizione del preprocessamento degli
esempi. Per l’addestramento `e stata impiegata una particolare funzione d’errore
adatta al tipo di problema, detta classification figure of merit. Infine vengono
presentati i risultati ottenuti.
La sezione 7 introduce il modello di Hidden Markov Model, esponendo quali
siano le problematiche collegate al suo utilizzo per la classificazione di segnali
ed i relativi algoritmi, tra cui l’algoritmo di Baum-Welch per l’addestramento
di un HMM. Sono poi esposti i risultati ottenuti per il riconoscimento di lettere
pronunciate dell’alfabeto inglese.
Nella sezione 8 vengono presentate le Serie di Volterra, il cui modello pu`o
essere dedotto da quello delle reti neurali attraverso un’approssimazione poli-
nomiale delle non-linearit`a che contraddistinguono i neuroni artificiali. Sono
dati inoltre alcuni risultati preliminari dell’applicazione di serie volterriane al
problema di classificazione di lettere pronunciate dell’alfabeto inglese.
Per ultima, la Sezione 9 contiene le conclusioni relative al progetto di questa
tesi ed i risultati ottenuti. Inoltre `e data una lista degli sviluppi che non si sono
potuti avviare o portare a termine, o che si sono delineati come deduzioni dal
lavoro svolto.
Nell’appendice `e presentato un’esempio completo di utilizzo del plugin Ma-
ven per multilayer perceptron (Appendice A) e una descrizione dell’implemen-
tazione dell’algoritmo di batch back propagation (Appendice B).
1.3 Strumenti utilizzati
Una parte del software, riguardante Hidden Markov Model e Serie di Volterra, `e
stata sviluppata nel linguaggio C. Il software che si occupa del preprocessamento
dei file di esempio `e stato implementato in C, ed in Java quello che converte i ri-
sultati del preprocessamento in formato json. Il plugin per multilayer perceptron
`e invece scritto interamente in Java 1.7.
7
8. Oltre all’ambiente di build Maven, descritto nella Sezione 2, `e stato utiliz-
zato lo strumento di continuous integration Jenkins1
. Si tratta di una webapp
generalmente impiegata per effettuare build automatizzate, che richiede il sup-
porto di un servlet container per la sua esecuzione. Nel caso di questa tesi `e
stato utilizzato il server Tomcat2
.
Tra le varie funzionalit`a vi `e la possibilit`a di memorizzare le ultime build
effettuate, per poter confrontare i risultati e generare reportistica. Le build
possono essere avviate manualmente, venir temporizzate o lanciate in risposta
a degli eventi, come l’aggiornamento di una repository attraverso un sistema di
version control.
Oltre ad ospitare il progetto del plugin in Java, Jenkins `e stato configurato
per l’addestramento di multilayer perceptron attraverso il suo interfacciamento
con Maven.
1.4 Codice sorgente del progetto
Il progetto `e suddiviso in due repository, versionato con il sistema di controllo
di versione Mercurial3
, ed i suoi sorgenti sono ospitati sul sito BitBucket:
Genesis : https://bitbucket.org/0xdeadc0de/genesis/
libreria contenente le difinizioni di servizio e factory, e l’implementazione
di application context che li gestisce;
Seshat : https://bitbucket.org/0xdeadc0de/seshat/
definizioni delle interfacce dei servizi per mulilayer perceptron, plugin
Maven e implementazioni di servizi basilari per il suo funzionamento.
1 Jenkins CI: http://jenkins-ci.org/
2 Apache Tomcat: http://tomcat.apache.org/
3 Mercurial SCM: http://mercurial.selenic.com/
8
9. 2 Maven
Una definizione formale di Maven4
`e che si tratta di uno strumento di gestione
di progetti, il quale provvede un insieme di standard, un lifecycle di progetto, un
meccanismo di gestione delle dipendenze, e la logica per eseguire goal di plugin
in determinate fasi di un lifecycle. Non si tratta quindi di uno strumento di
build incentrato solo su compilazione e distribuzione del codice, ma fornisce un
soprainsieme di funzionalit`a.
2.1 Modello concettuale di progetto
Un progetto in generale consiste in codice sorgente e un insieme di risorse.
Maven consente di aggiungere al progetto una descrizione, come nome, licenza
e informazioni sugli sviluppatori. Ma le informazioni pi`u importanti sono le
coordinate che lo identificano:
groupId : famiglia di progetti, data ad esempio dal nome dell’azienda o
associazione;
artifactId : identificativo del progetto, solitamente una versione codificata
del nome;
version : numero di versione che pu`o essere di tipo stabile (release), men-
tre per le versioni ancora in fase di sviluppo viene aggiunto il suffisso
-SNAPSHOT;
packaging : `e la tipologia di artefatto, inteso come risultato prodotto dalla
compilazione, e definisce un proprio insieme di goal in determinate fasi del
lifecycle; di default `e jar e altri packaging integrati in Maven sono war,
ear e pom.
La definizione di un modello per i progetti consente di implementare funzio-
nalit`a aggiuntive rispetto a un sistema unicamente dedicato alla build.
2.1.1 Dependency management
Poich´e ciascun progetto `e univocamente identificato da groupId, artifactId
e version, si possoo usare queste coordinate per dichiarare dipendenze.
2.1.2 Repository remote
Sfruttando lo stesso meccanismo delle dipendenze, si possono usare le coordi-
nate dei progetti per creare repository di artefatti. Maven gestisce gli artefatti
attraverso un repository locale e uno o pi`u repository remoti. Tutte gli artefatti
dichiarati come dipendenze vengono installati nel repository locale, e inclusi nel
classpath al momento dell’esecuzione di un plugin.
Esiste un repository principale di riferimento: il Central Maven Reposito-
ry5
. Qui sono pubblicati tuti gli artefatti che passano i criteri di accettazione
necessari ad ottenere uno spazio.
Quando vi sia la necessit`a di condividere delle librerie ma senza dover depo-
sitarle sul repository centrale, come nel caso di aziende, dipartimenti o gruppi
4 Apache Maven: https://maven.apache.org/
5 The Central Repository. http://search.maven.org/
9
10. di sviluppo, `e possibile gestire un repository personalizzato attraverso la we-
bapp Nexus6
. Questo servizio si interpone tra i repository locali degli utenti
e quello centrale, arricchendo la collezione di librerie con quelle sviluppate dal
gruppo. I repository personalizzati possono essere resi pubblici, e aggiungendoli
alla configurazione della propria installazione di Maven vengono inclusi durante
la ricerca di librerie.
2.1.3 Portabilit`a
Maven definisce un’interfaccia comune a ciascun progetto, permettendo di com-
pilare un clone di progetto di terze parti semplicemente attraverso il comando
mvn install. Inoltre non `e pi`u necessario per gli IDE definire un proprio
sistema di metadati per il progetto, in quanto attraverso il Project Object Model
(POM) dispongono di una sorgente di informazioni comune.
2.2 Convention over Configuration
Maven adotta il paradigma Convention over Configuration. Secondo i suoi det-
tami, un sistema deve poter funzionare senza richiedere parametri non stretta-
mente necessari, assumendo per questi dei valori di default. Senza customizza-
zione, Maven assume che il codice sorgente sia in
${basedir}/src/main/java/
e quello di test in
${basedir}/src/main/test/
mentre la tipologia di artefatto sia jar. I risultati della build vengono infine
posti nel path
${basedir}/target/
L’adozione del paradigma Convention over Configuration non si limita alla
definizione di directory per il progetto. I plugin fondamentali applicano un
insieme di convenzioni per la compilazione dei sorgenti, per la distribuzione
degli artefatti, per la generazione della documentazione e per molti altri processi.
Quando si seguono le convenzioni si ha il vantaggio di dover fornire a Maven
una configuraziuone minima, mentre nel caso sia necessario modificare un certo
comportamento `e possibile modificare i parametri di default.
2.3 Estensione del framework
Il nucleo di Maven comprende solo alcune funzionalit`a di base, come il parsing
di xml ed esecuzione di un lifecycle. Infatti il suo design prevede che la maggior
parte delle responsabilit`a siano delegate a un insieme di plugin Maven, che
interagiscono con il lifecycle e forniscono dei goal da poter collegarvi. I plugin
sono a loro volta dei progetti Maven, e sono installabili in un repository allo
stesso modo degli altri artefatti.
Un goal di un plugin rappresenta uno specifico task che contribuisce alla
build o alla gestione di un progetto Maven. In Maven `e possibile definire dei
lifecycle aventi una nuova lista di fasi. I goal vengono eseguiti durante la fase a
6 Nexus: http://www.sonatype.org/nexus/
10
11. cui sono stati assegnati, imponendo l’ordine con cui le fasi sono state dichiarate
nel rispettivo lifecycle.
11
12. 3 Multilayer perceptron
Questa sezione introduce i multilayer perceptron, una tra le tipologie di reti
neurali artificiali pi`u comunemente usate. Viene presentato inoltre l’algoritmo
di addestramento back propagation, nella sua variante batch.
3.1 Il modello
I multilayer perceptron sono formati da unit`a chiamate neuroni, interconnesse
tra loro da collegamenti sinaptici, a ciascuna delle quali viene associato un peso.
Il livello di attivazione di una sinapsi `e determinato moltiplicando il valore di
output del neurone sorgente per il peso. Ogni unit`a effettua la somma dei propri
input, rappresentanti i livelli di attivaione delle sinapsi in ingresso, a cui viene
aggiunto un eventuale termine costante detto bias.
La somma complessiva viene mappata da una funzione non lineare denomina-
ta funzione di attivazione, il cui risultato rappresenta l’output del neurone. Due
tra le funzioni di attivazione pi`u comunemente usate sono la funzione logistica
(Figura 1) e la tangente iperbolica (Figura 2).
Figura 1: funzione logistica 1
1+e−x
Figura 2: tangente iperbolica ex
−e−x
ex+e−x
12
13. Detti w = (w1, . . . , ws) i pesi delle sinapsi e b il bias, il vettore in ingresso
x = (x1, . . . , xs) viene mappato dal neurone nel valore di output y attraverso
y = f( b +
s
i=1
xiwi ) (1)
I multilayer perceptron sono organizzati in layer, composti da neuroni che
ottengono i propri input unicamente dai neuroni del layer precedente, cos`ı come
i propri output sono usati solo da quelli del layer successivo.
Figura 3: multilayer perceptron formato da due layer, uno nascosto e quello
di output; all’interno dei neuroni, rappresentati come cerchi, avviene la som-
ma degli input pesati dalle sinapsi e la mappatura attraverso la funzione di
attivazione, come specificato dall’Equazione 1
L’operazione effettuata da un multilayer perceptron `e la mappatura di un
vettore di dimensione pari al layer di input in un vettore composto dai valori
di output dei neuroni dell’ultimo layer. I segnali vengono mappati attraverso
ciascun layer per attivare le sinapsi di quello successivo.
Il comportamento di un multilayer perceptron, ovvero la trasformazione ef-
fettuata sui vettori in ingresso, dipende dai pesi delle sinapsi e dai bias dei singoli
neuroni. `E attraverso la variazione di questi pesi che un multilayer perceptron
viene addestrato a svolgere una determinata operazione.
3.2 Addestramento
L’addestramento di un multilayer perceptron avviene applicando un vettore in
ingresso e confrontando il vettore prodotto in uscita con uno desiderato. Ta-
le metodo `e detto di apprendimento supervisionato in quanto sono note delle
coppie di segnali di input e output desiderato (xk, dk), di cui si vuole che ven-
ga riprodotta la corrispondenza da parte del multilayer perceptron addestra-
to. La differenza tra output effettivo ok e desiderato dk fornisce l’errore di
riconoscimento:
ek = ok − dk (2)
Tale errore viene mappato attraverso una funzione d’errore o di costo, che
fornisce una misura scalare dello scostamento della rete neurale dal suo com-
portamento ideale. Una funzione spesso usata `e l’errore quadratico
Ek = ek
2
2 (3)
ma altre funzioni possono essere impiegate in base al tipo di problema di rico-
noscimento da risolvere, dove l’errore quadratico non sia la miglior misura della
13
14. deviazione dal comportamento ideale.
Ek = C(ek) (4)
La funzione di costo C dovrebbe essere scelta in modo che rappresenti pi`u
verosimilmente le relative importanze degli errori nel contesto in cui la rete neu-
rale viene applicata. In generale una funzione di errore ha un minimo assoluto
per e = 0.
Considerando l’intero insieme di esempi per l’addestramento, lo scostamento
della rete neurale dal comportamento ideale si misura attraverso la somma dei
singoli errori:
E =
k
Ek (5)
Dato un inseme di esempi per l’addestramento e fissata la struttura del
multilayer perceptron, l’errore `e funzione dei soli pesi. Una tra le procedure
pi`u semplici per la minimizzazione dell’errore E(w) `e il metodo del gradiente:
consiste nell’iterare passi, nello spazio dei pesi, proporzionali all’opposto del
gradiente della funzione da ottimizzare. I pesi sono aggiornati ad ogni passo
con
w = w − η · E(w) (6)
dove per semplicit`a w indica il vettore contenente tutti i pesi della rete. Se l’er-
rore presenta una debole regolarit`a e il parametro η `e sufficientemente piccolo,
le iterazioni convergono verso un minimo locale di E. Il parametro η `e noto
come learning rate.
In questo metodo la parte critica risulta essere il calcolo delle componenti
del gradiente ∂E/∂wi. Per le reti neurali feedforward, ed in particolare per i
multilayer perceptron, questo calcolo assume una forma semplice.
3.2.1 Batch back propagation
L’algoritmo consiste nella costruzione di una rete neurale detta rete di back
propagation, richiedendo per`o che le funzioni di attivazione e la funzione d’errore
siano differenziabili. Detto wij il peso della sinapsi in ingresso nel neurone i e
proveniente dal neurone j, e definendo il livello di attivazione di un neurone
come la somma di bias e degli input pesati
si = bi +
j
xjwij (7)
tale rete ha le componenti non lineari dell’originale sostituite da guadagni co-
stanti
gi = fi (si) (8)
dove fi `e la derivata della funzione di attivazione associata al neurone i. Inol-
tre la struttura viene trasposta invertendo la direzione delle sinapsi e delle
diramazioni, sostituendo i nodi di somma in divergenze e viceversa.
La singola iterazione dell’algoritmo prevede quindi di applicare alla rete di
back propagation i valori ∂Ek/∂oi e calcolare gli output dei neuroni con
¯yi = gi ·
j
¯xjwji (9)
14
15. Le componenti del gradiente dei pesi posono essere ottenuti attraverso la
seguente regola:
∂Ek
∂wij
= yi ¯yj (10)
Per l’equazione (5) le componenti del gradiente sono date dalla somma delle
componenti valutate per ogni singolo esempio, con
∂E
∂wij
=
k
∂Ek
∂wij
(11)
Questi valori vengono quindi usati per aggiornare i valori dei pesi come
evidenziato nell’equazione (6). L’attributo batch dell’algoritmo sta proprio a
significare che prima di effettuare l’aggiornamento dei pesi vengono valutati gli
errori, e quindi i gradienti, di tutti gli esempi dell’insieme di addestramento.
3.2.2 Parametrizzazione dell’algoritmo
L’algoritmo di back propagation converge per un learning rate η al di sotto
di un certo valore ηmax. Tale massimo dipende dalla rete neurale, dall’insie-
me di esempi e dalla funzione di costo, e non pu`o essere determinato a priori.
Diminuendo il valore di η al di sotto di ηmax la velocit`a di convergenza pu`o ral-
lentare notevolente, rendendo la scelta del learning rate uno degli aspetti critici
dell’addestramento di una rete neurale.
Inoltre la superficie dell’errore pu`o presentare delle brusche variazioni, nelle
quali l’uso di un learning rate elevato porterebbe a oscillazioni divergenti intorno
a queste aree. Una delle soluzioni adottate `e l’utilizzo di learning rate ηij distinti
per ogni peso, adattati ad ogni iterazione dell’algoritmo in base ai segni di due
gradienti successivi.
Un’altra tecnica simula l’inerzia dello spostamento lungo la superficie del-
l’errore, accumulando le direzioni dei gradienti precedenti. Aggiungendo un
termine accumulatore all’equazione (6) si ottiene
wn+1 = wn − ( η · E(wn) + α · ∆wn−1 ) (12)
Il termine 0 ≤ α < 1 consente di aumentare la velocit`a lungo discese ripide
evitando movimenti oscillatori. Tuttavia quando troppa inerzia venisse accumu-
lata, lo spostamento successivo porterebbe ad uscire dall’intorno di un minimo
locale raggiunto.
3.3 Generalizzazione
Nell’addestramento di una rete neurale artificiale, spesso l’insieme di esempi
rappresenta un sottoinsieme relativamente piccolo dei possibili input che la rete
dovr`a riconoscere. Una volta addestrata deve essere in grado di classificare
pattern non presenti nell’insieme di addestramento. La condizione ideale per
l’addestramento sarebbe minimizzare la funzione di costo calcolata su tutti gli
elementi dell’universo degli input, ma ci`o risulta impossibile per universi infiniti
o non del tutto noti, o per un costo computazionale troppo elevato. Per questo
l’insieme di addestramento andrebbe selezionato in modo da rappresentare tutte
le caratteristiche dell’universo degli input.
15
16. Una rete neurale che riconosca correttamente gli elementi dell’universo come
quelli dell’insieme di addestramento ha ottenuto la capacit`a di generalizzare la
propria classificazione. Per valutare l’entit`a del livello di generalizzazione viene
utilizzato un insieme di esempi disgiunto da quello di addestramento, detto
insieme di test. Si ha cos`ı modo di valutare la generalizzazione della rete neurale
e adattare di conseguenza la struttura della rete o l’insieme di addestramento.
16
17. 4 Plugin Maven per multilayer perceptron
In seguito `e presentato il funzionamento del plugin, assieme a una configurazione
di progetto di multilayer perceptron d’esempio.
Sono definiti due goal: il primo per l’addestramento del multilayer percep-
tron, il secondo per verificarne la capacit`a di generalizzazione.
4.1 Layout di un progetto
Il plugin definisce una nuova tipologia di progetto:
multilayer-perceptron
Su un progetto avente questo tipo, Maven esegue i goal definiti dal plugin in-
vece che quelli standard del lifecycle di default, cos`ı da effettuare l’addestra-
mento della rete neurale e, dopo aver terminato, testare le sue capacit`a di
generalizzazione.
Per abilitarne l’esecuzione, il plugin va dichiarato nella sezione riguardante
la build all’interno del descrittore di progetto pom.xml. Oltre alle sue coordi-
nate Maven, sono fondamentali la sua configurazione e le dipendenze a tempo
di esecuzione che gli vengono attribuite. La dichiarazione di dipendenze per
il plugin `e il meccanismo con cui altre librerie vengono aggiunte al classpath
e rese disponibili durante la sua esecuzione, lasciando a Maven il compito di
recuperarle automaticamente, da remoto se necessario.
Listing 1: dichiarazione del plugin per multilayer perceptron nel pom; le esten-
sioni del plugin sono abilitate per permettere l’override del lifecycle Maven con
il packaging multilayer-perceptron
1 <project>
2 ...
3 <packaging>multilayer-perceptron</packaging>
4 <build>
5 <plugins>
6 <plugin>
7 <groupId>dev.deadc0de.seshat</groupId>
8 <artifactId>multilayer-perceptron-maven-plugin</artifactId>
9 <version>0.2</version>
10 <extensions>true</extensions>
11 <configuration>
12 <!-- configurazione del plugin -->
13 </configuration>
14 <dependencies>
15 <!-- dipendenze da aggiungere durante l’esecuzione -->
16 </dependencies>
17 </plugin>
18 </plugins>
19 </build>
20 </project>
Oltre alla configurazione del plugin, nel progetto vanno inseriti file contenenti
le strutture dati con cui operare. Si tratta di fornire i descrittori dei multilayer
perceptron che si vogliono addestrare e gli esempi da utilizzare durante le fasi
di addestramento e di test. La disposizione di tali file segue la convenzione7
di
layout di un progetto Maven: i file contenenti il codice dell’applicativo vanno
collocati, a partire dalla root del progetto, nella cartella
src/main/source-type/
7 I parametri sono modificabili, tuttavia si incoraggia a mantenere la configurazione
predefinita come vuole il paradigma Convention over Configuration.
17
18. Project root
pom.xml
src
main
examples
examples-set-1.json
examples-set-2.json
multilayer-perceptron
network-a.json
network-b.json
network-c.json
test
examples
examples-set-3.json
examples-set-4.json
examples-set-5.json
Figura 4: possibile disposizione dei file all’interno di un progetto di multilayer
perceptron; nell’esempio il loro contenuto `e interpretato come json in quanto il
marshaller di default del plugin fa uso di tale formato
mentre per i test in
src/test/source-type/
La cartella da cui il plugin recupera i descrittori per le reti neurali da
addestrare `e multilayer-perceptron, mentre gli esempi sono cercati in
examples, sia nell’albero main che in quello di test. Un esempio di disposizio-
ne dei file in un progetto per multilayer perceptron `e rappresentato in Figura 4.
4.2 Addestramento
Il primo dei due goal definiti dal plugin `e train. Il suo compito `e caricare
la struttura del multilayer perceptron e gli esempi per fornirli all’algoritmo di
addestramento, dopodich´e persistere la nuova struttura con i pesi modificati.
La configurazione del goal di addestramento viene letta dal pom a partire
dal tag <trainingMethod>. Qui vengono specificati il tipo di algoritmo da
utilizzare, i suoi parametri e i collaboratori.
18
19. Listing 2: configurazione del servizio di training in cui vengono specificati tipo
e parametri dell’algoritmo e quali collaboratori utilizzare; tra questi la funzione
d’errore e il logger
1 <configuration>
2 <trainingMethod>
3 <name>batchBackPropagation</name>
4 <configuration>
5 <learningRate>0.001</learningRate>
6 <momentum>0.5</momentum>
7 <tolerance>0.1</tolerance>
8 <maximumIterations>1000</maximumIterations>
9 </configuration>
10 <collaborators>
11 <collaborator>
12 <role>errorFunction</role>
13 <name>meanSquaredError</name>
14 </collaborator>
15 <collaborator>
16 <role>logger</role>
17 <name>maven</name>
18 </collaborator>
19 </collaborators>
20 </trainingMethod>
21 ...
22 </configuration>
4.3 Test
Il secondo goal test carica un multilayer perceptron addestrato precedente-
mente da target/multilayer-perceptron/ e un insieme di esempi per
valutarne il livello di generalizzazione raggiunto dalla rete neurale. Di ogni
esempio viene calcolato l’output e confrontato con quello atteso: il test passa
se l’errore, calcolato con una funzione impostata, non supera una certa soglia
prestabilita. Al termine viene dato un resoconto del numero di test passati e
falliti.
Nonostante vi siano similitudini con i test unitari, la fase di test per un mul-
tilayer perceptron non prevede il fallimento della build in quanto generalmente
ci si aspetta un certo numero di esempi non riconosciuti.
Allo stesso modo del goal di addestramento, quello di test recupera dal pom
la propria configurazione a partire dal tag <test>.
Listing 3: configurazione del servizio di test con specificati la sua tipologia e
il logger da utilizzare
1 <configuration>
2 ...
3 <test>
4 <name>errorFunctio</name>
5 <configuration>
6 <tolerance>0.1</tolerance>
7 </configuration>
8 <collaborators>
9 <collaborator>
10 <role>errorFunction</role>
11 <name>meanSquaredError</name>
12 </collaborator>
13 <collaborator>
14 <role>logger</role>
15 <name>maven</name>
16 </collaborator>
17 </collaborators>
18 </test>
19 </configuration>
19
20. 4.4 Rappresentazione di multilayer perceptron
Per descrivere un’istanza di multilayer perceptron `e stata definita una struttura
dati versatile capace di rappresentare le informazioni con il massimo livello di
dettaglio ed avere un formato conciso nel caso pi`u generico. Ad esempio `e
possibile definire una funzione di attivazione diversa per ogni neurone, oppure
specificarne una sola per tutta la rete neurale, o ancora applicare certe funzioni
di attivazione solo ad alcuni neuroni mentre ai rimanenti viene assegnata quella
globale.
4.4.1 Funzioni di attivazione
L’entit`a base della struttura `e il servizio generico, inteso come funzione di
attivazione o come collaboratore. Un servizio `e definito da tre parametri:
name
Il nome del servizio rappresentato come stringa.
configuration
Una mappa di stringhe contenente i parametri che costituiscono i dati del
servizio. Pu`o non essere specificata se non vi sono parametri o se il servizio
prevede dei valori predefiniti.
collaborators
Una mappa che associa ricorsivamente altri oggetti di questo a dei ruoli,
come per la configurazione pu`o essere omessa.
Listing 4: definizione di una tangente iperbolica traslata nel tempo di 1
1 {
2 "name": "shift",
3 "configuration": {
4 "shift": "1.0"
5 },
6 "collaborators": {
7 "inner": {
8 "name": "tanh"
9 }
10 }
11 }
4.4.2 Neuroni
Il componente fondamentale di un multilayer perceptron `e il neurone, definito
attraverso i parametri:
function
Entit`a di tipo servizio che rappresenta la funzione di attivazione del neu-
rone. Se non specificata verr`a fatto riferimento ad una funzione definita a
un livello superiore.
bias
Livello di attivazione intrinseco del neurone che si somma alle sollecitazioni
dalle sinapsi, nullo se non specificato.
20
21. weights
Lista di pesi delle sinapsi che collegano il neurone a quelli del layer pre-
cedente. Se specificati la lunghezza della lista deve corrispondere con la
dimensione del layer precedente, mentre se omessi sono considerati nulli.
4.4.3 Layer
I neuroni sono aggregati in layer, la dimensione dei quali `e definita come il
numero di neuroni contenuti. Il formato di un layer presenta due alternative:
contenere le definizioni di ciascun neurone oppure specificare solo la propria
dimensione. Nel secondo caso tutti i pesi dei neuroni sono considerati nulli e
la funzione di attivazione `e quella globale. L’entit`a che definisce un layer `e
composta dai parametri:
function
Funzione di attivazione globale da usare come default per tutti i neuroni
contenuti nel layer.
neurons
Una lista contenente le entit`a dei neuroni che vanno a comporre il layer.
size
Specifica direttamente il numero di neuroni contenuti, attribuendogli pesi
nulli e funzione di attivazione globale. Se specificato assieme alla lista
di neuroni del punto precedente, il parametro viene ignorato in favore di
quello contenente maggiori dettagli.
4.4.4 Multilayer perceptron
Infine l’entit`a di pi`u alto livello `e il multilayer perceptron. Anche qui vi sono
due formati alternativi: uno consente di specificare ciascun layer mentre l’altro
permette di indicare unicamente le loro dimensioni. L’entit`a espone i seguenti
parametri:
function
Funzione di attivazione globale da usare dove n´e il neurone n´e il layer che
lo contiene ne abbiano specificata una.
sources
Numero di neuroni in ingresso, adibiti a ricevere la propria ativazione da
sorgenti esterne. Interpreta il ruolo dell’input layer, anche se i suoi neuroni
non possiedono una funzione di attivazione.
layers
Lista di layer che costituiscono il multilayer perceptron. Tutti i neuroni
di un layer devono avere, dove specificate, un numero di sinapsi pari alla
dimensione del layer precedente, o del numero di sorgenti se si tratta
del primo layer. La dimensione dell’ultimo layer definisce la dimensione
dell’output del multilayer perceptron.
sizes
Lista di dimensioni che i layer devono avere, i cui neuroni hanno pesi
nulli e funzione di attivazione globale. Se specificato assieme alla lista di
21
22. layer del punto precedente, il parametro viene ignorato in favore di quello
contenente maggiori dettagli.
In seguito `e riportato un documento json contenente un multilayer percep-
tron descritto usando la forma estesa della struttura dati, specificando i dettagli
di tutti i neuroni che lo compongono.
Listing 5: multilayer perceptron addestrato per riconoscere la funzione
booleana xor
1 {
2 "sources": 2,
3 "layers": [
4 {
5 "neurons": [
6 {
7 "function": { "name": "tanh" },
8 "bias": -1.1656643239012312,
9 "weights": [0.8590827611395182, 0.8583199921043884]
10 }, {
11 "function": { "name": "tanh" },
12 "bias": -0.4244875431029639,
13 "weights": [1.7354223753836655, 1.7325046953575243]
14 }
15 ]
16 }, {
17 "neurons": [
18 {
19 "function": { "name": "tanh" },
20 "bias": -0.6540816448579929,
21 "weights": [-1.730661310571226, 1.6476378061166113]
22 }
23 ]
24 }
25 ]
26 }
Quando interessa definire unicamente le dimensioni della rete neurale, ad
esempio per indicare la struttura della rete da addestrare, `e possibile utilizzare
la forma contratta.
Listing 6: multilayer perceptron formato da un hidden layer ed un output
layer avente come funzione di attivazione per tutti i suoi neuroni la tangente
iperbolica
1 {
2 "function": { "name": "tanh" },
3 "sources": 2,
4 "sizes": [2, 1]
5 }
22
23. 5 Servizi
I componenti fondamentali su cui si appoggia l’architettura del plugin Maven per
multilayer perceptron sono i servizi. Essi rappresentano singole unit`a funzionali
configurabili e componibili tra loro. In questo capitolo `e mostrato il modo in
cui vengono istanziati programmaticamente e come definire nuovi servizi.
Per evitare che librerie di reti neurali artificiali dipendano dal plugin nel-
l’esporre i propri oggetti come servizi, quest’ultimi non devono implementare
o estendere alcun componente del framework. In questo modo per`o ottenere
informazioni sulle loro caratteristiche e renderli utilizzabili `e possibile solo at-
traverso la costruzione di un layer che faccia da collante tra i servizi e il plugin.
Le definizioni dei servizi sono quindi delegate a factory che si occupano di attri-
buire loro un nome, un tipo, un insieme di parametri e dei ruoli di collaboratori
da cui un servizio dipende.
5.1 Motivazioni
Esistono gi`a librerie e framework che si occupano dell’inizializzazione di applica-
tion context, in cui gli oggetti di un’applicazione vengono composti in maniera
dichiarativa attraverso dependency injection e resi disponibili al suo avvio. Il
pi`u famoso tra quelli in ambiente Java `e il framework Spring8
.
Nelle prime fasi del progetto, Spring `e stato utilizzato per la creazione e
composizione dei servizi, ma la configurazione del progetto risultava prolissa,
complicata e troppo legata all’effettiva implementazione dei servizi. Era inoltre
impossibile definire dei collaboratori di default.
Come passaggio successivo sono state introdotte le factory, ma non `e sta-
to trovato un modo che permettesse al meccanismo di generazione di essere
configurato in maniera semplice.
Infine si `e optato per l’implementazione di una libreria dedicata al partico-
lare problema di inizializzazione di oggetti avente come obiettivi la minimizza-
zione della configurazione, da fornire all’application context per la generazione
di un servizio, e la semplicit`a di definizione delle factory, attraverso un mecca-
nismo dichiarativo di dependency injection e la possibilit`a di definire parametri
e collaboratori di default.
5.2 Identificazione e configurazione
Il tipo associato ad un servizio rappresenta la categoria a cui appartiene ed `e
definito come il tipo restituito dalla sua factory. Pu`o quindi essere un’interfaccia
che la classe del servizio implementa, una superclasse o la classe stessa.
Per distinguere servizi dello stesso tipo, ad ognuno di essi `e attribuito un
nome. Un servizio viene quindi univocamente identificato dal suo nome e dal
suo tipo.
Prima di poter essere utilizzato, il servizio potrebbe richiedere un’inizializ-
zazione con argomenti i cui valori vadano a formare il suo stato. Tali argomen-
ti possono essere puri dati, come numeri e stringhe, oppure oggetti dotati di
comportamento le cui funzionalit`a sono usate dal servizio.
I parametri sono i nomi attribuiti ai dati richiesti per l’inizializzazione, ed un
insieme di associazioni parametro-valore va a formare la configurazione del ser-
8 Spring: http://spring.io/
23
24. vizio. I collaboratori appartengono invece alla categoria di oggetti con compor-
tamento, utilizzabili attraverso l’associazione di ciascuno con un ruolo. Questi
oggetti sono a loro volta servizi.
5.3 Descrizione gerarchica
La composizione di servizi forma una struttura gerarchica ad albero dove nei
nodi si collocano nome, tipo e parametri, mentre i ruoli sono rappresentati dalle
relazioni genitore-figlio. Come foglie vi sono istanze di servizi con un livello di
astrazione sufficientemente basso da non richiedere collaboratori. Con questa
disposizione risulta semplice trasporre la gerarchia in un documento puramente
descrittivo.
In seguito `e mostrato l’oggetto necessario ad una factory per istanziare e
configurare il servizio.
Listing 7: un descrittore di servizio contiene il suo nome oltre ad una sua
configurazione e associazioni tra ruoli e altri descrittori di collaboratori
1 public class ServiceDescriptor {
2
3 public final String name;
4 public final Map<String, String> configuration;
5 public final Map<String, ServiceDescriptor> collaborators;
6 }
L’informazione riguardante il tipo `e assente, poich´e `e la factory a determi-
nare il tipo del servizio generato. Lo stesso vale per i tipi di eventuali colla-
boratori: ottenendo dal descrittore unicamente il nome vengono completate le
informazioni richieste per identificarli univocamente.
5.4 Generazione di servizi
Il compito per una factory di un servizio `e generare un’istanza dello stesso
a partire da un oggetto descrittivo, del tipo mostrato precedentemente. La
definizione di factory prevede un unico metodo create che usa la descrizione
fornita per istanziare un servizio.
Listing 8: una factory di servizi ha un unico metodo il cui compito `e generare
un’istanza a partire da un oggetto descrittore
1 public interface ServiceFactory<S> {
2
3 S create(ServiceDescriptor service);
4 }
Oltre ad applicare una configurazione, la factory deve interagire con altre per
richiedere la generazione dei collaboratori da iniettare nel servizio. Allo scopo
di rendere implicita la richiesta di generare i collaboratori necessari ad altre
factory, `e stato sviluppato un’application context che funga da intermediario
aggregando in un unico oggetto la funzionalit`a di generazione dei servizi.
Listing 9: application context che si occupa di generare servizi usando le
factory
1 public interface Context {
2
3 <S> S generate(Class<S> serviceType, ServiceDescriptor service);
4
5 <S> Map<String, ServiceFactory<S>> load(Class<S> serviceType);
6 }
24
25. L’application context pu`o quindi generare un servizio a partire dal suo tipo
e da un descrittore che ne descriva la composizione,
Listing 10: esempio di generazione di un servizio attraverso l’application
context
1 Context context = ...
2
3 Map<String, String> configuration = ...
4 Map<String, ServiceDescriptor> collaborators = ...
5 ServiceDescriptor trainingMethodDescriptor = new ServiceDescriptor(
6 "batchBackPropagation",
7 configuration,
8 collaborators
9 );
10
11 MultilayerPerceptronTrainingMethod trainingMethod = context.generate(
12 MultilayerPerceptronTrainingMethod.class,
13 trainingMethodDescriptor
14 );
Ciascuna factory necessita per`o di un riferimento all’application context per
poter generare collaboratori, e deve esporre il nome e il tipo del proprio servizio
in modo da poter essere recuperata quando richiesta. `E stato quindi aggiunto
un meccanismo di definizione delle factory attraverso una particolare scrittura
di metodi all’interno di classi di configurazione, per ridurre l’interazione espli-
cita tra factory nell’istanziazione dei collaboratori. La definizione di servizi
attraverso questo metodo `e spiegata nella sezione successiva.
5.5 Definizione di servizi
Attraverso la classe CofigurationContext, implementazione di application
context, la definizione delle factory assume una forma del tipo dell’esempio dato
nel listato sottostante.
Listing 11: definizione di factory per funzioni di attivazione
1 public class ActivationFunctionConfiguration implements Configuration {
2
3 public ActivationFunction tanh() {
4 return new HyperbolicTangent();
5 }
6
7 public ActivationFunction logistic() {
8 return new LogisticFunction();
9 }
10
11 public ActivationFunction scale(
12 @Role("inner") ActivationFunction inner,
13 @Parameter("scale")
14 @Parser(ParseDouble.class) @Default("1.0") Double scale) {
15 return new Scale(inner, scale);
16 }
17
18 public ActivationFunction shift(
19 @Role("inner") ActivationFunction inner,
20 @Parameter("shift")
21 @Parser(ParseDouble.class) @Default("0.0") Double shift) {
22 return new Shift(inner, shift);
23 }
24 }
Le factory cos`ı dichiarate sono interpretate nel seguente modo:
• il tipo di servizio `e rappresentato dal tipo restituito dal metodo;
• il nome corrisponde col nome del metodo;
• gli argomenti annotati con @Parameter vengono mappati in base al nome
specificato nell’annotazione;
25
26. • gli argomenti annotati con @Role vengono popolati con un collaboratore
del tipo dell’argomento;
• se un argomento ha come tipo Context, in questo viene passato l’appli-
cation context nel quale si trova la factory.
Inoltre `e possibile specificare un valore da utilizzare nel caso il parametro non
sia presente nella configurazione attraverso l’annotazione @Default. Essendo
i valori della configurazione unicamente stringhe, l’annotazione @Parser per-
mette di convertire automaticamente la stringa in un oggetto specificando la
classe con cui effettuare la trasformazione.
Attraverso l’uso di annotazioni e definendo ciascuna factory come un singolo
metodo risulta pi`u chiaro quale sia la sua parametrizzazione e pi`u semplice la
sua implementazione, lasciando all’application context il compito di istanziare
i suoi collaboratori.
5.6 Pubblicazione delle factory
Uno dei punti di forza del plugin Maven per multilayer perceptron `e la mo-
dularit`a dei servizi di cui pu`o disporre. In seguito viene brevemente spiegato
come le factory di servizi possono essere rese disponibili al plugin durante la sua
esecuzione.
5.6.1 Recupero delle configurazioni dal classpath
Vi sono diversi modi per caricare classi dal classpath conoscendo solo alcune
delle loro caratteristiche, come l’interfaccia implementata, un’annotazione o un
particolare pattern cotenuto nel nome della classe. Il plugin in particolare fa
uso della funzionalit`a fornita da ServiceLoader9
, appartenente a libreria
standard Java. Per dichiarare dei servizi10
di un determinato tipo, si aggiunge
nel percorso META-INF/services/ del jar un file che abbia per nome quello
completo della classe in questione, comprensivo del package in cui `e contenuta.
All’interno del file si possono specificare i nomi, sempre includendo il package di
appartenenza, delle classi che implementano o estendono il suddetto tipo, con
la restrizione che abbiano il costruttore vuoto.
Utilizzando il metodo load di ServiceLoader, passando come parametro
la classe del servizio, viene restituita la sequenza delle istanze di tutte le classi
dichiarate all’interno del rispettivo file.
Le classi sviluppate seguendo la convenzione di ConfigurationContext,
delle quali ogni metodo viene trasformato in factory, non hanno per`o alcun
elemento distintivo che le renda caricabili attraverso ServiceLoader. Nella
libreria dei servizi `e stata definita appositamente l’interfaccia Configuration
pensata per il ruolo di marker interface11
, da far implementare a tutte le classi di
configurazione che definiscono al loro interno metodi per factory. Si possono cos`ı
esporre al ServiceLoader le classi di configurazione che si intende esportare.
9 Per maggiori informazioni sul funzionamento di ServiceLoader si consulti la
documentazione Java.
http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html
10 In questo caso il termine servizi non si rifrisce a quelli delle sezioni precedenti, ma alle
classi caricate attraverso ServiceLoader (in questo caso le factory).
11 Una marker interface `e un’interfaccia, solitamente priva di metodi, il cui scopo `e aggiun-
gere metadati alla classe che la implementa. Il ruolo delle marker interface `e stato in seguito
preso in carico dalle annotazioni, ma nella libreria standard sono ancora presenti. Ad esempio
sono dei marker le interfacce Serializable e Cloenable.
26
27. Oltre a caricare tutte le implementazioni di Configuration, il plugin iniet-
ta nel context di cui fa uso una sua classe di configurazione contenente factory
strettamente correlate al suo funzioamento. Ad esempio `e presente come servizio
un adapter per il logger di Maven.
5.6.2 Recupero delle librerie
Alcune librerie di reti neurali artificali di terze parti si trovano gi`a in Maven
Central. Prima che il plugin per multilayer perceptron raggiunga una maturit`a
tale da poter essere caricato nel repository centrale, `e possibile eseguirlo instal-
landolo localmente12
o su un repository Nexus. Lo stesso vale per le librerie di
servizi.
5.7 Organizzazione delle dipendenze per il plugin Maven
per multilayer perceptron
Per disaccoppiare il plugin Maven dalle implementazioni di servizi, le interfacce e
gli oggetti rappresentanti dati sono stati inseriti in librerie separate dall’artefatto
del plugin. Inoltre sono stati divisi tra due librerie distinte, una per gli elementi
riguardanti le definizioni generali di factory e servizi, l’altra contenente tipi
specializzati per i multilayer perceptron. In questo modo viene resa disponibile
l’astrazione dei servizi ad altre librerie e plugin per altre tipologie di reti neurali
artificiali.
Alle due librerie fanno riferimento anche tutti gli artefatti contenenti fac-
tory. Questi possono contenere al loro interno le implementazioni dei servizi,
come la libreria di built-in fornita col plugin per i servizi base, oppure essere di
adattamento per librerie gi`a esistenti.
Nel descrittore di progetto, tra le dipendenze del plugin `e sufficiente indicare
l’artefatto contenente le factory, in quanto le dipendenze transitive sono risolte
automaticamente da Maven. `E necessario per`o che tutte le dipendenze siano
reperibili in almeno uno dei repository che si vanno ad utilizzare.
12 Clonando i sorgenti ed eseguendo il comando mvn install nella home del progetto.
27
29. 6 Risultati sperimentali
In questa sezione `e riportato come sia stato eseguito l’addestramento di un
multilayer perceptron per il riconoscimento di lettere prounciate dell’alfabeto
inglese. La rete neurale classifica una lettera attivando maggiormente uno tra i
suoi 26 nodi di output, secondo l’ordine alfabetico.
I risultati ottenuti servono poi come riferimento per il paragone tra multilayer
perceptron e le altre tipologie di reti utilizzate: Hidden Markov Model e serie
di Volterra.
6.1 Dominio di apprendimento
Gli esempi di lettere pronunciate sono divisi in un insieme di addestramento
e uno di test. In quello di addestramento sono presenti per ogni lettera 10
pronunce effettuate dalla setssa persona. Sono presenti gli alfabeti pronunciati
da 16 persone diverse, di cui 8 donne e 8 uomini, per un totale di 4.160 esempi.
Nell’insieme di test vi sono le pronunce delle stesse persone, ma diverse da quelle
dell’insieme di addestramento e in numero di 16, per un totale di 6.656 esempi.
Alla rete neurale in questione non sono dati in input le ampiezze del segnale
campionato rappresentante la pronuncia di una lettera, ma ciascun esempio
viene preprocessato come segue.
1. In primo luogo la registrazione viene troncata in testa e in coda per
rimuovere le parti che non comprendono il segnale d’interesse.
2. Per omogenizzare la dimensione dei segnali, questi vengono espansi o
compressi per avere la durata di un secondo.
3. Come ultimo passaggio vengono estratti i coefficienti cepstrali di ciascun
segnale, suddividendolo in 50 frame e prendendo 12 coefficienti per frame,
per un totale di 600 coefficienti cepstrali per segnale.
Il vettore contenente i 600 coefficienti cepstrali `e infine utilizzato come esem-
pio per l’addestramento o per il test del multilayer perceptron, inserito all’in-
terno del progetto in formato json.
6.2 Scelta della funzione d’errore
In un articolo, A. Waibel introduce una funzione d’errore che pi`u si adatta
al riconoscimento di un dato insieme di suoni rispettio alla classica funzione
di errore MSE13
. Il MSE compara i livelli di attivazione dell’output della rete
neurale con quelli di un insieme ideale di attivazioni per un dato stimolo in input.
L’obiettivo in questo caso `e minimizzare ciascuna differenza per raggiungere la
corrispodenza tra attivazioni dell’output e quelle ideali.
La funzione introdotta, chiamata Classification Figure of Merit (CFM), usa
invece le attivazioni ideali solo per identificare il nodo di output corrispondente
con la classificazione corretta. La funzione CFM cerca quindi di massimizzare
la differenza tra l’attivazione del nodo corretto e quelle di tutti gli altri nodi.
13 Errore quadratico medio, dall’Inglese Mean Squared Error.
29
30. La funzione CFM `e definita come
CFM =
1
N − 1
·
N
n=1
n=c
α
1 + e−(β∆n−γ)
(13)
dove
• ∆n = Oc − On
• Oc `e il livello di attivazione del nodo relativo alla corretta classificazione
c (1 per a, 2 per b, ecc. . . )
• On `e il livello di attivazione del nodo n relativo ad una classificazione
sbagliata
• N `e il numero di classi (in questo caso le 26 lettere dell’alfabeto inglese)
• α `e l’ampiezza della sigmoide
• β `e la rapidit`a con cui la sigmoide cresce, detta anche discontinuit`a della
sigmoide
• γ `e il ritardo della sigmoide, che causa uno scostamento laterale del grafico
verso destra quando positivo
Le derivate parziali rispetto all’output, necessarie per il metodo di discesa
del gradiente, sono date da
∂CFM
∂On
=
−αβ
N − 1
· yn(1 − yn) (14)
∂CFM
∂Oc
=
αβ
N − 1
·
N
n=1
n=c
yn(1 − yn) (15)
dove yn `e la sigmoide
yn =
1
1 + e−(β∆n−γ)
(16)
Poich´e l’obiettivo della funzione CFM `e massimizzare la differenza tra livello
di attivazione del nodo corretto e quelli dei restanti nodi, va utilizzata invertendo
la variabile ∆n affinch´e porti a scendere anzich´e salire lungo il gradiente.
La funzione CFM cos`ı definita `e monotona solo per N = 2, mentre per N ≥ 3
`e necessario applicare una modifica, ponendo
CFMM = CFMn(min ∆n) (17)
dove
CFMn(∆) =
α
1 + e−(β∆n−γ)
(18)
che rende la funzione monotona per output di dimensione maggiore di due, ma
riduce la rapidit`a della ricerca del minimo in quanto produce un gradiente di
magnitudine minore rispetto all’Equazione 13.
30
31. 6.3 Topologia del multilayer perceptron
La dimensione dell’input layer `e quella corrispondente al numero di coefficienti
cepstrali calcolati per ciascun esempio, ovvero 600. L’output layer contiene 26
nodi, ognuno associato ad una lettera dell’alfabeto inglese.
Le quantit`a di hidden layer e le loro rispettive dimensioni sono state ottenute
per prove successive, e i risultati di maggior generalizzazione sono stati ottenuti
utilizzando un multilayer perceptron con due hidden layer rispettivamente di
140 e 80 neuroni.
Listing 12: topologia finale del multilayer perceptron
1 {
2 "function":{"name":"tanh"},
3 "sources":600,
4 "sizes":[140,80,26]
5 }
Per l’addestramento `e stato usato l’algoritmo di batch back propagation, con
i parametri contenuti nella seguente configurazione.
Listing 13: parametrizzazione dell’addestramento
1 <configuration>
2 <trainingMethod>
3 <name>batchBackPropagation</name>
4 <configuration>
5 <learningRate>0.005</learningRate>
6 <tolerance>0.15</tolerance>
7 <momentum>0.5</momentum>
8 <maximumIterations>1000</maximumIterations>
9 </configuration>
10 <collaborators>
11 <collaborator>
12 <role>errorFunction</role>
13 <name>classificationFigureOfMerit</name>
14 </collaborator>
15 <collaborator>
16 <role>logger</role>
17 <name>maven</name>
18 </collaborator>
19 </collaborators>
20 </trainingMethod>
21 <test>
22 <name>maximumActivation</name>
23 <collaborators>
24 <collaborator>
25 <role>logger</role>
26 <name>maven</name>
27 </collaborator>
28 </collaborators>
29 </test>
30 </configuration>
6.4 Risultati dell’addestramento
La funzione di test usata verifica quale sia il nodo col livello di attivazione
pi`u alto, determinando un successo se `e quello associato alla lettera corretta.
Il multilayer perceptron col quale si `e raggiunto il maggior numero di esempi
riconosciuti ne ha classificati correttamente 4.525 su 6.586, circa il 68.72%.14
In seguito si riportano i dati per le singole lettere.
14 Il numero di esempi di test `e minore di quello riportato in precedenza in quanto alcuni file
sono mancanti ed altri hanno causato errori nel processo di estrazione dei coefficienti cepstrali.
31
32. A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 %
10 %
20 %
30 %
40 %
50 %
60 %
70 %
80 %
90 %
100 %
Percentualediclassificazionicorrette
Nella Tabella 1 `e riportata invece la matrice di confusione di questa rete
neurale.
32
34. 7 Modelli di Markov nascosti (HMM)
Il metodo statistico maggiormente utilizzato per caratterizzare le propriet`a spet-
trali dei segnali acustici, in particolare vocali, `e il modello di Markov nascosto
(HMM, dall’inglese Hidden Markov Model). L’idea su cui si fonda l’uso di un
sistema statistico, di questo o di altro tipo, `e che i segnali possano essere op-
portunamente modellizzati da un processo parametrico casuale, i cui parametri
possano essere stimati con una certa precisione.
7.1 Introduzione ai processi stocastici
Per la classificazione di sorgenti sonore, mediante l’analisi di segnali divisi in
blocchi, `e possibile utilizzare i processi stocastici tempo discreti. In quest’ambito
il modello pi`u semplice `e rappresentato dai processi di Markov, da cui gli HMM
derivano.
Processi di Markov tempo discreti
Si consideri un sistema descrivibile, ad ogni istante, con lo stato in cui si trova, ci
siano N stati distinti {1, 2, . . . , N}. Ad istanti di tempo regolarmente spaziati, il
sistema subisce un cambiamento di stato (ma pu`o esser preso in considerazione
anche il caso che rimanga nello stesso) in accordo ad un insieme di probabilit`a
associate allo stato di partenza. Gli istanti di tempo associati alle variazioni
di stato possono essere indicati con t = 1, 2, . . . e lo stato attuale al tempo
t con qt. Una descrizione probabilistica completa del sistema richiederebbe la
specificazione dello stato corrente e di tutti quelli precedenti. Nel caso che
questa descrizione possa venir troncata allo stato presente e ad un solo stato
precedente, il sistema prende il nome di catena o processo di Markov discreto
del primo ordine. In altri termini:
P[qt = j|qt−1 = i, qt−2 = k, . . . ] = P[qt = j|qt−1 = i] (19)
Inoltre considerando i soli processi dove il secondo membro dell’equazione 19 `e
indipendente dal tempo, si arriva ad un insieme di probabilit`a di transizione di
stato aij della forma:
aij = P[qt = j|qt−1 = i] con 1 ≤ i, j ≤ N (20)
e che soddisfano alle seguenti propriet`a:
aij ≥ 0 ∀i, j e
N
j=1
aij = 1 ∀i (21)
in quanto obbediscono alle costrizioni stocastiche standard. Il processo stoca-
stico visto pu`o essere chiamato modello di Markov osservabile, in quanto la sua
uscita coincide con lo stato al particolare istante di tempo, ed ogni stato cor-
risponde ad un evento osservabile. In figura 6 viene riportato l’esempio di una
catena di Markov a 4 stati.
34
35. 1
2
3
4
a11
a14
a41
a13
a33
a32a21
a22
Figura 6: Catena di Markov a 4 stati
Modelli di Markov nascosti (HMM)
Finora si sono considerati modelli di Markov nei quali ogni stato corrispon-
deva ad un evento osservabile; questi processi risultano inadatti ai fini della
modellizzazione di molti problemi di interesse pratico. Risulta quindi neces-
sario estendere la trattazione per includere il caso nel quale l’osservazione `e
una funzione probabilistica dello stato, cio`e il modello risultante `e un processo
doppiamente stocastico. In questi casi vi sono due processi, uno visibile ed uno
nascosto, che pu`o essere osservato solo attraverso un altro insieme di processi
stocastici che producono la sequenza di osservazione.
Esempio
Un classico esempio usato per spiegare la definizione dei modelli di Markov
nascosti `e il modello ad urne e palline. Ci siano N urne in una stanza, con-
tenenti un grande numero di palline colorate, e siano M i colori distinti che le
palline possono assumere. Si pu`o pensare che il processo fisico per ottenere le
osservazioni sia il seguente:
1. Con una procedura casuale viene scelta un’urna e da tale urna viene
prelevata una pallina a caso. Il colore `e registrato come osservazione.
2. La pallina viene rimessa nell’urna e, a meno che non si voglia terminare
cos`ı le osservazioni, si ripete il passo 1.
Questo processo genera una sequenza finita di colori che si possono pensare come
l’uscita di un HMM. Un possibile HMM che modellizza il sistema urne-palline
`e quello nel quale ogni stato corrisponde ad una specifica urna e, ad ogni stato,
sono associate tante probabilit`a quanti sono i colori che la pallina pu`o assume-
re. Siccome `e possibile ritrovare gli stessi colori in tutte la urne a disposizione,
l’unica differenza `e la quantit`a di palline presenti relativamente ai vari colori.
Un’osservazione isolata di una particolare pallina colorata non dice nulla sul-
l’urna da cui `e stata estratta, ma `e possibile fare delle ipotesi probabilistiche.
Si pu`o pensare ad un esperimento in cui una persona estrae una serie di palline
dalle urne, scegliendo quest’ultime a caso di volta in volta, e annota il colore
delle palline, ma non le urne dalle quali vengono estratte. Dai dati registrati
35
36. sarebbe possibile indovinare, in termini probabilistici, la sequenza con la qua-
le sono state scelte le urne. Sarebbe, cio`e, possibile estrarre informazioni sul
processo nascosto “scelta dell’urna” tramite il processo osservabile “estrazione
della pallina colorata”.
Formalizzazione
L’esempio visto d`a un’idea di cosa sia un HMM e di come possa essere applicato
ad alcune semplici situazioni. Un modello di Markov nascosto, per osservazioni
di simboli discreti, `e caratterizzato dai seguenti aspetti:
• N, il numero di stati del modello. Sebbene gli stati siano nascosti, per
molte applicazioni pratiche vi `e un significato fisico attribuito agli stati o
agli insiemi di stati del modello. Solitamente gli stati sono interconnessi in
modo tale che qualsiasi stato possa essere raggiunto da qualsiasi altro. Ci
sono comunque altre possibili connessioni interessanti anche nel campo del
riconoscimento vocale. I singoli stati si possono indicare con {1, 2, . . . , N}
e lo stato al tempo t con qt.
• M, il numero di simboli distinti d’osservazione per stato. I simboli d’osser-
vazione corrispondono all’uscita fisica del sistema che viene modellizzato.
I simboli individuali si possono denotare con V = {v1, v2, . . . , vM }.
• A = {aij}, l’insieme delle probabilit`a delle transizioni di stato, dove aij =
P[qt+1 = j|qt = i] con 1 ≤ i, j ≤ N. Nel caso particolare in cui ogni
stato `e raggiungibile da ogni altro in un singolo passo (modello ergodico),
avremo aij > 0 ∀i, j. Per altri tipi di HMM avremo aij = 0 per una o
pi`u coppie i, j.
• B = {bj(k)}, l’insieme delle distribuzioni di probabilit`a dei simboli d’os-
servazione, dove bj(k) = P[Ot = vk|qt = j] `e la probabilit`a che lo stato j
produca il simbolo k.
• π = {πi}, la distribuzione dello stato iniziale, dove πi = P[q1 = i] con
1 ≤ i ≤ N.
Si osserva quindi che, per una completa descrizione di un HMM, `e necessa-
rio specificare i parametri N e M, dire quali sono i simboli di osservazione e
specificare i tre insiemi di distribuzione della probabilit`a A, B, π. Per indicare
appropriatamente un modello `e possibile utilizzare una notazione compatta del
tipo λ = (A, B, π).
Dati tutti i parametri che lo caratterizzano, un HMM pu`o essere visto come
un generatore che fornisce una sequenza di osservazione O = (o1, o2, . . . , oT ),
dove ot `e uno dei simboli dell’insieme V , e T `e il numero di osservazioni della
sequenza. La procedura di generazione pu`o essere schematizzata nei seguenti
punti:
1. Scelta dello stato iniziale q1 in accordo con π.
2. Impostazione di t a 1.
3. Scelta di ot = vk in accordo alla bi(k).
4. Passaggio al prossimo stato secondo le aij.
36
37. 5. Se t < T, allora incremento di t e ritorno al passo 3, altrimenti fine della
procedura.
Tale procedura pu`o essere usata anche come modello, per comprendere come
una data sequenza di osservazione sia stata generata.
7.2 I tre problemi principali degli HMM
Per l’utilizzo pratico degli HMM sorgono tre problemi basilari da risolvere:
1. Data la sequenza di osservazione O = (o1, o2, . . . , oT ) e un modello λ =
(A, B, π), com’`e possibile calcolare efficientemente la quantit`a P(O|λ), cio`e
la probabilit`a che la sequenza O sia stata prodotta dal modello λ?
2. Data la sequenza di osservazione O = (o1, o2, . . . , oT ) e un modello λ =
(A, B, π), com’`e possibile scegliere una corrispondente sequenza di stati
q = (q1, q2, . . . , qT ) che sia ottima secondo certi criteri scelti?
3. Com’`e possibile aggiustare i parametri del modello λ = (A, B, π) in modo
da massimizzare P(O|λ), data una certa O?
7.2.1 Il primo problema
Calcolo diretto di P(O|λ)
Il metodo pi`u semplice e diretto per risolvere il primo problema `e l’enu-
merazione di tutte le possibili sequenze di stati di lunghezza T. Tuttavia
il calcolo diretto di P(O|λ) richiede circa 2 T NT
operazioni. Tale calcolo
diventa inaccessibile anche per piccoli valori di N ed `e dunque necessario
l’uso di procedure pi`u efficienti.
Forward-backward procedure
Un sistema efficace per il calcolo di P(O|λ) si basa sulla cosidetta procedura
in avanti o forward procedure. Si pu`o definire una variabile forward nel
seguente modo:
αt(i) = P(o1o2 . . . ot, qt = i|λ) (22)
Basandosi su questa definizione `e possibile elaborare un algoritmo indut-
tivo per il calcolo di P(O|λ):
1. Inizializzazione: α1(i) = π bi(o1) con 1 ≤ i ≤ N
2. Induzione: αt+1(j) =
N
i=1
αt(i) aij bj(ot+1)
con 1 ≤ t ≤ T − 1 e 1 ≤ j ≤ N
3. Conclusione: P(O|λ) =
N
i=1
αT (i)
37
38. Backward procedure
Un’altra tecnica utilizzabile per il calcolo di P(O|λ) `e basata sulla pro-
cedura all’indietro o backward procedure. La variabile backward βt(i) `e
definibile nel seguente modo:
βt(i) = P(ot+1ot+2 . . . oT |qt = i, λ) (23)
Data questa definizione, il procedimento ricorsivo per il calcolo di P(O|λ)
pu`o essere impostato come segue:
1. Inizializzazione: βT (i) = 1 con 1 ≤ i ≤ N
2. Induzione: βt(i) =
N
j=1
aij bj(ot+1) βt+1(j)
con t = T − 1, T − 2, . . . , 1 e 1 ≤ i ≤ N
3. Conclusione: P(O|λ) =
N
i=1
π bi(o1) β1(i)
Anche in questo caso l’ordine computazionale dell’algoritmo `e di sole N2
T
operazioni.
7.2.2 Il secondo problema
Per il secondo problema non esiste una soluzione esatta, ma un ventaglio di pos-
sibili risultati che dipendono dai criteri di ottimalit`a scelti. Il criterio pi`u usato
consiste nel trovare la migliore sequenza di stati (percorso) ossia massimizzare
P(q|O, λ), che `e equivalente a massimizzare P(q, O|λ). Una tecnica formale per
trovare questa sequenza di stati, basata sulla programmazione dinamica, `e l’al-
goritmo di Viterbi.
7.2.3 Il terzo problema
Il terzo e di gran lunga il pi`u difficile problema degli HMM `e la determinazione
di un metodo per ricalcolare i parametri del modello λ = (A, B, π), con lo scopo
di massimizzare P(O|λ). Non esiste nessun metodo per trovare analiticamente
l’insieme dei parametri del modello, in modo da massimizzare in forma stretta
la probabilit`a della sequenza di osservazione partendo da un insieme finito di
dati di addestramento. `E possibile, invece, scegliere un modello λ = (A, B, π)
tale che la probabilit`a P(O|λ) sia massimizzata localmente. Un metodo di ot-
timizzazione utilizzabile `e noto come algoritmo di Baum-Welch ed `e un proce-
dimento iterativo che ristima i parametri del modello usando la minimizzazione
del gradiente.
Le formule per la ristima dei parametri di un HMM, sono:
πj = γ1(j) (Frequenza attesa dello stato j all’istante t = 1) (24)
38
39. aij =
Numero atteso di transizioni dallo stato i allo stato j
Numero atteso di transizioni dallo stato i
=
T −1
t=1
ξt(i, j)
T −1
t=1
γt(i)
(25)
bj(k) =
Frequenza attesa dello stato j e simbolo vk
Frequenza attesa dello stato j
=
t:ot=vk
γt(j)
T
t=1
γt(j)
(26)
dove
ξt(i, j) =
P(qt = i, qt+1 = j, O|λ)
P(O|λ)
=
αt(i) aij bj(ot+1) βt+1(j)
P(O|λ)
=
αt(i) aij bj(ot+1) βt+1(j)
N
i=1
N
j=1
αt(i) aij bj(ot+1) βt+1(j)
(27)
e
γt(i) =
N
j=1
ξt(i, j) (28)
Utilizzando iterativamente la procedura descritta, usando λρ al posto di
λ e ripetendo il calcolo delle restime, `e possibile migliorare P(O|λ) fino al
raggiungimento del punto limite.
7.3 Risultati sperimentali
L’addestramento di un modello di Markov discreto, utilizzando 8 stati, ha dato
come risultato la capacit`a di classificazione riportata nel successivo grafico.
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 %
10 %
20 %
30 %
40 %
50 %
60 %
Percentualediclassificazionicorrette
Nella Tabella 2 `e riportata la matrice di confusione del HMM addestrato.
39
41. 8 Volterra vs. NN
In un sistema lineare, si pu`o sempre definire una risposta impulsiva h(t) che
relaziona, tramite un integrale di convoluzione, il segnale di ingresso x(t) con il
segnale di uscita y(t):
y(t) =
+∞
−∞
h(τ)x(t − τ)dτ (29)
Naturalmente questo viene interpretato nel seguente modo: l’uscita y(t) `e da-
ta dalla composizione degli effetti dell’ingresso x(t) in tutti gli istanti precedenti,
pesati tramite una funzione peso h(t) denominata risposta impulsiva.
Nel caso di sistemi non lineari, Norbert Wiener pens`o di estendere la pre-
cedente relazione utilizzando la serie funzionale di Volterra, ovvero esprimendo
l’uscita y(t) come una serie di funzioni (integrali):
y(t) =
+∞
−∞
h1(τ)x(t − τ)dτ+
+∞
−∞
h2(τ1, τ2)x(t − τ1)x(t − τ2)dτ1dτ2+
+∞
−∞
h3(τ1, τ2, τ3)x(t − τ1)x(t − τ2)x(t − τ3)dτ1dτ2dτ3 + . . . (30)
Questa serie, detta ‘serie di Volterra’, converge alla soluzione sotto ipotesi nor-
malmente verificate. Le funzioni hn(dτ1, dτ2, ..., dτn) possono essere viste come
le risposte impulsive non lineari di ordine n e vengono chiamate Nuclei (kernel)
di Volterra. L’espansione a tempo discreto e memoria limitata diventa perci`o:
y(t) =
+∞
−∞
h1(l)x(t − l)+
+∞
−∞
+∞
−∞
h2(l1, l2)x(t − l1)x(t − l2)+
+∞
−∞
+∞
−∞
+∞
−∞
h3(l1, l2, l3)x(t − l1)x(t − l2)x(t − l3) + . . . (31)
Consideriamo ora un neurone artificiale feedforward time delay. Per sem-
plificare consideriamo una rete con cinque ingressi. Se rappresentiamo la non
linearit`a con una sigmoide, allora g(x) = (1 + e−x
)−1
. Se la rappresentia-
mo con la tangente iperbolica, allora g(x) = ex
−e−x
ex+e−x . In ogni caso, abbiamo
y(n) = g(
4
i=0 wix(n − i)). Introduciamo ora una approssimazione polinomiale
della nonlinearit`a. Si pu`o verificare che una buona approssimazione polinomiale
tra -4 e 4 `e data da un polinomio di terzo grado: g(x) ≈ a3x3
+a2x2
+a1x+a0.
Quindi:
y(n) = a3[
4
i=0 wix(n−i)]3
+a2[
4
i=0 wix(n−i)]2
+a1[
4
i=0 wix(n−i)]+a0 =
a3
4
i
4
j
4
k wiwjwkx(n − i)x(n − j)x(n − k) + a2
4
i
4
j wiwjx(n − i)x(n −
j) + a1
4
i wix(n − i) + a0 che `e una serie discreta di Volterra non lineare nei
coefficienti.
41
42. Figura 7: Neurone artificile
Lo stesso tipo di approssimazione si ha quando consideriamo una intera rete
neurale, visualizzata nella seguente figura. Naturalmente ogni nodo della figura
rappresenta una sommatoria e una nonlinearit`a.
Figura 8: Semplice rete neurale time delayed
Questa rete `e descritta dalle relazioni:
y(n) = f[
i
qi5zi(n)]
zj(n) = f[
i
wijx(n − i)]
Assumiamo ora che non ci sia nonlinearit`a sull’ultimo neurone ma solo sullo
strato intermedio. Allora le equazioni diventano:
y(n) =
j
qj5zj(n)
42
43. zj(n) = f[
i
wijx(n − i)] =
= a3[
i
wijx(n − i)]3
+ a2[
i
wijx(n − i)]2
+ a1
i
wijx(n − i) + a0 =
= a3
i k l
wijwkjwljx(n−i)x(n−k)x(n−l)+a2
i k
wijwkjx(n−i)x(n−k)+
+a1
i
wijx(n − i)
Quindi:
y(n) =
j
qj5zj(n) =
j
qj5a3
i k l
wijwkjwljx(n − i)x(n − k)x(n − l)+
+
j
qj5a2
i k
wijwkjx(n − i)x(n − k) +
j
qj5a1
i
wijx(n − i) =
=
i k l j
qj5a3wijwkjwljx(n − i)x(n − k)x(n − l)+
+
i k j
qj5a2wijwkjx(n − i)x(n − k) +
i j
qj5a1wijx(n − i) (32)
In conclusione, Il calcolo della rete neurale di Figura 8 equivale approssima-
tivamente al calcolo di una serie discreta di Volterra del terzo ordine. La serie
di Volterra non pu`o essere tuttavia usata per stimare i pesi della rete. Tuttavia
se si inglobano i coefficienti e si stimano con una tecnica adattativa, il risultato
dovrebbe essere lo stesso. Il vantaggio `e che la stima dei coefficienti della serie di
Volterra `e velocissima nel caso che si consideri una serie lineare nei coefficienti.
Per provare quanto detto, `e stato realizzato un sistema come illustrato nella
seguente figura.
Figura 9: Sistema adattativo realizzato
43
44. Il sistema `e stato provato nel contesto del riconoscimento delle lettere del-
l’alfabeto pronunciate a voce. Per motivi di tempo `e stata fatta una prova
limitata ad alcune lettere. Inoltre `e stata provata una serie di Volterra del se-
condo ordine, non del terzo. In sintesi, l’uso del sistema `e stato il seguente: per
ogni lettera `e stata stimata una serie di Volterra fornendo in ingresso il segnale
corrispondente alla lettera e un segnale desiderato pari a 1. In questo modo
i coefficienti della serie venivano stimati in modo tale da fornire in uscita un
valore elevato, mentre per tutte le altre lettere veniva fornito un segnale nega-
tivo. Pur nel contesto molto limitato che `e stato provato, i risultati sono stati
le seguenti percentuali di riconoscimento delle lettere.
A B C D E F G H
0 %
10 %
20 %
30 %
40 %
50 %
60 %
Percentualediclassificazionicorrette
44
45. 9 Conclusioni
Non tutti gli obiettivi citati nell’introduzione della tesi sono stati raggiunti. Dei
tre plugin preventivati, solo quello per multilayer perceptron `e stato portato a
termine e di quello per HMM `e stata implementata una versione incompleta.
Gli addestramenti su HMM e serie di Volterra sono stati eseguiti attraverso
un’implementazione in C dei relativi algoritmi di addestramento.
9.1 Risultati ottenuti
Il modello di multilayer perceptron si `e rivelato essere superiore, come qua-
lit`a della classificazione, a quello di Hidden Markov Model. I risultati sono
comparati nel seguente grafico.
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 %
10 %
20 %
30 %
40 %
50 %
60 %
70 %
80 %
90 %
100 %
Percentualediclassificazionicorrette
Multilayer Perceptron
Hidden Markov Model
Il lavoro riguardante i sistemi volterriani necessita ancora di approfondimenti
che, per motivi di tempo, non si sono potuti portare a termine.
9.2 Vantaggi dovuti all’uso di Maven
Il plugin sviluppato ha semplificato il processo di addestramento di multilayer
perceptron. `E stato possibile installare il plugin e le librerie su diverse macchi-
ne su cui si trovasse Maven clonando i sorgenti ed eseguendo il comando mvn
install, rendendo immediatamente disponibile l’ambiente di addestramento.
Alla prima esecuzione del plugin, le dipendenze ancora mancanti vengono scari-
cate ed installate nel repository locale, senza dover preoccuparsi di recuperarle
manualmente.
Il progetto di multilayer perceptron presentato nella Sezione 6 non `e stato
l’unico. Sono state addestrate anche reti a singolo neurone di output per il
riconoscimento di un’unica lettera, dando responso negativo nel caso di una
delle altre venticinque, per le quali si `e dovuto unicamente cambiare i valori di
output atteso per ciascun esempio.
45
46. Alcuni di questi progetti sono stati gestiti dallo strumento di continuous
integration Jenkins, menzionato nella Sezione 1.3. Gli addestramenti vengono
avviati manualmente attraverso l’interfaccia web del tool, oppure in risposta
ad aggiornamenti dei repository Mercurial remoti in cui sono versionati i vari
progetti. Al termine di ogni addestramento viene avviato uno step aggiuntivo
per copiare la rete neurale addestrata in una cartella differente. Per gli adde-
stramenti pi`u lunghi, al termine della build viene fatta inviare una notifica via
mail includendo i log dell’esecuzione con i risultati dei test.
La possibilit`a di definire e integrare nuovi servizi pu`o permettere l’integra-
zione con tool esistenti o di svilupparne di nuovi. Utilizzando un logger che
scrive su file in formato csv, `e stata creata una semplice pagina web che mostra
l’avanzamento dell’addestramento, attraverso un grafico rappresentante l’errore
in una data iterazione.
Figura 10: semplice implementazione di una pagina web che mostra l’avanza-
mento dell’addestramento, i cui dati vengono recuperati da un file csv scritto
da un apposito logger
9.3 Sviluppi futuri
Modularizzazione degli artefatti
Oltre al plugin per multilayer perceptron, alcuni sviluppi sono stati fatti su
plugin per HMM e serie di Volterra. `E risultato che, per riutilizzare parte
delle componenti sviluppate per il primo plugin, la libreria contenente le
interfacce dei servizi per multilayer perceptron deve essere frammentata.
Infatti risulta conveniente che funzioni, marshaller e altre tipologie di ser-
vizi non strettamente legate ai multilayer perceptron risiedano in artefatti
separati.
Generalizzazione del plugin
I servizi come metodi di addestramento o di test sono stati legati ad uti-
lizzare l’oggetto MultilayerPerceptronDescriptor come formato
si scambio, passato esplicitamente ai servizi generati da parte del plugin.
Aggiungendo un servizio che racchiuda questa particolare implementazio-
ne `e possibile astrarre il plugin in modo tale che possa eseguire qualsiasi
46
47. metodo di addestramento, senza dover limitarsi all’ambito dei multilayer
perceptron.
Questo suggerisce che una possibile estensione del framework vada, in-
vece che in direzione dello sviluppo di molteplici plugin, in quella nella
generalizzazione di quello attuale.
Servizi integrati
Al momento della stesura di questa tesi, l’unico caso di servizio fornito
direttamente dal plugin `e l’implementazione di un logger che delega il
proprio compito a quello di Maven. Vi sono altre tipologie di servizi che
possono astrarre alcune carateristiche del contesto di esecuzione attraverso
il framework Maven, come:
• astrazione delle risorse e delle gerarchie di cartelle all’interno del
progetto;
• accesso ai risultati di sottoprogetti per rendere possibile la combina-
zione di pi`u classificatori in uno composito;
• logging orientato ai dati che utilizzi json come formato di scambio.
Validazione dei descrittori di servizio
L’implementazione di application context cerca di generare un servizio
basandosi su un suo descrittore, istanziando ricorsivamente i collaboratori
attraverso le factory, e nel caso manchi una delle factory richieste la gene-
razione del servizio viene interrotta con un’eccezione. Un tentativo fallito
di generazione di un servizio con un descrittore non valido, ad esempio
a causa di una svista nella configurazione, in una fase diversa da quella
iniziale potrebbe causare la perdita dei dati dell’esecuzione del plugin in
corso, che in ogni caso verrebbe interrotta.
Dotare l’application context di un metodo che verifichi la coerenza di
un descrittore con le factory inserite nel contesto, senza la necessit`a di
istanziare servizio e collaboratori, garantirebbe al plugin di poter fallire
subito nella fase di validazione del progetto.
Parallelizzazione
L’algoritmo di back propagation pu`o essere eseguito in parallelo per cia-
scun esempio dell’insieme di addestramento, poich´e i pesi del multilayer
perceptron non vengono aggiornati fino a quando tutti i gradienti siano
stati calcolati. Anche il calcolo delle attivazioni dei neuroni di un layer `e
un operazione parallelizzabile.
Nell’implementazione dell’algoritmo fatta per questa tesi la parallelizzazio-
ne non `e stata introdotta, ma con la successiva release di Java sono previsti
nuovi strumenti che la rendono implicita e di pi`u facile realizzazione. Si `e
quindi scelto di attendere la nuova versione per passare ad implementazioni
degli algoritmi che traggano vantaggio dal calcolo parallelo.
47
48. A Esempio di progetto per multilayer percep-
tron: xor
La funzione booleana xor, o or esclusivo, `e un esempio classico usato per intro-
durre i multilayer perceptron, in quanto le classi dei risultati non sono linear-
mente separabili sul piano degli input e quindi non riconoscibili dal perceptron.
Per la semplicit`a di descrizione del problema, e per seguire la tradizione, verr`a
utilizzato anche come esempio di utilizzo del plugin.
Una possibile struttura di multilayer perceptron per il riconoscimento dello
xor `e composta da un singolo hidden layer di tre neuroni. Come funzione di
attivazione si pu`o optare per la tangente iperbolica, una sigmoide che mappa R
nell’intervallo (−1, 1).
Listing 14: Struttura di multilayer perceptron per il riconoscimento della
funzione xor
1 {
2 "function": {"name": "tanh"},
3 "sources": 2,
4 "sizes": [3, 1]
5 }
Riguardo gli esempi, che risultano essere le quattro combinazioni di v e f
rappresentabili con 1 e −1 rispettivamente, si richiedono come valori di output
dei numeri vicini agli estremi dell’intervallo invece che gli estremi stessi: in
questo modo si hanno degli output comunque distinguibili, evitando di avere i
pesi delle sinapsi con modulo molto elevato al termine dell’addestramento.
Vista la semplicit`a della rete neurale, sar`a utilizzato lo stesso insieme di
esempi sia durante l’addestramento che per i test.
Listing 15: Esempi usati per addestrare e testare il multilayer perceptron
1 [
2 {"label":"(f,f)", "input":[-1, -1], "output":[-0.9]},
3 {"label":"(f,v)", "input":[-1, 1], "output":[0.9]},
4 {"label":"(v,f)", "input":[1, -1], "output":[0.9]},
5 {"label":"(v,v)", "input":[1, 1], "output":[-0.9]}
6 ]
Nella sezione build del descrittore di progetto viene inserita la configurazio-
ne del plugin, dichiarando quali siano i servizi di addestramento e test, i loro
parametri e collaboratori. Ad esempio, come metodo di addestramento si im-
posta batchBackPropagation con alcuni collaboratori configurati, tra cui
la funzione d’errore da applicare all’output per il calcolo del gradiente e il si-
stema di logging su cui scrivere. Allo stesso modo si configura come metodo di
test errorFunction, che applica una funzione d’errore all’output della rete
neurale e fa fallire un test se tale errore superasse una soglia impostata.
Nel Listato 16 `e mostrata la configurazione dei servizi con i relativi col-
laboratori. Tutti i collaboratori elencati, tranne il logger, sono definiti come
default dei servizi batchBackPropagation e errorFunction e quindi si
pu`o rimuovere la loro dichiarazione nel descrittore di progetto, ma sono stati
comunque inclusi per rendere pi`u chiaro l’esempio.
48
49. Listing 16: Configurazione del plugin per l’addestramento e i test
1 <project ...>
2 ...
3 <build>
4 <plugins>
5 <plugin>
6 <groupId>dev.deadc0de.seshat</groupId>
7 <artifactId>multilayer-perceptron-maven-plugin</artifactId>
8 <version>0.2</version>
9 <extensions>true</extensions>
10 <configuration>
11 <trainingMethod>
12 <name>batchBackPropagation</name>
13 <configuration>
14 <learningRate>0.1</learningRate>
15 <tolerance>0.1</tolerance>
16 <maximumIterations>100</maximumIterations>
17 </configuration>
18 <collaborators>
19 <collaborator>
20 <role>errorFunction</role>
21 <name>meanSquaredError</name>
22 </collaborator>
23 <collaborator>
24 <role>logger</role>
25 <name>maven</name>
26 </collaborator>
27 </collaborators>
28 </trainingMethod>
29 <test>
30 <name>errorFunction</name>
31 <configuration>
32 <tolerance>0.1</tolerance>
33 </configuration>
34 <collaborators>
35 <collaborator>
36 <role>errorFunction</role>
37 <name>meanSquaredError</name>
38 </collaborator>
39 <collaborator>
40 <role>logger</role>
41 <name>maven</name>
42 </collaborator>
43 </collaborators>
44 </test>
45 </configuration>
46 </plugin>
47 </plugins>
48 </build>
49 ...
50 </project>
L’addestramento pu`o essere avviato con Maven specificando il goal compile,
mentre per includere anche i test bisogna utilizzare il goal test. Un esempio
di output `e mostrato nel Listato 17.
49
52. B Implementazione dell’algoritmo di back-propagation
In seguito `e descritta l’implementazione dell’algoritmo di back propagation, nel-
la variante batch dove tutti i gli esempi del training set sono valutati prima di
procedere all’aggiornamento dei pesi. Inoltre `e stato specializzato per il parti-
colare caso dei multilayer perceptron, a partire dall’algoritmo per reti neurali
feedforward descritto nella Sezione 3.
Dal punto di vista implementativo, seppur nell’ambito di un linguaggio orien-
tato agli oggetti come Java, si `e optato per un approccio funzionale. Alla base
dell’astrazione vi `e il considerare il multilayer perceptron come una sequenza di
mappature: tutte le operazioni sono legate alla trasformazione di un segnale du-
rante l’attraversamento di un layer, avendo come dati l’input e la struttura (bias,
pesi delle sinapsi e funzioni di attivazione). Diventa quindi possibile limitarsi
a considerare un layer per volta, semplificando notevolmente l’implementazio-
ne. Un ulteriore vantaggio dato dal paradigma funzionale `e la possibilit`a di
parallelizzare alcune parti dell’algoritmo.
All’inizio dell’addestramento i pesi del multilayer perceptron vengono inizia-
lizzati con valori casuali, in quanto se nulli non permetterebbero la propagazioe
dell’errore all’indietro. Dato un esempio dotato del vettore di input e di quello
di output desiderato, l’algoritmo si divide nelle due fasi esposte in seguito.
B.1 Fase feedforward
Le informazioni raccolte durante la fase feedforward sono:
• l’input in ingresso a ciascun layer;
• i valori delle derivate di ciascun neurone calcolate attraverso il livello di
attivazione;
• l’output del multilayer perceptron.
Per ottenerle `e sufficiente effettuare una riduzione15
sul multilayer perceptron,
visto come lista di layer, applicando ad ogni layer una funzione che, dato un
accumulatore contenente i dati raccolti per i layer precedenti, vi aggiunga quelli
del layer corrente.
La funzione combinante di feedforward `e strutturata come segue:
• in input sono dati un accumulatore, contenente derivate e input di tutti i
layer precedenti, l’output del layer precedente e i dati del layer corrente:
bias bi, pesi delle sinapsi wi e funzione di attivazione fi di ciascun neurone
i;
• vengono calcolati i livelli di attivazione si del layer, con
si = bi +
j
xjwij (33)
dove il vettore x rappresenta l’output generato dai neuroni del layer pre-
cedente, e il peso wij `e associato alla sinapsi che dal neurone j del layer
precedente arriva al neurone i;
15 Nella programmazione funzionale, l’operazione di riduzione consiste nella combinazione
di elementi di una struttura dati ricorsiva attraverso una funzione combinante: dato un valore
di partenza, detto accumulatore, la funzione viene applicata sistematicamente al successivo
elemento usando il valore attuale dell’accumulatore ed aggiornandolo col nuovo valore appena
calcolato.
52
53. • viene calcolata la derivata della funzione di attivazione per ciascun neu-
rone, con gi = fi (si);
• viene infine calcolato l’output del layer con oi = fi(gi);
• l’input del layer, ovvero l’output di quello precedente, e le derivate sono
aggiunte all’accumulatore e viene restituito l’output del layer corrente.
I parametri iniziali della riduzione sono un accumulatore vuoto e l’input del
multilayer perceptron.
B.2 Fase di back propagation
Attraverso la funzione d’errore scelta per l’addestramento viene calcolato il suo
gradiente, confrontando l’output desiderato con quello ottenuto al termine della
fase feedforward. L’obiettivo `e ottenere le componenti del gradiente per tutti i
pesi del multilayer perceptron a partire dal gradiente dell’errore. Nella fase di
back propagation, la lista contenente gli input e le derivate dei layer viene inver-
tita ed utilizzata per propagare all’indietro l’errore, accumulando nel frattempo
le componenti del gradiente per ciascun layer visitato.
Come nel caso della fase feedforward, viene definita una funzione combinante
di back propagation, con il seguente comportamento:
• in input sono dati un accumulatore, contenente le componenti parziali
del gradiente per i layer successivi (considerati nell’ordine originale del
multilayer perceptron), l’output di back propagation del layer successivo
e i dati del layer corrente;
• viene calcolata l’attivazione di backpropagation del layer, moltiplicando
l’input per le derivate delle funzioni di attivazione calcolate nella fase
feedfroward, con ¯si = ¯xigi;
• il gradiente per i pesi delle sinapsi si ottiene moltiplicando l’attivazione di
back propagation ¯s per l’input della fase feedforward x
∆wij =
j
¯sixj (34)
mentre il gradiente del bias ∆wi0 `e dato semplicemente dall’attivazione
¯si;
• infine l’output viene calcolato percorrendo al contrario le sinapsi, con
¯oj =
i
¯siwij (35)
• il gradiente del layer viene aggiunto all’accumulatore e viene restituito
l’output da passare al layer precedente.
I parametri iniziali della riduzione sono un accumulatore vuoto e il gra-
diente della funzione d’errore come input. Al termine l’output viene scartato,
mentre le componenti raccolte nell’accumulatore vanno a formare il gradiente
del multilayer perceptron.
53