From daa34cb8bc1687e2d62231b8623ef29fe0ca7508 Mon Sep 17 00:00:00 2001 From: mirimatcode Date: Sat, 22 Feb 2025 18:48:02 +0100 Subject: [PATCH] ottimizzato il codice, messo relu(ma non attivato), pronto per prossima sessione di test --- classificatore_singolo | Bin 21344 -> 21504 bytes classificatore_singolo.c | 53 ++++++++----------- classificatore_singolo_xor | Bin 21344 -> 0 bytes mnist/mnist_manager | Bin 15952 -> 0 bytes mnist/mnist_manager.h | 12 +++++ percettroni.h | 98 ++++++++++++++++++++++++------------ prova_passaggio_parametri.c | 40 +++++++++++++++ visualizzatore | Bin 22448 -> 26752 bytes visualizzatore.c | 55 +++++++++++--------- 9 files changed, 170 insertions(+), 88 deletions(-) delete mode 100755 classificatore_singolo_xor delete mode 100755 mnist/mnist_manager create mode 100644 prova_passaggio_parametri.c diff --git a/classificatore_singolo b/classificatore_singolo index 5b9c29a760678bacfd701652cabf82515dde2878..17c7706ed4224480030f1234fd0865b9eaaebaf2 100755 GIT binary patch delta 4988 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 eg0Y+kFcy&j delta 4271 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 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 d0b75e9cd3cff022791fc875bc19e73a4af62567..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21344 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 Of3@T|(;?ufivI?0|ECWC diff --git a/mnist/mnist_manager b/mnist/mnist_manager deleted file mode 100755 index 269d8bc9c40622b02bf540244acb0dc4d8d33d42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15952 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 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 9395e1eb87302ef57172f4727ef35397054da250..ba15974ffab9f4e8398ddc1aa000f5ae37017068 100755 GIT binary patch literal 26752 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 T+Gu13(|=vI;{_QC87TV?mQuA- literal 22448 zcmeHP4Rlo1oxc+ZrU;o}LBS6g`A|fN0Rcfu36KX5OC%z+*j9&0GD)UPX41(70}Glq z>he0oQrlYEYM1S*t9xpfs>_MC3kgyJJ*d&zZrWlUF|uz2ZK_d6n|Aj1zaMYjJm$ID zJ$rUf4>#w{|NTGj|NigCyZ64Ad%L!JMS;h|R2s%U%?R_ICn)8TQC1~y0Ls|{HX6SZ z*(GcQ@Zp>$_~inCD^g!UE-aGtVSuDJo^JBMiv^h}s5~S{dTwctS8x<$B?2eCLb{c> z6J9z&$SJ7!R(@rI&m6Fm8)ZyEyB@{n;l)Dl;mTaNLzcTi6-N3+;Uc|Gsn;p>6l5}< z3aWUL8M+ooyG~dR9;I^r%a~KIRq8omg_Kv2@}P9%Yw_B@Cci4Fw|lm*FDIPlxM zFX;GrTk^qWv)(TaEZfgpI`J>VMRq7Y8_SE9vo>D|(Wc|N5?95a{THn~fB&zB`tRL# z_uub0_bS|LxWIBvyTOq|K#t54$S5Cuq6>Y6i=9hA_vKg?$Ql9hrkNo4oJ8P1fWqWF^c|q(i^CMi=cAXo(Cc07+~h+4 zu?s!yV*j8E{R=Mi^IhnVy3ikS@#m*5@>^Wwx4X!%bD_7o(097fX&lQ}FXy_*KLhzO zYyvC40XIl$oPG!QMAs!I`gkuSLv?} z#)9>s=6Eo+u5x)e8VRloRELAi@2_u+M*Pk3KrHU}3(>rS!PX{L8*GlpqFemcp?G7U zi8Zyvn?kL@FsqA3;w&C)jYnJJ{+eJU9t-+|t*j;-48;8LsJ|u}j>cGX5KOv*FHP|V zj@Q?<`WvIQLAEKlg~ec=`9l#n6At@v1?yu`|K?zuySz@{K< zL8T^M7Yc`2W3;6?=&zQrRl+SyS>t@x+z`DL`9YMSB*A!1gTFc)iZhj0uoVb$2*hDa z6jB+0gVoVMtd>gM%$kC+7>eYlz}0MmZ=3vefe<1A-CD$>2|mUGkySOK1Oxv~X#stRuIZxVfmo|!&e#y9T8<8BxmE}!3&;|G!tHhY5e3z-*u z(is~Hji#sSg%WSMFoZ{Q0h=oI)%;BLw~|ki6~^|;`In-1sm|=^Z%pFj9rO~KBp~@5 z^of!_-9cX@>78qY9zE0L6q6IWY;+XJN=IyTJ~5D-UK^d_pi-ZWK1LA%lQ#Mk8@*im zNxsnBLM1gG5&d#S1XSY@(Wl$!YJ4F&%}rF=XtRHXA_69D^cglfs}jgL0H}5=71`*r zYB{gOMwe4vP9JZht1*=rJ{z6tK&9z6I_0gBS|1TjwH4wmu*s{rAkoWh^pQl6Nw?9@ zRYbrl8-0|GzQIN>w$V4*=&H#QyTL}6O`K~r+2}OyRH@ZQAE$_bZ8rM(Hu?@5{Q?_( zmyJH&M&E6t%Ox1+?y=D?w8=kgqhDmB@3qm@nvvL@Hag8YRqC?QCn_S~5gUDyjoxdc z`)u?+8~sunJ!zv)w$V)+eX5N;nb~CO&tFk;nc-a8#(?}!l`SesyM!taOzU2 za*oFcr>>ML>UT%kde6Qx{9^;rL|2scWTnar{EUsY|8WIDQ`C)Rj_A z93M$Ib)nQoju#M4T_;t=@ee)?oVrY^oa1j1PF*Ec#_`t)r!JE6ar^|~)HPBi9RDrh z6A5R)seR0TW0mpzExK_+Z|@(dTBptKntfF7SiBNJ$c+2`V#WsRO1+crfC?H=$Kv0> zfZkE~0)d6;_&7AJTOdSD>l2xzcTyY4JuM;RAK~)zen{Yozv#w*-u>nhy*oWj_Z-%r z|4V!<3`~;-iZaPM@1%;XKKa+ScmiU;TCQHNw=XV$B-4%8;-mG%;)$@C88`4L#>^Vj z-QmIk5Ii?Oo%Q$Wy6io*Z?c!FhwOUTFrP&PjDvd3FLdLG-kqGNdjL#dclwg<4<=o4 zu+IC3uD8514&MAUN#BTmr0d4^PNU_Cg!Y8K8ydrOqsP?$oXO~h*4v{UqoSXht|zqK z#QI};%?o<>iD7!j#U-7@Fn1u|I^BC)mu?Je*N%A-+Ob926We+P_e)u>)`tuXEvY9e zJIR=ySl_1`9^JSB9T{X}X$c@$H>Zzs-{6|h*nT>po#t*0C%1kw#N8SI(a_S6AAlJt zPi1K^w*Sm%>8#Zg!>7?B97Ql^cO|r+={3E&(W`s9bWg7;W34b|m2o9p>xKVk$aY-p z(L1zViS?bvugQyp2r=^Bg}is8*t&5e6=9EVEHAM_@Uv|{LAHk02aYIfqSCC@uN=kw ziWiy>QSSD_mZKhy7%hiH4UN%~JsPdd*{Kx??Kt_A(2l@+?>^?;*9D=YsKz58mL%4L zEvm)S`ti;Ic$?i=G)%eMqi3fR_Fa( zH?L9rM7qp3Kd>rT8z43MDJ+5@tRJEKA@tO@ytnY2(qt-Ifv#m*PG#DycZ~fx6;T!q zx)jKdS)hNTEZquJ1>YP6x+HIbuHl6c1-jCuK-9t(=tf#Mx_`>uHs02aN;IsS(UR96 zNuaW=4s;H3q1M-<^^<7oYrL4$zWUE-U!EfsiSiQB`toqQNyi>56Wy;sPi#K|e~NI8 z*Nu~U!lNh9m5dR(@mWL>y~$WnQehl6@29TZe#n>YrTu6NeG9dI?@sEUh`5<;h##kn zQ{MmoQpS#tRYvL()KEtsTtF=s4YtmERd?*1PMQ*&D&#|#7$4CkP2FfoqI#(#n~CzG zcGF{MgQ<5R+oPp<-5%!mL;U^~Ue6R!mRLV1`sHvMbP`1gj9AWL2!k^T4&`)UR3Fbu zwx*6M8tIbU2)SE=t1xp7xqcJc(_oHRpAf^Sm}8P;50cscfnR(qVeQ%wTH41jgr>bv z8}jZvDMrnY?g5Ia7m4y^#|aq*XZd(cPR-{r`FQ1&VZ>U^P=_U^n8{qbZp~BFP^=Q03^k{>;SuC?Pm%UaK;iYqF61nvU$zwV7>}U=H z*v1gefwwVw=GYz;U3gUBQZ3*kXRB&F8yKof#A2~EZn)Tzb@!n@e@gf)tIO38cY>;C zkXH|{jzRCvAKNRS{d5_+Dn{WJdQA4|9pkRTbX6CR>z#vQn9|#~o2+F5=6T~dv&X#W zolNEcYKEB$NQR=;(aL)thWMw5v7cuB=CzRP(UQ1jso&s-OH#j0+B&#FlM!5bEu>*z zJqp@|1xOd=e;VMqK|MYVQzd{Hf$YvaDqKy|BZJQhAPbKw&Hc2(p!rEcN}S;e37C!G zwrl+q%mE%uJO>(4pY2+bXuX`4^zOVs)iEqifX*&!TE?I15Iur8n^-o;I8S|>$2o~O zCql?SBs5bOwP8f19@L`;*pfvBMTY$GL~A%2~k z6>Z88(L;3Z?BeylOy=-CD~E6Ke%S|ySc+DJJU6P@KG&Lcc(I={6rnt0bVuYef23lP zKLa}V2i0!*^BC4(RAD16e};2^j&pww;g{=CJK;0HoEa=09l7nq;n+0c7;h)mw4}*$ z2eTLo4{tmO&-v&UQ=~h82Tfi9r&>wE+0c?!Lpw;;L_?)slXZYMv#7s=-386bSVoIpfqP@Ye~#wL%rk=4*?$a z9j&~~)LNm+_CuPP_mbWAbcy%Qqd@bi89gw7YUzH8!Y8yg3aujVo!! zbfM>IxlB&|+q*n?e%SmJV`G~rZ8D!-dofTtVfZ-&L0?<~+ zL{*WPA%wbk4Iuj2FlNKCML2?na;Cf}CXYK6OB7Rwf_&m66KtV2xNR5mgHVq-8m#PC zD3`%$L|#vfGfD{*ZY3ZBJdZD=3#+c;j8z2C+s2}|EtbW*|BXy0wU6r;F64?m<~RB3 zq3}GRb*@e8a;a5MT5ZrWU!uSz#=QyE#K`Zy_r9@yD4`9((f7bTHHWu#^AKWTJ}x8= zogsN6%6)+LpUiTIc=r{~g~%OU@uyLi&A6pvk3fb%qY{1ZbS7iQKofOq_Tcu(VZ(=G z8)e)Vur;O|hY!FYGw%k&oIpSQP&wcu+6doT5fIfIQi$&8qd)z|^+9rVgU*Z#r@@S|tYP-QIl_1s<%| zF;Zj7ny5^p5gE_Ip=;o%p$);zB`}ky97?PoNVE)68CIkC)b=pZyy&*?v}*&n8@TAU zJ9cGTo$sj(+}Te*2k6H%p=01FQ`j>T1?9UG-v$YjmIYvA=0Tv7!g-~ZG!AyZKFQPj zd>R93C&l?nt>2=xn_~^cCNXb2EWzMy0EzYeYcbiubsCqscIlH;1xq{WSJWVGc>I$H z7A-aruzNv5xTXWhj0dbt5DrX`FGki+9RYto{T!ela}pJ#2P+~3u%csl0Yyz4=onQ1 zS5D#W3vpV~OO5v_QZKxo$vg!uwx51Pd;2{+FtB7E>S!Ga&1{yan6w8Wnl}n&VC{Ya zSU`U%v(z}c)JPl8qv@WHU01T)3Ck!4o{;mNnZd;)5O1JhHBc0n@?zWDFnK_lKTZkF zY-N=h+m9y-FN1!2(t{nvEs4T!z$Sv9C~W07r$2JIFl;W;(%a^Xuy}eGYUb@%pxG|c zhPGWQqDI8iw~xh$4sYJZE|Ums9ZDp9qBZ_>IE5hWMgExZ$)yDp){y&f4ZLshg6Fc! zIGd(3n3WQA(vWA!J!qYBT!!W)DM%yf0i#dr?Gg836Z46TQO0yIn-q*Fhj z;3Wzt%N*BZ7lbynXyI&mhek-$j#0njp+-BzHpmzX`S(rod6?KHp$$y2VmA3wn4J8@ z6=WX03>J>+-LJsz5s7rneMXq8By+{No}MC4XDDv>vo zBDJBK;I+PKwKIL21NdN(-TKlkqdxQ+-zX#WIkSPPS zWHx1ObbAfmHyO%@zRkWFb&rKW)=n_%Cw;SA5B_BoR~4^emllu&>Hi4)MzoQy z0A~5yJc@q|^k@Gwlc9XF{CbOj8uSaX#tG-xuea=v0=*7x?b#gtqn7?m@W*0l{{qZg z_6wfj1t9-cgMS$OkvaN>mOkaX7j2k!`?C6XTlzb}pMqt=Z*urATKpe@e;j=J2Hnyh z_ONCD82BOdg>U8Pf1T_5KsycoOW;3b*GD}LyN{b-BtyGoe)OM9aBtzj`M$iBiidv58R(%HT_Wpn10&7MQ=1V1EEGaJtSNbeWVNcrf(%`r^< zf4owfh8qvN!0HEzzKGMuF=su$gp7S?)#)lFDPRSFGZe(3aO9)cf}ZdHQa4HZfQ+N+ zSG3+IdA1e;NQ(Xn{5g*mTjxvgwLbVsbntxnei^)c^fu7Ppj<_ceD46=hs&904Vcf) z11|K>b3dI{7<=4BzMJR;UZ%!VrP;&fi`kT^g2LCDxcv`K7c~3t>n`*m(5bx6|1TUN zmt9&g--iZ zWJmp9plT0WK=;`*l=t7}c8b{(mkPoQlKxMikD*nu?2l+>JUvG81;vcX=b2h7KPl}j z#tS}5d@T;x4Z4pAj`TawOY-y=Q`+g3aeh(i(N}d;FV6qt^x(lT*|i{Q>y^eO}U|l0GEcA>Y#guieG|H>7-reDL!td> zD(^<==k0>bZg8<5k#=64E(H1h5N>Y=y##j39dS-@`{P-OBM#qpvA<8+ze!G%`lUa8 zF7mHQ`FdF{zGn!XAxVE###44nHVzd^JHK?H|Blm(SquGV zAX2{o>`#(@*JMH9d!clT3HW&hnEYa>w5Jh7w-eO;=1_ABog%O`5XU=<(i$8SfLV@T z)BP*fF0Iu3dc|7iU%7hCvZbs2YgVkdQCsIOkzvUF$+1_S;tQBlP^B(e2wNncyqwY-oI)M&VHy3Mf^B|qL#@69GYTq zt2Xo@hi~|~1#xTyYYrjCp<0|!L9g)WO&kh}mv_=#b(BPo!_KoexR&*@jUO6;qc-?) z67~S%m0wLTjx#?HB`e$7XbYVjQX6Ux)<*(3uLEa_)CFp4LIKCo88y)ujuNR4iF$w_ zngg6%SGnA;U0;FIM$SAkL`1$dd$b5j-W>He;3y4bS=~}shYE#7@7^;c> zcPEGNqd9VeLUpqiZ%eNa;=Ly9Q$>X6un}<{iSyWv9A#=%{J0Y;B-#-QR^8mJswi3? z4h8%wWZ>nV6JlAK%jApDkUtQQhc=5>r!rtN&^afSoDow5ADzZtY5e_fL>5T|w3_*Y zIE+LbE@EX)9h#rHBD$PC65`;I97)G%F7jZL91(FUN)Cw*LCGQbgVYygsCn2NC!$!= zIG{uw^YS4<67RA3Nh;JX>_@z?(&jCV@jx|TJSJd+y5p_3iIqm8@nC6vq@@(^bLj>5 z7D-yVY}KrIpx!1>-4eo4Vxd~b#Tx?64Xm_wO9WX67>@~#Jg+7P@q-r&h6AJ^@0!AK zR?0mtrEb7V`QTR?i}LW41{?f!u|Q+c-%tx(g$WIRAQlV2QPNQNFdRTHK(0~P!cQsB zKo~>AWTiFH#zqW&>S6KML)uru6q3KnB`f1Gf3QQfuOz6sXL}HB3NG5qk&pW`&buoI z&z{u$RMGHXZ8`eR^X_~~P(nOjb5aE`d;Ytn{|ZjckrwB;*-4)R@-FschKOuWY$}K(p-)2ck>afM)xH*e96>HCeYHQQpxTdv2v20gp1ur(_P&(9 z+V4_ugA`W&D>(&k1E2QN6t4Eu6x=BFRg9JYlFT}ALq$~j)_$Jc*Him>Du1P~%Ksgy zzf2lb`-2Lq{Y28Isj*Z4A3>v-DErp@O3t&?z9~d_Qq`kyTBq6deNs_#euaW+Us%aI{eN8QtN5#RxPrSK4aS-OPaXPde@j8N zu6E1+s6)SLj*wJPm;F)ctNK&;FL8ri0^SFRruMtl`H)U|g)8_nbi6iwwI9BBFygeuv?mA3{tHS;>(BrI 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) {