• Non ci sono risultati.

Struttura del neurocontrollore e gestione del sistema con ARI

N/A
N/A
Protected

Academic year: 2021

Condividi "Struttura del neurocontrollore e gestione del sistema con ARI"

Copied!
16
0
0

Testo completo

(1)

Dopo l’acquisizione dei segnali provenienti dagli strain gage del sistema di masticazione e la trasmissione al PC, tramite USB, dei dati ottenuti, il passo successivo consiste nell’interfacciamento di questa struttura software con l’ambiente ARI. Questo software, come detto, è in grado di provvedere alla gestione parallela ed in tempo reale di vari tipi di hardware eterogenei e di elaborare i dati acquisiti tramite una rete neurale, che costituisce il controllore di tipo neuromorfo. ARI prende i dati direttamente dall’OCX, sostituendo l’interfaccia utente utilizzata per eseguire le misure e gestendo tutte le operazioni di comando della scheda.

Considerando che il controllore può essere realizzato utilizzando varie strutture ed algoritmi, per capire proprietà e limiti della scelta effettuata vengono innanzitutto descritte le principali proprietà delle reti neurali; successivamente, viene illustrato l’ambiente ARI e il driver implementato per l’interfacciamento con la scheda hardware realizzata.

6.1 Reti neurali artificiali

L’utilizzo delle reti neurali ha conosciuto un notevole sviluppo e la loro applicazione si è diffusa in svariati campi. Spesso, però, possono presentare problemi di natura opposta: da una parte, per migliorare la capacità di elaborazione ed avere

(2)

strutture più facilmente gestibili, si è cercato di semplificare i modelli delle reti; dall’altra questa operazione, pur essendo giustificata dai risultati ottenuti in molte applicazioni, ha portato all’utilizzo di strutture ed algoritmi che si allontanano dai fondamenti biologici che hanno ispirato l’ideazione delle reti neurali stesse.

Finora è stata implementata una parte del neurocontrollore tramite una mappa di

Kohonen, una struttura che permette di avere un compromesso tra queste due specifiche

ed è descritta in questo paragrafo dopo aver illustrato brevemente i concetti alla base delle reti neurali. In ogni caso, tra gli obiettivi futuri vi è anche il miglioramento della plausibilità biologica, tramite l’aggiunta di ulteriori stadi di elaborazione neuromorfa.

6.1.1 Tipologie di reti neurali

Le scoperte riguardanti i neuroni e il sistema nervoso umano e animale sono andate di pari passo con i tentativi di creare modelli matematici che ne descrivessero la struttura e il funzionamento.

I limiti principali cui questi studi sono soggetti riguardano la conoscenza ancora incompleta del sistema nervoso, dovuta anche alla sua notevole complessità, alla quale bisogna aggiungere le difficoltà legate alla limitatezza della potenza di calcolo [29]. A causa di questi problemi, un modello matematico può riuscire a riprodurre in modo plausibile solo alcuni aspetti delle reti neurali biologiche, a seconda del tipo di applicazione e del “punto di vista” che si utilizza.

In particolare, storicamente si possono riconoscere due filoni che, partendo da due punti di vista praticamente opposti, si sono evoluti perseguendo obiettivi ed applicazioni divergenti, anche se parzialmente sovrapponibili.

Il primo filone parte dal tentativo di creare modelli matematici di neurone che ne replichino in modo fedele le principali caratteristiche biofisiche. Come punto di partenza si potrebbe assumere il lavoro di Hodgkin e Huxley del 1952 [30], che ha dato vita ad una serie di modelli detti “a conduttanze”. Questi sono alla base delle spiking

neural networks, reti neurali di cui vengono studiati gli effetti emergenti per metterli in

(3)

punto di vista matematico e spesso, soprattutto in caso di reti neurali molto estese, i vantaggi in termini di precisione e plausibilità biofisica sono largamente superati dalle eccessive difficoltà di calcolo. Pertanto, il loro campo di applicazione riguarda quasi esclusivamente la biofisica e la neurofisiologia.

Nel secondo filone, invece, pur rimanendo un’ispirazione biologica di fondo, l’attenzione viene spostata dalla biofisica dei neuroni ad un livello di astrazione superiore, che ha portato alla creazione di modelli che prescindono dalle caratteristiche anatomiche del neurone e del sistema nervoso [29]. Si tratta di un orientamento in cui, piuttosto che descrivere il neurone e le reti neurali biologiche, vengono elaborati modelli di computazione e trasmissione dell’informazione con diverse finalità applicative (dalla classificazione ai sistemi esperti, fino alla costruzione di robot “intelligenti”), detti Reti Neurali Artificiali (Artificial Neural Networks). Il punto di partenza può essere considerato il modello di neurone di McCulloch e Pitts (1943), dal quale questo filone si è evoluto, in forte connessione con la Teoria dell’Informazione, e all’interno del quale si sono sviluppate la Cibernetica e l’Intelligenza Artificiale.

Grossolanamente si potrebbe dire che il primo filone ha a che fare con i neuroni biologici, avendo come obiettivo la loro descrizione matematica, mentre il secondo si pone in una prospettiva di costruzione di macchine, reali o virtuali, biologicamente ispirate. Pertanto, è innanzitutto in quest’ultimo ambito che vanno ricercati gli elementi con cui sviluppare un controllo neuromorfo, ovvero avente struttura e funzionamento ispirati a quelli del sistema nervoso, per un sistema biorobotico.

Non è tra gli obiettivi di questo lavoro definire in modo esatto le relazioni con questo paradigma biologico; si può semplicemente dire che l’ottica sulla quale si lavora è quella che considera l’essenza delle operazioni svolte dai neuroni nel “controllo attraverso la comunicazione” [31].

6.1.2 Modelli di neurone e apprendimento

(4)

l’unità computazionale, collegati tramite delle connessioni, le sinapsi, ad ognuna delle quali è associato un peso.

In una rete neurale artificiale vi sono tre elementi particolarmente importanti [31]: • La struttura dei neuroni;

• La topologia della rete;

• L’algoritmo di apprendimento utilizzato per l’aggiornamento dei pesi.

Il modello matematico di un neurone artificiale riproduce le caratteristiche computazionali essenziali di un neurone biologico, implementando la versione discreta dell’Integrate-and-Fire, la versione più semplificata dei modelli a conduttanze. L’operazione che svolge consiste nella somma, pesata con i valori delle sinapsi, degli ingressi, alla quale viene applicata una funzione f non lineare, detta funzione di

attivazione, che fornisce un output. Ovvero, in riferimento alla figura 6.1, l’uscita è data

da:

( )

⎟⎟ ⎠ ⎞ ⎜⎜ ⎝ ⎛ + = =

= n k j jk k j j f y f x w w y 1 0 ' (6.1)

Tra le funzioni di attivazione più utilizzate vi sono il gradino, la rampa e la sigmoide. Nella nostra applicazione è stata utilizzata la funzione:

2 1 ) tanh( ) (y = y + f (6.2)

L’apprendimento è la proprietà che caratterizza maggiormente una rete neurale [31], e consiste nell’applicazione di un determinato algoritmo tramite il quale vengono variati i pesi della rete in seguito alla presentazione, durante la fase di apprendimento, di una serie di ingressi che costituiscono degli esempi del compito da apprendere. La capacità di generalizzazione acquisita dalla rete per effetto dell’algoritmo di apprendimento può essere valutata ponendo in ingresso degli esempi non conosciuti dalla rete.

Esistono due tipologie di apprendimento: quello supervisionato e quello non supervisionato [32].

(5)

Nell’apprendimento supervisionato si ha a disposizione un training set, ovvero una serie di coppie ingressi/uscita che devono essere appresi dalla rete. Durante la fase di apprendimento gli ingressi del training set vengono presentati ciclicamente in ingresso alla rete, la cui uscita viene confrontata con quella indicata nel training set; l’algoritmo di apprendimento modifica i parametri della rete in modo da ridurre progressivamente la scostamento tra le due. Tra gli algoritmi più usati c’è quello detto di backpropagation, che sfrutta il metodo del gradiente per trovare il minimo della funzione di errore (data dalla differenza tra l’uscita della rete e quella del training set). Questo tipo di apprendimento, pur essendo in molti casi efficace, non ha però una plausibilità biologica: nel sistema nervoso umano ed animale, infatti, i segnali provenienti dall’apparato sensoriale vengono elaborati senza alcun feedback esplicito dall’ambiente [33], ovvero senza alcun tipo di training set con cui confrontare i segnali elaborati durante il processo di apprendimento.

Figura 6.1: rappresentazione del modello discreto di neurone Integrate-and-fire. Gli n ingressi X1,…,Xn vengono combinati linearmente con i pesi sinaptici W1,…,Wn. A tale somma viene aggiunto un offset W0 e viene applicata una funzione di attivazione f.

Nell’apprendimento non supervisionato, a differenza del caso precedente, l’evoluzione dei parametri della rete non dipende dal confronto delle uscite con un valore desiderato (che costituiva, appunto, l’elemento di supervisione), ma è governata

(6)

da meccanismi di autoregolazione che, almeno nei loro tratti essenziali, riproducono modalità di apprendimento di cui si sono avuti riscontri biologici.

In particolare, si possono riconoscere due principali classi di apprendimento non supervisionato [31]: il rafforzamento e l’apprendimento competitivo.

Nel primo caso ogni ingresso produce una variazione dei pesi sinaptici della rete che porta ad una migliore riproduzione dell’uscita desiderata. Un esempio di regola appartenente a questa classe di apprendimento, dalla quale sono state tratte varie implementazioni matematiche, è quella proposta da Hebb nel 1949. In base a questa regola, detta hebbiana, un collegamento sinaptico si rafforza quando i due neuroni si attivano simultaneamente, e si indebolisce quando l’attivazione è incorrelata. Sperimentalmente si è verificata la presenza di meccanismi di tipo hebbiano nei processi cerebrali di apprendimento noti come long-term potentiation (LTP) e long-term

depression (LTD), che consistono rispettivamente nel rafforzamento e

nell’indebolimento non transitori dell’efficienza sinaptica tra due neuroni dipendente dall’attività di entrambi [33], e spike-timing dependent plasticity (STDP), secondo la quale i pesi sinaptici evolvono in modo dipendente dall’ordine di attivazione dei due neuroni che collega [34].

Nell’apprendimento non supervisionato di tipo competitivo, invece, le variazioni dei pesi sinaptici sono finalizzate all’individuazione di un neurone la cui attivazione sia associata con un determinato ingresso.

Le topologie delle reti neurali, infine, possono essere diverse. In alcune, ad esempio, si hanno vari strati di neuroni, di cui uno collegato agli ingressi, uno che produce le uscite ed altri, detti nascosti, posti tra i due; in altre, invece, tutti i neuroni sono collegati agli ingressi ma non lo sono tra di loro.

6.1.3 Mappe di Kohonen

La configurazione del controllore utilizzato all’interno di ARI è ispirata alla struttura della corteccia cerebrale motoria e somatosensoriale. Questa, come abbiamo già visto nel capitolo 1, è suddivisa in aree che complessivamente formano una

(7)

rappresentazione topologica planare degli organi motori e sensoriali del corpo umano, consentendo in questo modo la riproduzione di un evento sensoriale, per sua natura multidimensionale, in una struttura planare. Questo tipo di rappresentazione viene mantenuto anche all’interno delle singole aree; la corteccia visiva, ad esempio, è divisa in regioni, ognuna delle quali è associata ad una determinata zona del campo visivo. In tal modo si ottiene una mappatura del campo visivo che è deformata in base alle differenze di risoluzione e dettaglio con cui vengono elaborati i segnali delle varie zone. In ogni caso, la demarcazione spaziale tra le varie regioni è netta, e la rappresentazione mantiene l’ordine topologico del campo visivo [32].

Il fondamento biologico di un controllore neuromorfo contenuto all’interno di un’architettura per l’acquisizione multisensoriale di segnali non può che essere quello appena descritto. Per questo motivo è stata implementata una rete neurale la cui struttura replica, ovviamente in modo estremamente semplificato, questa rappresentazione topologica suddivisa in aree: la mappa di Kohonen.

Si tratta di una rete costituita, nel nostro caso, da una griglia rettangolare bidimensionale di neuroni aventi uscita flottante (e pertanto non connessi tra di loro) e collegati allo stesso vettore d’ingresso.

Nelle mappe di Kohonen viene implementato un algoritmo di apprendimento non supervisionato di tipo competitivo, che è bene illustrare un po’ più in dettaglio.

Innanzitutto è necessario disporre di una serie di vettori d’ingresso n-dimensionali

[

x ,...,1 xn

]

=

x , appartenenti ad n classi da presentare in ingresso alla rete ciclicamente o in modo casuale in fase di addestramento e rappresentanti le altrettante caratteristiche (features) che la rete, una volta addestrata, deve saper riconoscere.

Supponiamo di avere una mappa di Kohonen rettangolare contenente m neuroni; per ognuno di questi viene definita una bolla di attivazione, o vicinato, che comprende un certo numero di neuroni ad esso vicini, tipicamente contenuti all’interno di un quadrato. Nello stato iniziale, per ogni neurone la bolla di attivazione coincide con tutta la rete; ad ogni passo della fase di apprendimento deve corrispondere una variazione della bolla in modo che alla fine sia costituita solamente dal neurone.

(8)

Detto w il peso della connessione tra il neurone j-esimo e l’ingresso ij x , i consideriamo la distanza euclidea tra tale neurone e il vettore degli ingressi x, data da:

(

)

2 1

= − = n i ij i j x w d (6.3)

Calcolando questo valore per ogni neurone della mappa viene determinato il

neurone vincente j*, ovvero quello avente distanza euclidea minore. Al passo k i pesi

sinaptici di questo neurone e di quelli appartenenti alla sua bolla di attivazione Vj*

( )

k vengono aggiornati in base alla legge seguente:

( )

k =w

(

k−1

) ( ) ( )

+ k

[

x kw

(

k−1

)

]

wij ij α i ij , i=1, 2,…, n (6.4) dove α(k) è il fattore di convergenza o learning rate, che deve essere mantenuto costante e prossimo a 1 per un certo numero di iterazioni, per poi essere diminuito fino a raggiungere, alla fine della fase di apprendimento, un valore pari solitamente a 0.1.

Una volta che le bolle di attivazione di tutti i neuroni coincidono con il neurone stesso e il fattore di convergenza si è stabilizzato su tale valore, si ha un secondo ciclo di iterazioni, analogo al primo tranne per il fatto che vengono corretti solo i pesi sinaptici del neurone vincente.

L’apprendimento termina dopo questa fase ulteriore. A questo punto, in corrispondenza di un vettore d’ingresso, la rete dovrebbe essere in grado di riconoscerne la classe di appartenenza, ovvero la feature. A seconda dell’applicazione, viene scelto un modo per codificare l’uscita: si può utilizzare l’indice del neurone vincente, oppure il suo vettore dei pesi (in quest’ultimo caso la rete si comporta da codificatore dello spazio di ingresso). Un’alternativa è quella di eseguire il labeling; in questo caso, dopo aver codificato le classi di appartenenza del vettore d’ingresso con un numero da 1 a n, vengono ripresentati alla rete gli ingressi utilizzati in fase di addestramento, e il neurone vincente viene individuato ed etichettato con il numero corrispondente alla classe di appartenenza del vettore d’ingresso. Ripetendo questa operazione fino alla totale

(9)

copertura dei neuroni della rete, si ottiene proprio la mappatura di uno spazio n-dimensionale su una struttura planare di cui parlavamo all’inizio del paragrafo.

6.2 L’ambiente ARI

Esistono vari software per la simulazione di reti neurali, sia commerciali, come Matlab, che scaricabili liberamente da Internet, come il software PDP++ [33]. Nessuno di questi, però, risponde in modo completo ai requisiti necessari per il raggiungimento degli obiettivi del presente lavoro. In particolare, nell’ottica in cui ci siamo posti si ha l’esigenza di avere a disposizione un’unica architettura in grado di comunicare parallelamente ed in tempo reale con più dispositivi di trasduzione e attuazione, riportare tutti i dati acquisiti in uno stesso formato ed elaborarli utilizzando delle reti neurali con cui controllare gli attuatori.

Il software ARI (Artificial Robot Interface) risponde ai requisiti richiesti: si tratta di un insieme di librerie in Microsoft® VisualC++®, costituenti un ambiente (framework) che genera una struttura di base alla quale è possibile adattare i dati provenienti da un determinato hardware utilizzando un driver specifico (un discorso duale può essere fatto per gli attuatori). In questa struttura sono comprese le dichiarazioni e definizioni degli elementi che formano la rete neurale di controllo e di quelli che permettono di tradurre i dati acquisiti in un protocollo che ne consenta l’interfacciamento con la rete stessa.

Un sistema complesso che utilizza l’ambiente ARI può essere rappresentato come in figura 6.2 [1]. Per ogni sensore è presente una catena di elaborazione costituita da: una scheda hardware per l’acquisizione del segnale; un driver per l’interfacciamento con il PC; un secondo driver per riportare i dati nel protocollo ARI; l’elaborazione tramite rete neurale all’interno del framework. Per gli attuatori si ha un percorso inverso: le uscite del controllore vengono filtrate con due driver per essere poi messe in ingresso al dispositivo di attuazione.

Da questo punto di vista, il sistema realizzato è formato da una catena sensoriale, che provvede all’acquisizione dei segnali dagli strain gage, e una di attuazione, con cui

(10)

si controlla il pistone. In questo caso, pertanto, la scheda hardware implementa sia la funzione di acquisizione che quella di attuazione, mentre la comunicazione con il PC viene svolta tramite il protocollo USB. I driver di interfacciamento con ARI, come vedremo tra poco, sono risultati essere relativamente semplici, grazie alla flessibilità e generalità del framework.

Figura 6.2: architettura che utilizza il framework ARI per la gestione parallela di m catene di acquisizione da sensori ed n catene di attuazione [1].

Essenzialmente, ARI è costituito da un insieme di classi in grado di riportare i dati acquisiti da un hardware in un formato tale da poter essere elaborati con un controllore di tipo neurale definito al suo interno.

La classe base del framework, denominata ARI_3DObject, rappresenta un oggetto fisico identificato da un nome e dotato di proprietà che ne definiscono collocazione

(11)

topologia e caratteristiche geometriche, come la posizione e il volume occupato. Al suo interno sono definite le funzionalità base di tutte le entità dell’ambiente, che sono:

• void Render(), che si occupa della parte grafica (di default disegna un cubo giallo);

• void SetInput(), che imposta gli ingressi dei neuroni (di default non fa nulla); • void Update(double dt), che si occupa delle operazioni di aggiornamento degli

Input con un intervallo di tempo pari a dt (di default non fa nulla).

Queste operazioni sono definite virtuali, in modo da poter essere ridefinite nelle classi derivate e poter essere invocata anche se la chiamata proviene dalla classe base, e per ognuna di esse è presente un flag che indica se la funzione è overridable. Notiamo che SetInput e Update possono sembrare apparentemente ridondanti, in quanto entrambe impostano i valori degli ingressi dei neuroni; in realtà, sono separate per permettere un’elaborazione indipendente dall’ordine di processamento.

La classe ARI_3DWorld è una collezione di ARI_3DObject, ovvero costituisce l’ambiente nel quale si collocano gli elementi che compongono ARI. Come abbiamo detto, in ARI_3DObject sono definite la posizione e le entità connesse in ingresso e in uscita, ma non le relazioni dell’oggetto con il resto del mondo; ARI_3DWorld, invece, conosce i collegamenti e la collocazione topologica di tutte le entità, comprese quelle topologicamente sconnesse. Le funzioni Render(), SetInput() e Update(dt) sono ridefinite in modo da invocare la funzione omonima negli ARI3D_Object che hanno abilitato l’operazione di override nel flag corrispondente. Tra le altre funzioni vi sono

Add e Remove, che consentono di aggiungere e rimuovere un oggetto, e unsigned int GetCount(), che restituisce il numero di ARI3D_Object presenti.

ARI_W è una classe derivata da ARI3D_Object che implementa una generica

funzione di trasferimento a n ingressi e un’uscita OUTDATA di tipo DATA, in modo che il dominio della funzione, ovvero il tipo dell’uscita, sia definibile in ogni istanza della classe in modo indipendente. La connessione all’ingresso di un ARI_W dell’uscita di un’altra entità di tipo ARI_W avviene per mezzo di un elemento della classe

(12)

valore della sua uscita OUTDATA ed un campo CONNSPEC contenente informazioni aggiuntive dipendenti dal tipo di classe derivata da ARI_W dell’entità trasmettente. In altre parole, si definisce una ARI_W<OUTDATA, CONNSPEC> che fornisce un’uscita di tipo DATA e riceve gli ingressi tramite connessioni ARI_WConnection<OUTDATA, CONNSPEC>.

Le CONNSPEC vengono passate al momento dell’inserimento di una connessione tra un ARI_W ed altri elementi dello stesso tipo, che si ottiene tramite le funzioni Add e Remove. Ogni ARI_W ha una lista interna (_inputList) in cui sono memorizzati le ARI_WConnection instaurate con le entità trasmettenti, ovvero che compongono gli ingressi dell’elemento. Inoltre, pur essendo ridondante, è presente anche una _outputList contenente i riferimenti agli ARI_W riceventi, in modo che questi possano essere richiamati in modo efficiente, ad esempio in caso di distruzione dell’entità trasmittente.

Le funzioni definite in ARI_W sono:

• void SetOutput(OUTDATA output), che imposta l’uscita corrente;

• OUTDATA GetOutput(), che restituisce il valore corrente dell’uscita, senza ricalcolarlo;

• virtual OUTDATA Process(double dt)=0, funzione privata e virtuale pura, che definisce il processo da realizzare per il calcolo dell'uscita, il quale può essere funzione degli OUTDATA e delle CONNSPEC delle connessioni in ingresso; Vengono poi ridefinite le funzioni SetInput() e Update (dt): la prima passa in rassegna la lista delle connessioni e invoca GetOutput() su ogni ARI_W trasmittente, memorizzando il valore OUTDATA all'interno della connessione, mentre la seconda calcola l'uscita invocando Process (dt) e la memorizza come output corrente.

La classe ARI_WGroup rappresenta una collezione di ARI_W. Essendo anch’essa un ARI_3DObject, può essere inserita in ARI_3DWorld, e contiene le funzioni Render, SetInput e Update, evocate negli elementi del gruppo in base ai flag corrispondenti. Internamente è presente una lista di riferimenti agli ARI_W del gruppo, che possono essere aggiunti o rimossi tramite le funzioni Add e Remove. All’interno di questa classe sono definite le funzioni void Dispose2D(unsigned int xSize), che dispone le ARI_W in

(13)

modo bidimensionale, e unsigned int GetCount(), che restituisce il numero di ARI presenti nel gruppo.

Implementando una generica funzione di trasferimento a n ingressi e un’uscita, ARI_W costituisce la classe base dei modelli di neurone: ogni classe derivata contiene, pertanto, un modello matematico specifico di neurone, che viene implementato tramite la ridefinizione della funzione virtuale pura Process. Allo stesso modo, da ARI_WGroup si derivano classi costituite da gruppi di elementi appartenenti ad una stessa classe derivata da ARI_W, e da ARI_WConnection classi tramite le quali tali elementi vengono collegati. Per ognuna delle classi derivate da ARI_W devono essere specificati il tipo dell’uscita OUTDATA e del campo CONNSPEC della classe ARI_WConnection.

Con questo metodo l’intera struttura è resa flessibile, in quanto è possibile scegliere il modello di neurone e la struttura della rete neurale da utilizzare a seconda dell’applicazione, o anche confrontare i risultati ottenuti con diversi modelli su dati dello stesso hardware.

Finora è stata implementato il modello classico di neurone utilizzato nelle reti neurali artificiali, l’Integrate-and-Fire. Questo modello è definito nella classe

ARI_IFNeuron, che è di tipo ARI_W<double, ARI_IFNeuronConnectionSpec>; ovvero,

la sua uscita OUTDATA è di tipo double, quindi un numero reale, mentre CONNSPEC è di tipo ARI_IFNeuronConnectionSpec, che a sua volta definisce una classe di tipo double e che in questo caso rappresenta il peso della connessione. Pertanto, la classe

ARI_IFNeuronConnection, che rappresenta le connessioni tra ARI_IFNeuron, è definita

come ARI_WConnection<double, double>.

La classe che rappresenta un gruppo di neuroni ARI_IFNeuron, derivata da ARI_WGroup, è detta ARI_IFNeuronGroup.

Da questa si può derivare una classe che implementa la struttura e l’algoritmo di apprendimento della rete neurale che si è deciso di utilizzare. Come detto nel paragrafo precedente, la scelta è caduta su una mappa di Kohonen bidimensionale composta da neuroni IF, rappresentata dalla classe ARI_IFKohonen, che è un ARI_IFNeuron_Group. L’inizializzazione di questa classe avviene invocando la funzione interna bool

(14)

Init(ARI_IFNeuronGroup* pClassIFNeuronGroup, unsigned int sizeX), tramite la quale

viene fornito il riferimento ad un altro ARI_IFNeuronGroup che rappresenta la risposta desiderata, e viene specificata la larghezza della mappa in modo da poterne stabilire la geometria ed invocare automaticamente la funzione Dispose2D. I flag di Update dei neuroni della mappa vengono disattivati per evitare il processo di somma pesata e filtraggio. La funzione Update è ridefinita in modo da calcolare il neurone vincente, aggiornare i pesi della rete in base ai parametri di addestramento ed eseguire il labeling sulla mappa.

L’interfaccia tra ARI e il sistema operativo per consentire il dialogo con un sistema di input sensoriale è realizzata tramite la classe ARI_SensorDriver. Questa è costituita da un insieme di ARI_IFNeuron che prende in ingresso i dati provenienti dall’hardware e i cui flag di SetInput e Update sono disattivati; in questo modo l’aggiornamento delle uscite può essere gestito indipendentemente da quello del resto della rete, pertanto tale insieme di neuroni si comporta da strato cuscinetto, ovvero da buffer. In particolare, tale gestione avviene tramite una funzione definita internamente a questa classe.

Il driver specifico per un hardware si ottiene semplicemente creando una classe derivata da ARI_SensorDriver e ridefinendo alcune funzioni virtuali della classe base. Le funzioni definite in quest’ultima sono:

• void InitDriver(unsigned int countIFNeurons): è una funzione privata che inizializza un vettore dinamico interno alla classe, in cui vengono memorizzati i riferimenti agli ARI_IFNeuron che la comporranno. Il buffer precedente viene distrutto e ricreato. Questa funzione deve essere invocata dalla classe derivata in fase di inizializzazione;

• bool Register(ARI_IFNeuronGroup * pIFNeuronGroup): registra un gruppo di ARI_IFNeuron, ovvero ne memorizza i riferimenti e disabilita i flag di SetInput ed Update. Tali flag sono anche rimossi dal corrispondente ARI_IFNeuronGroup. Se il buffer è pieno ritorna false;

• bool Register(ARI_IFNeuron* pIFNeuron): registra un ARI_IFNeuron, ovvero ne memorizza il riferimento e rimuove i flag di SetInput ed Update. Se il buffer

(15)

è pieno ritorna false;

• virtual void Init(): è una funzione virtuale che deve essere ridefinita nella classe derivata per inizializzare il driver ed invocare InitDriver passando come parametro il numero di ARI_IFNeuron che l’utente deve registrare;

• virtual void Update(float dt)=0: è virtuale pura e deve essere ridefinita nella classe base in modo da distribuire i dati provenienti dai sensori in ingresso agli ARI_IFNeuron registrati. Questa funzione deve essere chiamata dall’utente prima di invocare SetInput e Update sulla rete.

La creazione di un driver specifico, pertanto, prevede innanzitutto la dichiarazione di una classe derivata da una classe base di tipo ARI_SensorDriver, dalla quale viene invocata la funzione InitDriver(), opportunamente ridefinita con il numero di neuroni da registrare, che provvede all’allocazione del vettore dinamico interno. In seguito a questo, l’utente dovrà registrare tutti gli ARI_IFNeuron richiesti tramite le funzioni Register(). A questo punto, gli ARI_IFNeuron registrati non riceveranno più i messaggi di SetInput ed Update ed i loro output saranno governati dal driver.

Figura 6.3: schema del neurocontrollore. L’interfacciamento avviene tramite un buffer di otto neuroni le cui uscite vengono impostate con i risultati delle acquisizioni provenienti dall’OCX. Questi neuroni vengono posti in ingresso ad una mappa di Kohonen che costituisce il primo stadio del neurocontrollore e alla quale dovranno essere collegate altre strutture neurali di elaborazione.

Mappa di

Kohonen

IF1

IF2

IF3

IF4

IF5

IF6

IF7

IF8

Altre strutture neurali

OCX

(16)

Nella classe creata, denominata ARIChewingSensorDriver (vedi Appendice D) la funzione Init provvede a: effettuare il collegamento con il controllo OCX tramite il quale può gestire la periferica con i comandi visti nel capitolo precedente (Connect, Disconnect, MOVE, CALIBRATE); invocare la funzione InitDriver(8), in modo da inizializzare un vettore di 8 neuroni IF. Successivamente, la funzione Update invia il comando GET_DATA e pone il vettore delle acquisizioni channels[] in uscita agli 8 neuroni creati. In questo modo abbiamo ottenuto uno “strato cuscinetto”, ovvero un buffer di neuroni la cui gestione non dipende da ARI come per gli altri elementi, ma dalla classe ARIChewingSensorDriver.

Le uscite di questi neuroni vengono poste in ingresso alla mappa di Kohonen, che costituisce il primo stadio del neurocontrollore, il quale dovrà essere completato con ulteriori strutture (vedi figura 6.3).

Figura

Figura 6.1: rappresentazione del modello discreto di neurone Integrate-and-fire. Gli n ingressi  X1,…,Xn vengono combinati linearmente con i pesi sinaptici W1,…,Wn
Figura 6.2: architettura che utilizza il framework ARI per la gestione parallela di m catene di  acquisizione da sensori ed n catene di attuazione [1]
Figura 6.3: schema del neurocontrollore. L’interfacciamento avviene tramite un buffer di otto  neuroni le cui uscite vengono impostate con i risultati delle acquisizioni provenienti dall’OCX

Riferimenti

Documenti correlati

[r]

Usando il teorema della convergenza dominata risulta che la funzione F `e ben definita e continua.. Verifichiamo ora che possiamo derivare F (s) sotto il segno dell’integrale in ogni

Perci`o c’`e da aspettarsi che F abbia in 0 la derivata destra 0 ed in 1 la derivata sinistra infinita +∞.. Che avviene veramente cos`ı, risulta dal

Una dimostrazione si trova, per esempio, nel libro (Teorema 49.3) T. K¨ orner: Fourier Analysis, Cambridge University Press, 1988.. Allora per il punto

Se la funzione assume almeno un valore positivo nel rettangolo R, ` e chiaro che il valore massimo di f in R sar` a assunto all’interno del rettangolo;. inoltre, tale valore sar`

Usando il criterio dell’ordine di infinitesimo, si conclude che questo accade se e solo se α

■ Quindi il vero argomento della prima funzione non é la seconda funzione, ma un normale valore, che può avere qualsiasi origine (variabile, espressione ecc...), e in particolare

In uno stato immaginario, la moneta ha qualsiasi valore reale; l’imposta I sul reddito delle persone fisiche dipende dal reddito imponibile R come segue.. • per lo scaglione di