By Claudio Fin 16-8-2000
Ho voluto verificare la possibilità di realizzare reti neurali senza dover effettuare calcoli con numeri reali, ma usando solo interi. Questo per poter realizzare una rete in assembler senza il bisogno di coprocessori matematici o routines in floating point. Inoltre mi interessava verificare la possibilità di contenere i valori di attività in 8 bit (range 0..255) in modo da poter interfacciare direttamente la rete con comuni convertitori ADC a 8 bit in ingresso, o DAC in uscita.
L'obbiettivo era quindi quello di ottenere una funzione di attività del neurone integer perfettamente identica a quella di un comune neurone formale real, in modo da poter effettuare una semplice conversione matematica per passare dal modello real a quello integer.
Il neurone formale ha uno o più ingressi pesati (con valori di attività afferente compresi tra 0 e 1 e pesi qualsiasi), un'attivazione interna Ai e una funzione di trasferimento di uscita sigmoidale Y=1/(1+exp(-X)). In più ogni neurone ha un bias (o polarizzazione) ottenuto aggiungendo un ingresso pesato idealmente collegato a un'unità fittizia sempre attiva al massimo. In questo modo, variando il peso di bias si può aumentare o diminuire il valore dell'attivazione interna.
Il neurone formale "h" riceve l'attività "Ox" del neurone afferente "x" pesata (moltiplicata) per il valore del peso "Wxh". Inoltre riceve l'attività di bias, sempre 1, pesata per il peso di bias "Wb". Queste attività pesate vengono sommate e danno l'attivazione interna "Ai". Questa attivazione passa per la funzione di trasferimento a sigmoide e si ottiene l'attività di uscita "Oh". Nel caso di più neuroni afferenti, chiamiamoli x1 x2 x3 ecc..., si sommano in "Ai" tutti i loro contributi. Se i pesi "W..." sono minori di 1 hanno una funzione attenuante sull' attività afferente, se sono maggiori di 1 hanno un effetto moltiplicativo. Inoltre se sono positivi aumentano l'attivazione "Ai", se sono negativi la diminuiscono (connessione inibitoria). |
|
di trasferimento sigmoidale Sull'asse delle x abbiamo l'attivazione interna "Ai", su quello delle y l'attività di uscita "Oh" |
Andamento dell' attività
Oh in funzione di dell'attività
afferente Ox con tre
diverse configurazioni di pesi.
Wb = -5.30 |
Wb = 6.00 |
Wb = 0.80 |
Avendo come punto di partenza il vincolo di realizzare una rete "eseguibile" su un hardware "povero" sono da fare alcune considerazioni:Non abbiamo la possibilità di effettuare calcoli floating point, la funzione di trasferimento sigmoidale deve perciò essere precalcolata e inserita in una tabella. Dobbiamo interfacciare la rete con circuiti reali a 8 bit, l'attività delle unità (neuroni) deve perciò essere ristretta a 8 bit. Idealmente anche i pesi dovrebbero essere contenuti in 8 bit, ma questo non consente un adeguato range e si ottiene una attività di uscita fortemente a gradini assolutamente non accettabile. Usando 16 bit possiamo rappresentare il peso in 15 di essi e il segno nel rimanente, abbiamo così 32768 punti per rappresentare il range dei pesi. L'attività di moltiplicazione delle attività integer con i pesi integer genera numeri molto grandi (calcolabili in 32 bit). L'attivazione Ai dovrà perciò essere divisa alla fine per un adeguato coefficiente potenza di 2 in modo da essere "proiettabile" all'interno della tabella della funzione di trasferimento sigmoidale. La funzione di trasferimento deve essere adeguatamente "espansa" all'interno degli elementi della tabella in modo da far coincidere la rappresentazione real con quella integer con una minima conversione matematica. I due punti precedenti sono mutuamente vincolati, nel senso che esistono più possibilità per ottenere lo stesso risultato, quello che cambia è la dimensione della tabella. Visto che questa deve essere contenuta in memoria su un hardware "povero" la sua dimensione non deve eccedere gli 8K.
Detto questo empiricamente si è dimostrata valida una tabella di 8K contenente la funzione sigmoidale espansa su circa 6000 elementi e centrata sull'elemento 4095 (avendo come indice un range da 0 a 8190). Come indicato nella procedura seguente il coefficiente 407 "allarga" la sigmoide e anch'esso è stato ricavato empiricamente. Il 255 rappresenta il valore massimo che può assumere l'attività di uscita del neurone.
Procedura di calcolo
punti sigmoide
var
begin
|
La pesatura degli ingressi si effettua con una semplice moltiplicazione integer e il valore ottenuto va sommato ad Ai. Quindi, nel caso del neurone rappresentato all'inizio (con un solo afferente) possiamo dire che Ai vale:
Ai = Ox * Wxh
+ 255 * Wb
(ricordare che sono calcoli con interi!)
A questo punto dobbiamo dividere Ai per un secondo coefficiente di "regolazione", che empiricamente è risultato essere 1024, ed infine dobbiamo applicare la funzione di trasferimento. In pratica possiamo ottenere l'indice della tabella con 4095+Ai e leggere il valore di attività contenuto. Nasce un problema se Ai è minore di -4095 o maggiore di 4095, perchè in questo caso si andrebbe a puntare a elementi inesistenti (prima dell'inizio o dopo la fine della tabella). Si risolve usando la tabella solo se Ai è nel range ammesso. Se è minore l'attività è sicuramente 0, se è maggiore è sicuramente 255.
Procedura di applicazione
funzione di trasferimento
function ftrasf(Ai:integer):byte;
Nota:Ai deve essere un intero a 32 bit e non a 16 |
Fatte queste premesse di seguito sono riportati i grafici dell'attività di uscita del neurone integer impostando le stesse condizioni viste nel caso del neurone real. Come si può vedere l'andamento dell'attività è identico, solo che il valore della sua attività varia da 0 a 255 invece che da 0.000 a 1.000, e i pesi sono la controparte intera moltiplicata per 1638.35 dei pesi reali. Si può così progettare o studiare una rete real e passarla in integer semplicemente moltiplicando i pesi per 1638.35 e convertendo il range 0..1 in 0..255!
Wb = -8683 |
Wb = 9830 |
Wb = 1311 |
- L'attività di uscita è composta da soli 256 punti e risente in minima parte di un effetto "quantizzazione".
- L'intero range dei pesi è rappresentato in soli 32768 punti, e con i coefficienti impostati come in precedenza la rete è limitata all' l'equivalente reale di un range di pesi da -20 a +20 come valori massimi e +/-0.00061 come valori minimi.
- Per non rischiare l'overflow dell'attivazione Ai nel caso peggiore, si deve limitare il numero di neuroni afferenti a non più di 250. Infatti considerando che la max attività è 255 e il max peso è 32767 un termine della moltiplicazione (connessione) può dare origine al massimo ad un incremento o decremento di Ai pari a 8.355.585, questo significa che in 32 bit con segno possono essere contenute al massimo 2.147.483.647 / 8.355.585 = 257 attività (pari a 257 connessioni afferenti sullo stesso neurone, tutte attive a 255 e tutte con peso al massimo e dello stesso segno!)
Questo oggetto Delphi 2.0 realizza in modo semplice il comportamento del neurone integer, e incapsula tutti i coefficienti e la funzione di trasferimento. Si usa nel seguente modo: si istanzia l'oggetto, ad esempio usando una variabile N di tipo Tneurone, lo si inizializza chiamando il metodo N.init.Poi si impostano peso e attività afferente (N.p:=.... N.i:=....) e si chiama il metodo N.calc, si ripetono questi tre passi per tutte le connessioni afferenti e alla fine si imposta il bias con N.b:=... e si chiama la funzione N.o che fornisce l'attività di uscita del neurone. Prima di effettuare un altro calcolo si chiama N.reset che azzera bias e attività interna.
unit neurone;
interface type
implementation const
//--------------------------------------------------------------- function Tneurone.O:byte;
//--------------------------------------------------------------- procedure Tneurone.Init;
//--------------------------------------------------------------- procedure Tneurone.Reset;
//--------------------------------------------------------------- procedure Tneurone.Calc;
end. |
Pagina e disegni realizzati da Claudio Fin
Ultimo aggiornamento 22-9-2000
|
|