diff --git a/AGENTS.md b/AGENTS.md index 231fcdf..b1a2b41 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -30,6 +30,9 @@ gcc -o rete_neurale rete_neurale.c -lm # Automated training with pauses (prevents overheating) ./addestratore.sh + +# Memory leak detection (valgrind) +valgrind --leak-check=full ./codice_ricordo ``` ### Running a Single Test @@ -103,7 +106,7 @@ No formal test framework. Use these approaches: 1. `codice_ricordo.c` - XOR validation (4 inputs, quick convergence test) 2. Visual inspection of weight outputs via `stampa_pesi_rete()` 3. Monitor epoch error rates in training output -4. Check for memory leaks with valgrind: `valgrind --leak-check=full ./codice_ricordo` +4. Check for memory leaks with valgrind ## Project Structure - `percettroni.h` - Core neural network (header-only library with implementations) diff --git a/codice_ricordo b/codice_ricordo deleted file mode 100755 index 44b9f84..0000000 Binary files a/codice_ricordo and /dev/null differ diff --git a/codice_ricordo.c b/codice_ricordo.c index 176b0d3..8708a6c 100644 --- a/codice_ricordo.c +++ b/codice_ricordo.c @@ -3,32 +3,14 @@ #define EPOCHE 100000 void main() { - ReteNeurale rete = inizializza_rete_neurale(2, 2, 2); + ReteNeurale rete = inizializza_rete_neurale(2, 5, 50, 10); //stampa_pesi_rete(rete); Dataset xor = *crea_dataset_xor(); - //for(int i = 0; i < xor->size; i++) { - // printf("%d\n", xor->istanze[i].classificazione); - //} - - //double **sigmoidi; - - /* for(int epoca = 0; epoca < EPOCHE; epoca++) { - for(int indice_istanza = 0; indice_istanza < xor->size; indice_istanza++) { - sigmoidi = elabora_sigmoidi(rete, xor->istanze[indice_istanza]); - } - } */ - for(int epoca = 0; epoca < EPOCHE; epoca++) { - printf("\nEPOCA %d\n", epoca); + //printf("\nEPOCA %d\n", epoca); if (addestra(&rete, xor)) break; } - - //0:0 -> 0 - /* sigmoidi = elabora_sigmoidi(rete, xor->istanze[0]); - - int previsto = previsione(sigmoidi[rete.size -1][0]); - printf("La previsione per la prima istanza: %d\n", previsto); */ } \ No newline at end of file diff --git a/percettroni.h b/percettroni.h index 6094387..d63684c 100644 --- a/percettroni.h +++ b/percettroni.h @@ -49,16 +49,16 @@ typedef struct double randomico(); Percettrone inzializza_percettrone(int); -ReteNeurale inizializza_rete_neurale(int, int, int); +ReteNeurale inizializza_rete_neurale(int, int, int, int); Layer inizializza_layer(int, int); double sigmoide(Percettrone p, double *); double derivata_sigmoide(double); -double **elabora_sigmoidi(ReteNeurale, Istanza); +double **elabora_sigmoidi(ReteNeurale *, Istanza); -double **elabora_gradienti(ReteNeurale, double, double **); -void discesa_gradiente(ReteNeurale, double **, double **); -double calcola_gradiente_disceso(ReteNeurale, int, int, double **); +double **elabora_gradienti(ReteNeurale *, double, double **); +void discesa_gradiente(ReteNeurale *, double **, double **); +double calcola_gradiente_disceso(ReteNeurale *, int, int, double **); void aggiorna_pesi(ReteNeurale *, double **, double **, Istanza); void correggi_pesi_percettrone_double(Percettrone *, int, double **, double); @@ -69,7 +69,7 @@ int previsione(double); void salvaReteNeurale(const char *, ReteNeurale *); ReteNeurale *caricaReteNeurale(const char *); -void stampa_pesi_rete(ReteNeurale); +void stampa_pesi_rete(ReteNeurale *); /* ################# INIZIALIZZAZIONI ################################ @@ -79,6 +79,7 @@ double randomico() { // Genero numeri nell'intervallo [-1,1] return ((double)(rand() % 101 * 0.01 * 2.0) - 1.0); + //return (double)(rand() % 101 * 0.01); } Percettrone inizializza_percettrone(int n_pesi) @@ -112,22 +113,28 @@ Layer inizializza_layer(int n_percettroni, int n_pesi) return layer; } -ReteNeurale inizializza_rete_neurale(int numero_layers, int numero_percettroni_iniziali, int numero_input) +ReteNeurale inizializza_rete_neurale(int numero_input, int numero_layers, int numero_percettroni_iniziali, int numero_percettroni_finali) { srand(time(NULL)); ReteNeurale r; r.layers = (Layer *)malloc(sizeof(Layer) * numero_layers); r.size = numero_layers; - // Funzione esponenziale inversa layer 5 + // Funzione esponenziale inversa layer for (int livello = 0; livello < numero_layers; livello++) { - double esponente = (double)livello / (double)numero_layers; - double frazione = (double)1 / (double)numero_percettroni_iniziali; + //double esponente = (double)livello / (double)numero_layers; + //double frazione = (double)1 / (double)numero_percettroni_iniziali; + //int numero_percettroni_livello = (int)((double)numero_percettroni_iniziali * pow(frazione, esponente)); + + int numero_percettroni_livello = 1; - int numero_percettroni_livello = (int)((double)numero_percettroni_iniziali * pow(frazione, esponente)); if (livello == numero_layers - 1) - numero_percettroni_livello = 1; + numero_percettroni_livello = numero_percettroni_finali; + else { + double frazione = (double) (numero_layers - livello) / (double) numero_layers; + numero_percettroni_livello = (int)((double)(numero_percettroni_iniziali * frazione)); + } // printf("esponente %f -> frazione: %f\n", esponente, frazione); printf("Layer %d -> percettroni: %d\n", livello, numero_percettroni_livello); @@ -146,19 +153,21 @@ ReteNeurale inizializza_rete_neurale(int numero_layers, int numero_percettroni_i */ // Da eseguire a mano 2 -double **elabora_gradienti(ReteNeurale rete_neurale, double gradiente_errore, double **sigmoidi) +double **elabora_gradienti(ReteNeurale *rete_neurale, double gradiente_errore, double **sigmoidi) { - double **gradienti = (double **)malloc(sizeof(double *) * rete_neurale.size); + double **gradienti = (double **)malloc(sizeof(double *) * rete_neurale->size); // Alloco la dimensione per ogni layer - for (int indice_layer = 0; indice_layer < rete_neurale.size; indice_layer++) + for (int indice_layer = 0; indice_layer < rete_neurale->size; indice_layer++) { - gradienti[indice_layer] = (double *)malloc(sizeof(double) * rete_neurale.layers[indice_layer].size); + gradienti[indice_layer] = (double *)malloc(sizeof(double) * rete_neurale->layers[indice_layer].size); } - // Gradiente del percettrone output - gradienti[rete_neurale.size - 1][0] = gradiente_errore * derivata_sigmoide(sigmoidi[rete_neurale.size - 1][0]); + // Qui mi trovo il gradiente del percettrone output (ultimo livello) + for(int indice_percettrone = 0; indice_percettrone < rete_neurale->layers[rete_neurale->size - 1].size; indice_percettrone++) + gradienti[rete_neurale->size - 1][indice_percettrone] = gradiente_errore * derivata_sigmoide(sigmoidi[rete_neurale->size - 1][indice_percettrone]); + //Dal gradiente trovato per l'output, mi discendo tutti gli altri discesa_gradiente(rete_neurale, sigmoidi, gradienti); return gradienti; @@ -210,11 +219,11 @@ int previsione(double valore) } // Invocata da elabora_gradienti() -void discesa_gradiente(ReteNeurale rete, double **sigmoidi, double **gradienti) +void discesa_gradiente(ReteNeurale *rete, double **sigmoidi, double **gradienti) { - for (int indice_layer = rete.size - 2; indice_layer >= 0; indice_layer--) + for (int indice_layer = rete->size - 2; indice_layer >= 0; indice_layer--) { - for (int indice_percettrone = 0; indice_percettrone < rete.layers[indice_layer].size; indice_percettrone++) + for (int indice_percettrone = 0; indice_percettrone < rete->layers[indice_layer].size; indice_percettrone++) { double derivata_attivazione = derivata_sigmoide(sigmoidi[indice_layer][indice_percettrone]); double gradiente_disceso = calcola_gradiente_disceso(rete, indice_layer + 1, indice_percettrone, gradienti); @@ -225,39 +234,39 @@ void discesa_gradiente(ReteNeurale rete, double **sigmoidi, double **gradienti) } // Invocata da discesa_gradienti() -double calcola_gradiente_disceso(ReteNeurale rete, int livello, int indice_peso, double **gradienti) +double calcola_gradiente_disceso(ReteNeurale *rete, int livello, int indice_peso, double **gradienti) { double sommatoria = 0.0; - for (int indice_percettrone = 0; indice_percettrone < rete.layers[livello].size; indice_percettrone++) + for (int indice_percettrone = 0; indice_percettrone < rete->layers[livello].size; indice_percettrone++) { - sommatoria += (gradienti[livello][indice_percettrone] * rete.layers[livello].percettroni[indice_percettrone].pesi[indice_peso]); + sommatoria += (gradienti[livello][indice_percettrone] * rete->layers[livello].percettroni[indice_percettrone].pesi[indice_peso]); } return sommatoria; } // Da eseguire a mano 1 -double **elabora_sigmoidi(ReteNeurale rete, Istanza istanza) +double **elabora_sigmoidi(ReteNeurale *rete, Istanza istanza) { - double **sigmoidi = (double **)malloc(sizeof(double *) * rete.size); - double *inputs = (double *)malloc(sizeof(double *) * N_INPUTS); + double **sigmoidi = (double **)malloc(sizeof(double *) * rete->size); + double *inputs = (double *)malloc(sizeof(double) * N_INPUTS); for (int i = 0; i < N_INPUTS; i++) { inputs[i] = (double)istanza.dati[i]; } - sigmoidi[0] = (double *)malloc(sizeof(double) * rete.layers[0].size); - for (int indice_percettrone = 0; indice_percettrone < rete.layers[0].size; indice_percettrone++) + sigmoidi[0] = (double *)malloc(sizeof(double) * rete->layers[0].size); + for (int indice_percettrone = 0; indice_percettrone < rete->layers[0].size; indice_percettrone++) { - sigmoidi[0][indice_percettrone] = sigmoide(rete.layers[0].percettroni[indice_percettrone], inputs); + sigmoidi[0][indice_percettrone] = sigmoide(rete->layers[0].percettroni[indice_percettrone], inputs); } - for (int indice_layer = 1; indice_layer < rete.size; indice_layer++) + for (int indice_layer = 1; indice_layer < rete->size; indice_layer++) { - sigmoidi[indice_layer] = (double *)malloc(sizeof(double) * rete.layers[indice_layer].size); - for (int indice_percettrone = 0; indice_percettrone < rete.layers[indice_layer].size; indice_percettrone++) + sigmoidi[indice_layer] = (double *)malloc(sizeof(double) * rete->layers[indice_layer].size); + for (int indice_percettrone = 0; indice_percettrone < rete->layers[indice_layer].size; indice_percettrone++) { - sigmoidi[indice_layer][indice_percettrone] = sigmoide(rete.layers[indice_layer].percettroni[indice_percettrone], sigmoidi[indice_layer - 1]); + sigmoidi[indice_layer][indice_percettrone] = sigmoide(rete->layers[indice_layer].percettroni[indice_percettrone], sigmoidi[indice_layer - 1]); } } @@ -338,11 +347,13 @@ byte addestra(ReteNeurale *rete_neurale, Dataset set) //Per ogni istanza del dataset for (int indice_set = 0; indice_set < set.size; indice_set++) { - double **sigmoidi = elabora_sigmoidi(*rete_neurale, set.istanze[indice_set]); + double **sigmoidi = elabora_sigmoidi(rete_neurale, set.istanze[indice_set]); byte output_corretto = set.istanze[indice_set].classificazione; int previsto = previsione(sigmoidi[rete_neurale->size - 1][0]); - printf("\tPrevisto: %d, corretto: %d\n", previsto, output_corretto); + + //printf("\tPrevisto: %d, corretto: %d\n", previsto, output_corretto); + if (previsto == output_corretto) { corrette++; } @@ -351,13 +362,20 @@ byte addestra(ReteNeurale *rete_neurale, Dataset set) double gradiente_errore = (output_corretto - sigmoidi[rete_neurale->size - 1][0]); errore_totale += pow(gradiente_errore, 2); - double **gradienti = elabora_gradienti(*rete_neurale, gradiente_errore, sigmoidi); - + double **gradienti = elabora_gradienti(rete_neurale, gradiente_errore, sigmoidi); aggiorna_pesi(rete_neurale, sigmoidi, gradienti, set.istanze[indice_set]); + + for(int i = 0; i < rete_neurale->size; i++) + free(gradienti[i]); + free(gradienti); } + + for(int i = 0; i < rete_neurale->size; i++) + free(sigmoidi[i]); + free(sigmoidi); } - printf("Errore: %f, risposte corrette: %d%\n", errore_totale, (corrette * 100) / set.size); + //printf("Errore: %f, risposte corrette: %d%\n", errore_totale, (corrette * 100) / set.size); if(corrette == set.size) return 1; @@ -460,17 +478,17 @@ ReteNeurale *caricaReteNeurale(const char *filename) /* ################ STAMPE ############################ */ -void stampa_pesi_rete(ReteNeurale rete) +void stampa_pesi_rete(ReteNeurale *rete) { - for (int indice_layer = 0; indice_layer < rete.size; indice_layer++) + for (int indice_layer = 0; indice_layer < rete->size; indice_layer++) { printf("\nLivello %d", indice_layer); - for (int indice_percettrone = 0; indice_percettrone < rete.layers[indice_layer].size; indice_percettrone++) + for (int indice_percettrone = 0; indice_percettrone < rete->layers[indice_layer].size; indice_percettrone++) { printf("\n\tPercettrone %d", indice_percettrone); - for (int indice_peso = 0; indice_peso < rete.layers[indice_layer].percettroni[indice_percettrone].size; indice_peso++) + for (int indice_peso = 0; indice_peso < rete->layers[indice_layer].percettroni[indice_percettrone].size; indice_peso++) { - printf("\n\t\tPeso %d: %f", indice_peso, rete.layers[indice_layer].percettroni[indice_percettrone].pesi[indice_peso]); + printf("\n\t\tPeso %d: %f", indice_peso, rete->layers[indice_layer].percettroni[indice_percettrone].pesi[indice_peso]); } } }