aggiornamento codice percettroni.h
This commit is contained in:
@@ -30,6 +30,9 @@ gcc -o rete_neurale rete_neurale.c -lm
|
|||||||
|
|
||||||
# Automated training with pauses (prevents overheating)
|
# Automated training with pauses (prevents overheating)
|
||||||
./addestratore.sh
|
./addestratore.sh
|
||||||
|
|
||||||
|
# Memory leak detection (valgrind)
|
||||||
|
valgrind --leak-check=full ./codice_ricordo
|
||||||
```
|
```
|
||||||
|
|
||||||
### Running a Single Test
|
### 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)
|
1. `codice_ricordo.c` - XOR validation (4 inputs, quick convergence test)
|
||||||
2. Visual inspection of weight outputs via `stampa_pesi_rete()`
|
2. Visual inspection of weight outputs via `stampa_pesi_rete()`
|
||||||
3. Monitor epoch error rates in training output
|
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
|
## Project Structure
|
||||||
- `percettroni.h` - Core neural network (header-only library with implementations)
|
- `percettroni.h` - Core neural network (header-only library with implementations)
|
||||||
|
|||||||
Binary file not shown.
+2
-20
@@ -3,32 +3,14 @@
|
|||||||
#define EPOCHE 100000
|
#define EPOCHE 100000
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
ReteNeurale rete = inizializza_rete_neurale(2, 2, 2);
|
ReteNeurale rete = inizializza_rete_neurale(2, 5, 50, 10);
|
||||||
//stampa_pesi_rete(rete);
|
//stampa_pesi_rete(rete);
|
||||||
|
|
||||||
Dataset xor = *crea_dataset_xor();
|
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++) {
|
for(int epoca = 0; epoca < EPOCHE; epoca++) {
|
||||||
printf("\nEPOCA %d\n", epoca);
|
//printf("\nEPOCA %d\n", epoca);
|
||||||
if (addestra(&rete, xor))
|
if (addestra(&rete, xor))
|
||||||
break;
|
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); */
|
|
||||||
}
|
}
|
||||||
+62
-44
@@ -49,16 +49,16 @@ typedef struct
|
|||||||
double randomico();
|
double randomico();
|
||||||
|
|
||||||
Percettrone inzializza_percettrone(int);
|
Percettrone inzializza_percettrone(int);
|
||||||
ReteNeurale inizializza_rete_neurale(int, int, int);
|
ReteNeurale inizializza_rete_neurale(int, int, int, int);
|
||||||
Layer inizializza_layer(int, int);
|
Layer inizializza_layer(int, int);
|
||||||
|
|
||||||
double sigmoide(Percettrone p, double *);
|
double sigmoide(Percettrone p, double *);
|
||||||
double derivata_sigmoide(double);
|
double derivata_sigmoide(double);
|
||||||
double **elabora_sigmoidi(ReteNeurale, Istanza);
|
double **elabora_sigmoidi(ReteNeurale *, Istanza);
|
||||||
|
|
||||||
double **elabora_gradienti(ReteNeurale, double, double **);
|
double **elabora_gradienti(ReteNeurale *, double, double **);
|
||||||
void discesa_gradiente(ReteNeurale, double **, double **);
|
void discesa_gradiente(ReteNeurale *, double **, double **);
|
||||||
double calcola_gradiente_disceso(ReteNeurale, int, int, double **);
|
double calcola_gradiente_disceso(ReteNeurale *, int, int, double **);
|
||||||
|
|
||||||
void aggiorna_pesi(ReteNeurale *, double **, double **, Istanza);
|
void aggiorna_pesi(ReteNeurale *, double **, double **, Istanza);
|
||||||
void correggi_pesi_percettrone_double(Percettrone *, int, double **, double);
|
void correggi_pesi_percettrone_double(Percettrone *, int, double **, double);
|
||||||
@@ -69,7 +69,7 @@ int previsione(double);
|
|||||||
void salvaReteNeurale(const char *, ReteNeurale *);
|
void salvaReteNeurale(const char *, ReteNeurale *);
|
||||||
ReteNeurale *caricaReteNeurale(const char *);
|
ReteNeurale *caricaReteNeurale(const char *);
|
||||||
|
|
||||||
void stampa_pesi_rete(ReteNeurale);
|
void stampa_pesi_rete(ReteNeurale *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
################# INIZIALIZZAZIONI ################################
|
################# INIZIALIZZAZIONI ################################
|
||||||
@@ -79,6 +79,7 @@ double randomico()
|
|||||||
{
|
{
|
||||||
// Genero numeri nell'intervallo [-1,1]
|
// Genero numeri nell'intervallo [-1,1]
|
||||||
return ((double)(rand() % 101 * 0.01 * 2.0) - 1.0);
|
return ((double)(rand() % 101 * 0.01 * 2.0) - 1.0);
|
||||||
|
//return (double)(rand() % 101 * 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
Percettrone inizializza_percettrone(int n_pesi)
|
Percettrone inizializza_percettrone(int n_pesi)
|
||||||
@@ -112,22 +113,28 @@ Layer inizializza_layer(int n_percettroni, int n_pesi)
|
|||||||
return layer;
|
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));
|
srand(time(NULL));
|
||||||
ReteNeurale r;
|
ReteNeurale r;
|
||||||
r.layers = (Layer *)malloc(sizeof(Layer) * numero_layers);
|
r.layers = (Layer *)malloc(sizeof(Layer) * numero_layers);
|
||||||
r.size = numero_layers;
|
r.size = numero_layers;
|
||||||
|
|
||||||
// Funzione esponenziale inversa layer 5
|
// Funzione esponenziale inversa layer
|
||||||
for (int livello = 0; livello < numero_layers; livello++)
|
for (int livello = 0; livello < numero_layers; livello++)
|
||||||
{
|
{
|
||||||
double esponente = (double)livello / (double)numero_layers;
|
//double esponente = (double)livello / (double)numero_layers;
|
||||||
double frazione = (double)1 / (double)numero_percettroni_iniziali;
|
//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)
|
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("esponente %f -> frazione: %f\n", esponente, frazione);
|
||||||
printf("Layer %d -> percettroni: %d\n", livello, numero_percettroni_livello);
|
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
|
// 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
|
// 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
|
// Qui mi trovo il gradiente del percettrone output (ultimo livello)
|
||||||
gradienti[rete_neurale.size - 1][0] = gradiente_errore * derivata_sigmoide(sigmoidi[rete_neurale.size - 1][0]);
|
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);
|
discesa_gradiente(rete_neurale, sigmoidi, gradienti);
|
||||||
|
|
||||||
return gradienti;
|
return gradienti;
|
||||||
@@ -210,11 +219,11 @@ int previsione(double valore)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invocata da elabora_gradienti()
|
// 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 derivata_attivazione = derivata_sigmoide(sigmoidi[indice_layer][indice_percettrone]);
|
||||||
double gradiente_disceso = calcola_gradiente_disceso(rete, indice_layer + 1, indice_percettrone, gradienti);
|
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()
|
// 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;
|
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;
|
return sommatoria;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Da eseguire a mano 1
|
// 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 **sigmoidi = (double **)malloc(sizeof(double *) * rete->size);
|
||||||
double *inputs = (double *)malloc(sizeof(double *) * N_INPUTS);
|
double *inputs = (double *)malloc(sizeof(double) * N_INPUTS);
|
||||||
for (int i = 0; i < N_INPUTS; i++)
|
for (int i = 0; i < N_INPUTS; i++)
|
||||||
{
|
{
|
||||||
inputs[i] = (double)istanza.dati[i];
|
inputs[i] = (double)istanza.dati[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
sigmoidi[0] = (double *)malloc(sizeof(double) * rete.layers[0].size);
|
sigmoidi[0] = (double *)malloc(sizeof(double) * rete->layers[0].size);
|
||||||
for (int indice_percettrone = 0; indice_percettrone < rete.layers[0].size; indice_percettrone++)
|
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);
|
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++)
|
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
|
//Per ogni istanza del dataset
|
||||||
for (int indice_set = 0; indice_set < set.size; indice_set++)
|
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;
|
byte output_corretto = set.istanze[indice_set].classificazione;
|
||||||
int previsto = previsione(sigmoidi[rete_neurale->size - 1][0]);
|
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) {
|
if (previsto == output_corretto) {
|
||||||
corrette++;
|
corrette++;
|
||||||
}
|
}
|
||||||
@@ -351,13 +362,20 @@ byte addestra(ReteNeurale *rete_neurale, Dataset set)
|
|||||||
double gradiente_errore = (output_corretto - sigmoidi[rete_neurale->size - 1][0]);
|
double gradiente_errore = (output_corretto - sigmoidi[rete_neurale->size - 1][0]);
|
||||||
errore_totale += pow(gradiente_errore, 2);
|
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]);
|
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)
|
if(corrette == set.size)
|
||||||
return 1;
|
return 1;
|
||||||
@@ -460,17 +478,17 @@ ReteNeurale *caricaReteNeurale(const char *filename)
|
|||||||
/*
|
/*
|
||||||
################ STAMPE ############################
|
################ 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);
|
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);
|
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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user