Neuro.dll
Esempi di implementazione.

 

 

 


Implementazione in C

 

La libreria, in questa versione, deve essere utilizzata in modalità "run time", quindi utilizzando le funzioni LoadLibrary e GetProcAddress di Windows. Includere le seguenti dichiarazioni:

#include <windows.h>

typedef short int INTG;
typedef float REAL;
typedef void NET; /* Che significa?!? Che ci serve solo il puntatore... */

NET* (FAR PASCAL *GenerateNetwork)(INTG nlayers, INTG* laycnt, REAL alpha, REAL eta, REAL gain);
void (FAR PASCAL *InitializeRandoms)(INTG s);
void (FAR PASCAL *RandomWeights)(NET* Net);
void (FAR PASCAL *SetInput)(NET* Net, REAL* Input);
void (FAR PASCAL *GetOutput)(NET* Net, REAL* Output);
REAL (FAR PASCAL *GetError)(NET* Net);
void (FAR PASCAL *SetParam)(NET* Net, REAL alpha, REAL eta, REAL gain);
void (FAR PASCAL *SaveNet)(NET* Net, char* FileName);
NET* (FAR PASCAL *LoadNet)(char* FileName);
void (FAR PASCAL *SimulateNet)(NET* Net, REAL* Input, REAL* Output, REAL* Target, INTG Training);
void (FAR PASCAL *Informations)(void);

All'interno della funzione che carica la libreria (il main di solito...) includere:

/* Dichiarare queste variabili */
HINSTANCE hLib;
NET *net;


hLib = LoadLibrary("Neuro.dll");
if (hLib!=NULL)
{
   printf("\nLibreria trovata e caricata..."); /*  questo è opzionale ovviamente */

   GenerateNetwork =(NET* (FAR PASCAL *)(INTG, INTG*, REAL, REAL, REAL)) GetProcAddress(hLib, "GenerateNetwork");
   InitializeRandoms =(void (FAR PASCAL *)(INTG)) GetProcAddress(hLib, "InitializeRandoms");
   RandomWeights =(void (FAR PASCAL *)(NET*)) GetProcAddress(hLib, "RandomWeights");
   SetInput =(void (FAR PASCAL *)(NET*, REAL*)) GetProcAddress(hLib, "SetInput");
   GetOutput = (void (FAR PASCAL *)(NET*, REAL*))GetProcAddress(hLib, "GetOutput");
   GetError = (REAL (FAR PASCAL *)(NET*))GetProcAddress(hLib, "GetError");
   SetParam = (void (FAR PASCAL *)(NET*, REAL, REAL, REAL)) GetProcAddress(hLib, "SetParam");
   SaveNet = (void (FAR PASCAL *)(NET*, char*)) GetProcAddress(hLib, "SaveNet");
   LoadNet = (NET* (FAR PASCAL *)(char*)) GetProcAddress(hLib, "LoadNet");
   SimulateNet = (void (FAR PASCAL *)(NET*, REAL*, REAL*, REAL*, INTG)) GetProcAddress(hLib, "SimulateNet");
   Informations = (void (FAR PASCAL *)(void)) GetProcAddress(hLib, "Informations");
}
else
  printf("\nLibreria non trovata!!!"); /*  anche questo è opzionale... */

A questo punto le funzioni possono essere chiamate normalmente.
Ad esempio:

net = GenerateNetwork(3, layers, 0, 0.5, 1); /* genera la rete */
RandomWeights(net); /* inizializza i pesi */
SimulateNet(net, inp, outp, targ, 1); /* addestra la rete */
err = GetError(net); /* legge l'errore */

Dove (in questo caso) layers è un array di dimensione 3 che contiene il numero di neuroni in ognuno dei 3 strati della rete, inp, outp e targ, sono sempre degli array di dimensione opportuna che rappresentano gli ingressi, le uscite e l'uscita desiderata.

 

 


Applicazione di esempio in C

 

Il seguente programmino dimostra l'utilizzo della rete in C/C++, e consiste nell'addestramento della rete al fine di farle apprendere la funzione Sen(x) nell'intervallo [0, PI].
Per provare il programma inserire tutto il codice sottostante in una funzione o anche nel main, ed aggiungere opzionalmente le funzioni per il plotting dei dati (diverse a secondo l'ambiente di sviluppo che si sta utilizzando...).
Il risultato è visibile, assieme ad alcuni commenti nel paragrafo "Osservazioni importanti".

 

INTG layers[3]={1,4,1};				// numero neuroni per ogni layer
REAL inp[1], outp[1], targ[1];			// array di input, output e target
int i;

net = GenerateNetwork(3, layers, 0, 2, 1);	// genera la rete
RandomWeights(net);				// inizializza i pesi


// *** Addestramento della rete: 10000 esempi! ***
for(i=0; i<10000; i++)
{
	
	inp[0]=((REAL) random(100))/100;	// ingresso: angolo casuale normalizz.
	targ[0]=sin(M_PI*inp[0]);		// target: seno dell'angolo
	
	
	SimulateNet(net, inp, outp, targ, 1);	// addestramento rete
	
	// Opzionalmente:
	// Plotting di inp[0]: ingresso rete
	// Plotting di outp[0]: uscita rete
	// Plotting di GetError(net): errore rete
}


// *** Simulazione della rete ***
for(i=0; i<500; i++)
{
	
	inp[0]=((REAL) i) / 500;		// input: angolo normalizzato
	//targ[0]=sin(M_PI*inp[0]);		// target: seno (solo per il plotting)
	
	SimulateNet(net, inp, outp, targ, 0);
	
	// Opzionalmente:
	// Plotting di inp[0]: ingresso rete
	// Plotting di outp[0]: uscita rete
	// Plotting di GetError(net): errore rete
}

 


Implementazione in Visual Basic

 

Per utilizzare la libreria basta dichiarare le seguenti funzioni in un modulo:

Declare Function GenerateNetwork Lib "Neuro.dll" (ByVal n As Integer, ByRef ulc As Integer, ByVal alpha As Single, ByVal eta As Single, ByVal gain As Single) As Long
Declare Sub InitializeRandoms Lib "Neuro.dll" (ByVal Seed As Integer)
Declare Sub RandomWeights Lib "Neuro.dll" (ByVal Net As Long)
Declare Sub SetInput Lib "Neuro.dll" (ByVal Net As Long, ByRef i As Single)
Declare Sub GetOutput Lib "Neuro.dll" (ByVal Net As Long, ByRef o As Single)
Declare Sub SaveNet Lib "Neuro.dll" (ByVal Net As Long, ByVal FileName As String)
Declare Function LoadNet Lib "Neuro.dll" (ByVal FileName As String) As Long
Declare Sub SimulateNet Lib "Neuro.dll" (ByVal Net As Long, ByRef i As Single, ByRef o As Single, ByRef t As Single, ByVal tflag As Integer)
Declare Function GetError Lib "Neuro.dll" (ByVal Net As Long) As Single
Declare Sub Informations Lib "Neuro.dll" ()

Se la libreria risiede in un altra directory è necessario includere l'intero percorso.
Le funzioni possono ora essere chiamate normalmente (o quasi...).
Il problema è che il VB non permette di utilizzare in maniera esplicita i puntatori (o forse non ho ancora capito come si fa!), per cui ho utilizzato il seguente metodo per passare gli array: dichiarare un passaggio per riferimento (ByRef) e passare, nella chiamata di funzione il primo elemento dell'array.
Pensavo che ci fosse un problema del genere anche per le stringhe, che invece sembrano comportarsi bene...
Un esempio è il seguente:

' La rete creata avrà 3 layer di 4, 3 e 2 neuroni rispettivamente

Dim NetPt As Long		' Puntatore alla rete
Dim Nlay(2) As Integer		' Array contenente il numero di neuroni per layer
Dim Inp(3) As Single		' Array di input
Dim Outp(1) As Single		' Array di output
Dim Targ(1) As Single		' Array di Target
Dim NomeFile As String		' Stringa

Nlay(0) = 4			' Numero di neuroni in ciascun layer
Nlay(1) = 3
Nlay(2) = 2
NomeFile="MiaRete.ann"		' Nome del file in cui salvare la rete

NetPt = GenerateNetwork(3, Nlay(0), 0, 2, 1)	' notare il passaggio di Nlay(0) come array
Call RandomWeights(NetPt)

...

Call SimulateNet(NetPt, Inp(0), Outp(0), Targ(0), 1)

Call SaveNet(NetPt, NomeFile)

 

 


Applicazione di esempio in VisualBasic

 

Il seguente programmino dimostra l'utilizzo della rete in VisualBasic, e consiste nell'addestramento della rete al fine di farle apprendere la funzione Sen(x) nell'intervallo [0, PI].
Per provare il programma inserire il codice sottostante in una funzione qualsiasi, ad esempio in Form_Click(), e modificare opzionalmente le funzioni per il plotting (PSet) secondo le preferenze.
Il risultato è visibile, assieme ad alcuni commenti nel paragrafo "Osservazioni importanti".

 

' Variabili relative alla rete
Dim NetPt As Long		' Puntatore alla rete
Dim Nlay(2) As Integer		' Array contenente il numero di neuroni per layer
Dim Inp(0) As Single		' Array di input
Dim Outp(0) As Single		' Array di output
Dim Targ(0) As Single		' Array di Target
Dim NomeFile As String		' Stringa

' Variabili ausiliarie
Dim angolo As Single
Dim seno As Single
Dim pi As Single
Dim esempi As Integer


Nlay(0) = 1	' Numero di neuroni del layer 1 (ingresso)
Nlay(1) = 8	' Numero di nueroni del layer 2 (nascosto)
Nlay(2) = 1	' Numero di neuroni del nayer 3 (output)

pi = 4 * Atn(1)	' Valore del Pi greco

esempi = 10000	' Numero esempi per l'addestramento

' Creazione della rete:
' 3 layer di lunghezza Nlay(i)
' Alpha=0 ("momentum")
' Eta=2 ("learning rate")
' Gain=1 (guadagno funzione sigmoide)
NetPt = GenerateNetwork(3, Nlay(0), 0, 2, 1)

' Inizializzazione casuale dei pesi
Call RandomWeights(NetPt)

' *** Addestramento rete (10000 esempi!) ***
For t = 0 To esempi

	' Dati per l'addestramento
	angolo = Rnd			' angolo normalizzato
	seno = Sin(angolo * pi)		' seno dell'angolo

	' Training set
	Inp(0) = angolo
	Targ(0) = seno

	' Training
	Call SimulateNet(NetPt, Inp(0), Outp(0), Targ(0), 1)

	' Plotting errore
	'PSet (10 + 490 * t / esempi, 100 - 200 * GetError(NetPt)), vbRed
	'PSet (10 + 490 * t / esempi, 200 - 50 * seno), vbGreen
	'PSet (10 + 490 * t / esempi, 300 - 50 * Outp(0)), vbMagenta

Next


' *** Simulazione rete ***
For t = 0 To 400

	' Training set
	angolo = t / 400
	seno = Sin(angolo * pi)

	' Simulazione rete
	Inp(0) = angolo

	Call SimulateNet(NetPt, Inp(0), Outp(0), Targ(0), 0)

	' Plotting funzione
	'PSet (t, 350 - 50 * seno), vbGreen
	'PSet (t, 350 - 50 * Outp(0)), vbCyan
	'PSet (t, 350 - 50 * GetError(NetPt)), vbRed

Next

 


Osservazioni importanti

 

Le reti neurali sono degli oggetti complessi e difficili da utilizzare in genere. Questa difficoltà non è dovuta soltanto alla complessità del codice che le implementa (che in realtà è abbastanza semplice), ma al fatto che è difficile riuscire ad ottenere i risultati voluti. Una prima grossa difficoltà consiste nel determinare la topologia della rete migliore per l'applicazione che si vuole implementare: non esistono teorie riguardo alla scelta ottima del numero di layer e del numero di neuroni per ciascun layer. In genere si procede per esperienza, rifacendosi ad applicazioni simili o per tentativi. Una scelta sbagliata in questa fase può portare a pessime prestazioni o alla necessità di addestramenti lunghisimi.
Una seconda difficoltà è data dalla scelta dei parametri della simulazione: il coefficiente di momentum, il learning rate e il guadagno della funzione sigmoide. Anche in questo caso si procede di solito per esperienza o per tentatvi.
L'ultima difficoltà, forse quella più grande, è data dalla scelta del training set e soprattutto dal modo di presentarlo alla rete nella fase di addestramento. Se in questa fase non si procede nel modo corretto la rete non impara affatto o impara male.

Si possono fare inoltre diverse altre considerazioni. A tale scopo consideriamo il programma di esempio riportato sopra (apprendimento della funzione sen(x)), nel modo in cui è stato impostato si ottengono i seguenti risultati:

 

 

Si può notare che:

  1. Le coppie di esempio (angolo, seno) sono state scelte in maniera casuale (con distribuzione di probabilità uniforme) tra tutte quelle possibili. Se si fossero mostrate coppie in ordine crescente di angolo ad esempio, la rete si sarebbe "assestata" di volta in volta sugli ultimi valori forniti, "dimenticando" quelli passati.
    Non è sempre così comunque, ogni tipo di problema necessita di un addestramento studiato su misura (cioè di diverse prove per stabilire quale sia il migliore!)

  2. I valori forniti alla rete devono essere normalizzati, cioè espressi da un numero compreso tra 0 e 1. Per fare questo è sufficiente dividere tutti i valori di ingresso per il valore massimo presente nell'insieme i addestramento. Anche in uscita si ottengono dei valori normalizzati (a causa del codominio della funzione sigmoide), è quindi opportuno riscalarli.

  3. Sono necessari circa 7000 esempi prima che l'errore inizi a diminuire visibilmente. Questo numero può variare ampiamente comunque (vista la natura stocastica dell'algoritmo di apprendimento e della scelta dei pesi iniziali).

  4. L'uscita della rete ha un errore maggiore quando il valore teorico che dovrebbe restituire è 0 o 1 (o vicino), questo è dovuto al fatto la funzione sigmoide vale 0 o 1 soltanto asintoticamente. Per diminuire questo effetto spesso è sufficiente aumentare il parametro di "guadagno", o se non bastasse aumentare anche il numero di neuroni.

 

 


F.A.Q.

 

 

 


Questa casa non
è un albergo!
Hosted by www.Geocities.ws

1