diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5947999 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "files.associations": { + "array": "cpp", + "bitset": "cpp", + "string_view": "cpp", + "format": "cpp", + "initializer_list": "cpp", + "ranges": "cpp", + "span": "cpp", + "stacktrace": "cpp", + "regex": "cpp" + }, + "copilot.baseUrl": "http://10.8.0.6:11434" +} \ No newline at end of file diff --git a/cifar-10/cifar10_manager.h b/cifar-10/cifar10_manager.h index 0391eec..7e58c47 100644 --- a/cifar-10/cifar10_manager.h +++ b/cifar-10/cifar10_manager.h @@ -1,7 +1,7 @@ #include #include -#define N_PIXEL 3072 // 1024 pixel * 3 (R, G, B) +#define N_INPUTS 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 typedef unsigned char byte; @@ -9,8 +9,8 @@ typedef unsigned char byte; // Singola istanza del dataset. typedef struct { - byte categoria; - byte immagine[N_PIXEL]; + byte classificazione; + byte dati[N_INPUTS]; } Istanza; // Questo tipo fornisce il vettore delle istanze e il size (dimensione) del vettore @@ -38,9 +38,9 @@ Dataset *get_dataset(char *path) 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) + while (fread(&istanze[numero_righe].classificazione, sizeof(byte), 1, file) == 1) { - if (fread(istanze[numero_righe].immagine, sizeof(byte), N_PIXEL, file) == N_PIXEL) + if (fread(istanze[numero_righe].dati, sizeof(byte), N_INPUTS, file) == N_INPUTS) { numero_righe++; istanze = (Istanza *)realloc(istanze, sizeof(Istanza) * (numero_righe + 1)); @@ -57,7 +57,7 @@ Dataset *get_dataset(char *path) return set; } -void salva_dataset(const char *filename, Dataset *set) +/* void salva_dataset(const char *filename, Dataset *set) { FILE *file = fopen(filename, "wb"); if (!file) @@ -68,9 +68,9 @@ void salva_dataset(const char *filename, Dataset *set) 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); + fwrite(&set->istanze[indice_istanze].classificazione, sizeof(byte), 1, file); + fwrite(&set->istanze[indice_istanze].dati, sizeof(byte), N_INPUTS, file); } fclose(file); -} \ No newline at end of file +} */ \ No newline at end of file diff --git a/classificatore_singolo b/classificatore_singolo index 6c66ed3..fc5b2c1 100755 Binary files a/classificatore_singolo and b/classificatore_singolo differ diff --git a/classificatore_singolo.c b/classificatore_singolo.c index 4c0361c..69ff035 100644 --- a/classificatore_singolo.c +++ b/classificatore_singolo.c @@ -1,28 +1,14 @@ #include #include "percettroni.h" -#include "mnist/mnist_manager.h" +//#include "mnist/mnist_manager.h" +//#include "cifar_10/cifar10_manager.h" +#include "xor_manager.h" +//Scelgo quale categoria voglio identificare. nel caso dello xor -1 +#define CATEGORIA -1 #define NUM_LAYERS 5 - -#define PERCETTRONI_LAYER_0 128 -#define INPUT_LAYER_0 N_PIXEL - -#define PERCETTRONI_LAYER_1 64 -#define INPUT_LAYER_1 PERCETTRONI_LAYER_0 - -#define PERCETTRONI_LAYER_2 32 -#define INPUT_LAYER_2 PERCETTRONI_LAYER_1 - -#define PERCETTRONI_LAYER_3 16 -#define INPUT_LAYER_3 PERCETTRONI_LAYER_2 - -#define PERCETTRONI_LAYER_4 1 -#define INPUT_LAYER_4 PERCETTRONI_LAYER_3 - -#define MAX_EPOCHE 10 - -//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 +#define PERCETTRONI_LAYER_0 256 +#define MAX_EPOCHE 10000 byte get_out_corretto(byte); void stampa_layer_indirizzo(Layer*); @@ -33,7 +19,7 @@ void main() { srand(time(NULL)); - Dataset *set_appoggio = get_dataset(file_immagini, file_label); + Dataset *set_appoggio = crea_dataset_xor();//get_dataset(file_immagini, file_label); if(set_appoggio == NULL) return; @@ -43,24 +29,14 @@ void main() { ReteNeurale rete_neurale; ReteNeurale *puntatore_rete = caricaReteNeurale(file_pesi); if(puntatore_rete == NULL) { - rete_neurale = inizializza_rete_neurale(NUM_LAYERS); - //inizializzo layer 0 - rete_neurale.layers[0] = inizializza_layer(PERCETTRONI_LAYER_0, INPUT_LAYER_0); - //inizializzo layer 1 - rete_neurale.layers[1] = inizializza_layer(PERCETTRONI_LAYER_1, INPUT_LAYER_1); - //inizializzo layer 2 - rete_neurale.layers[2] = inizializza_layer(PERCETTRONI_LAYER_2, INPUT_LAYER_2); - //inizializzo layer 3 - rete_neurale.layers[3] = inizializza_layer(PERCETTRONI_LAYER_3, INPUT_LAYER_3); - //inizializzo layer ULTIMO - rete_neurale.layers[4] = inizializza_layer(PERCETTRONI_LAYER_4, INPUT_LAYER_4); + rete_neurale = init_rete_neurale(NUM_LAYERS, PERCETTRONI_LAYER_0, N_INPUTS); } else { rete_neurale = *puntatore_rete; free(puntatore_rete); printf("Caricate impostazioni rete neurale da file\n"); } - printf("Numero immagini: %d\n", set.size); + printf("Numero elementi nel dataset: %d\n", set.size); //ADDESTRAMENTO for(int i = 0; i < MAX_EPOCHE; i++) { @@ -74,27 +50,32 @@ void main() { double **sigmoidi = (double **)malloc(sizeof(double*) * NUM_LAYERS); sigmoidi[0] = (double*)malloc(sizeof(double) * PERCETTRONI_LAYER_0); - sigmoidi[0] = funzioni_attivazione_layer_byte(rete_neurale.layers[0], set.istanze[indice_set].immagine); + sigmoidi[0] = funzioni_attivazione_layer_byte(rete_neurale.layers[0], set.istanze[indice_set].dati); for(int j = 1; j < NUM_LAYERS; 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); + byte output_corretto = get_out_corretto(set.istanze[indice_set].classificazione); + + printf("Inputs: %d %d\t", set.istanze[indice_set].dati[0], set.istanze[indice_set].dati[1]); + printf("Previsione: %d, out corretto: %d\n", previsione(sigmoidi[NUM_LAYERS-1][0]), output_corretto); //Se prevede male if(previsione(sigmoidi[NUM_LAYERS-1][0]) != output_corretto) { + double **gradienti = (double**)malloc(sizeof(double*) * NUM_LAYERS); for(int indice_layer = 0; indice_layer < NUM_LAYERS; indice_layer++) { gradienti[indice_layer] = (double*)malloc(sizeof(double) * rete_neurale.layers[indice_layer].size); } - gradienti[NUM_LAYERS-1][0] = (output_corretto - sigmoidi[NUM_LAYERS-1][0]); + //Errore + gradienti[NUM_LAYERS-1][0] = (output_corretto - sigmoidi[NUM_LAYERS-1][0]); correggi_layer_interni(&rete_neurale, gradienti, sigmoidi); - correggi_layer_input(&rete_neurale.layers[0], gradienti, sigmoidi, set.istanze[indice_set].immagine, NUM_LAYERS); + correggi_layer_input(&rete_neurale.layers[0], gradienti, sigmoidi, set.istanze[indice_set].dati, NUM_LAYERS); } else { @@ -103,17 +84,24 @@ void main() { } printf("\tRisposte corrette: %d\n", corrette); + + if(corrette == set.size) { + break; + } } - salvaReteNeurale(file_pesi, &rete_neurale); + //salvaReteNeurale(file_pesi, &rete_neurale); } //Questa funzione ritorna 1 se la categoria è quella che voglio individuare, altrimenti 0 byte get_out_corretto(byte categoria) { - if(categoria == CATEGORIA) - return 1; - else - return 0; + if(CATEGORIA != -1) { + if(categoria == CATEGORIA) + return 1; + else + return 0; + } + else return categoria; } void stampa_layer_indirizzo(Layer *layer) { diff --git a/mnist/mnist_manager.h b/mnist/mnist_manager.h index b967796..d2c0a7a 100644 --- a/mnist/mnist_manager.h +++ b/mnist/mnist_manager.h @@ -19,7 +19,7 @@ Byte 8 in poi: 60.000 byte, ognuno dei quali rappresenta l'etichetta di un'immag #include #include -#define N_PIXEL 784 // Immagine 28x28 +#define N_INPUTS 784 // Immagine 28x28 // 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; @@ -27,8 +27,8 @@ typedef unsigned char byte; // Singola istanza del dataset. typedef struct { - byte categoria; - byte immagine[N_PIXEL]; + byte classificazione; + byte dati[N_INPUTS]; } Istanza; // Questo tipo fornisce il vettore delle istanze e il size (dimensione) del vettore @@ -64,10 +64,10 @@ Dataset *get_dataset(char *path_mnist, char *path_categoria) int numero_righe = 0; //Leggo male il file, cambiare in base alle dichiarazioni sopra - if(fread(istanze[numero_righe].immagine, sizeof(byte), 16, file) == 16 && fread(&istanze[numero_righe].categoria, sizeof(byte), 8, categorie) == 8) - while (fread(istanze[numero_righe].immagine, sizeof(byte), N_PIXEL, file) == N_PIXEL) + if(fread(istanze[numero_righe].dati, sizeof(byte), 16, file) == 16 && fread(&istanze[numero_righe].classificazione, sizeof(byte), 8, categorie) == 8) + while (fread(istanze[numero_righe].dati, sizeof(byte), N_INPUTS, file) == N_INPUTS) { - if(fread(&istanze[numero_righe].categoria, sizeof(byte), 1, categorie) == 1) { + if(fread(&istanze[numero_righe].classificazione, sizeof(byte), 1, categorie) == 1) { numero_righe++; istanze = (Istanza *)realloc(istanze, sizeof(Istanza) * (numero_righe + 1)); } @@ -81,7 +81,7 @@ Dataset *get_dataset(char *path_mnist, char *path_categoria) return set; } -void salva_dataset(const char *filename, Dataset *set) +/* void salva_dataset(const char *filename, Dataset *set) { FILE *file = fopen(filename, "wb"); if (!file) @@ -92,12 +92,12 @@ void salva_dataset(const char *filename, Dataset *set) 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); + fwrite(&set->istanze[indice_istanze].classificazione, sizeof(byte), 1, file); + fwrite(&set->istanze[indice_istanze].dati, sizeof(byte), N_INPUTS, file); } fclose(file); -} +} */ /* void main() { Dataset *set = get_dataset("t10k-images.idx3-ubyte", "t10k-labels.idx1-ubyte"); @@ -108,6 +108,6 @@ void salva_dataset(const char *filename, Dataset *set) } for(int i = 0; i < set->size; i++) { - printf("immagine %d - valore rappresentato: %d\n", i, set->istanze[i].categoria); + printf("immagine %d - valore rappresentato: %d\n", i, set->istanze[i].classificazione); } } */ \ No newline at end of file diff --git a/percettroni.h b/percettroni.h index d7c3a14..9943596 100644 --- a/percettroni.h +++ b/percettroni.h @@ -32,7 +32,8 @@ typedef struct { double randomico(); Percettrone inzializza_percettrone(int); -ReteNeurale inizializza_rete_neurale(int); +//ReteNeurale inizializza_rete_neurale(int); +ReteNeurale init_rete_neurale(int, int, int); Layer inizializza_layer(int, int); double sigmoide_byte(Percettrone, byte*, int); @@ -69,14 +70,41 @@ Percettrone inizializza_percettrone(int n_pesi) { } //Questa funzione inizializza una rete neurale. Diamo il numero di layer desiderato e restituisce un ReteNeurale -ReteNeurale inizializza_rete_neurale(int n_layers) { +/* ReteNeurale inizializza_rete_neurale(int n_layers) { ReteNeurale r; r.layers = (Layer*)malloc(sizeof(Layer) * n_layers); r.size = n_layers; + return r; +} */ + +ReteNeurale init_rete_neurale(int numero_layers, int numero_percettroni_iniziali, int numero_input) { + ReteNeurale r; + r.layers = (Layer*)malloc(sizeof(Layer) * numero_layers); + r.size = numero_layers; + + //Funzione esponenziale inversa layer 5 + for (int livello = 0; livello < numero_layers; livello++) { + 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)); + if(livello == numero_layers -1) + numero_percettroni_livello = 1; + + //printf("esponente %f -> frazione: %f\n", esponente, frazione); + printf("Layer %d -> percettroni: %d\n", livello, numero_percettroni_livello); + + if(livello == 0) + r.layers[livello] = inizializza_layer(numero_percettroni_livello, numero_input); + else + r.layers[livello] = inizializza_layer(numero_percettroni_livello, r.layers[livello-1].size); + } + return r; } + //Questa funzione serve ad inizializzare il singolo layer con il numero di percettroni che vogliamo //Ogni percettrone a sua volta viene automaticamente inizializzato con il numero di pesi che vogliamo e coi valori di partenza Layer inizializza_layer(int n_percettroni, int n_pesi) { diff --git a/rete_pesi.bin b/rete_pesi.bin deleted file mode 100644 index 16f244c..0000000 Binary files a/rete_pesi.bin and /dev/null differ diff --git a/xor_manager.h b/xor_manager.h new file mode 100644 index 0000000..f525694 --- /dev/null +++ b/xor_manager.h @@ -0,0 +1,47 @@ +#include +#include + +#define N_INPUTS 2 + +// 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 +{ + byte classificazione; + byte dati[N_INPUTS]; +} Istanza; + +// Questo tipo fornisce il vettore delle istanze e il size (dimensione) del vettore +typedef struct +{ + int size; + Istanza *istanze; +} Dataset; + +Dataset *crea_dataset_xor(); + +Dataset *crea_dataset_xor() { + Dataset *set = (Dataset *)malloc(sizeof(Dataset)); + set->istanze = (Istanza *)malloc(sizeof(Istanza) * 4); + set->size = 4; + + set->istanze[0].dati[0] = 0; + set->istanze[0].dati[1] = 0; + set->istanze[0].classificazione = 1; + + set->istanze[1].dati[0] = 0; + set->istanze[1].dati[1] = 1; + set->istanze[1].classificazione = 0; + + set->istanze[2].dati[0] = 1; + set->istanze[2].dati[1] = 0; + set->istanze[2].classificazione = 0; + + set->istanze[3].dati[0] = 1; + set->istanze[3].dati[1] = 1; + set->istanze[3].classificazione = 1; + + return set; +} \ No newline at end of file