Sviluppo di reti neurali innovative: un approccio efficace basato sulla logica Fuzzy

Scopriamo un particolare ed efficiente approccio allo sviluppo di reti neurali, basato su una logica che prescinde dal concetto di stati logici 1 e 0.

L’opportunità dell’utilizzo delle Reti Neurali è stata spiegata con la necessità di trovare sistemi efficienti per trattare input ad output analogici (grandezze a valori continui), complicati da gestire con l’uso dei calcolatori digitali.

Infatti i calcolatori, per loro natura, sono dedicati a trattare valori puntuali e ad usare la logica Booleana (a due stati: si/no). Invece, come abbiamo visto, una semplice rete neurale a due strati (più quello di ingresso), può realizzare una soddisfacente funzione complessa tra input e output analogico. Infatti l’abbiamo usata per pilotare un rover come Ardusumo sulla base dei due sensori anteriori di distanza.

L’inconveniente (per così dire) dell’utilizzo delle Reti Neurali è che sono sistemi che vanno addestrati con l’imitazione, oppure fornendo loro una serie di esempi prototipi e ripetendo più volte la loro presentazione: almeno qualche migliaio di ripetizioni.

Riassumiamo le caratteristiche salienti della logica Fuzzy.
• L’input analogico viene partizionato in classi: per esempio grande distanza, media distanza, piccola distanza. Ogni classe risulta centrata su un valore caratteristico con le bande laterali decrescenti.
• Le classi dell’output analogico sono rappresentate solo da valori caratteristici senza le bande laterali (Fuzzy Systems in modalità Sugeno, chiamato così grazie studioso che lo ha proposto).
• Un insieme di regole collega classi di input a conseguenti valori di output (per esempio if sensore 1 = Molto vicino and sensore 2 = Vicino then classe-output-C).

Il funzionamento del sistema così descritto è il seguente:
• in base al valore di input si determina il grado di appartenenza di quel valore alla classe corrispondente;
• viene esaminata ogni regola e valutato il suo grado di verità, il quale diventa un “peso” da attribuire al valore di output collegato a quella regola;
• alla fine della valutazione di tutte le regole, viene calcolata la media pesata dei valori di output assegnati ad ogni regola e questo risultato rappresenta l’output analogico.

In sostanza il sistema Fuzzy divide il complesso in sottoinsiemi che valuta singolarmente in base all’associazione fornita dalle regole e poi ne riassume il risultato. L’insieme delle classi in cui viene partizionato ogni output si chiama Fuzzy set.

Fig. 1 Esempio di Fuzzy set.

 

In Fig. 1 vedete come viene rappresentato, di conseguenza, ogni valore di input; ovvero come insieme di appartenenze ad ogni classe.

Fig. 2 Esempio di inferenza delle regole e determinazione dell’output

 

In Fig. 2 è invece rappresentato il processo di inferenza delle regole per la costituzione dei valori di output.

Gli inviluppi che determinano le classi si chiamano funzioni di membership e possono avere diverse forme analitiche, ma in genere sono formati da tratti lineari e si sovrappongono parzialmente (come in Figura 1). In questo modo il sistema Fuzzy finisce per scomporre la funzione input->output in combinazioni di tratti lineari.

Un sistema Fuzzy, quindi, non va addestrato ma rientra nella programmazione anche se di tipo non tradizionale. I sistemi Fuzzy sono utilizzati anche nei processori di ridottissimo hardware per fornire una risposta più uniforme e “morbida” (Fuzzy) in varie apparecchiature, sia civili che sia industriali.

Per utilizzarlo in un hardware limitato, il sistema software deve poter essere configurato in modo efficiente per eseguire velocemente il processo di inferenza delle regole.

Ne consegue una certa macchinosità di programmazione, a meno di non usare IDE predisposti.

Ma in questo post vi proponiamo un’alternativa che utilizza una variante delle Neural Network classiche e che permette una rapida descrizione e soprattutto una rapida elaborazione di un sistema Fuzzy.

Una Rete Neurale che è un sistema Fuzzy

Le Reti Neurali sono un universo vasto ed in evoluzione; tra le topologie di reti proposte ce n’è una che utilizza un tipo di nodi dello strato hidden diverso da quello classico che effettua la somma pesata degli input. Questo nodo si chiama Radial Basis Function (in gergo RBF). In questo caso l’attivazione di ogni nodo è dovuta alla distanza dell’input dal centro del nodo (Fig. 3).

Fig. 3 Differenti tipi di nodi delle Neural Network.

 

La funzione di attivazione più utilizzata per i nodi RBF è senza dubbio la Gaussiana:

In questa formula s2 è l’ulteriore parametro della devianza. Lo strato successivo (strato di output) è invece di tipo classico.

In queste condizioni è stato dimostrato che questo tipo di rete risulta essere il migliore approssimatore universale. In genere lo strato RBF viene addestrato con metodi statistici sulla base delle distribuzioni dei valori di input, lasciando la EBP per l’ultimo strato. Ma ci sono situazioni in cui si assegnano i centri dei nodi RBF d’autorità e si addestrano solo i pesi di uscita.

La struttura che proponiamo è un’elaborazione delle reti RBF. Invece di determinare la distanza totale dell’input dal centro di ogni nodo, consideriamo ogni nodo come una regola di un sistema Fuzzy. L’attivazione sarà allora l’AND delle distanze dalle componenti del centro. In parole povere:

dove le f sono le funzioni di membership ed i centri corrispondono alle classi dei fuzzy set. Ma per rendere completa l’analogia occorre definire ancora due parametri per ogni dimensione di input. Questi due parametri corrispondono alle bande laterali delle funzioni di membership (vedi Fig. 4).

Poiché in ambito Fuzzy l’AND è generalmente associato alla funzione MIN, l’attivazione è semplicemente il valore minimo fra tutti i valori di verità dell’array di input. Più precisamente:

dove:

Lo strato successivo a questo punto realizzerà la somma pesata delle attivazioni. Dove i pesi non saranno altro che i valori delle classi di output:

Benché dalla descrizione, l’utilizzo di questo sistema possa sembrare un po’ complicato, in realtà si tratta di utilizzare praticamente la stessa libreria delle reti neurali descritta nel precedente articolo, con qualche piccolo cambiamento nelle descrizioni delle reti. Infatti ora ci sono più parametri per i nodi hidden.

Questa volta la rete va inizializzata completamente perché non sarà più addestrata. Il compito di trasformare degli assunti in logica Fuzzy nella struttura della rete, potrebbe rivelarsi un po’ macchinoso; per questo abbiamo pensato di fornire un programmino C++ che legge una descrizione Fuzzy del sistema da implementare e scrive su un file la descrizione completa della rete.

Pilotare Ardusumo con la logica Fuzzy

Nell’articolo presentato in novembre scorso abbiamo usato una Rete Neurale addestrata per pilotare il rover Ardusumo, il quale dispone, fra le altre cose, di due sensori di distanza posti ad un angolo di circa 30° rispetto alla direttrice di marcia e di due motori pilotati in PWM.

Il rover è gestito da un Arduino Uno. I sensori danno una risposta analogica inversamente proporzionale alla distanza dell’ostacolo.

La risposta dei sensori è normalizzata tra 1 (contatto) e 0 (campo libero > di 40cm), dal software di gestione. Mentre il pilotaggio dei motori è normalizzato tra -1 (indietro tutta) e +1 (avanti tutta).

L’addestramento è stato realizzato off-line (su PC), fornendo un set di esempi prototipali di risposte motorie ad impulsi sensoriali.

Vediamo ora come programmare il pilotaggio di Ardusumo usando il sistema Fuzzy implementato mediante la rete Neural Network modificata.

Per prima cosa descriviamo la logica Fuzzy utilizzando una terminologia gestita dal programmino di transcodifica per produrre una descrizione completa della rete neurale fuzzy da inserire nello sketch per Arduino. Si tenga presente che il valore del sensore è inversamente proporzionale alla distanza.

Come si vede dal Listato 1, vengono utilizzate poche parole chiave: “input” e “output” per definire le dimensioni degli ingressi e delle uscite; “inpfuzzyset” per elencare le classi in cui si vogliono partizionare gli input (in questo caso sono le stesse); “outclass” per definire gli insiemi dei valori di uscita conseguenti ad una regola (in questo caso corrispondono ai valori PWM normalizzati da applicare ai due motori); infine le regole descritte dalla parola chiave “if” seguita dalle classi in cui gli input si devono collocare collegate dalla parola chiave “and” e conclusa dalla parola chiave “then” seguita dalla conseguente classe di output.

Tenete presente che carattere minuscolo e maiuscolo contano (case-sensitive), e tutto ciò che è preceduto da “/” viene considerato commento e non è preso in considerazione.
Dando un file con questa descrizione al programma “FuzzyDefine.exe”, quest’ultimo produce un file contenente la descrizione operativa della Neural Network Fuzzy, che può essere riportata in uno sketch Arduino.

Listato 1

input 2 // numero degli input (sensori)
output 2 // numero degli output (motori)
/* insieme delle classi per il sensore 0 ed 1 */
inpfuzzyset 0 L=0.000 V=0.400 VV=0.800 // L:lontano, V:vicino, VV:molto vicino 
inpfuzzyset 1 L=0.000 V=0.400 VV=0.800 // L:lontano, V:vicino, VV:molto vicino 
/* classi per i conseguenti delle regole */
outclass BD -0.200 -0.800 // indietro(back) ruotando a destra
outclass RD 0.400 -0.400 // ruota a destra
outclass RS -0.400 0.400 // ruota a sinistra
outclass AM 0.600 0.600 // avanti con media velocità
outclass AS 1.000 0.600 // avanti piegando a sinistra
outclass AD 0.600 1.000 // avanti piegando a destra
outclass AV 1.000 1.000 // avanti veloce
/* Regole */
if 0=VV and 1=VV then BD
if 0=VV and 1=V then RD
if 0=V and 1=VV then RS
if 0=V and 1=V then AM
if 0=V and 1=L then AS
if 0=L and 1=V then AD
if 0=L and 1=L then AV

Libreria Fuzzy Neural Network

Nel repository https://github.com/open-electronics/NNetFuzzy è presente la versione Fuzzy della Neural Network illustrata nel fascicolo di novembre scorso; la trovate nel Listato 2 e per distinguerla le abbiamo dato un nome differente: “NNetFuzzy”.

Ma in realtà è praticamente identica (solo nell’uso) all’altra, tuttavia i nodi dello strato hidden devono obbligatoriamente chiamarsi “NodeFuzzy” mentre quelli dello strato di uscita devono chiamarsi “NodeDeFuzz” oppure “NodeDFTnh” se si vuole costringere l’uscita tra i valori -1 e +1, o infine “NodeDFSig” se si vogliono uscite comprese tra 0 ed 1 (a patto che la logica implementata lo consenta).

Nello stesso sito è presente il programma “FuzzyDefine” nella forma eseguibile (per Windows) o come sorgente.

Listato 2

char* netdef=
“L0 2 “
“L1 7 NodeFuzzy “
“FCT0 0.8 0.8 “ //regola 0
“FCT1 0.8 0.4 “ //regola 1
“FCT2 0.4 0.8 “ //regola 2
“FCT3 0.4 0.4 “ //regola 3
“FCT4 0.4 0.0 “ //regola 4
“FCT5 0.0 0.4 “ //regola 5
“FCT6 0.0 0.0 “ //regola 6
// pendenze sinistre per le classi utilizzate nelle regole
“FWA0 2.5 2.5 “ 
“FWA1 2.5 2.5 “
“FWA2 2.5 2.5 “
“FWA3 2.5 2.5 “
“FWA4 2.5 0.1 “
“FWA5 0.1 2.5 “
“FWA6 0.1 0.1 “
// pendenze destre per le classi utilizzate nelle regole
“FWB0 0.1 0.1 “ 
“FWB1 0.1 2.5 “
“FWB2 2.5 0.1 “
“FWB3 2.5 2.5 “
“FWB4 2.5 2.5 “
“FWB5 2.5 2.5 “
“FWB6 2.5 2.5 “
“L2 2 NodeDFTnh “
// valori del motore 0 ed 1 per le 6 regole
“OLW0 -0.2 0.4 -0.4 0.6 1.0 0.6 1.0 “
“OLW1 -0.8 -0.4 0.4 0.6 0.6 1.0 1.0 “
;
/* da istanziare come al solito */
NNfuzzy net(netdef); // net instance

Confronto dei due approcci su Ardsumo

Nel Listato 3 è proposto lo sketch che utilizza la Neural Network Fuzzy, mentre nel Listato 4 è mostrato lo sketch presentato nel precedente articolo e che usa una normale Neural Network addestrata su un set di 16 esempi per alcune migliaia di ripetizioni.

Come si vede, gli sketch sono quasi identici, ma se andiamo a vedere il loro funzionamento possiamo verificare che la Rete Neurale produce un comportamento un po’ più “equilibrato”, mentre quella programmata con logica fuzzy e con sole sette regole ha un comportamento un po’ più “schematico”.

In Fig. 5 è rappresentato il comportamento dei due motori per i vari valori dei sensori del sistema con rete neurale, mentre in Fig. 6 l’analoga rappresentazione è relativa al sistema in logica fuzzy.

Fig. 5 Versione dello scketch per Ardusumo con NN e con NNfuzzy.

 

La spiegazione del diverso comportamento sta proprio nella natura dei due processi: il primo, quello relativo al funzionamento con la rete neurale, produce una sintesi interpolata degli esempi e quindi presenta una maggiore continuità, mentre il secondo applica delle regole che, se benché in logica sfumata (Fuzzy), sono più definite e quindi producono una variazione meno uniforme.

Utilizzando un maggior numero di regole, il sistema programmato può diventare più “morbido”.

Questo sistema proposto per implementare un sistema a logica Fuzzy è abbastanza efficiente in esecuzione e permette di usare la stessa modalità operativa del sistema con Neural Network classico (Fig. 6) presenta, inoltre, delle sue caratteristiche ben determinate:
• Adotta il paradigma Sugeno e non il più classico Mamdani (lo studioso che lo ha proposto). Ma ciò a poca importanza perché la maggior parte delle implementazioni con microprocessori adotta questo modello.
• Le funzioni di membership sono lineari e triangolari (al massimo trapezoidali ma solo agli estremi).
• Le funzioni di membership si sovrappongono parzialmente (sul centro di ognuna termina la precedente e inizia la successiva).
• Le regole hanno sempre lo stesso numero di antecedenti e di conseguenti (input e output).

Fig. 6 Pilotaggio di Ardusumo con Neural Network addestrata.

 

Nel caso di due variabili di input possiamo dare una rappresentazione tridimensionale della combinazione delle funzioni di membership in ogni regola (ovvero la sua attivazione) che risulta così rappresentata da una piramide nel grafico (Fig. 8).

Fig. 8 Attivazione delle regole in base ai valori dei due sensori.

 

Vediamo ora cosa ci può entrare in un Arduino Uno. La libreria occupa meno di 10 chilobyte di memoria di programma, quindi molto poco (circa il 25%). Ma lo spazio di lavoro (variabili) è veramente limitato su Arduino Uno.

In ogni caso è possibile creare reti Fuzzy da circa 300 parametri totali (nodi + link). In pratica si può creare al massimo una rete da 4 input 20 regole e 4 output; oppure da 2 input, 30 regole e 2 output; oppure da 5 input, 14 regole e 5 output; oppure ogni altra combinazione intermedia. È chiaro che con queste dimensioni rimane pochissimo spazio alle altre eventuali variabili del programma (Fig. 7).

Fig. 7 Pilotaggio di Ardusumo con NNfuzzy programmata.

 

Riguardo ai tempi di esecuzione, si ha una elaborazione della rete (funzione forward) in un tempo che va da un minimo inferiore a 2 millisecondi (per la rete per Ardusumo) ad un massimo di circa 7 millisecondi, secondo le dimensioni della rete.

In conclusione sul sito github.com/open-electronics sono scaricabili due alternative che permettono di elaborare gli input e gli output analogici di Arduino in modo da fargli generare una risposta anche complessa ma di bassissimo impatto computazionale e abbastanza veloce in un hardware limitato.

Sono sistemi che si possono applicare ad un’infinità di applicazioni che spaziano dalla robotica ai veicoli terrestri o ai velivoli, dai sistemi di allarme all’automazione casalinga o industriale.

Infatti si tenga presente che i sistemi Fuzzy possono essere usati anche come sistemi di controllo dinamici al posto dei PID (controller Proportional Integrative Derivative), perché le variabili di ingresso possono anche rappresentare le derivate (o più precisamente la velocità di variazione ad ogni step temporale) delle funzioni da controllare.

 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Menu