miei programmi in c su knoppix e relativi problemi

anche_per_il_direttore

Nuovo Utente
63
2
ciao, oggi posto un codice (quello che il codice fa e specificato al suo interno)
ho un problema col ciclo for, mi spiego, il ciclo dovrebbe stamparmi riga per riga i valori di ingresso della funzione OR, ossia le quattro combinazioni 0,0; 0,1; 1,0; 1,1 con a fianco per ogni riga il valore della funzione ma cosi non fa.
comunque posto il codice e se qualcuno ha qualche suggerimento ben venga.
grazie in anticipo

C:
/*questo programma descrive il comportamento del percettrone a due ingressi
e una uscita  e calcola la funzione OR come uscita, la funzione di attivazione
e la sommatoria del prodotto dei pesi e degli ingressi e la funzione di trasferimento e la
funzione a gradino, quindi il percettrone ha solo due uscite o zero o uno,
in ingresso abbiamo 4 coppie che combinate ci danno i valori OR*/

#include<stdio.h>
//#include<stdlib.h>
//#include<cstdio.h>
//#include<cstdlib.h>
//#include<iostream.h>
//#include"pr9.h"

typedef double T_Precision;
const size_t n = 2;    /*numero di ingressi*/

T_Precision activation_function(const T_Precision *x,const T_Precision *w, size_t n) {

T_Precision potential = 0;

size_t i,j;

for (i=0;i<=n;i++) {
potential += x[i]*w[i]; }
return potential; }



T_Precision transfer_function(const T_Precision *x,const T_Precision *w, size_t n) {
                                 
                                  T_Precision potential = activation_function(x,w,n);
                                  return (T_Precision) (potential>0);}



     int main (void)
     {
        
       
         T_Precision x[n+1];    /*vettore ingressi del percettrone piu il bias*/
         T_Precision w[n+1];    /*vettore pesi sinaptici piu il peso del bias*/
         T_Precision y;         /*uscita del percettrone*/
        

         size_t i,j;            /*iteratori*/

         x[n] = -1;             /*valore di bias*/
        
        
         w[0] = 5;              /*imposto valore dei pesi*/
         w[1] = 5;
         w[2] = 4;              /*peso sinaptico del bias*/
       
        
         printf ("[x1]\t[x2]\t[y]\n");  /*stampo intestazione tabella*/
   
        
   
         for (j=0; j<=1; j++)
         {         /*provo tutte le combinazioni degli ingressi,ossia permuto gli ingressi, se gli ingressi
                        sono solo coppie di zeri e uno ho un quadrato nello spazio degli ingressi quindi 4 vertici */
            
             for (i=0; i<=1; i++);
             {
               
                 x[0]=i;
                 x[1]=j;
                
                 y=transfer_function(x,w,n);    /*calcolo l uscita del percettrone*/
                 printf("%.0f\t%.0f\t%.0f\n",x[0],x[1],y);  /*stampo gli ingressi e la rispettiva uscita*/
               
             }
                    
         }
         return 0;
     } /*chiusura main*/
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
Ciao, se ti riferisci al for più interno nel main l'errore è aver messo il punto e virgola alla fine della riga.
Mi sono permesso di formattare il codice in una maniera più leggibile e ho spostato la variabile n nel main perché è meglio evitare l'uso di variabili globali, a meno che non sia strettamente necessario (e non è questo il caso). Il motivo è quello di applicare il principio del privilegio minimo, che dice che ciascuna parte del programma deve avere a disposizione solo le informazioni strettamente necessarie per fare ciò che deve fare, nulla di più. Poi ho aggiunto i prototipi delle due funzioni, che è sempre meglio includere perché così il compilatore fa un controllo sui tipi (comunque servono anche per rendere il codice compatibile con un compilatore c++, casomai servisse). A tal proposito, visto che la funzione activation_function deve essere chiamata solo dalla funzione transfer_function, ho messo il suo prototipo nella definizione di quest'ultima in modo da renderla invisibile al resto del programma, sempre in ossequio al principio del privilegio minimo. Infine nella funzione activation_function ho eliminato la variabile j perché inutilizzata.
C:
/*questo programma descrive il comportamento del percettrone a due ingressi
e una uscita  e calcola la funzione OR come uscita, la funzione di attivazione
e la sommatoria del prodotto dei pesi e degli ingressi e la funzione di trasferimento e la
funzione a gradino, quindi il percettrone ha solo due uscite o zero o uno,
in ingresso abbiamo 4 coppie che combinate ci danno i valori OR*/

#include<stdio.h>
//#include<stdlib.h>
//#include<cstdio.h>
//#include<cstdlib.h>
//#include<iostream.h>
//#include"pr9.h"

typedef double T_Precision;

// prototipi funzioni
T_Precision transfer_function(const T_Precision *x, const T_Precision *w, size_t n);

int main (void)
{
    const size_t n = 2;    /*numero di ingressi*/
    T_Precision x[n+1];    /*vettore ingressi del percettrone piu' il bias*/
    T_Precision w[n+1];    /*vettore pesi sinaptici piu' il peso del bias*/
    T_Precision y;         /*uscita del percettrone*/
    size_t i, j;            /*iteratori*/
    x[n] = -1;             /*valore di bias*/
    w[0] = 5;              /*imposto valore dei pesi*/
    w[1] = 5;
    w[2] = 4;              /*peso sinaptico del bias*/
      
    printf ("[x1]\t[x2]\t[y]\n");  /*stampo intestazione tabella*/
  
    for (j=0; j<=1; j++) { /*provo tutte le combinazioni degli ingressi,ossia permuto gli ingressi, se gli ingressi
                             sono solo coppie di zeri e uno ho un quadrato nello spazio degli ingressi quindi 4 vertici */
        for (i=0; i<=1; i++) {
            x[0]=i;
            x[1]=j;
            y=transfer_function(x,w,n); /*calcolo l'uscita del percettrone*/
            printf("%.0f\t%.0f\t%.0f\n",x[0],x[1],y); /*stampo gli ingressi e la rispettiva uscita*/
        }
    }
    return 0;
} /*chiusura main*/

// definizioni funzioni
T_Precision activation_function(const T_Precision *x, const T_Precision *w, size_t n) {
  
    T_Precision potential = 0;
    size_t i;

    for (i=0;i<=n;i++) {
        potential += x[i]*w[i];
    }
    return potential;
}

T_Precision transfer_function(const T_Precision *x, const T_Precision *w, size_t n) {
    // prototipo funzione activation_function 
    T_Precision activation_function(const T_Precision *x, const T_Precision *w, size_t n);
  
    T_Precision potential = activation_function(x,w,n);
    return (T_Precision) (potential>0);
}
 

anche_per_il_direttore

Nuovo Utente
63
2
Ok grazie fabio della risposta, ci lavorero' sopra questo pomeriggio, purtroppo non sono un informatico e sto cercando di acquisire piu nozioni possibili nei ritagli di tempo, comunque grazie dell aiuto, ciao
 

anche_per_il_direttore

Nuovo Utente
63
2
salve a tutti, oggi ho aggiornato il codice postato la volta precedente, in questo caso ho inserito una funzione nel codice che ha lo scopo di addestrare la rete, il problema riscontrato stavolta e' sulla dimensione del vettore che contiene i dati di training, (non ho avuto molto tempo di pensarci sopra) comunque posto il codice e se qualcuno ha qualche idea, ben venga, grazie in anticipo
PS la funzione di addestramento inserita utilizza la funzione delta di minimizzazione della funzione E dei pesi nel rispettivo spazio, per quanto riguarda lo spazio degli ingressi non e' cambiato rispetto al codice precedente, la rete a singolo neurone e' sufficiente per la ricerca dei valori corretti della funzione OR oppure della funzione AND ( il prossimo passo, sempre tempo permettendo e' la costruzione di una rete multistrato con unita' di base il percettrone costruito nel precedente codice e richiamato in questo di codice)
ecco il codice (spero sia leggibile)

C:
/*questo programma descrive il comportamento del percettrone a due ingressi
e una uscita  e calcola la funzione OR come uscita, la funzione di attivazione
e la sommatoria del prodotto dei pesi e degli ingressi e la funzione di trasferimento e la
funzione a gradino, quindi il percettrone ha solo due uscite o zero o uno,
in ingresso abbiamo 4 coppie che combinate ci danno i valori OR, e' inoltre definita la funzione
di addestramento*/

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

typedef double T_Precision;

T_Precision training_function( T_Precision *x, T_Precision *w, size_t n,
const T_Precision *dx, const T_Precision *dy, size_t sn,
const T_Precision eta, const T_Precision desired_error );//dichiarazione funzione di addestramento

T_Precision transfer_function(const T_Precision *x,const T_Precision *w, size_t n);//dichiarazione funzione di trasferimento



int main( void )
{
        // Inizializzo il generatore di numeri pseudocasuali
        srand( (size_t) time( NULL ) );
      
        // Numero di ingressi
        const size_t n = 2;
       
        // Ingressi del percettrone (più il bias)
        T_Precision x[n + 1];
       
        // Pesi sinaptici (più il peso del bias)
        T_Precision w[n + 1];
       
        // Uscita del percettrone
        T_Precision y;
       
        // Iteratori
        size_t i, j;
       
        // Imposto il valore negativo unitario del bias
        x[n] = -1;
       
        // Numero di esempi dell'insieme di addestramento
        const size_t sn = 4;
       
        // Preparo l'insieme di addestramento per l'operatore OR, se voglio fare AND cambio i valori
        const T_Precision dx[sn * n] = {0,0,0,1,1,0,1,1};
       
        const T_Precision dy[sn] = { 0, 0, 0, 1 };
       
        // Tasso di apprendimento
        const T_Precision eta = 0.5;
       
        // Errore desiderato
        const T_Precision desired_error = 0.00001;
       
       
       
       
       
       
        // Addestro il percettrone
        training_function( x, w, n, dx, dy, sn, eta, desired_error );//chiamata funzione di addestramento
       
        // Stampo l'intestazione della tabella
        printf( "[x1]\t[x2]\t[y]\n" );
       
        // Provo tutte le combinazioni degli ingressi
        for ( j = 0; j <= 1; j++ )
        {
                for ( i = 0; i <= 1; i++ )
                        {
                            // Imposto gli ingressi
                            x[0] = i;
                            x[1] = j;
                       
                            // Calcolo l'uscita del percettrone
                            y = transfer_function( x, w, n );
                       
                            // Stampo gli ingressi e la rispettiva uscita
                            printf( "%.0f\t%.0f\t%.0f\n", x[0], x[1], y );

                        }
        }
       
        return 0;

}







T_Precision training_function( T_Precision *x, T_Precision *w, size_t n,
const T_Precision *dx, const T_Precision *dy, size_t sn,
const T_Precision eta, const T_Precision desired_error ) //definizione funzione di addestramento

{
        // Uscita calcolata
        T_Precision y;
        // Errore della rete
        T_Precision error;
        // Errore dell'uscita
        T_Precision dEdy;
        // Errore dei pesi sinaptici
        T_Precision dEdw[n];
        // Modifica del peso sinaptico
        T_Precision deltaw;
        // Contatore delle epoche
        size_t epochs = 0;
        // Iteratore
        size_t i, t;

        // Log di lavoro
        printf( "Inizio l'addestramento (eta = %.2f, errore desiderato = %f).\n", desired_error );
       
       
                // Inizializzo i pesi sinaptici con dei valori casuali
                for ( i = 0; i < n; i++ )
                {
                    w[i] = rand() % 10;
                }
       
       
        // Continuo l'addestramento finché non raggiungo
        // l'errore desiderato (max 100 epoche)
       
        do
       
        {
                // Stampo il numero dell'epoca corrente
                printf( "Epoca #%zu: ", epochs );
       
                // Azzero l'errore della rete
                error = 0.0;
       
                // Azzero gli errori dei pesi sinaptici
                for ( i = 0; i <= n; i++ )
                {
                    dEdw[i] = 0;
                }
       
                // Ripeto per tutti gli esempi nell'insieme di addestramento, sn e' il numero delle coppie di ingressi
                for ( t = 0; t < sn; t++ )
                {
       
                            // Prendo gli ingressi dall'esempio
                            for ( i = 0; i < n; i++ )
                                {
                                    x[i] = dx[t * n + i];
                                }
                   
                            // Calcolo l'uscita del percettrone
                            // con gli ingressi dell'esempio
                            y = transfer_function( x, w, n );

                           
                            // Calcolo l'errore sull'uscita
                            dEdy = -(dy[t] - y);


                            // Calcolo l'errore dei pesi sinaptici
                            for ( i = 0; i <= n; i++ )
                                {
                                    dEdw[i] += dEdy * x[i];
                                }
                   

                            // Calcolo il quadrato dell'errore necessario
                            // per trovare l'errore quadratico medio
                            // E(x) = SUM( e^2 ) / n_samples
                            error += ( dEdy * dEdy ) / 2.0;

                }
               
                // Correggo i pesi usando la regola delta
                for ( i = 0; i <= n; i++ )
                    {
                            // Calcolo la modifica del peso
                            deltaw = - eta * dEdw[i];

                            // Applico la modifica al peso sinaptico
                            w[i] = w[i] + deltaw;

                            // Stampa il nuovo valore del peso
                            printf( "w[%zu]=%.1f (E=%.1f), ", i, w[i], dEdw[i] );
                    }

                // Termino la riga di log aggiungendo l'errore corrente
                printf( "MSE=%f\n", error );

                // Incremento il numero delle epoche
                epochs++;
        }

        while ( error > desired_error && epochs < 100 );

        // Log di lavoro
        printf( "Addestramento terminato dopo %zu epoche.\n\n", epochs ); //fine definizione della funzione di addestramento
}







T_Precision transfer_function(const T_Precision *x,const T_Precision *w, size_t n) //definizione funzione di trasferimento
    {
                                 
                                  T_Precision activation_function(const T_Precision *x,const T_Precision *w, size_t n);//dichiarazione funzione di attivazione
                                 
                                  T_Precision potential = activation_function(x,w,n);
                                  return (T_Precision) (potential>0);
    }//fine definizione funzione di trasferimento


   
   
T_Precision activation_function(const T_Precision *x,const T_Precision *w, size_t n) //definizione funzione di attivazione
{

T_Precision potential = 0;
size_t i;

for (i=0;i<=n;i++)
    {
    potential += x[i]*w[i];
    }
    return potential;
}//fine definizione funzione di attivazione
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
L'errore è dovuto al fatto che gli array che hanno la dimensione di una variabile non possono essere inizializzati esplicitamente alla dichiarazione. Per risolvere il problema è sufficiente togliere la dimensione dalle parentesi quadre (così: T_Precision dx[] = {1,2,3}; ad esempio). Così il programma viene compilato correttamente. Un'ultima cosa: training_function è dichiarata come una funzione ma non restituisce nessun valore, perciò dovresti dichiararla come una procedura, cioè con tipo di ritorno void.
 
Ultima modifica:

anche_per_il_direttore

Nuovo Utente
63
2
ciao fabio, grazie della risposta, non appena riesco faccio le modifiche e provo a farlo girare ancora, sto cercando di generalizzare la rete e successivamente controllare il suo comportamento con funzioni note, vedremo cosa salta fuori, comunque, grazie ancora, ciao
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
Ciao, siccome nelle scorse ore c'è stato il "trasloco" del forum il tuo ultimo post è andato perso, ma l'avevo letto oggi pomeriggio e avevo copiato il codice in un editor per testarlo perciò cerco di risponderti ugualmente. Purtroppo non ti posso essere di grande aiuto perché è una materia che non conosco affatto, anche se mi sembra molto interessante. Il codice funziona (in realtà non ho avuto tempo di studiarlo per bene), l'unica "correzione" che ti suggerisco è semplicemente eliminare i puntatori globali che hai dichiarato sotto le dichiarazioni delle struct, perché non gli usi dopo, quindi sono inutili. Posto qui sotto il codice.
C:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>

// Precisione dei valori
typedef double T_Precision;

// Struttura di un neurone
struct Neuron
{
    T_Precision value;// Uscita del percettrone
};

// Struttura di una connessione tra due neuroni (sinapsi)
struct Synapse
{
    T_Precision weight; // Peso della connessione
};


float sigmoid(float x);//dichiarazione funzione sigmoide

float d_sigmoid(float x);//dichiarazione funzione derivata della sigmoide

//dichiarazione funzione che fa operare la rete di 3 strati,calcola le uscite di
//ogni strato, un percettrone alla volta, fino a determinare le uscite della rete
void run_network( struct Neuron *i_neuron, size_t input_size, 
                    struct Neuron *h_neuron, struct Synapse *h_synapse, size_t hidden_size,
                    struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size );


int main( void )
{
    // Dimensioni della rete
    const size_t input_size = 2;
    const size_t hidden_size = 3;
    const size_t output_size = 1;
    // Creo i neuroni degli strati
    struct Neuron i_neuron[ input_size ];
    struct Neuron h_neuron[ hidden_size ];
    struct Neuron o_neuron[ output_size ];
    // Creo le sinapsi degli strati (+ quelle del bias)
    struct Synapse h_synapse[ (input_size + 1) * hidden_size ];
    struct Synapse o_synapse[ (hidden_size + 1) * output_size ];

    // Imposto i pesi sinaptici
    h_synapse[0].weight = -3.9340242026; //sinapsi da i a h
    h_synapse[1].weight = 8.2505052824;
    h_synapse[2].weight = 0.3043062447;  //peso del bias

    h_synapse[3].weight = 6.8427240303;
    h_synapse[4].weight = 6.8347133644;
    h_synapse[5].weight = -1.4695877520;

    h_synapse[6].weight = 8.2647545506;
    h_synapse[7].weight = -4.1937195208;
    h_synapse[8].weight = 0.5536933684;

    o_synapse[0].weight = -12.2588589492; //sinapsi da h a o
    o_synapse[1].weight = 13.6915483842;
    o_synapse[2].weight = -12.2575228405;
    o_synapse[3].weight = 4.8756901299;

    // Iteratore
    size_t i, j;

    // Stampo l'intestazione della tabella
    printf( "[x1]\t[x2]\t[y]\n" );


    // Provo tutte le combinazioni degli ingressi
    for ( j = 0; j <= 1; j++ ) {

        for ( i = 0; i <= 1; i++ ) {

            // Imposto gli ingressi
            i_neuron[0].value = i;
            i_neuron[1].value = j;

            // Eseguo la rete neurale
            run_network( i_neuron, input_size,
                            h_neuron, h_synapse, hidden_size,
                            o_neuron, o_synapse, output_size );

            // Stampo gli ingressi e la rispettiva uscita
            printf( "%.0f\t%.0f\t%.0f\n", i_neuron[0].value, i_neuron[1].value,o_neuron[0].value);
        }
    }
    return 0;
}

float sigmoid(float x) //definizione funzione sigmoide
{
    float exp_value;
    float return_value;

    /*** Exponential calculation ***/
    exp_value = exp((double) -x);

    /*** Final sigmoid value ***/
    return_value = 1 / (1 + exp_value);

    return return_value;
}

float d_sigmoid(float x) //definizione funzione derivata della sigmoide
{
    float exp_value;
    float return_value;

    /*** Exponential calculation ***/
    exp_value = exp((double) -x);

    /*** Final sigmoid value ***/
    return_value = (1 / (1 + exp_value))*(1-(1 / (1 + exp_value)));


    return return_value;
}

//definizione della funzione che fa operare la rete di 3 strati,calcola le uscite di
//ogni strato, un percettrone alla volta, fino a determinare le uscite della rete
void run_network(struct Neuron *i_neuron, size_t input_size, 
                    struct Neuron *h_neuron,struct Synapse *h_synapse, size_t hidden_size,
                    struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size)
{
    // Potenziale di attivazione
    float potential;
    // Iteratori
    size_t j, i;

    // Calcolo le uscite dello strato intermedio hidden
    for ( i = 0; i < hidden_size; i++ ) {
        // Azzero il potenziale di attivazione
        potential = 0;
        // Calcolo il potenziale di attivazione
        for ( j = 0; j < input_size; j++ ) {
            potential += i_neuron[j].value * h_synapse[i * ( input_size + 1 ) + j].weight;
        }
        // Aggiungo il valore del bias
        potential += h_synapse[i * ( input_size + 1 ) + j].weight;
        // Calcolo l'uscita del neurone sulla base del potenziale di attivazione
        h_neuron[i].value = sigmoid( potential ); //uscita del generico neurone nello strato hidden
    }
    // Calcolo le uscite dello strato di uscita
    for ( i = 0; i < output_size; i++ ) {
        // Azzero il potenziale di attivazione
        potential = 0;
        // Calcolo il potenziale di attivazione
        for ( j = 0; j < hidden_size; j++ ) {
            potential += h_neuron[j].value * o_synapse[i * ( hidden_size + 1 ) + j].weight;
        }
        // Aggiungo il valore del bias
        potential += o_synapse[i * ( hidden_size + 1 ) + j].weight;
        // Calcolo l'uscita del neurone sulla base del potenziale di attivazione
        o_neuron[i].value = sigmoid( potential );//uscita del neurone output
    }
}//fine funzione (procedura) run_network
 

anche_per_il_direttore

Nuovo Utente
63
2
ciao fabio, grazie della risposta, a dir la verita mi sei di grande aiuto perche' il mio problema principale e' che non essendo un informatico non riesco a tradurre in codice quello che ho in testa, sulla carta e' piu facile, ma i pezzi di carta li perdo sempre e i codici mi restano, molto tempo fa avevo studiato il fortran 77 poi utilizzando linux che ha gia il compilatore c ho preferito usare questo linguaggio e comunque il fatto di sapere che i codici sono almeno formal mente corretti e' di grande aiuto, ciao e grazie ancora
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
Di niente, mi fa piacere servire a qualcosa:ok:, e parlare di programmazione è sempre interessante. Progettare algoritmi su carta è la cosa migliore soprattutto quando sono non banali. Comunque, come immagino tu già sappia, su linux ci sono compilatori e interpreti per tutti i linguaggi. Il vantaggio del C è che, nell'ambito dei linguaggi ad alto livello, è quello più a basso livello, e ti fa capire meglio come funziona un linguaggio di programmazione, per esempio inerentemente alla gestione della memoria (puntatori, malloc...). Questo però lo rende anche più complicato perché, per fare cose anche banali, ci vogliono più righe di codice rispetto ad altri linguaggi. Da un altro punto di vista però il C è "semplice" perché compatto, con poche keyword, con una libreria standard abbastanza piccola rispetto ad esempio a C++ o java, e privo di cose moderne come la programmazione orientata agli oggetti (che in realtà si può fare anche in C, con degli artifici, ma non è il paradigma principe di quel linguaggio). Inoltre il C ha prestazioni tendenzialmente migliori. Per cui non è una scelta del tutto sbagliata, è il linguaggio giusto per "farsi le ossa". È stato il mio primo linguaggio, ed è quello con cui mi sento più a mio agio (pur essendo un principiante). Per il calcolo scientifico va molto bene anche il python, è più immediato e dispone di tante librerie ad hoc come numpy e pyplot, che ne fanno un mezzo molto potente per questo scopo. Io lo sto imparando proprio in questo periodo per l'università, anche se in maniera semplice. Magari dagli un'occhiata. Saluti.
 

anche_per_il_direttore

Nuovo Utente
63
2
ciao a tutti, il codice che posto oggi e' un estensione del precedente.
la struttura della rete e' formalmente la stessa (posso naturalmente cambiare il numero dei neuroni nello strato intermedio, modificare la costante del tasso di apprendimento, modificare l errore che mi aspetto in uscita non che' il numero delle epoche, eventualmente potrei modificare il numero degli strati "cosa che pero' comporterebbe in questa fase la ridefinizione delle funzioni accessorie").
in questo codice la rete viene addestrata con l'algoritmo di retropropagazione dell'errore (backpropagation a tasso di apprendimento costante).
la rete e' stata testata per imparare a riprodurre le uscite della funzione logica XOR che come avevo detto in precedenza non poteva essere separata con l uscita del percettrone semplice (la rete resta naturalmente valida per funzioni logiche come AND e OR, per testarlo basta cambiare nel codice i valori desiderati del vettore dy).
il codice sembra corretto ma lo posto con la speranza che qualcuno che conosce l algoritmo backpropagation a tasso di apprendimento costante e ha maggiori competenze informatiche delle mie possa darmi qualche dritta nella correzione di eventuali errori.
da notare che come la letteratura sulle reti neurali dice la scelta iniziale dei pesi non e' banale e influenza il comportamento generale della rete, non mi dilungo oltre, ecco il codice.

C:
/*rete di tre layers; layer 1 con 2 neuroni; layer 2 con 3 (ne ho provati 200) neuroni; layer 3 con 1 neurone*/

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

// Precisione dei valori
typedef double T_Precision;


// Struttura di un neurone
struct Neuron
{
 T_Precision value;// Uscita del percettrone
 T_Precision dEdy;//Errore del neurone
};
struct Neuron *i_neuron, *h_neuron, *o_neuron;//variabili di tipo Neuron


// Struttura di una connessione tra due neuroni (sinapsi)
struct Synapse
{
 T_Precision weight; // Peso della connessione
 T_Precision dEdw;//Errore della connessione
};
struct Synapse *h_synapse, *o_synapse;//variabili di tipo Synapse




//DICHIARAZIONE FUNZIONI

float sigmoid(float x);//dichiarazione funzione sigmoide

float d_sigmoid(float x);//dichiarazione funzione derivata della sigmoide

void run_network( struct Neuron *i_neuron, size_t input_size,    //dichiarazione funzione che fa operare la rete di 3 strati,calcola le uscite di
struct Neuron *h_neuron, struct Synapse *h_synapse, size_t hidden_size, //ogni strato, un percettrone alla volta, fino a determinare le uscite
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size );//della rete

void init_weight( struct Synapse *synapse, size_t layer_size, size_t prev_layer_size );//dichiarazione funzione inizializzazione pesi

void backpropagation( struct Neuron *i_neuron, size_t input_size,
struct Neuron *h_neuron, struct Synapse *h_synapse, size_t hidden_size,
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size,
const T_Precision *dx, const T_Precision *dy, size_t sn,
const T_Precision eta, const T_Precision desired_error );//dichiarazione funzione di retropropagazione dell'errore

//FINE DICHIARAZIONI FUNZIONI
 
 
 
 int main( void )
 
{
    // Inizializzo il generatore di numeri pseudocasuali
    srand( (size_t) time( NULL ) );
 
    // Dimensioni della rete
    const size_t input_size = 2;
    const size_t hidden_size = 200;
    const size_t output_size = 1;
 
    // Creo i neuroni degli strati
    struct Neuron i_neuron[ input_size ];
    struct Neuron h_neuron[ hidden_size];
    struct Neuron o_neuron[ output_size];
 
    // Creo le sinapsi degli strati (+ quella del bias)
    struct Synapse h_synapse[ (input_size + 1) * (hidden_size) ];
    struct Synapse o_synapse[ (hidden_size + 1) * (output_size) ];
 
    // Iteratore
    size_t i, j;
 
    // Numero di esempi dell'insieme di addestramento
    const size_t sn = 4;
 
    // Preparo l'insieme di addestramento per l'operatore XOR//---sn*input_size
    const T_Precision dx[] = { 0,0, 0,1, 1,0, 1,1 };
                        
    const T_Precision dy[] = { 0, 1, 1, 0 };//valori desiderati--- sn*output_size
 
    // Tasso di apprendimento
    const T_Precision eta = 0.5;
    
    // Errore desiderato
    const T_Precision desired_error = 0.00001;
 
    // Addestro la rete neurale
    backpropagation( i_neuron, input_size,
    h_neuron, h_synapse, hidden_size,
    o_neuron, o_synapse, output_size,
    dx, dy, sn, eta, desired_error );
 
    
 
//    i_neuron[input_size+1].value = -1;
//    h_neuron[hidden_size+1].value = -1;
//    o_neuron[output_size].value = -1;
 
 
    // Stampo l'intestazione della tabella
    printf( "[x1]\t[x2]\t[y]\n" );
 
    // Provo tutte le combinazioni degli ingressi
    for ( j = 0; j <= 1; j++ )
    {
        for ( i = 0; i <= 1; i++ )
        {
 
        // Imposto gli ingressi
        i_neuron[0].value = i;
        i_neuron[1].value = j;
 
        // Eseguo la rete neurale
        run_network( i_neuron, input_size,
        h_neuron, h_synapse, hidden_size,
        o_neuron, o_synapse, output_size );
 
        // Stampo gli ingressi e la rispettiva uscita
        printf( "%.0f\t%.0f\t%.0f\n", i_neuron[0].value, i_neuron[1].value, o_neuron[0].value );
        
        }
    }
 
 return 0;
 
}




float sigmoid(float x)//definizione funzione sigmoide
{
     float exp_value;
     float return_value;

     /*** Exponential calculation ***/
     exp_value = exp((double) -x);

     /*** Final sigmoid value ***/
     return_value = 1 / (1 + exp_value);

     return return_value;
}




float d_sigmoid(float x)//definizione funzione derivata della sigmoide
{
     float exp_value;
     float return_value;

     /*** Exponential calculation ***/
     exp_value = exp((double) -x);

     /*** Final sigmoid value ***/
     return_value = (1 / (1 + exp_value))*(1-(1 / (1 + exp_value)));


     return return_value;
}




void run_network(struct Neuron *i_neuron, size_t input_size,    //definizione della funzione che fa operare la rete di 3 strati,calcola le uscite di
struct Neuron *h_neuron,struct Synapse *h_synapse, size_t hidden_size, //ogni strato, un percettrone alla volta, fino a determinare le uscite
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size )//della rete

{

 // Potenziale di attivazione
 float potential;
 // Iteratori
 size_t j, i;

    // Calcolo le uscite dello strato intermedio hidden
    for ( i = 0; i < hidden_size; i++ )
 
        {
            // Azzero il potenziale di attivazione
            potential = 0;
                // Calcolo il potenziale di attivazione
                    for ( j = 0; j < input_size; j++ )
                    {
                        potential += i_neuron[j].value * h_synapse[i * ( input_size + 1 ) + j].weight;
                    }
            // Aggiungo il valore del bias
            potential += h_synapse[i * ( input_size + 1 ) + j].weight;
 
            // Calcolo l'uscita del neurone sulla base del potenziale di attivazione
            h_neuron[i].value = sigmoid( potential ); //uscita del generico neurone nello strato hidden
        }
 
 
 
    // Calcolo le uscite dello strato di uscita
    for ( i = 0; i < output_size; i++ )
        
        {
            // Azzero il potenziale di attivazione
            potential = 0;
                // Calcolo il potenziale di attivazione
                    for ( j = 0; j < hidden_size; j++ )
                    {
                        potential += h_neuron[j].value * o_synapse[i * ( hidden_size + 1 ) + j].weight;
                    }
 
            // Aggiungo il valore del bias
            potential += o_synapse[i * ( hidden_size + 1 ) + j].weight;
 
            // Calcolo l'uscita del neurone sulla base del potenziale di attivazione
            o_neuron[i].value = sigmoid( potential );//uscita del neurone output
        }
}//fine funzione (procedura) run_network


void init_weight( struct Synapse *synapse, size_t layer_size, size_t prev_layer_size )//definizione funzione inizializzazione pesi
{
    // Valore casuale
    T_Precision random_;
    
    // Iteratori
    size_t j, i = 0;
 
    // Inizializzo i pesi sinaptici con dei valori casuali (inizializzo anche il peso del  bias)
    for (i=0 ; i < layer_size; i++ )
    {
        for ( j = 0; j <= prev_layer_size; j++ )
        {
            // Prelevo un valore casuale
            random_ = rand();
            // Imposto il valore del peso tra 0 e 1
            synapse[i * (prev_layer_size + 1) + j].weight = ( sin(random_) * sin(random_));//col seno al quadrato
                                                 //ho valori tra zero e uno
        }
    }
}//fine definizione funzione inizializzazione pesi
 


void backpropagation( struct Neuron *i_neuron, size_t input_size,
struct Neuron *h_neuron, struct Synapse *h_synapse, size_t hidden_size,
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size,
const T_Precision *dx, const T_Precision *dy, size_t sn,
const T_Precision eta, const T_Precision desired_error )//definizione funzione di retropropagazione dell'errore
 
{
     // Errore della rete
    T_Precision error;
 
    // Modifica del peso sinaptico
    T_Precision delta_w;
 
    // Contatore delle epoche
    size_t epochs = 0;
 
    // Iteratori
    size_t t, j, i;
 
    // Log di lavoro
    printf( "Inizio l'addestramento (eta = %.2f, errore desiderato = %f).\n", eta,desired_error );
    
    // Inizializzo i pesi sinaptici con dei valori casuali
    init_weight( h_synapse, hidden_size, input_size ); //inizializzazione peso neuroni dello strato nascosto
    init_weight( o_synapse, output_size, hidden_size );//inizializzazione peso neuroni dello strato output
 
    // Continuo l'addestramento finché non raggiungo
    // l'errore desiderato (max 50000 epoche)
    do
    {
    // Azzero l'errore della rete (somma degli errori della rete)
    error = 0.0;
    
    // Ripeto per tutti gli esempi nell'insieme di addestramento
    for ( t = 0; t < sn; t++ )
    {
        
            // Prendo gli ingressi dall'esempio
            for ( i = 0; i < input_size; i++ )
            
            {
                i_neuron[i].value = dx[t * input_size + i];
            }
 
            // Eseguo la rete neurale
            run_network( i_neuron, input_size,
            h_neuron, h_synapse, hidden_size,
            o_neuron, o_synapse, output_size );
 
 
 
 
 
        // Calcolo l'errore dello strato di uscita (in questo caso un neurone)
        for ( i = 0; i < output_size; i++ )
        {
        
            // Calcolo l'errore dell'uscita del neurone dE/dy_i = -(D_i - Y_i)
            o_neuron[i].dEdy = -( dy[t * output_size + i] - o_neuron[i].value );
 
            // Aggiungo l'errore al totale
            error += (( o_neuron[i].dEdy )*( o_neuron[i].dEdy)) ;
        }
 
 
 
         // Calcolo l'errore dello strato intermedio
        for ( i = 0; i < hidden_size; i++ )
            {
            
            // Azzero l'errore dei neuroni dello strato intermedio hidden
            h_neuron[i].dEdy = 0;
            
            // Calcolo l'errore dello strato intermedio dE/dz_k = SUM( dE/dy_j * dy_j/dP_j * dP_j/dz_k )
            for ( j = 0; j < output_size; j++ )
                {
                
                // Calcolo l'errore dell'uscita dei neuroni dello strato intermedio
                h_neuron[i].dEdy += o_neuron[j].dEdy *
                d_sigmoid ( o_neuron[j].value ) * o_synapse[j * ( hidden_size + 1 ) + i].weight;
                }
 
            // Calcolo l'errore dell'uscita del bias
            h_neuron[i].dEdy += o_neuron[j].dEdy *
            d_sigmoid ( o_neuron[j].value ) * o_synapse[j * ( hidden_size + 1 ) + i].weight;
            }
 
 
 
 
        // Aggiusto i pesi dello strato di uscita
        for ( i = 0; i < output_size; i++ )
        {
        
            // Correggo il peso sinaptico
            for ( j = 0; j < hidden_size; j++ )
            {
 
            // Calcolo la modifica del peso sinaptico delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = - eta * o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value;
 
            // Applico la modifica al peso sinaptico w = w + delta_w dei neuroni in uscita (uno in questo caso)
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;
            }
 
            // Calcolo la modifica del peso del bias delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = - eta * o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value );
 
            // Aggiungo la correzione del bias w = w + delta_w
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;
        }
 
        // Aggiusto i pesi dello strato intermedio
        for ( i = 0; i < hidden_size; i++ )
        {
                
            // Correggo il peso sinaptico dei neuroni dello strato intermedio
            for ( j = 0; j < input_size; j++ )
            {
 
            // Calcolo la modifica del peso sinaptico delta_w = - eta * dE/dz_k * dz_k/dP_k * dP_k/dw_ki
            delta_w = - eta * h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value;
 
            // Applico la modifica al peso sinaptico w = w + delta_w
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;
            
            }
 
            // Calcolo la modifica del peso del bias delta_w = - eta * dE/dz_k * dz_k/dP_k * dP_k/dw_ki
            delta_w = - eta * h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value );
 
            // Aggiungo la correzione del bias w = w + delta_w
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;
        }
        
 }//fine del primo for
 
 
 // Calcolo l'errore quadratico medio della rete (MSE) E(x) = SUM( e^2 ) / n_samples
 error /= ( input_size * sn );
 
 // Ogni 1000 epoche stampo il log di addestramento
 if ( epochs % 1000 == 0 )
 {
 printf( "Epoca #%zu, MSE=%f\n", epochs, error );
 }
 
 // Incremento il numero delle epoche
 epochs++;
 
 } while ( error > desired_error && epochs < 50000 );//fine ciclo do-while
 
 // Log di lavoro
 printf( "Addestramento terminato dopo %zu epoche.\n\n", epochs );
 
}//fine definizione funzione di retropropagazione dell'errore
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
Ciao, come nel programma precedente i puntatori
C:
struct Neuron *i_neuron, *h_neuron, *o_neuron;//puntatori a variabili di tipo struct Neuron
e
C:
struct Synapse *h_synapse, *o_synapse;//puntatori a variabili di tipo struct Synapse
non servono perché non gli usi mai, dal momento che dopo dichiari gli array qui sotto,
C:
    // Creo i neuroni degli strati
    struct Neuron i_neuron[ input_size ];
    struct Neuron h_neuron[ hidden_size];
    struct Neuron o_neuron[ output_size];

    // Creo le sinapsi degli strati (+ quella del bias)
    struct Synapse h_synapse[ (input_size + 1) * (hidden_size) ];
    struct Synapse o_synapse[ (hidden_size + 1) * (output_size) ];
e usi questi ultimi invece dei puntatori di prima, che restano pertanto inutilizzati. Sono due cose diverse! Se invece vuoi usare i puntatori, anziché dichiarare gli array qui sopra, devi scrivere
C:
    // Creo i neuroni degli strati
    i_neuron = malloc(input_size * sizeof(struct Neuron));
    h_neuron = malloc(hidden_size * sizeof(struct Neuron));
    o_neuron = malloc(output_size * sizeof(struct Neuron));

    // Creo le sinapsi degli strati (+ quella del bias)
    h_synapse = malloc((input_size + 1) * hidden_size * sizeof(struct Synapse));
    o_synapse = malloc((hidden_size + 1) * output_size * sizeof(struct Synapse));
non dimenticando di aggiungere una free() per ogni malloc() quando questi vettori non serviranno più (per esempio alla fine del programma, prima di return 0). E comunque, se decidi di usare i puntatori, è meglio dichiararli all'interno della funzione main, esattamente come hai fatto per gli array, dato che non vedo il motivo di renderli globali (una variabile globale in C è una variabile dichiarata al di fuori di qualunque funzione). Le variabili globali in genere vanno evitate, perché sono accessibili a qualsiasi funzione (anche se non incluse nell'elenco dei parametri), il che può creare dei problemi.
Piccolo suggerimento stilistico: se vuoi, per brevità, puoi scrivere
C:
typedef struct Neuron Neuron
in questo modo potrai scrivere solo Neuron anziché struct Neuron a ogni dichiarazione di una variabile struct Neuron. Lo stesso vale anche per struct Synapse ovviamente. Si può anche fare direttamente così:
C:
typedef struct
{
    T_Precision value;// Uscita del percettrone
    T_Precision dEdy;//Errore del neurone
} Neuron;
 
Ultima modifica:

anche_per_il_direttore

Nuovo Utente
63
2
ciao fabio, come sempre grazie degli aiuti, le dichiarazioni dei puntatori le avevo intenzionalmente lasciate propro perche in fututo volevo utilizzarli con le malloc con l ottica di generalizzare il codice, purtroppo ancora sono ben lontano dall obbiettivo che mi sono posto, comunque grazie ancora, ciao
 

anche_per_il_direttore

Nuovo Utente
63
2
salve a tutti, il codice che propongo oggi e' parente di quello precedente, l unica differenza sta nella funzione di addestramento, non e' piu una backpropagation ma e' una resilient backpropagation (non mi soffermo sulla spiegazione della matematica dietro l algoritmo), allora, punto primo il codice da degli errori (che ho provato a carreggere senza successo e senza perdere il mio filo logico), sono abbastanza sicuro dei passi logici dell algoritmo (ma se c'e' qualcuno che conosce la matematica dietro l algoritmo sarebbe di grande aiuto) , comunque sia se qualcuno riesce ad aiutarmi a capire gli errori del codice sarebbe un aiuto molto apprezzato. grazie e a presto.
ecco il codice
PS chiedo anticipatamente venia per eventuali difficolta di indentazione, purtroppo il tempo e' quel che e'
C:
/*rete di tre layers; layer 1 con 2 neuroni; layer 2 con 3 (ne ho provati 200) neuroni; layer 3 con 1 neurone*/

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

// Precisione dei valori
typedef double T_Precision;


// Struttura di un neurone
struct Neuron
{
 T_Precision value;// Uscita del percettrone
 T_Precision dEdy;//Errore del neurone
};
//struct Neuron *i_neuron, *h_neuron, *o_neuron;//variabili di tipo Neuron


// Struttura di una connessione tra due neuroni (sinapsi)
struct Synapse
{
 T_Precision weight; // Peso della connessione
 T_Precision dEdw;//Errore della connessione
};
//struct Synapse *h_synapse, *o_synapse;//variabili di tipo Synapse




//DICHIARAZIONE FUNZIONI

float sigmoid(float x);//dichiarazione funzione sigmoide

float d_sigmoid(float x);//dichiarazione funzione derivata della sigmoide

void run_network( struct Neuron *i_neuron, size_t input_size,    //dichiarazione funzione che fa operare la rete di 3 strati,calcola le uscite di
struct Neuron *h_neuron, struct Synapse *h_synapse, size_t hidden_size, //ogni strato, un percettrone alla volta, fino a determinare le uscite
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size );//della rete

void init_weight( struct Synapse *synapse, size_t layer_size, size_t prev_layer_size );//dichiarazione funzione inizializzazione pesi


void init_dEdw( struct Synapse *synapse, size_t layer_size, size_t prev_layer_size );//dichiarazione funzione inizializzazione dEdw


void resilient_backpropagation( struct Neuron *i_neuron, size_t input_size,
struct Neuron *h_neuron, struct Synapse *h_synapse, size_t hidden_size,
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size,
const T_Precision *dx, const T_Precision *dy, size_t sn,
const T_Precision etapiu, const T_Precision etameno, const T_Precision desired_error );//dichiarazione funzione di retropropagazione dell'errore

//FINE DICHIARAZIONI FUNZIONI
 
 
 
 int main(void)
 
{
    // Inizializzo il generatore di numeri pseudocasuali
    srand( (size_t) time( NULL ) );
 
    // Dimensioni della rete
    const size_t input_size = 2;
    const size_t hidden_size = 5;
    const size_t output_size = 1;
 
    // Creo i neuroni degli strati
    struct Neuron i_neuron[ input_size ];
    struct Neuron h_neuron[ hidden_size];
    struct Neuron o_neuron[ output_size];
 
    // Creo le sinapsi degli strati (+ quella del bias)
    struct Synapse h_synapse[ (input_size + 1) * (hidden_size) ];
    struct Synapse o_synapse[ (hidden_size + 1) * (output_size) ];
    
    
    // Iteratore
    size_t i, j;
 
    // Numero di esempi dell'insieme di addestramento
    const size_t sn = 4;
 
    // Preparo l'insieme di addestramento per l'operatore XOR//---sn*input_size
    const T_Precision dx[] = { 0,0, 0,1, 1,0, 1,1 };
                        
    const T_Precision dy[] = { 0, 1, 1, 0 };//valori desiderati--- sn*output_size
 
    const T_Precision etapiu = 1.2; 
    const T_Precision etameno = 0.5;
    
    // Tasso di apprendimento
    //const T_Precision eta = 0.5;
    
    // Errore desiderato
    const T_Precision desired_error = 0.00001;
 
    // Addestro la rete neurale
    resilient_backpropagation(i_neuron, input_size,
    h_neuron, h_synapse, hidden_size,
    o_neuron, o_synapse, output_size,
    dx, dy, sn, etapiu, etameno, desired_error );
 
    
    // Stampo l'intestazione della tabella
    printf( "[x1]\t[x2]\t[y]\n" );
 
    // Provo tutte le combinazioni degli ingressi
    for ( j = 0; j <= 1; j++ )
    {
        for ( i = 0; i <= 1; i++ )
        {
 
        // Imposto gli ingressi
        i_neuron[0].value = i;
        i_neuron[1].value = j;
 
        // Eseguo la rete neurale
        run_network( i_neuron, input_size,
        h_neuron, h_synapse, hidden_size,
        o_neuron, o_synapse, output_size );
 
        // Stampo gli ingressi e la rispettiva uscita
        printf( "%.0f\t%.0f\t%.0f\n", i_neuron[0].value, i_neuron[1].value, o_neuron[0].value );
        
        }
    }
 
 return 0;
 
}


float sigmoid(float x)//definizione funzione sigmoide
{
     float exp_value;
     float return_value;

     /*** Exponential calculation ***/
     exp_value = exp((double) -x);

     /*** Final sigmoid value ***/
     return_value = 1 / (1 + exp_value);

     return return_value;
}




float d_sigmoid(float x)//definizione funzione derivata della sigmoide
{
     float exp_value;
     float return_value;

     /*** Exponential calculation ***/
     exp_value = exp((double) -x);

     /*** Final sigmoid value ***/
     return_value = (1 / (1 + exp_value))*(1-(1 / (1 + exp_value)));


     return return_value;
}


void run_network(struct Neuron *i_neuron, size_t input_size,    //definizione della funzione che fa operare la rete di 3 strati,calcola le uscite di
struct Neuron *h_neuron,struct Synapse *h_synapse, size_t hidden_size, //ogni strato, un percettrone alla volta, fino a determinare le uscite
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size )//della rete

{

 // Potenziale di attivazione
 float potential;
 // Iteratori
 size_t j, i;

    // Calcolo le uscite dello strato intermedio hidden
    for ( i = 0; i < hidden_size; i++ )
 
        {
            // Azzero il potenziale di attivazione
            potential = 0;
                // Calcolo il potenziale di attivazione
                    for ( j = 0; j < input_size; j++ )
                    {
                        potential += i_neuron[j].value * h_synapse[i * ( input_size + 1 ) + j].weight;
                    }
            // Aggiungo il valore del bias
            potential += h_synapse[i * ( input_size + 1 ) + j].weight;
 
            // Calcolo l'uscita del neurone sulla base del potenziale di attivazione
            h_neuron[i].value = sigmoid( potential ); //uscita del generico neurone nello strato hidden
        }
 
 
 
    // Calcolo le uscite dello strato di uscita
    for ( i = 0; i < output_size; i++ )
        
        {
            // Azzero il potenziale di attivazione
            potential = 0;
                // Calcolo il potenziale di attivazione
                    for ( j = 0; j < hidden_size; j++ )
                    {
                        potential += h_neuron[j].value * o_synapse[i * ( hidden_size + 1 ) + j].weight;
                    }
 
            // Aggiungo il valore del bias
            potential += o_synapse[i * ( hidden_size + 1 ) + j].weight;
 
            // Calcolo l'uscita del neurone sulla base del potenziale di attivazione
            o_neuron[i].value = sigmoid( potential );//uscita del neurone output
        }
}//fine funzione (procedura) run_network






void init_weight( struct Synapse *synapse, size_t layer_size, size_t prev_layer_size )//definizione funzione inizializzazione pesi
{
    // Valore casuale
    T_Precision random_;
    
    // Iteratori
    size_t i,j = 0;
 
    // Inizializzo i pesi sinaptici con dei valori casuali (inizializzo anche il peso del  bias)
    for (i=0 ; i < layer_size; i++ )
    {
        for ( j = 0; j <= prev_layer_size; j++ )
        {
            // Prelevo un valore casuale
            random_ = rand();
            // Imposto il valore del peso tra 0 e 1
            synapse[i * (prev_layer_size + 1) + j].weight = ( sin(random_) * sin(random_));//col seno al quadrato
                                                 //ho valori tra zero e uno
        }
    }
}//fine definizione funzione inizializzazione pesi
 
 
 
 
void init_dEdw( struct Synapse *synapse, size_t layer_size, size_t prev_layer_size )//definizione funzione inizializzazione dEdw
{
    // Valore casuale
    T_Precision random_;
    
    // Iteratori
    size_t i, j = 0;
 
    // Inizializzo i pesi sinaptici con dei valori casuali (inizializzo anche il peso del  bias)
    for (i=0 ; i < layer_size; i++ )
    {
        for ( j = 0; j <= prev_layer_size; j++ )
        {
            // Imposto il valore del peso tra 0 e 1
            synapse[i * (prev_layer_size + 1) + j].dEdw = 0.1;//col seno al quadrato
                                         //ho valori tra zero e uno
        }
    }
}//fine definizione funzione inizializzazione dEdw



void resilient_backpropagation(struct Neuron *i_neuron, size_t input_size,
struct Neuron *h_neuron, struct Synapse *h_synapse, size_t hidden_size,
struct Neuron *o_neuron, struct Synapse *o_synapse, size_t output_size,
const T_Precision *dx, const T_Precision *dy, size_t sn,
const T_Precision eta_piu, const T_Precision eta_meno , const T_Precision desired_error )//definizione funzione di retropropagazione dell'errore
 
{
     // Errore della rete
    T_Precision error;
 
    // Modifica del peso sinaptico
    T_Precision delta_w;
    
    
    // Contatore delle epoche
    size_t epochs = 0;
 
    // Iteratori
    size_t  i,j,t;
 
    // tasso di apprendimento positivo
    const T_Precision etapiu = 1.2;
    
    // tasso di apprendimento negativo
    const T_Precision etameno = 0.5;
 
    // Log di lavoro
    printf( "Inizio l'addestramento (etapiu = %.2f,etameno = %.2f, errore desiderato = %f).\n", etapiu, etameno, desired_error );
    
    // Inizializzo i pesi sinaptici con dei valori casuali
    init_weight( h_synapse, hidden_size, input_size ); //inizializzazione peso neuroni dello strato nascosto
    init_weight( o_synapse, output_size, hidden_size );//inizializzazione peso neuroni dello strato output
 
    //inizializzo i dEdw
    
    init_dEdw( h_synapse, hidden_size, input_size ); //inizializzazione dEdw peso neuroni dello strato nascosto
    init_dEdw( o_synapse, output_size, hidden_size );//inizializzazione dEdw peso neuroni dello strato output
 
    
    
    
    // Continuo l'addestramento finché non raggiungo
    // l'errore desiderato (max 50000 epoche)
    do
    {
    // Azzero l'errore della rete (somma degli errori della rete)
    error = 0.0;
    
    // Ripeto per tutti gli esempi nell'insieme di addestramento
    for ( t = 0; t < sn; t++ )
    {       //primo for
        
            // Prendo gli ingressi dall'esempio
            for ( i = 0; i < input_size; i++ )
            
            {
                i_neuron[i].value = dx[t * input_size + i];
            }
 
            // Eseguo la rete neurale
            run_network( i_neuron, input_size,
            h_neuron, h_synapse, hidden_size,
            o_neuron, o_synapse, output_size );
 
             // CALCOLO ERRORI DEGLI STRATI
        // Calcolo l'errore dello strato di uscita (in questo caso un neurone)
        for ( i = 0; i < output_size; i++ )
        {
        
            // Calcolo l'errore dell'uscita del neurone dE/dy_i = -(D_i - Y_i)
            o_neuron[i].dEdy = -( dy[t * output_size + i] - o_neuron[i].value );
 
            // Aggiungo l'errore al totale
            error += (( o_neuron[i].dEdy )*( o_neuron[i].dEdy)) ;
        }
 
 
         // Calcolo l'errore dello strato intermedio
        for ( i = 0; i < hidden_size; i++ )
            {
            
            // Azzero l'errore dei neuroni dello strato intermedio hidden
            h_neuron[i].dEdy = 0;
            
            // Calcolo l'errore dello strato intermedio dE/dz_k = SUM( dE/dy_j * dy_j/dP_j * dP_j/dz_k )
            for ( j = 0; j < output_size; j++ )
                {
                
                // Calcolo l'errore dell'uscita dei neuroni dello strato intermedio
                h_neuron[i].dEdy += o_neuron[j].dEdy *
                d_sigmoid ( o_neuron[j].value ) * o_synapse[j * ( hidden_size + 1 ) + i].weight;
                }
 
            // Calcolo l'errore dell'uscita del bias
            h_neuron[i].dEdy += o_neuron[j].dEdy *
            d_sigmoid ( o_neuron[j].value ) * o_synapse[j * ( hidden_size + 1 ) + i].weight;
            }
                 //FINE CALCOLO ERRORI DEGLI STRATI
 
 
 
                 //INIZIO AGGIORNAMENTO PESI DEI VARI STRATI
            // Aggiusto i pesi dello strato di uscita
        for ( i = 0; i < output_size; i++ )
    {
             // Correggo il peso sinaptico
            for ( j = 0; j < hidden_size; j++ )
        {
 
                            if     (synapse[i].dEdw * (o_neuron[i].dEdy*
            d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value)  > 0) then
            {
                delta_w = - etapiu * o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value;
 
            // Applico la modifica al peso sinaptico w = w + delta_w dei neuroni in uscita (uno in questo caso)
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;//nuovi pesi strato uscita
            }
            // Calcolo la modifica del peso del bias delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = - etapiu * o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value );
            // Aggiungo la correzione del bias w = w + delta_w
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;//nuovo peso bias strato di uscita
            else if (synapse[i].dEdw * (o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value)  < 0)  then
            {
                delta_w = etameno * o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value;
            // Applico la modifica al peso sinaptico w = w + delta_w dei neuroni in uscita (uno in questo caso)
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;
            }
            // Calcolo la modifica del peso del bias delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = etameno * o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value );
            // Aggiungo la correzione del bias w = w + delta_w
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;
            
            (o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value) = 0;
            
            else if  (synapse[i].dEdw * (o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value)  = 0) then
            {
            delta_w = 0;
            // Applico la modifica al peso sinaptico w = w + delta_w dei neuroni in uscita (uno in questo caso)
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;
            }
                        // Calcolo la modifica del peso del bias delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = o_neuron[i].dEdy *
            d_sigmoid ( o_neuron[i].value );
            // Aggiungo la correzione del bias w = w + delta_w
            o_synapse[i * ( hidden_size + 1 ) + j].weight += delta_w;
        }
    }
        
        //aggiusto i pesi dello strato nascosto
        for ( i = 0; i < hidden_size; i++ )
        {
             // Correggo il peso sinaptico
            for ( j = 0; j < input_size; j++ )
            {
                            if     (synapse[i].dEdw * (h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value) > 0) then
            {
                delta_w = - etapiu * h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value;
 
            // Applico la modifica al peso sinaptico w = w + delta_w dei neuroni nascosti
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;//nuovi pesi strato nascosto
            }
            // Calcolo la modifica del peso del bias delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = - etapiu * h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value );
            // Aggiungo la correzione del bias w = w + delta_w
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;//nuovo peso bias strato nascosto
            
            
            else if (synapse[i].dEdw * (h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value) < 0) then
            {
                delta_w = etameno * h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value;
            // Applico la modifica al peso sinaptico w = w + delta_w dei neuroni in uscita (uno in questo caso)
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;
            }
            // Calcolo la modifica del peso del bias delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = etameno * h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value );
            // Aggiungo la correzione del bias w = w + delta_w
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;
            
            synapse[i].dEdw * (h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value) = 0;
            
            else if (synapse[i].dEdw * (h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value) = 0) then
            {
            delta_w = 0;
            // Applico la modifica al peso sinaptico w = w + delta_w dei neuroni in uscita (uno in questo caso)
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;
            }
                        // Calcolo la modifica del peso del bias delta_w = - eta * dE/dy_j * dy_j/dP_j * dP_j/dw_jk
            delta_w = h_neuron[i].dEdy *
            d_sigmoid ( h_neuron[i].value );
            // Aggiungo la correzione del bias w = w + delta_w
            h_synapse[i * ( input_size + 1 ) + j].weight += delta_w;
            }
        }   
        
        //FINE AGGIORNAMENTO DEI PESI DEI VARI STRATI
 
}//fine del primo for (quello con il numero delle coppie sn)
 
 
 // Calcolo l'errore quadratico medio della rete (MSE) E(x) = SUM( e^2 ) / n_samples
 error /= ( input_size * sn );
 
 // Ogni 1000 epoche stampo il log di addestramento
 if ( epochs % 1000 == 0 )
 {
 printf( "Epoca #%zu, MSE=%f\n", epochs, error );
 }
 
 // Incremento il numero delle epoche
 epochs++;


//*devo aggiornare il valore del dEdw che cambia per ogni epoca sia per lo strato nascosto che per lo strato output

for (i=0 ; i < hidden_size; i++ )
    {
        for ( j = 0; j <= input_size; j++ )
        {

                        synapse[i].dEdw = h_neuron[i].dEdy * d_sigmoid ( h_neuron[i].value ) * i_neuron[j].value
            }
         }


for (i=0 ; i < output_size; i++ )
    {
        for ( j = 0; j <= hidden_size; j++ )
        {

            synapse[i].dEdw = o_neuron[i].dEdy * d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value
        }
}

//*/
 
 } while ( error > desired_error && epochs < 50000 );//fine ciclo do-while
 
 // Log di lavoro
 printf( "Addestramento terminato dopo %zu epoche.\n\n", epochs );
 
}//fine definizione funzione di retropropagazione dell'errore
 

fabio93

Utente Attivo
609
173
CPU
AMD Ryzen 5 2400G
Dissipatore
Arctic Alpine64 Plus
Scheda Madre
Gigabyte GA-AX370-Gaming 3
HDD
Crucial MX500 250 GB, Crucial BX500 240 GB
RAM
G.Skill F4-3200C14D-16GFX FlareX 16 GB
Monitor
HP 2010i
PSU
Corsair TX550M
Case
Sharkoon M25-W
Periferiche
Magicforce 68, Logitech G203
OS
Windows 10 Pro, Fedora 31
A partire dalla riga 386 usi più volte il nome synapse ma non esiste, dato che i possibili parametri formali della funzione sono h_synapse e o_synapse (non so quale avresti dovuto scrivere). Poi ci sono degli errori con la sintassi delle istruzioni condizionali, cioè ci sono degli else if preceduti da ";", il che non è permesso perché la sintassi giusta è:
C:
if (condizione_1) {
    codice;
} // il codice di un if deve essere racchiuso tra due graffe (come per while, for, do-while)
else if (condizione_2) {
    codice;
} // idem
else {
    codice;
} // idem
Solo se nel corpo di un if (o else if o else) c'è una sola istruzione si può scrivere
C:
if (condizione_1)
    una_istruzione;
else if (condizione_2)
    una_istruzione;
else
    una_istruzione;
Poi più volte c'è un "then" che non è una keyword del C. Per quanto riguarda l'indentazione ci sono moltissimi editor che la fanno in automatico, e anche il bilanciamento delle parentesi.
 
Ultima modifica:

anche_per_il_direttore

Nuovo Utente
63
2
ciao fabio grazie delle correzioni, il codice adesso viene compilato ma non fa quello che voglio e credo che il problema sia nelle if, per cercare di farmi capire posto due pezzi di codice, il primo e' relativo all algoritmo backpropagation del quale sono sicuro che funziona sia la sintassi che la matematica, il secondo pezzo di codice e' relativa all algoritmo resilient backpropagation che vorrebbe replicare quella parte di for con le if annidate.
allora posto il primo pezzo di codice e spiego come funziona, poi posto il secondo pezzo di codice e spiego come vorrei che funzionasse

C:
        for ( i = 0; i < 1; i++ )
               {
                        for ( j = 0; j < 3; j++ )
                               {
                                             delta_w = - eta * o_neuron[i].dEdy * d_sigmoid ( o_neuron[i].value ) * h_neuron[j].value;
                                              o_synapse[ i * ( 3 + 1 ) + j ].weight += delta_w;
                               }

                        delta_w = - eta * o_neuron[ i ].dEdy  *  d_sigmoid ( o_neuron[ i ].value );
                        o_synapse[ i * ( hidden_size + 1 ) + j ].weight += delta_w;
             }

ok questo sopra e' il primo pezzo di codice, proviene dal codice funzionante che avevo postato con algoritmo backpropagation (ho sostituito nelle condizioni valori numerici per facilitare e tolto i commenti).
allora dopo aver terminato il ciclo j, vengono eseguite le altre due istruzioni con j impostato a 3 (quando usciamo), poi il ciclo i riparte. e questo funziona.
ora il secondo pezzo di codice
C:
for ( i = 0; i < 1; i++ )
       {//apro1
          
                           for ( j = 0; j < 3; j++ )
                                 {//apro2
                                             
                                                 if     (o_synapse[ i ].dEdw * (o_neuron[ i ].dEdy* d_sigmoid ( o_neuron[ i ].value ) * h_neuron[ j ].value)  > 0)
                                                        {//apro3
                                                                       {//apro 4
                                                                                  delta_w = - etapiu * o_neuron[ i ].dEdy * d_sigmoid ( o_neuron[ i ].value ) * h_neuron[ j ].value;
                                                                                  o_synapse[i * ( 3 + 1 ) + j ].weight += delta_w;
                                                                       }//chiudo 4

                                                        delta_w = - etapiu * o_neuron[ i ].dEdy * d_sigmoid ( o_neuron[ i ].value );
                                                        o_synapse[i * ( 3 + 1 ) + j ].weight += delta_w;
                                                        }//chiudo3
         

                                                else if (o_synapse[ i ].dEdw * (o_neuron[ i ].dEdy * d_sigmoid ( o_neuron[ i ].value ) * h_neuron[ j ].value)  < 0)
                                                            {//apro3
                                                                         {//apro4
                                                                                  delta_w = etameno * o_neuron[ i ].dEdy * d_sigmoid ( o_neuron[ i ].value ) * h_neuron[ j ].value;
                                                                                   o_synapse[ i * ( 3 + 1 ) + j ].weight += delta_w;
                                                                         }//chiudo4
         
                                                        delta_w = etameno * o_neuron[ i ].dEdy * d_sigmoid ( o_neuron[ i ].value );
                                                        o_synapse[ i * ( 3 + 1 ) + j ].weight += delta_w;
                                                       (o_neuron[ i ].dEdy * d_sigmoid ( o_neuron[ i ].value ) * h_neuron[ j ].value) == 0;
                                                          }//chiudo3


                                              else if  (o_synapse[ i ].dEdw * (o_neuron[ i ].dEdy * d_sigmoid ( o_neuron[ i ].value ) * h_neuron[ j ].value) == 0)
                                                            {//apro3
                                                                        {//apro4
                                                                                delta_w == 0;
                                                                                o_synapse[ i * ( 3 + 1 ) + j ].weight += delta_w;
                                                                        }//chiudo4
                                                        delta_w == 0;
                                                        o_synapse[ i * ( 3 + 1 ) + j ].weight += delta_w;
                                                           }//chiudo3
                        }//chiudo2
    }//chiudo1

in questo codice con le scelte operate nelle if vorrei replicare lo stesso comportamento all uscita del ciclo j (come nel pezzo di codice numero uno), ossia catturare il valore j +1 (ossia ad esempio in corrispondenza di i=0 il valore j=3) prima di ricominciare il ciclo i, spero di essermi spiegato sull intento del codice, tuttavia non sono sicuro del comportamento di questa struttura, in ogni caso grazie dei suggerimenti, ciao.
PS in questo momento forse ho avuto un'illuminazione divina (saranno i 46 gradi di oggi) ma in ogni caso mi piacerebbe confrontarla con qualche tua idea, ciao
 
Ultima modifica:

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili