diff --git a/classificatore_singolo b/classificatore_singolo index 5b9c29a..17c7706 100755 Binary files a/classificatore_singolo and b/classificatore_singolo differ diff --git a/classificatore_singolo.c b/classificatore_singolo.c index da47838..0ba977c 100644 --- a/classificatore_singolo.c +++ b/classificatore_singolo.c @@ -5,7 +5,10 @@ #define CATEGORIA 7 #define NUM_LAYERS 4 #define PERCETTRONI_LAYER_0 64 -#define MAX_EPOCHE 1000 +#define MAX_EPOCHE 10 + +//1 relu, 2 sigmoide +#define TIPO_FUNZIONE 2 byte get_out_corretto(byte); void stampa_layer_indirizzo(Layer *); @@ -45,34 +48,19 @@ void main() // ADDESTRAMENTO for (int i = 0; i < MAX_EPOCHE; i++) { - /* if (corrette == 4) - { - printf("\nConvergo in epoche: %d\n", i); - - // stampa_risultati_layer_multi(p_ext_1, p_ext_2, pout); - for (int j = 0; j < 4; j++) - { - double **risultato = elabora_sigmoidi(rete_neurale, set.istanze[j]); - - printf("Input: [%d,%d] -> probabilità: %f -> risultato atteso: %d\n", set.istanze[j].dati[0], set.istanze[j].dati[1], risultato[NUM_LAYERS - 1][0], set.istanze[j].classificazione); - } - - break; - } */ - - // printf("Epoca %d\n", i); - // stampa_tempo(tempo_epoche, i); + printf("Epoca %d\n", i); + stampa_tempo(tempo_epoche, i); corrette = 0; double errore_totale = 0.0; for (int indice_set = 0; indice_set < set.size -1; indice_set++) { //printf("Qui ci arrivo %d\n", indice_set); - double **sigmoidi = elabora_sigmoidi(rete_neurale, set.istanze[indice_set]); + double **funzioni_attivazione = elabora_funzioni_attivazione(rete_neurale, set.istanze[indice_set], TIPO_FUNZIONE); /* for(int k = 0; k < rete_neurale.size; k++) for(int j = 0; j < rete_neurale.layers[k].size; j++) - printf("sigmoide[%d][%d] = %f\n", k, j, sigmoidi[k][j]); */ + printf("sigmoide[%d][%d] = %f\n", k, j, funzioni_attivazione[k][j]); */ byte output_corretto = get_out_corretto(set.istanze[indice_set].classificazione); @@ -87,19 +75,19 @@ void main() // Derivata funzione di perdita - // printf("output_corretto = %d, previsione: %f\n", output_corretto, sigmoidi[NUM_LAYERS - 1][0]); - double gradiente_errore = (output_corretto - sigmoidi[NUM_LAYERS - 1][0]); + // printf("output_corretto = %d, previsione: %f\n", output_corretto, funzioni_attivazione[NUM_LAYERS - 1][0]); + double gradiente_errore = (output_corretto - funzioni_attivazione[NUM_LAYERS - 1][0]); - errore_totale += pow(gradiente_errore, 2); + errore_totale += pow(gradiente_errore, 2) * 0.5; // Derivata funzione attivazione - double derivata_sigmoide_out = sigmoidi[NUM_LAYERS - 1][0] * (1.0 - sigmoidi[NUM_LAYERS - 1][0]); - // if (derivata_sigmoide_out == 0.0) derivata_sigmoide_out = 1; + double derivata_funzione_out = derivata_sigmoide(funzioni_attivazione[NUM_LAYERS - 1][0]); + // if (derivata_funzione_out == 0.0) derivata_funzione_out = 1; // Gradiente del percettrone output - gradienti[NUM_LAYERS - 1][0] = gradiente_errore * derivata_sigmoide_out; + gradienti[NUM_LAYERS - 1][0] = gradiente_errore * derivata_funzione_out; - discesa_gradiente(rete_neurale, sigmoidi, gradienti); + discesa_gradiente(rete_neurale, funzioni_attivazione, gradienti, TIPO_FUNZIONE); // A questo punto ho tutti i gradienti dei percettroni, non mi resta che trovare i gradienti dei pesi e correggerli @@ -107,7 +95,7 @@ void main() for (int indice_peso = 0; indice_peso < rete_neurale.layers[NUM_LAYERS - 1].percettroni[0].size; indice_peso++) { // Determino gradiente del peso - double gradiente_peso = gradienti[NUM_LAYERS - 1][0] * sigmoidi[NUM_LAYERS - 2][indice_peso]; + double gradiente_peso = gradienti[NUM_LAYERS - 1][0] * funzioni_attivazione[NUM_LAYERS - 2][indice_peso]; rete_neurale.layers[NUM_LAYERS - 1].percettroni[0].pesi[indice_peso] += gradiente_peso * LRE; } rete_neurale.layers[NUM_LAYERS - 1].percettroni[0].bias += gradienti[NUM_LAYERS - 1][0] * LRE; @@ -121,7 +109,7 @@ void main() // Devo prendere il gradiente del percettrone e moltiplicarlo con gli input associati ai pesi if (indice_layer != 0) { - correggi_pesi_percettrone_double(&rete_neurale.layers[indice_layer].percettroni[indice_percettrone], indice_layer, sigmoidi, gradienti[indice_layer][indice_percettrone]); + correggi_pesi_percettrone_double(&rete_neurale.layers[indice_layer].percettroni[indice_percettrone], indice_layer, funzioni_attivazione, gradienti[indice_layer][indice_percettrone]); } else { @@ -130,13 +118,14 @@ void main() } } - if (previsione(sigmoidi[NUM_LAYERS - 1][0]) == output_corretto) + if (previsione(funzioni_attivazione[NUM_LAYERS - 1][0]) == output_corretto) { corrette++; } } - printf("Errore: %f, risposte corrette: %d/%d\n", errore_totale / 10000, corrette, set.size); + errore_totale /= 10000; + printf("Errore: %f, risposte corrette: %d/%d\n", errore_totale, corrette, set.size); // printf("\tRisposte corrette: %d\n", corrette); /* if (i == MAX_EPOCHE - 1) @@ -145,7 +134,7 @@ void main() double **risultato; for (int j = 0; j < 4; j++) { - risultato = elabora_sigmoidi(rete_neurale, set.istanze[j]); + risultato = elabora_funzioni_attivazione(rete_neurale, set.istanze[j]); printf("Input: [%d,%d] -> probabilità: %f -> previsione: %d -> risultato attesto: %d\n", set.istanze[j].dati[0], set.istanze[j].dati[1], risultato[NUM_LAYERS - 1][0], previsione(risultato[NUM_LAYERS - 1][0]), set.istanze[j].classificazione); for (int k = 0; k < rete_neurale.size; k++) for (int j = 0; j < rete_neurale.layers[k].size; j++) diff --git a/classificatore_singolo_xor b/classificatore_singolo_xor deleted file mode 100755 index d0b75e9..0000000 Binary files a/classificatore_singolo_xor and /dev/null differ diff --git a/mnist/mnist_manager b/mnist/mnist_manager deleted file mode 100755 index 269d8bc..0000000 Binary files a/mnist/mnist_manager and /dev/null differ diff --git a/mnist/mnist_manager.h b/mnist/mnist_manager.h index d2c0a7a..0d9516e 100644 --- a/mnist/mnist_manager.h +++ b/mnist/mnist_manager.h @@ -78,6 +78,18 @@ Dataset *get_dataset(char *path_mnist, char *path_categoria) (*set).istanze = istanze; fclose(file); + + //Trasformo tutto in 0 e 1 + + /* for(int indice_immagine = 0; indice_immagine < set->size; indice_immagine++) { + for(int indice_byte = 0; indice_byte < N_INPUTS; indice_byte++) { + if(set->istanze[indice_immagine].dati[indice_byte] >= 128) + set->istanze[indice_immagine].dati[indice_byte] = 1; + else + set->istanze[indice_immagine].dati[indice_byte] = 0; + } + } */ + return set; } diff --git a/percettroni.h b/percettroni.h index b3fac51..e5e9350 100644 --- a/percettroni.h +++ b/percettroni.h @@ -3,8 +3,12 @@ #include char *file_pesi = "rete_pesi.bin"; -char *file_immagini = "mnist/t10k-images.idx3-ubyte"; -char *file_label = "mnist/t10k-labels.idx1-ubyte"; +char *file_immagini = "mnist/train-images.idx3-ubyte"; +char *file_label = "mnist/train-labels.idx1-ubyte"; + +//Test dataset +/* char *file_immagini = "mnist/t10k-images.idx3-ubyte"; +char *file_label = "mnist/t10k-labels.idx1-ubyte"; */ #include "mnist/mnist_manager.h" // #include "cifar_10/cifar10_manager.h" @@ -13,7 +17,7 @@ char *file_label = "mnist/t10k-labels.idx1-ubyte"; // Siccome il char è un byte che rappresenta il valore tra 0 e 255. Per evitare confusioni definisco il tipo "byte" come in Java typedef unsigned char byte; -double LRE = 2; +double LRE = 1.414; double soglia_sigmoide = 0.5; typedef struct @@ -41,14 +45,18 @@ Percettrone inzializza_percettrone(int); ReteNeurale inizializza_rete_neurale(int, int, int); Layer inizializza_layer(int, int); -double sigmoide(Percettrone p, double*); -double **elabora_sigmoidi(ReteNeurale, Istanza); -void discesa_gradiente(ReteNeurale, double **, double **); +double funzione_attivazione(Percettrone p, double*, int); +double **elabora_funzioni_attivazione(ReteNeurale, Istanza, int); +void discesa_gradiente(ReteNeurale, double **, double **, int); double calcola_gradiente_disceso(ReteNeurale, int, int, double **); void correggi_pesi_percettrone_double(Percettrone *, int, double **, double); void correggi_pesi_percettrone_byte(Percettrone *, Istanza, double, int); int previsione(double); +double sigmoide(double); +double derivata_sigmoide(double); +double relu(double); +double derivata_relu(double); void salvaReteNeurale(const char *, ReteNeurale *); ReteNeurale *caricaReteNeurale(const char *); @@ -126,8 +134,8 @@ ReteNeurale inizializza_rete_neurale(int numero_layers, int numero_percettroni_i ################# PREVISIONI ################################ */ - -double sigmoide(Percettrone p, double *valori) +//Tipo 1 = relu, tipo 2 = sigmoide +double funzione_attivazione(Percettrone p, double *valori, int tipo) { double sommatoria = 0.0; for (int i = 0; i < p.size; i++) { @@ -136,10 +144,20 @@ double sigmoide(Percettrone p, double *valori) } sommatoria += p.bias; - double risultato = 1.0 / (1.0 + exp(-sommatoria)); //printf(" sommatoria %f -> %f\n",sommatoria, risultato); - return risultato; + if(tipo == 1) + return relu(sommatoria); + + return sigmoide(sommatoria); +} + +double sigmoide(double valore) { + return 1.0 / (1.0 + exp(-valore)); +} + +double derivata_sigmoide(double valore) { + return valore * (1.0 - valore); } int previsione(double valore) @@ -149,31 +167,42 @@ int previsione(double valore) else return 0; } - -void discesa_gradiente(ReteNeurale rete, double **sigmoidi, double **gradienti) + +double relu(double valore) { + if(valore > 0) + return valore; + + return 0; +} + +double derivata_relu(double valore) { + if(valore > 0) + return 1; + + return 0; +} + +void discesa_gradiente(ReteNeurale rete, double **funzioni, double **gradienti, int tipo_derivata) { - //printf("Qui?\n"); - // For che scorre i layer dal penultimo al primo QUINI SIZE -2 for (int indice_layer = rete.size - 2; indice_layer >= 0; indice_layer--) { - //printf("layer: %d ", indice_layer); - // printf("Mi trovo nel layer %d, ho %d percettroni\n", indice_layer, rete.layers[indice_layer].size); - - // For che scorre i percettroni del layer partendo dal primo - // Per ogni percettrone mi devo prendere il gradiente disceso dal livello sopra e moltiplicarlo per la derivata di attivazione for (int indice_percettrone = 0; indice_percettrone < rete.layers[indice_layer].size; indice_percettrone++) { - //printf("percettrone: %d ", indice_percettrone); - double derivata_attivazione = sigmoidi[indice_layer][indice_percettrone] * (1.0 - sigmoidi[indice_layer][indice_percettrone]); + //In base al tipo di funzione scelto, avvio relu o sigmoidi + + double derivata_attivazione; + + if(tipo_derivata == 1) + derivata_attivazione = derivata_relu(funzioni[indice_layer][indice_percettrone]); + else + derivata_attivazione = derivata_sigmoide(funzioni[indice_layer][indice_percettrone]); // Passo anche l'indice del percettrone perchè corrisponde all'indice del peso del livello sopra double gradiente_disceso = calcola_gradiente_disceso(rete, indice_layer + 1, indice_percettrone, gradienti); gradienti[indice_layer][indice_percettrone] = gradiente_disceso * derivata_attivazione; } - //printf("\n"); } - //printf("Qui ?\n"); } double calcola_gradiente_disceso(ReteNeurale rete, int livello, int indice_peso, double **gradienti) @@ -190,29 +219,34 @@ double calcola_gradiente_disceso(ReteNeurale rete, int livello, int indice_peso, return sommatoria; } -double **elabora_sigmoidi(ReteNeurale rete, Istanza istanza) +//tipo_funzione 1: relu, 2:sigmoide +double **elabora_funzioni_attivazione(ReteNeurale rete, Istanza istanza, int tipo_funzione) { - // sigmoidi è un array bidimensionale, la prima dimensione identifica il layer, la seconda il percettrone nel layer - // sigmoidi[indice_layer][indice_percettrone] - double **sigmoidi = (double **)malloc(sizeof(double *) * rete.size); + + double **funzioni = (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); + funzioni[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); + funzioni[0][indice_percettrone] = funzione_attivazione(rete.layers[0].percettroni[indice_percettrone], inputs, tipo_funzione); } + //Taglio fuori l'ultimo layer perchè in ogni caso sarà sigmoide for(int indice_layer = 1; indice_layer < rete.size; indice_layer ++) { - sigmoidi[indice_layer] = (double *)malloc(sizeof(double) * rete.layers[indice_layer].size); + funzioni[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]); + //Se è il livello output in ogni caso deve fare sigmoide + if(indice_layer == rete.size-1) + funzioni[indice_layer][indice_percettrone] = funzione_attivazione(rete.layers[indice_layer].percettroni[indice_percettrone], funzioni[indice_layer-1], 2); + else + funzioni[indice_layer][indice_percettrone] = funzione_attivazione(rete.layers[indice_layer].percettroni[indice_percettrone], funzioni[indice_layer-1], tipo_funzione); } } - return sigmoidi; + return funzioni; } diff --git a/prova_passaggio_parametri.c b/prova_passaggio_parametri.c new file mode 100644 index 0000000..7128446 --- /dev/null +++ b/prova_passaggio_parametri.c @@ -0,0 +1,40 @@ +#include +#include + +void stampa(int**); +void cambia(int**); + +void main() { + int **matrice = (int**)malloc(sizeof(int*) * 10); + + for(int i = 0; i < 10; i++) { + matrice[i] = (int*)malloc(sizeof(int) * 10); + for(int j = 0; j < 10; j++) { + matrice[i][j] = i * j; + } + } + + stampa(matrice); + + cambia(matrice); + + stampa(matrice); +} + +void stampa(int **matrix) { + for(int i = 0; i < 10; i++) { + + for(int j = 0; j < 10; j++) { + printf(" %d ", matrix[i][j]); + } + printf("\n"); + } +} + +void cambia(int **matrix) { + for(int i = 0; i < 10; i++) { + for(int j = 0; j < 10; j++) { + matrix[i][j] = 0; + } + } +} \ No newline at end of file diff --git a/visualizzatore b/visualizzatore index 9395e1e..ba15974 100755 Binary files a/visualizzatore and b/visualizzatore differ diff --git a/visualizzatore.c b/visualizzatore.c index c35890d..d501fd5 100644 --- a/visualizzatore.c +++ b/visualizzatore.c @@ -1,7 +1,6 @@ #include #include #include "percettroni.h" -#include "mnist/mnist_manager.h" //CIFAR_10 /* #define IMAGE_WIDTH 32 @@ -17,8 +16,8 @@ BITMAP *buffer; BITMAP *image; int *previsto; -ReteNeurale *rete_neurale; -Dataset *set; +ReteNeurale rete_neurale; +Dataset set; void init_allegro(); @@ -33,26 +32,42 @@ void main() init_allegro(); //get_dataset("cifar-10-batches/test_batch.bin"); - set = get_dataset(file_immagini, file_label); - if (set == NULL) { + Dataset *set_appoggio = get_dataset(file_immagini, file_label); + if (set_appoggio == NULL) { printf("Errore nel caricare il dataset\n"); return; } + set = *set_appoggio; - rete_neurale = caricaReteNeurale(file_pesi); - if (rete_neurale == NULL) { + ReteNeurale *rete_appoggio = caricaReteNeurale(file_pesi); + if (rete_appoggio == NULL) { printf("Errore nel caricare il modello\n"); return; } + rete_neurale = *rete_appoggio; - int indice_set = rand() % set->size; + free(set_appoggio); + free(rete_appoggio); + + //Trasformo tutto in 0 e 1 + + /* for(int indice_immagine = 0; indice_immagine < set.size; indice_immagine++) { + for(int indice_byte = 0; indice_byte < N_INPUTS; indice_byte++) { + if(set.istanze[indice_immagine].dati[indice_byte] == 0) + set.istanze[indice_immagine].dati[indice_byte] = 0; + else + set.istanze[indice_immagine].dati[indice_byte] = 255; + } + } */ + + int indice_set = rand() % set.size; // Carica la prima immagine carica_immagine(indice_set); while(!key[KEY_ESC]) { disegna_interfaccia(); - indice_set = rand() % set->size; + indice_set = rand() % set.size; evento_click_bottone(indice_set); rest(10); } @@ -94,7 +109,7 @@ void init_allegro() { void carica_immagine(int indice_set) { // Stampa informazioni sull'immagine - printf("Immagine indice: %d, valore: %d. è un 7? %d\n", indice_set, set->istanze[indice_set].categoria, prevedi(indice_set)); + printf("Immagine indice: %d, valore: %d. è un 7? %d\n", indice_set, set.istanze[indice_set].classificazione, prevedi(indice_set)); // Itera su ogni pixel dell'immagine for (int y = 0; y < IMAGE_HEIGHT; y++) @@ -102,7 +117,7 @@ void carica_immagine(int indice_set) for (int x = 0; x < IMAGE_WIDTH; x++) { // Ottieni il valore del pixel (scala di grigi, quindi un solo canale) - int gray_value = set->istanze[indice_set].immagine[y * IMAGE_WIDTH + x]; + int gray_value = set.istanze[indice_set].dati[y * IMAGE_WIDTH + x]; // Converti il valore in scala di grigi in un colore RGB (r = g = b = gray_value) int color = makecol(gray_value, gray_value, gray_value); @@ -169,20 +184,12 @@ void evento_click_bottone(int indice_set) int prevedi(int indice_set) { - double **sigmoidi = (double **)malloc(sizeof(double *) * rete_neurale->size); + + double **sigmoidi = elabora_funzioni_attivazione(rete_neurale, set.istanze[indice_set], 2); + + byte output_corretto = get_out_corretto(set.istanze[indice_set].classificazione); - sigmoidi[0] = (double *)malloc(sizeof(double) * rete_neurale->layers[0].size); - sigmoidi[0] = funzioni_attivazione_layer_byte(rete_neurale->layers[0], set->istanze[indice_set].immagine); - - for (int j = 1; j < rete_neurale->size; j++) - { - sigmoidi[j] = (double *)malloc(sizeof(double) * rete_neurale->layers[j].size); - sigmoidi[j] = funzioni_attivazione_layer_double(rete_neurale->layers[j], sigmoidi[j - 1]); - } - - byte output_corretto = get_out_corretto(set->istanze[indice_set].categoria); - - return previsione(sigmoidi[rete_neurale->size - 1][0]); + return previsione(sigmoidi[rete_neurale.size - 1][0]); } byte get_out_corretto(byte categoria) {