Newsgroup: it.comp.ia
Titolo: Informazione Algoritmi Reti Neurali





Salve cercavodei siti in cui sono implementati in 
linguaggio C o Pascal o altri degli algoritmi sulle Reti 
Neurali







Una implementazione di una semplice classe C++ per 
la gestione di una rete neuronale. La classe e' semplice e l'algoritmo 
implementato e' di tipo back-propagation senza momentum. Puoi modificarla, 
ottimizzarla, implementare nuove funzionalita' ... Insomma facci quello che 
vuoi. L'unica restrizione consiste nel lasciare inalterata l'intestazione. 



 


 


------- cut here - beginning of code  
-------------


/*
 Author:       
glu...@tiscalinet.it
 Version:      1.1
 Learning 
Algorithm: BackPropagation without momentum (in future 
versions)
 Date:        19-May-2001
 Info:
   
Neural Net classes definition.
   Questo header file contiene la 
definizione delle costanti, delle classi atte a descrivere una rete 
neuronale.
   Le reti trattate sono reti MLP feed-forward con 
algoritmo di apprendimento di tipo Back-Propagation con 
momentum.
   Ogni rete ha un generico numero di strati nascosti, 
uno strato di input e uno di output.
   Ogni strato e' 
completamente connesso con lo strato seguente.
   Non sono ammessi 
link ricorrenti (ie. un nodo non puo' essere linkato con se stesso)


 


 Notes:
  Originally written for 
Linux Mandrake 7.2 g++ and further ported for Microsoft 
VisualC++
  Porting process involved rand() and initstate(,,) 
functions. Modify depending on OS and compiler.
*/


 


#include<iostream.h>
#include<stdlib.h>
#include<math.h>
#include<stdio.h>


 


// random weigth generator parameters
const unsigned int SEED = 
254;
const unsigned int SIZE = 16;
char STATE[16];
//   
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//   0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};


 


//  Trasfer Function Parameter
const double K = 0.5;


 


//  MU=learning rate   default value = 0.
const double 
MU=0.75;


 


// BETA=momentum       default value = 
0.5
const double BETA=0.5;


 


// Potenziale di default dei neuroni della rete.
const double 
POTENZIALE_INIZIALE=0.0;


 


// definizione di tipo di matrice ad elementi reali
typedef double 
MATRIX_ELEMENT_TYPE;
typedef MATRIX_ELEMENT_TYPE* MATRIX_ROW;
typedef 
MATRIX_ROW* MATRICE;


 


 


 


class NeuralNetwork
{
private:
  // numero di strati della 
rete
  int iNum_layers;
  // vettore contenente la dimensione di 
ogni strato della rete
  int *iLayersSize;
  // numero totale di 
neuroni;
  long int iNumNeuroni;
  long int iNumPesi;


 


  // vettore per la rappresentazioone del potenziale dei singoli 
neuroni. V[i] = P(i-esimo neurone)
  double *dPotenziale;
  // 
vettore per la rappresentazione del peso del bias assimilato ad un neurone con 
potenziale di attivazione sempre pari ad 1.
  double 
*dBiasWeight;
  // puntatore agli elementi del vettore "dPotenziale" che 
rappresentano il potenziale dei neurono di output
  double 
*dOutput;
  // puntatore al vettore di Delta necessari per 
l'apprendimento
  double *dDelta;


 


  // vettore di matrici che descrivono le interconnessioni tra due 
piani consecutivi della rete
  // una matrice rappresenta i pesi con cui 
sono connessi due neuroni appartenenti a piani consecutivi.
  // le 
informazioni sono organizzate per colonne ossia, detti N1 ed N2 due neuroni 
appartenenti
  // ai piani 1 e 2 rispettivamente,  si ha che, detta 
M la matrice dei pesi di interconnessione tra detti piani,
  // M[N1,N2] 
e' il peso della connessione tra detti neuroni. Segue che per calcolare il 
potenziale di attivazione
  // di N2 e' necessario sommare M[n,N2] per 
ogni n appertenete al piano 1.
  // i neuroni dello starto di INPUT NON 
HANNO IL BIAS.
  //MATRICE *mVettMatrixPesi;
  double 
*mVettMatrixPesi;


 


  // retituisce un valore casuale compreso tra min e max
  
double GetWeight(double min, double max);
  long int 
GetIndiceNeurone(int iLayer, int iIndiceInLayer);
  double 
TransferFunction(double dPotenziale);
  double 
DerivataTransferFunction(double dPotenziale);
  double 
GetPesoConnessione(int iStrato, int iNeurone, int iNeuroneSucc);


 


public:
  NeuralNetwork(int NumeroLayers, int 
*DimensioneLayers);
  ~NeuralNetwork();


 


  int LayerSize(int layer); // dimensione dell'i-esimo layer
  
int LayerNum(); // numero di layer costituenti la rete
  long int 
NumeroNeuroni(); //restituisce il numero di neuroni;
  int 
InitWeights(double min, double max);  // inizializza i pesi in maniera 
casuale con valori compresi tra min e max
  void 
PrintWeights();
  double *Feed(double* pattern); // alimenta la rete 
neuronale
  void Learn(double* RealOutput);
  void 
PrintBias();
  void PrintPotenziale();
 void 
PrintOutput();


 


};


 


 


 


 


 


/*
  implementazione della rete neuronale
*/


 


// PRIVATE
double NeuralNetwork::GetWeight(double min, double 
max)
{
  // OK
  return 
((double)rand()/(double)RAND_MAX)*(double)(max-min)+(double)min;
}


 


long int NeuralNetwork::GetIndiceNeurone(int iLayer, int 
iIndiceInLayer)
{
  // OK
  int i;
  long int result 
= 0;
  for(i=0;i<iLayer;i++)
    result += 
LayerSize(i);
  return (result + iIndiceInLayer);
}


 


double NeuralNetwork::TransferFunction(double 
dPotenziale)
{
  return (1/(1+exp((-K)*dPotenziale)));
}


 


double NeuralNetwork::DerivataTransferFunction(double 
dPotenziale)
{
  // SLOW !!
  return (K * 
TransferFunction(dPotenziale) * (1-TransferFunction(dPotenziale)));
}


 


double NeuralNetwork::GetPesoConnessione(int iStrato, int iNeurone, int 
iNeuroneSucc)
{
  // il neurone identificato da iNeurone appartiene 
allo strato 
  // iStrato e quello identificato da iNeuroneSucc 
appartiene allo strato iStrato+1
  int i;
  long int 
k=0;
  for(i=0; i<iStrato; i++)
    k += 
LayerSize(i) * LayerSize(i+1);
  for(i=0; i<iNeuroneSucc; 
i++)
    k += LayerSize(iStrato);
  k += 
iNeurone;
  return (mVettMatrixPesi[k]);
}


 


// PUBLIC


 


// contructor
NeuralNetwork::NeuralNetwork(int NumeroLayers, 
int*DimensioneLayers)
{
  int i, j = 0;
  iNumNeuroni= 
0;
  iNumPesi = 0;
  
  //initstate(SEED, STATE, 
SIZE);
  iNum_layers = NumeroLayers;


 


  iLayersSize = new int[iNum_layers];
  for(i=0; 
i<iNum_layers;i++)
  {
    iLayersSize[i] = 
DimensioneLayers[i];
    iNumNeuroni += 
iLayersSize[i];
  }
  // create e init vettore dei potenziali, 
Delta, Offset
  dPotenziale = new double[iNumNeuroni];
  dDelta 
= new double[iNumNeuroni];
  dBiasWeight = new 
double[iNumNeuroni];
  for(i=0;i<iNumNeuroni;i++)
  
{
    dPotenziale[i] = 
POTENZIALE_INIZIALE;
    dDelta[i] = 
0.0;
    if (i < 
LayerSize(0))
      dBiasWeight[i] = 
0;
    else
      dBiasWeight[i] = 
GetWeight(-1,1);
  }
  // inizializza il vettore 
risultato
  dOutput = new double[LayerSize(NumeroLayers-1)]; 
//dPotenziale + (NumeroNeuroni() - LayerSize(NumeroLayers-1));


 


  // create ed init matrici dei pesi (calcolo la dimensione totale 
delle matrici e alloco un unico blocco per contenerle)
  
for(i=0;i<iNum_layers-1;i++)
    iNumPesi += LayerSize(i) * 
LayerSize(i+1);
  mVettMatrixPesi = new double[iNumPesi];
  

}


 


NeuralNetwork::~NeuralNetwork()
{
  delete 
iLayersSize;
  delete mVettMatrixPesi;
  delete 
dPotenziale;
  delete dBiasWeight;
}


 


int NeuralNetwork::LayerNum()
{
  return 
iNum_layers;
}


 


int NeuralNetwork::LayerSize(int layerNum)
{
  return 
iLayersSize[layerNum];
}


 


long int NeuralNetwork::NumeroNeuroni()
{
  return 
iNumNeuroni;
}


 


int NeuralNetwork::InitWeights(double min, double max)
{
  int 
i;
  double dTemp = 1;


 


  for(i=0; i<iNumPesi; i++)
    
mVettMatrixPesi[i] = GetWeight(min, max);
  return 0;
}


 


void NeuralNetwork::PrintWeights()
{
  int i,j,k, l = 0, 
m=0;
  for(i=1; i<iNum_layers;i++)
    
{
      l += 
LayerSize(i-1);      

   printf("Matrice di connessione livelli %d, %d; \t\t 
Dimesione Layer %d \n", i, i-1, l);
      for(j=0; 
j<iLayersSize[i-1]; j++)
 for(k=0; k<iLayersSize[i]; 
k++)     
   printf( "Connessione neurone 
%d con neurone %d : \t\t %f \n", (j+l-LayerSize(i-1)), (l + k), 
mVettMatrixPesi[m+ k*LayerSize(i-1) + j]);
      m 
+= LayerSize(i) * LayerSize(i-1);
    }
}


 


void NeuralNetwork::PrintBias()
{
  int i;
  for(i=0; 
i<NumeroNeuroni(); i++)
    printf("\nIl bias del neurone 
n.%d e': %f", i,dBiasWeight[i]);
}


 


void NeuralNetwork::PrintPotenziale()
{
  int i;
  
for(i=0; i<NumeroNeuroni(); i++)
    printf("\nIl 
potenziale del neurone n.%d e': %f", i,dPotenziale[i]);
}


 


void NeuralNetwork::PrintOutput()
{
  int 
i;
 printf("\nL'output della rete è: ");
  for(i=0; 
i<LayerSize(LayerNum()-1); i++)
    printf("\n\t Elemento 
%d = \t %f ", i,dOutput[i]);
}


 


double *NeuralNetwork::Feed(double *pattern)
{
  int i,j,k = 
0;
  long int iCurrentNeurone = 0;


 


  
  for(i=0; i<iNumNeuroni; i++) {
    
if (i < LayerSize(0))
      dPotenziale[i] = 
pattern[i];
    else
      
dPotenziale[i] = dBiasWeight[i];
  }
  
  // calcolo il 
potenziale dell'i-esimo neurone per i = 0 .. iNumNeuroni
  for(i=1; 
i<LayerNum(); i++)
    for(j=0; j<LayerSize(i); 
j++)
      for(k=0; k<LayerSize(i-1); 
k++)
      
{
/*
        cout << 
"GetIndiceNeurone(" << i << ", " << j << ")=" << 
GetIndiceNeurone(i, j) << 
"\t";
        cout << "dPotenziale " 
<< dPotenziale[GetIndiceNeurone(i, j)] << 
"\n";
        cout << 
"GetIndiceNeurone(" << i-1 << ", " << k << ")=" << 
GetIndiceNeurone(i-1, k) << 
"\t";
        cout << "dPotenziale " 
<< dPotenziale[GetIndiceNeurone(i-1, k)] << 
"\n";
        cout << 
"TransferFunction " << TransferFunction(dPotenziale[GetIndiceNeurone(i-1, 
k)]) << "\n";
       cout << 
"mVettMatrixPesi " << GetPesoConnessione(i-1,k,j) << "\n"; 
//mVettMatrixPesi[j*LayerSize(i-1)+k] << 
"\n";
        cout << "dPotenziale 
dopo TransferFunction " << dPotenziale[GetIndiceNeurone(i, j)] << 
"\n\n";
*/
        
dPotenziale[GetIndiceNeurone(i, j)] += 
TransferFunction(dPotenziale[GetIndiceNeurone(i-1, k)]) *  
GetPesoConnessione(i-1,k,j);//mVettMatrixPesi[j*LayerSize(i-1)+k];
      
}
  for(i=0; i<LayerSize(LayerNum()-1); i++)
    
dOutput[i] = TransferFunction(dPotenziale[GetIndiceNeurone(LayerNum()-1, 
i)]);
  return dOutput;
}


 


void NeuralNetwork::Learn(double* RealOutput)
{
  // 
apprendimento mediante algoritmo BackPropagation semplice
  // La 
metrica d'errore e': E=0.5*Sum(Yi-Di)^2 
  
//                        
dove Yi e' i-esimo elemento di NetOutput 
  
//                        
mentre Di e' i-esimo elemento di RealOutput


 


  int i, j, k;  
  double* 
dDeltaIndice;       // ptr al neurone di cui sto 
calcolando il delta
  double* dBiasIndice;    // ptr al 
bias del neurone in esame
  double* dPesoConnessione;   // ptr 
al peso della connessione in esame
  // calcolo Delta per i neuroni 
dello strato di output.


 


  


 


  // primo neurone dello strato di output.
  dDeltaIndice = 
dDelta + (NumeroNeuroni() - LayerSize(LayerNum()-1));
  // allineo il 
bias
  dBiasIndice = dBiasWeight + NumeroNeuroni() -1;


 


  for(i=0;i<LayerSize(LayerNum()-1);i++)
  
{
    dDeltaIndice[i] = (dOutput[i] - RealOutput[i]) 
*
            
TransferFunction(dPotenziale[GetIndiceNeurone(LayerNum()-1, 
i)])*
              
K*
            
((double)1-TransferFunction(dPotenziale[GetIndiceNeurone(LayerNum()-1, 
i)]));
                                        
// implemetazione piu' effciente della derivata prima della funzione di 
trasferimento
  }


 


  


 


  // Delta Wij = -MU * Delta-i * Zj dove i e' un neurone dello strato 
superiore a quello a cui appartiene j. (Zj e' l'output di j).


 


  // peso della connessione tra l'ultimo neorone dello strato di 
output e l'ultimo dello strato immediatamente precedente.
  
dPesoConnessione = mVettMatrixPesi;
  
for(i=0;i<LayerNum()-1;i++)
    dPesoConnessione += 
LayerSize(i) * LayerSize(i+1);
  dPesoConnessione--;
  // 
dDeltaIndice punta all'ultimo elemento del vettore dei DELTA
  
dDeltaIndice += LayerSize(LayerNum()-1)-1;
  
  
for(k=LayerNum()-2; k>=0; k--)
  // un layer alla volta partendo 
dall'ultimo HIDDEN a ritroso fino all'INPUT
  {
    
for(i=LayerSize(k+1)-1; i>=0; i--)
    // esamino un 
neurone alla volta (nello strato succesivo al k-esimo) partendo 
dall'ultimo.
    {
      
for(j=LayerSize(k)-1;j>=0; j--)
      // un 
neurone alla volta nel k-esimo strato
      
{
        *dPesoConnessione += -MU * 
(*dDeltaIndice) * 
TransferFunction(dPotenziale[GetIndiceNeurone(k,j)]);
        
dPesoConnessione--; 
      }
   // 
aggiorno il bias de neurone in esame
   *dBiasIndice += -MU * 
(*dDeltaIndice); // la funzione di trasferimento del neurone fittizio per il 
bias è sempre 
1
   dBiasIndice--;
      
dDeltaIndice--;
    }
    // calcolo i delta 
dei neuroni dello strato attuale.
    for(j=LayerSize(k)-1; 
j>=0; j--)
    {
      
*dDeltaIndice = 0.0;
      for(i=LayerSize(k+1)-1; 
i>=0; i--)
      
{
        *dDeltaIndice += 
dDelta[GetIndiceNeurone(k+1, i)] * GetPesoConnessione(k, j, 
i);
      }
      
*dDeltaIndice = *dDeltaIndice * K * 
TransferFunction(dPotenziale[GetIndiceNeurone(k, j)]) * 
(1-TransferFunction(dPotenziale[GetIndiceNeurone(k, 
j)]));
      dDeltaIndice--;
    
}
    dDeltaIndice += LayerSize(k);
  
}
}