diff --git a/src/mnist/main.c b/src/mnist/main.c index 18f2d4a..fec441f 100644 --- a/src/mnist/main.c +++ b/src/mnist/main.c @@ -83,6 +83,7 @@ void train(int batches, int couches, int neurons, char* recovery, char* image_fi void recognize(char* modele, char* entree, char* sortie) { Reseau* reseau = lire_reseau(modele); + Couche* derniere_couche = reseau->couches[reseau->nb_couches-1]; int* parameters = read_mnist_images_parameters(entree); int nb_images = parameters[0]; @@ -102,14 +103,14 @@ void recognize(char* modele, char* entree, char* sortie) { ecrire_image_dans_reseau(images[i], reseau, height, width); forward_propagation(reseau); - for (int j=0; j < reseau->couches[reseau->nb_couches-1]->nb_neurones; j++) { + for (int j=0; j < derniere_couche->nb_neurones; j++) { if (! strcmp(sortie, "json")) { - printf("%f", reseau->couches[reseau->nb_couches-1]->neurones[j]->activation); - if (j+1 < reseau->couches[reseau->nb_couches-1]->nb_neurones) { + printf("%f", derniere_couche->neurones[j]->activation); // CHECK: ->activation ou ->z + if (j+1 < derniere_couche->nb_neurones) { printf(", "); } } else - printf("Probabilité %d: %f\n", j, reseau->couches[reseau->nb_couches-1]->neurones[j]->activation); + printf("Probabilité %d: %f\n", j, derniere_couche->neurones[j]->activation); // CHECK: ->activation ou ->z } if (! strcmp(sortie, "json")) { if (i+1 < nb_images) { diff --git a/src/mnist/neural_network.c b/src/mnist/neural_network.c index 61a39ee..bc6b831 100644 --- a/src/mnist/neural_network.c +++ b/src/mnist/neural_network.c @@ -28,20 +28,23 @@ float ReLU(float x){ void creation_du_reseau_neuronal(Reseau* reseau_neuronal, int* neurones_par_couche, int nb_couches) { /* Créé et alloue de la mémoire aux différentes variables dans le réseau neuronal*/ + Couche* couche; reseau_neuronal->nb_couches = nb_couches; - reseau_neuronal->couches = (Couche**)malloc(sizeof(Couche*)*nb_couches); // + reseau_neuronal->couches = (Couche**)malloc(sizeof(Couche*)*nb_couches); for (int i=0; i < nb_couches; i++) { + reseau_neuronal->couches[i] = (Couche*)malloc(sizeof(Couche)); + couche = reseau_neuronal->couches[i]; + couche->nb_neurones = neurones_par_couche[i]; // nombre de neurones pour la couche + couche->neurones = (Neurone**)malloc(sizeof(Neurone*)*reseau_neuronal->couches[i]->nb_neurones); // Création des différents neurones dans la couche - reseau_neuronal->couches[i] = (Couche*)malloc(sizeof(Couche)); // Utilité ? - reseau_neuronal->couches[i]->nb_neurones = neurones_par_couche[i]; // nombre de neurones pour la couche - reseau_neuronal->couches[i]->neurones = (Neurone**)malloc(sizeof(Neurone*)*reseau_neuronal->couches[i]->nb_neurones); // Création des différents neurones dans la couche - for (int j=0; j < reseau_neuronal->couches[i]->nb_neurones; j++) { - reseau_neuronal->couches[i]->neurones[j] = (Neurone*)malloc(sizeof(Neurone)); - if (i!=reseau_neuronal->nb_couches-1) { // On exclut la dernière couche dont les neurones ne contiennent pas de poids sortants - reseau_neuronal->couches[i]->neurones[j]->poids_sortants = (float*)malloc(sizeof(float)*neurones_par_couche[i+1]);// Création des poids sortants du neurone - reseau_neuronal->couches[i]->neurones[j]->d_poids_sortants = (float*)malloc(sizeof(float)*neurones_par_couche[i+1]); + for (int j=0; j < couche->nb_neurones; j++) { + couche->neurones[j] = (Neurone*)malloc(sizeof(Neurone)); + + if (i != reseau_neuronal->nb_couches-1) { // On exclut la dernière couche dont les neurones ne contiennent pas de poids sortants + couche->neurones[j]->poids_sortants = (float*)malloc(sizeof(float)*neurones_par_couche[i+1]);// Création des poids sortants du neurone + couche->neurones[j]->d_poids_sortants = (float*)malloc(sizeof(float)*neurones_par_couche[i+1]); } } } @@ -72,22 +75,27 @@ void suppression_du_reseau_neuronal(Reseau* reseau_neuronal) { void forward_propagation(Reseau* reseau_neuronal) { /* Effectue une propagation en avant du réseau neuronal lorsque les données on été insérées dans la première couche. Le résultat de la propagation se - trouve dans la dernière couche*/ + trouve dans la dernière couche */ + Couche* couche; // Couche actuelle + Couche* pre_couche; // Couche précédante - for (int i=1; inb_couches; i++) { // La première couche contient déjà des valeurs - for (int j=0; jcouches[i]->nb_neurones; j++) { - - reseau_neuronal->couches[i]->neurones[j]->z = reseau_neuronal->couches[i]->neurones[j]->biais; - for (int k=0; kcouches[i-1]->nb_neurones; k++) { - reseau_neuronal->couches[i]->neurones[j]->z += reseau_neuronal->couches[i-1]->neurones[k]->activation * reseau_neuronal->couches[i-1]->neurones[k]->z * reseau_neuronal->couches[i-1]->neurones[k]->poids_sortants[i]; // ??? + for (int i=1; i < reseau_neuronal->nb_couches; i++) { // La première couche contient déjà des valeurs + couche = reseau_neuronal->couches[i]; + pre_couche = reseau_neuronal->couches[i-1]; + + for (int j=0; j < couche->nb_neurones; j++) { + couche->neurones[j]->z = couche->neurones[j]->biais; + + for (int k=0; k < pre_couche->nb_neurones; k++) { + couche->neurones[j]->z += pre_couche->neurones[k]->activation * pre_couche->neurones[k]->z * pre_couche->neurones[k]->poids_sortants[i]; // CHECK: ->poids_sortants[k] plutôt que i } - if (inb_couches-1) { // Pour toutes les couches sauf la dernière on utilise la fonction ReLU (0 si z<0, z sinon) - reseau_neuronal->couches[i]->neurones[j]->z=ReLU(reseau_neuronal->couches[i]->neurones[j]->z); + if (i < reseau_neuronal->nb_couches-1) { // Pour toutes les couches sauf la dernière on utilise la fonction ReLU (0 si z<0, z sinon) + couche->neurones[j]->z=ReLU(couche->neurones[j]->z); } - else{ // Pour la dernière couche on utilise la fonction sigmoid permettant d'obtenir un résultat entre 0 et 1 à savoir une probabilité - reseau_neuronal->couches[i]->neurones[j]->z = sigmoid(reseau_neuronal->couches[i]->neurones[j]->z); + else { // Pour la dernière couche on utilise la fonction sigmoid permettant d'obtenir un résultat entre 0 et 1 à savoir une probabilité + couche->neurones[j]->z = sigmoid(couche->neurones[j]->z); } } } @@ -116,33 +124,43 @@ int* creation_de_la_sortie_voulue(Reseau* reseau_neuronal, int pos_nombre_voulu) void backward_propagation(Reseau* reseau_neuronal, int* sortie_voulue) { /* Effectue une propagation en arrière du réseau neuronal */ + Neurone* neurone; + Neurone* neurone2; // On commence par parcourir tous les neurones de la couche finale - for (int i=0; icouches[reseau_neuronal->nb_couches-1]->nb_neurones; i++) { + for (int i=0; i < reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->nb_neurones; i++) { // On calcule l'erreur de la sortie - reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]->d_z = (reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]->z - sortie_voulue[i])*(reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]->z - sortie_voulue[i]); + neurone = reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]; + + neurone->d_z = (neurone->z - sortie_voulue[i])*(neurone->z - sortie_voulue[i]); for(int k=0; kcouches[reseau_neuronal->nb_couches-2]->nb_neurones; k++) { // Pour chaque neurone de l'avant dernière couche - reseau_neuronal->couches[reseau_neuronal->nb_couches-2]->neurones[k]->d_poids_sortants[i] = (reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]->d_z * reseau_neuronal->couches[reseau_neuronal->nb_couches-2]->neurones[k]->activation); - reseau_neuronal->couches[reseau_neuronal->nb_couches-2]->neurones[k]->d_activation = reseau_neuronal->couches[reseau_neuronal->nb_couches-2]->neurones[k]->poids_sortants[i] * reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]->d_z; + neurone2 = reseau_neuronal->couches[reseau_neuronal->nb_couches-2]->neurones[k]; + + neurone2->d_poids_sortants[i] = (neurone->d_z * neurone2->activation); + neurone2->d_activation = neurone2->poids_sortants[i] * neurone->d_z; } // ??? - reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]->d_biais = reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[i]->d_z; + neurone->d_biais = neurone->d_z; } - for(int i=reseau_neuronal->nb_couches-2; i>0; i--) { // On remonte les couche de l'avant dernière jusqu'à la première + for(int i=reseau_neuronal->nb_couches-2; i > 0; i--) { // On remonte les couche de l'avant dernière jusqu'à la première for(int j=0; jcouches[i]->nb_neurones; j++) { - if(reseau_neuronal->couches[i]->neurones[j]->z >= 0) // ??? ... - reseau_neuronal->couches[i]->neurones[j]->d_z = reseau_neuronal->couches[i]->neurones[j]->d_activation; + neurone = reseau_neuronal->couches[i]->neurones[j]; + + if(neurone->z >= 0) // ??? ... + neurone->d_z = neurone->d_activation; else // ??? ... - reseau_neuronal->couches[i]->neurones[j]->d_z = 0; + neurone->d_z = 0; for(int k=0; kcouches[i-1]->nb_neurones; k++) { - reseau_neuronal->couches[i-1]->neurones[k]->d_poids_sortants[j] = reseau_neuronal->couches[i]->neurones[j]->d_z * reseau_neuronal->couches[i-1]->neurones[k]->activation; + neurone2 = reseau_neuronal->couches[i-1]->neurones[k]; + + neurone2->d_poids_sortants[j] = neurone->d_z * neurone2->activation; if(i>1) // ??? ... - reseau_neuronal->couches[i-1]->neurones[k]->d_activation = reseau_neuronal->couches[i-1]->neurones[k]->poids_sortants[j] * reseau_neuronal->couches[i]->neurones[j]->d_z; + neurone2->d_activation = neurone2->poids_sortants[j] * neurone->d_z; } - reseau_neuronal->couches[i]->neurones[j]->d_biais = reseau_neuronal->couches[i]->neurones[j]->d_z; // ??? ... + neurone->d_biais = neurone->d_z; // ??? ... } } @@ -154,11 +172,15 @@ void backward_propagation(Reseau* reseau_neuronal, int* sortie_voulue) { void modification_du_reseau_neuronal(Reseau* reseau_neuronal) { /* Modifie les poids et le biais des neurones du réseau neuronal à partir du nombre de couches et de la liste du nombre de neurone par couche */ + Neurone* neurone; + for (int i=0; i < reseau_neuronal->nb_couches-1; i++) { // on exclut la dernière couche for (int j=0; j < reseau_neuronal->couches[i]->nb_neurones; j++) { - reseau_neuronal->couches[i]->neurones[j]->biais = reseau_neuronal->couches[i]->neurones[j]->biais - (TAUX_APPRENTISSAGE * reseau_neuronal->couches[i]->neurones[j]->d_biais); // On modifie le biais du neurone à partir des données de la propagation en arrière + neurone = reseau_neuronal->couches[i]->neurones[j]; + neurone->biais = neurone->biais - (TAUX_APPRENTISSAGE * neurone->d_biais); // On modifie le biais du neurone à partir des données de la propagation en arrière + for (int k=0; k < reseau_neuronal->couches[i+1]->nb_neurones; k++) { - reseau_neuronal->couches[i]->neurones[j]->poids_sortants[k] = reseau_neuronal->couches[i]->neurones[j]->poids_sortants[k] - (TAUX_APPRENTISSAGE * reseau_neuronal->couches[i]->neurones[j]->d_poids_sortants[k]); // On modifie le poids du neurone à partir des données de la propagation en arrière + neurone->poids_sortants[k] = neurone->poids_sortants[k] - (TAUX_APPRENTISSAGE * neurone->d_poids_sortants[k]); // On modifie le poids du neurone à partir des données de la propagation en arrière } } } @@ -170,26 +192,36 @@ void modification_du_reseau_neuronal(Reseau* reseau_neuronal) { void initialisation_du_reseau_neuronal(Reseau* reseau_neuronal) { /* Initialise les variables du réseau neuronal (activation, biais, poids, ...) en suivant de la méthode de Xavier ...... à partir du nombre de couches et de la liste du nombre de neurone par couche */ + Neurone* neurone; + double borne_superieure; + double borne_inferieure; + srand(time(0)); - for (int i=0; inb_couches-1; i++) { // On exclut la dernière couche - for (int j=0; jcouches[i]->nb_neurones-1; j++) { + for (int i=0; i < reseau_neuronal->nb_couches-1; i++) { // On exclut la dernière couche + for (int j=0; j < reseau_neuronal->couches[i]->nb_neurones-1; j++) { + + neurone = reseau_neuronal->couches[i]->neurones[j]; // Initialisation des bornes supérieure et inférieure - double borne_superieure = 1/sqrt(reseau_neuronal->couches[i]->nb_neurones); - double borne_inferieure = - borne_superieure; - reseau_neuronal->couches[i]->neurones[j]->activation = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); - for (int k=0; kcouches[i+1]->nb_neurones-1; k++) { // Pour chaque neurone de la couche suivante auquel le neurone est relié - reseau_neuronal->couches[i]->neurones[j]->poids_sortants[k] = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); // Initialisation des poids sortants aléatoirement - reseau_neuronal->couches[i]->neurones[j]->d_poids_sortants[k] = 0.0; // ... ??? + borne_superieure = 1/sqrt(reseau_neuronal->couches[i]->nb_neurones); + borne_inferieure = - borne_superieure; + + neurone->activation = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); + + for (int k=0; k < reseau_neuronal->couches[i+1]->nb_neurones-1; k++) { // Pour chaque neurone de la couche suivante auquel le neurone est relié + neurone->poids_sortants[k] = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); // Initialisation des poids sortants aléatoirement + neurone->d_poids_sortants[k] = 0.0; // ... ??? } if (i > 0) {// Pour tous les neurones n'étant pas dans la première couche - reseau_neuronal->couches[i]->neurones[j]->biais = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); // On initialise le biais aléatoirement + neurone->biais = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); // On initialise le biais aléatoirement } } } - double borne_superieure = 1/sqrt(reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->nb_neurones); - double borne_inferieure = - borne_superieure; - for (int j=0; j < reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->nb_neurones; j++) {// Intialisation de la dernière couche exclut ci-dessus - reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[j]->activation = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); - reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[j]->biais = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); // On initialise le biais aléatoirement + borne_superieure = 1/sqrt(reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->nb_neurones); + borne_inferieure = - borne_superieure; + + for (int j=0; j < reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->nb_neurones; j++) {// Intialisation de la dernière couche exclue ci-dessus + neurone = reseau_neuronal->couches[reseau_neuronal->nb_couches-1]->neurones[j]; + neurone->activation = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); + neurone->biais = borne_inferieure + ((double)rand())/((double)RAND_MAX)*(borne_superieure - borne_inferieure); // On initialise le biais aléatoirement } }