diff --git a/cavalli.bin b/cavalli.bin new file mode 100644 index 0000000..0cec6e2 Binary files /dev/null and b/cavalli.bin differ diff --git a/classificatore_singolo b/classificatore_singolo index a3311fc..df207f6 100755 Binary files a/classificatore_singolo and b/classificatore_singolo differ diff --git a/classificatore_singolo.c b/classificatore_singolo.c index 8d520c4..2e73a64 100644 --- a/classificatore_singolo.c +++ b/classificatore_singolo.c @@ -1,20 +1,20 @@ -#include "visualizzatore.h" +#include "percettroni.h" #include #define NUM_LAYERS 4 -#define PERCETTRONI_LAYER_0 256 +#define PERCETTRONI_LAYER_0 32 #define INPUT_LAYER_0 3072 -#define PERCETTRONI_LAYER_1 128 -#define INPUT_LAYER_1 256 -#define PERCETTRONI_LAYER_2 64 -#define INPUT_LAYER_2 128 +#define PERCETTRONI_LAYER_1 16 +#define INPUT_LAYER_1 32 +#define PERCETTRONI_LAYER_2 8 +#define INPUT_LAYER_2 16 #define PERCETTRONI_LAYER_3 1 -#define INPUT_LAYER_3 64 +#define INPUT_LAYER_3 8 //#define PERCETTRONI_LAYER_4 1 //#define INPUT_LAYER_4 10 -#define MAX_EPOCHE 100 +#define MAX_EPOCHE 50 //Scelgo quale categoria voglio identificare. La 7 sono i cavalli. La rete mi dirà per ogni immagine se è un cavallo o no #define CATEGORIA 7 @@ -26,22 +26,7 @@ void main() { srand(time(NULL)); - /* init_allegro(); - - // Carica la prima immagine - load_current_image(set); - - while (!key[KEY_ESC]) { - draw_interface(); - handle_input(set); - rest(10); - } - - destroy_bitmap(buffer); - destroy_bitmap(image); - allegro_exit(); */ - - Dataset *set_appoggio = get_dataset("cifar-10-batches/data_batch_1.bin"); + Dataset *set_appoggio = get_dataset("cifar-10-batches/test_batch.bin"); if(set_appoggio == NULL) return; Dataset set = *set_appoggio; @@ -106,6 +91,7 @@ void main() { byte output_corretto = get_out_corretto(set.istanze[indice_set].categoria); + //Se prevede male if(previsione(sigmoidi[NUM_LAYERS-1][0]) != output_corretto) { diff --git a/dataset_manager b/dataset_manager new file mode 100755 index 0000000..33a87ef Binary files /dev/null and b/dataset_manager differ diff --git a/dataset_manager.h b/dataset_manager.h index 3c8c7dd..c11ebfa 100644 --- a/dataset_manager.h +++ b/dataset_manager.h @@ -1,50 +1,54 @@ #include #include -#define N_PIXEL 3072 //1024 pixel * 3 (R, G, B) +#define N_PIXEL 3072 // 1024 pixel * 3 (R, G, B) -//Siccome il char è un byte che rappresenta il valore tra 0 e 255. Per evitare confusioni definisco il tipo "byte" come in Java +// 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; // Singola istanza del dataset. -typedef struct { +typedef struct +{ byte categoria; byte immagine[N_PIXEL]; } Istanza; -//Questo tipo fornisce il vettore delle istanze e il size (dimensione) del vettore -typedef struct { +// Questo tipo fornisce il vettore delle istanze e il size (dimensione) del vettore +typedef struct +{ int size; Istanza *istanze; } Dataset; -Dataset* get_dataset(char *); +Dataset *get_dataset(char *); -//Questo metodo legge il file in questione e restituisce un puntatore a Dataset se il file esiste, altrimenti NULL -//Ritorna un puntatore perchè in questo caso posso gestire il ritorno NULL. -Dataset* get_dataset(char *path) { - - Dataset *set = (Dataset *) malloc(sizeof(Dataset)); +// Questo metodo legge il file in questione e restituisce un puntatore a Dataset se il file esiste, altrimenti NULL +// Ritorna un puntatore perchè in questo caso posso gestire il ritorno NULL. +Dataset *get_dataset(char *path) +{ + Dataset *set = (Dataset *)malloc(sizeof(Dataset)); FILE *file; Istanza istanza; Istanza *istanze = (Istanza *)malloc(sizeof(Istanza)); file = fopen(path, "rb"); - if(file == NULL) + if (file == NULL) return NULL; int numero_righe = 0; - //Fino a quando questo fread restituisce 1 significa che il file contiene ancora roba - while(fread(&istanze[numero_righe].categoria, sizeof(byte), 1, file) == 1) { - if(fread(istanze[numero_righe].immagine, sizeof(byte), N_PIXEL, file) == N_PIXEL) { - numero_righe ++; + // Fino a quando questo fread restituisce 1 significa che il file contiene ancora roba + while (fread(&istanze[numero_righe].categoria, sizeof(byte), 1, file) == 1) + { + if (fread(istanze[numero_righe].immagine, sizeof(byte), N_PIXEL, file) == N_PIXEL) + { + numero_righe++; istanze = (Istanza *)realloc(istanze, sizeof(Istanza) * (numero_righe + 1)); - //printf("Caricata nel sistema riga %d\n", numero_righe); + // printf("Caricata nel sistema riga %d\n", numero_righe); } } - //Dataset set; + // Dataset set; (*set).size = numero_righe; (*set).istanze = istanze; @@ -53,22 +57,57 @@ Dataset* get_dataset(char *path) { return set; } -/* void main() { +void salva_dataset(const char *filename, Dataset *set) +{ + FILE *file = fopen(filename, "wb"); + if (!file) + { + perror("Errore nell'apertura del file"); + exit(EXIT_FAILURE); + } + + for (int indice_istanze = 0; indice_istanze < set->size; indice_istanze++) + { + fwrite(&set->istanze[indice_istanze].categoria, sizeof(byte), 1, file); + fwrite(&set->istanze[indice_istanze].immagine, sizeof(byte), N_PIXEL, file); + } + + fclose(file); +} + +/* void main() +{ char *path = "cifar-10-batches/data_batch_1.bin"; - //Carico il dataset e controllo che non sia nullo + // Carico il dataset e controllo che non sia nullo Dataset *dataset = get_dataset(path); - if(dataset == NULL) { + if (dataset == NULL) + { printf("Oggetto dataset nullo\n"); return; } - //Lo copio in una seconda variabile per non dover mettere sempre * davanti al nome e libero la memoria occupata dal puntatore + Dataset cavalli; + cavalli.size = 1; + cavalli.istanze = (Istanza *)malloc(sizeof(Istanza) * cavalli.size); + int indice_cavalli = 0; + + // Lo copio in una seconda variabile per non dover mettere sempre * davanti al nome e libero la memoria occupata dal puntatore Dataset set = *dataset; free(dataset); - //Stampa di debug - for(int i = 0; i < set.size; i++) { - printf("n: %d. Categoria: %d\n", i, (int)set.istanze[i].categoria); + // Stampa di debug + for (int i = 0; i < set.size; i++) + { + if (set.istanze[i].categoria == 7) + { + cavalli.size++; + cavalli.istanze[indice_cavalli] = set.istanze[i]; + cavalli.istanze = (Istanza *)realloc(cavalli.istanze, sizeof(Istanza) * cavalli.size); + printf("n: %d. Categoria: %d\n", indice_cavalli, cavalli.istanze[indice_cavalli].categoria); + indice_cavalli++; + } } + + salva_dataset("cavalli.bin", &cavalli); } */ \ No newline at end of file diff --git a/percettroni.h b/percettroni.h index d616064..14d9a21 100644 --- a/percettroni.h +++ b/percettroni.h @@ -1,14 +1,3 @@ -/* - Definisco i percettroni della rete neurale per il dataset CIFAR10 - Struttura della rete: - Livello 1: 256 percettroni con 3072 input ciascuno - Livello 2: 128 percettroni con 256 input ciascuno - Livello output: 10 percettroni con 128 input ciascuno - - In output ci sono 10 percettroni, ognuno di essi è associato ad una categoria del CIFAR10. Alla fine dell'addestramento, la previsione sarà - data dal percettrone di output che avrà il valore 1 rispetto agli altri 9. -*/ - #include #include "dataset_manager.h" @@ -162,6 +151,7 @@ int previsione(double valore) { return 0; } +//Questa funzione prende la matrice dei gradienti e la matrice delle sigmoidi per correggere tutti i layer tranne quello di ingresso void correggi_layer_interni(ReteNeurale *rete, double **gradienti, double **sigmoidi) { for(int indice_layer = rete->size-1; indice_layer > 0; indice_layer--) { @@ -183,6 +173,7 @@ void correggi_layer_interni(ReteNeurale *rete, double **gradienti, double **sigm } } +//Questa funzione prende tutti i parametri della precedente + gli input passati dal dataset per correggere il layer di ingresso void correggi_layer_input(Layer *layer, double **gradienti, double **sigmoidi, byte *inputs, int n_layers) { //L'indice del layer d'ingresso che prende byte per input int indice_layer = 0; @@ -196,6 +187,7 @@ void correggi_layer_input(Layer *layer, double **gradienti, double **sigmoidi, b } } +//Una volta finito il ciclo delle epoche viene salvato lo stato della rete neurale void salvaReteNeurale(const char *filename, ReteNeurale *rete) { FILE *file = fopen(filename, "wb"); if (!file) { @@ -223,6 +215,7 @@ void salvaReteNeurale(const char *filename, ReteNeurale *rete) { fclose(file); } +//Quando parte il programma carica lo stato della rete neurale dal file oppure inizializza una rete neurale con pesi random se il file non esiste ReteNeurale *caricaReteNeurale(const char *filename) { FILE *file = fopen(filename, "rb"); diff --git a/rete_cifar_pesi.bin b/rete_cifar_pesi.bin index ae78ae9..f9efa5d 100644 Binary files a/rete_cifar_pesi.bin and b/rete_cifar_pesi.bin differ diff --git a/rete_cifar_pesi_strammata.bin b/rete_cifar_pesi_strammata.bin new file mode 100644 index 0000000..ae78ae9 Binary files /dev/null and b/rete_cifar_pesi_strammata.bin differ diff --git a/visualizzatore b/visualizzatore index 8496919..096807d 100755 Binary files a/visualizzatore and b/visualizzatore differ diff --git a/visualizzatore.c b/visualizzatore.c new file mode 100644 index 0000000..e08e2fe --- /dev/null +++ b/visualizzatore.c @@ -0,0 +1,163 @@ +#include +#include +#include "percettroni.h" + +#define IMAGE_WIDTH 32 +#define IMAGE_HEIGHT 32 +#define SCALE_FACTOR 2 + +//Cavalli +#define CATEGORIA 7 + +BITMAP *buffer; +BITMAP *image; +int *previsto; +ReteNeurale *rete_neurale; +Dataset *set; + + +void init_allegro(); +void carica_immagine(int); +void disegna_interfaccia(); +void evento_click_bottone(int); +int prevedi(int); +byte get_out_corretto(byte); + +void main() +{ + init_allegro(); + + set = get_dataset("cifar-10-batches/test_batch.bin"); + if (set == NULL) { + printf("Errore nel caricare il dataset\n"); + return; + } + + rete_neurale = caricaReteNeurale("rete_cifar_pesi.bin"); + if (rete_neurale == NULL) { + printf("Errore nel caricare il modello\n"); + return; + } + + 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; + evento_click_bottone(indice_set); + rest(10); + } + + destroy_bitmap(buffer); + destroy_bitmap(image); + allegro_exit(); +} + +void init_allegro() { + allegro_init(); + install_keyboard(); + install_mouse(); + set_color_depth(32); + set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0); + buffer = create_bitmap(800, 600); + image = create_bitmap(IMAGE_WIDTH, IMAGE_HEIGHT); + show_mouse(screen); +} + +void carica_immagine(int indice_set) +{ + printf("Immagine indice: %d, categoria: %d, previsione: %d\n", indice_set, set->istanze[indice_set].categoria, prevedi(indice_set)); + + for (int y = 0; y < IMAGE_HEIGHT; y++) + { + for (int x = 0; x < IMAGE_WIDTH; x++) + { + int r = set->istanze[indice_set].immagine[y * IMAGE_WIDTH + x]; + int g = set->istanze[indice_set].immagine[1024 + y * IMAGE_WIDTH + x]; + int b = set->istanze[indice_set].immagine[2048 + y * IMAGE_WIDTH + x]; + putpixel(image, x, y, makecol(r, g, b)); + } + } +} + +void disegna_interfaccia() +{ + //printf("\tPrevisione: %d\n", previsione); + clear_to_color(buffer, makecol(255, 255, 255)); + + // Calcola la posizione per centrare l'immagine ingrandita + int scaled_width = IMAGE_WIDTH * SCALE_FACTOR; + int scaled_height = IMAGE_HEIGHT * SCALE_FACTOR; + int image_x = (800 - scaled_width) / 2; + int image_y = (600 - scaled_height) / 2 - 20; // Sposta leggermente sopra per fare spazio al pulsante + + // Disegna l'immagine ingrandita + stretch_blit(image, buffer, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, image_x, image_y, scaled_width, scaled_height); + + // Disegna il pulsante "prossima" + int button_width = 150; + int button_height = 40; + int button_x = (800 - button_width) / 2; + int button_y = 600 - 60; // Posizione in basso + + rectfill(buffer, button_x, button_y, button_x + button_width, button_y + button_height, makecol(200, 200, 200)); + textout_centre_ex(buffer, font, "prossima", button_x + button_width / 2, button_y + 10, makecol(0, 0, 0), -1); + + /* if(previsto == 1) + textout_centre_ex(buffer, font, "cavallo", button_x + button_width / 2, 70, makecol(0, 255, 0), -1); + else + textout_centre_ex(buffer, font, "non cavallo", button_x + button_width / 2, 70, makecol(255, 0, 0), -1); */ + + // Copia il buffer sullo schermo + blit(buffer, screen, 0, 0, 0, 0, 800, 600); +} + +void evento_click_bottone(int indice_set) +{ + if (mouse_b & 1) + { + int mx = mouse_x; + int my = mouse_y; + + // Coordinate del pulsante + int button_width = 150; + int button_height = 40; + int button_x = (800 - button_width) / 2; + int button_y = 600 - 60; + + // Controlla se il clic è avvenuto sul pulsante + if (mx >= button_x && mx <= button_x + button_width && my >= button_y && my <= button_y + button_height) + { + carica_immagine(indice_set); + rest(200); // Debounce + } + } +} + +int prevedi(int indice_set) +{ + double **sigmoidi = (double **)malloc(sizeof(double *) * rete_neurale->size); + + 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]); +} + +byte get_out_corretto(byte categoria) { + if(categoria == CATEGORIA) + return 1; + else + return 0; +} \ No newline at end of file diff --git a/visualizzatore.h b/visualizzatore.h deleted file mode 100644 index ded1525..0000000 --- a/visualizzatore.h +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include "percettroni.h" - -#define IMAGE_WIDTH 32 -#define IMAGE_HEIGHT 32 -#define SCALE_FACTOR 2 - -BITMAP *buffer; -BITMAP *image; - -void init_allegro() { - allegro_init(); - install_keyboard(); - install_mouse(); - set_color_depth(32); - set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0); - buffer = create_bitmap(800,600); - image = create_bitmap(IMAGE_WIDTH, IMAGE_HEIGHT); - show_mouse(screen); -} - -void load_current_image(Dataset *set) { - int indice = rand()%set->size; - for (int y = 0; y < IMAGE_HEIGHT; y++) { - for (int x = 0; x < IMAGE_WIDTH; x++) { - int r = set->istanze[indice].immagine[y * IMAGE_WIDTH + x]; - int g = set->istanze[indice].immagine[1024 + y * IMAGE_WIDTH + x]; - int b = set->istanze[indice].immagine[2048 + y * IMAGE_WIDTH + x]; - putpixel(image, x, y, makecol(r, g, b)); - } - } -} - -void draw_interface() { - clear_to_color(buffer, makecol(255, 255, 255)); - - // Calcola la posizione per centrare l'immagine ingrandita - int scaled_width = IMAGE_WIDTH * SCALE_FACTOR; - int scaled_height = IMAGE_HEIGHT * SCALE_FACTOR; - int image_x = (800 - scaled_width) / 2; - int image_y = (600 - scaled_height) / 2 - 20; // Sposta leggermente sopra per fare spazio al pulsante - - // Disegna l'immagine ingrandita - stretch_blit(image, buffer, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, image_x, image_y, scaled_width, scaled_height); - - // Disegna il pulsante "prossima" - int button_width = 150; - int button_height = 40; - int button_x = (800 - button_width) / 2; - int button_y = 600 - 60; // Posizione in basso - rectfill(buffer, button_x, button_y, button_x + button_width, button_y + button_height, makecol(200, 200, 200)); - textout_centre_ex(buffer, font, "prossima", button_x + button_width / 2, button_y + 10, makecol(0, 0, 0), -1); - - // Copia il buffer sullo schermo - blit(buffer, screen, 0, 0, 0, 0, 800, 600); -} - -void handle_input(Dataset *set) { - if (mouse_b & 1) { - int mx = mouse_x; - int my = mouse_y; - - // Coordinate del pulsante - int button_width = 150; - int button_height = 40; - int button_x = (800 - button_width) / 2; - int button_y = 600 - 60; - - // Controlla se il clic è avvenuto sul pulsante - if (mx >= button_x && mx <= button_x + button_width && my >= button_y && my <= button_y + button_height) { - load_current_image(set); - rest(200); // Debounce - } - } -} \ No newline at end of file