2022-03-24 13:42:03 +01:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>
# include <time.h>
2022-04-01 15:41:54 +02:00
# include "struct/neuron.h"
2022-03-24 13:42:03 +01:00
2022-03-25 19:19:27 +01:00
# define TAUX_APPRENTISSAGE 0.15 // Définit le taux d'apprentissage du réseau neuronal, donc la rapidité d'adaptation du modèle (compris entre 0 et 1)
2022-03-24 13:42:03 +01:00
2022-04-05 09:08:39 +02:00
float max ( float a , float b ) {
return a < b ? b : a ;
}
float sigmoid ( float x ) {
return 1 / ( 1 + exp ( x ) ) ;
}
float sigmoid_derivee ( float x ) {
float tmp = exp ( - x ) ;
return tmp / ( ( 1 + tmp ) * ( 1 + tmp ) ) ;
}
float ReLU ( float x ) {
return max ( x , 0 ) ;
}
2022-03-24 13:42:03 +01:00
2022-04-01 15:18:48 +02:00
void creation_du_reseau_neuronal ( Reseau * reseau_neuronal , int * neurones_par_couche , int nb_couches ) {
2022-04-05 09:08:39 +02:00
/* Créé et alloue de la mémoire aux différentes variables dans le réseau neuronal*/
2022-04-10 12:32:06 +02:00
Couche * couche ;
2022-04-05 09:08:39 +02:00
2022-03-28 13:53:16 +02:00
reseau_neuronal - > nb_couches = nb_couches ;
2022-04-10 12:32:06 +02:00
reseau_neuronal - > couches = ( Couche * * ) malloc ( sizeof ( Couche * ) * nb_couches ) ;
2022-04-01 15:18:48 +02:00
for ( int i = 0 ; i < nb_couches ; i + + ) {
2022-04-10 12:32:06 +02:00
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
2022-04-01 15:18:48 +02:00
2022-04-10 12:32:06 +02:00
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 ] ) ;
2022-04-01 15:18:48 +02:00
}
2022-03-24 13:42:03 +01:00
}
}
}
2022-04-01 15:18:48 +02:00
void suppression_du_reseau_neuronal ( Reseau * reseau_neuronal ) {
2022-03-24 13:42:03 +01:00
/* Libère l'espace mémoire alloué aux différentes variables dans la fonction
2022-04-05 09:08:39 +02:00
' creation_du_reseau_neuronal ' */
2022-03-24 13:42:03 +01:00
2022-03-28 13:29:29 +02:00
for ( int i = 0 ; i < reseau_neuronal - > nb_couches ; i + + ) {
if ( i ! = reseau_neuronal - > nb_couches - 1 ) { // On exclut la dernière couche dont les neurones ne contiennent pas de poids sortants
2022-03-28 13:53:16 +02:00
for ( int j = 0 ; j < reseau_neuronal - > couches [ i ] - > nb_neurones ; j + + ) {
2022-04-05 09:08:39 +02:00
free ( reseau_neuronal - > couches [ i ] - > neurones [ j ] - > poids_sortants ) ;
free ( reseau_neuronal - > couches [ i ] - > neurones [ j ] - > d_poids_sortants ) ;
2022-03-24 13:42:03 +01:00
}
}
2022-03-28 13:29:29 +02:00
free ( reseau_neuronal - > couches [ i ] - > neurones ) ; // On libère enfin la liste des neurones de la couche
2022-03-24 13:42:03 +01:00
}
free ( reseau_neuronal ) ; // Pour finir, on libère le réseau neronal contenant la liste des couches
}
2022-04-01 15:18:48 +02:00
void forward_propagation ( Reseau * reseau_neuronal ) {
2022-04-05 09:08:39 +02:00
/* 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
2022-04-10 12:32:06 +02:00
trouve dans la dernière couche */
Couche * couche ; // Couche actuelle
Couche * pre_couche ; // Couche précédante
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 + + ) {
2022-04-12 14:05:19 +02:00
couche - > neurones [ j ] - > z + = pre_couche - > neurones [ k ] - > z * pre_couche - > neurones [ k ] - > poids_sortants [ i ] ; // CHECK: ->poids_sortants[k] plutôt que i
2022-03-24 13:42:03 +01:00
}
2022-04-10 12:32:06 +02:00
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)
2022-04-12 14:05:19 +02:00
couche - > neurones [ j ] - > z = ReLU ( couche - > neurones [ j ] - > z ) ;
2022-03-24 13:42:03 +01:00
}
2022-04-10 12:32:06 +02:00
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 ) ;
2022-03-24 13:42:03 +01:00
}
}
}
}
2022-04-01 15:18:48 +02:00
int * creation_de_la_sortie_voulue ( Reseau * reseau_neuronal , int pos_nombre_voulu ) {
2022-03-25 14:26:46 +01:00
/* Renvoie la liste des sorties voulues à partir du nombre
de couches , de la liste du nombre de neurones par couche et de la
2022-03-24 13:42:03 +01:00
position du résultat voulue , */
2022-04-08 15:53:29 +02:00
int nb_neurones = reseau_neuronal - > couches [ reseau_neuronal - > nb_couches - 1 ] - > nb_neurones ;
2022-03-24 13:42:03 +01:00
2022-04-08 15:53:29 +02:00
int * sortie_voulue = ( int * ) malloc ( sizeof ( int ) * nb_neurones ) ;
for ( int i = 0 ; i < nb_neurones ; i + + ) // On initialise toutes les sorties à 0 par défault
sortie_voulue [ i ] = 0 ;
sortie_voulue [ pos_nombre_voulu ] = 1 ; // Seule la sortie voulue vaut 1
2022-03-24 13:42:03 +01:00
return sortie_voulue ;
}
2022-04-01 15:18:48 +02:00
void backward_propagation ( Reseau * reseau_neuronal , int * sortie_voulue ) {
2022-04-05 09:08:39 +02:00
/* Effectue une propagation en arrière du réseau neuronal */
2022-04-10 12:32:06 +02:00
Neurone * neurone ;
Neurone * neurone2 ;
2022-03-24 13:42:03 +01:00
// On commence par parcourir tous les neurones de la couche finale
2022-04-10 12:32:06 +02:00
for ( int i = 0 ; i < reseau_neuronal - > couches [ reseau_neuronal - > nb_couches - 1 ] - > nb_neurones ; i + + ) {
2022-04-05 09:08:39 +02:00
// On calcule l'erreur de la sortie
2022-04-10 12:32:06 +02:00
neurone = reseau_neuronal - > couches [ reseau_neuronal - > nb_couches - 1 ] - > neurones [ i ] ;
neurone - > d_z = ( neurone - > z - sortie_voulue [ i ] ) * ( neurone - > z - sortie_voulue [ i ] ) ;
2022-03-24 13:42:03 +01:00
2022-03-28 13:53:16 +02:00
for ( int k = 0 ; k < reseau_neuronal - > couches [ reseau_neuronal - > nb_couches - 2 ] - > nb_neurones ; k + + ) { // Pour chaque neurone de l'avant dernière couche
2022-04-10 12:32:06 +02:00
neurone2 = reseau_neuronal - > couches [ reseau_neuronal - > nb_couches - 2 ] - > neurones [ k ] ;
2022-04-12 14:05:19 +02:00
neurone2 - > d_poids_sortants [ i ] = neurone - > d_z ;
2022-04-10 12:32:06 +02:00
neurone2 - > d_activation = neurone2 - > poids_sortants [ i ] * neurone - > d_z ;
2022-03-24 13:42:03 +01:00
}
// ???
2022-04-10 12:32:06 +02:00
neurone - > d_biais = neurone - > d_z ;
2022-03-24 13:42:03 +01:00
}
2022-04-10 12:32:06 +02:00
for ( int i = reseau_neuronal - > nb_couches - 2 ; i > 0 ; i - - ) { // On remonte les couche de l'avant dernière jusqu'à la première
2022-03-28 13:53:16 +02:00
for ( int j = 0 ; j < reseau_neuronal - > couches [ i ] - > nb_neurones ; j + + ) {
2022-04-10 12:32:06 +02:00
neurone = reseau_neuronal - > couches [ i ] - > neurones [ j ] ;
if ( neurone - > z > = 0 ) // ??? ...
neurone - > d_z = neurone - > d_activation ;
2022-03-24 13:42:03 +01:00
else // ??? ...
2022-04-10 12:32:06 +02:00
neurone - > d_z = 0 ;
2022-03-24 13:42:03 +01:00
2022-03-28 13:53:16 +02:00
for ( int k = 0 ; k < reseau_neuronal - > couches [ i - 1 ] - > nb_neurones ; k + + ) {
2022-04-10 12:32:06 +02:00
neurone2 = reseau_neuronal - > couches [ i - 1 ] - > neurones [ k ] ;
2022-04-12 14:05:19 +02:00
neurone2 - > d_poids_sortants [ j ] = neurone - > d_z ;
2022-03-24 13:42:03 +01:00
if ( i > 1 ) // ??? ...
2022-04-10 12:32:06 +02:00
neurone2 - > d_activation = neurone2 - > poids_sortants [ j ] * neurone - > d_z ;
2022-03-24 13:42:03 +01:00
}
2022-04-10 12:32:06 +02:00
neurone - > d_biais = neurone - > d_z ; // ??? ...
2022-03-24 13:42:03 +01:00
}
}
}
2022-04-01 15:18:48 +02:00
void modification_du_reseau_neuronal ( Reseau * reseau_neuronal ) {
2022-03-24 13:42:03 +01:00
/* 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 */
2022-04-10 12:32:06 +02:00
Neurone * neurone ;
2022-04-08 19:34:26 +02:00
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 + + ) {
2022-04-10 12:32:06 +02:00
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
2022-04-08 19:34:26 +02:00
for ( int k = 0 ; k < reseau_neuronal - > couches [ i + 1 ] - > nb_neurones ; k + + ) {
2022-04-10 12:32:06 +02:00
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
2022-03-24 13:42:03 +01:00
}
}
}
}
2022-04-01 15:18:48 +02:00
void initialisation_du_reseau_neuronal ( Reseau * reseau_neuronal ) {
2022-03-24 13:42:03 +01:00
/* 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 */
2022-04-10 12:32:06 +02:00
Neurone * neurone ;
double borne_superieure ;
double borne_inferieure ;
2022-03-24 13:42:03 +01:00
srand ( time ( 0 ) ) ;
2022-04-10 12:32:06 +02:00
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 ] ;
2022-03-25 14:26:46 +01:00
// Initialisation des bornes supérieure et inférieure
2022-04-10 12:32:06 +02:00
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 ; // ... ???
2022-03-24 13:42:03 +01:00
}
2022-04-01 15:18:48 +02:00
if ( i > 0 ) { // Pour tous les neurones n'étant pas dans la première couche
2022-04-10 12:32:06 +02:00
neurone - > biais = borne_inferieure + ( ( double ) rand ( ) ) / ( ( double ) RAND_MAX ) * ( borne_superieure - borne_inferieure ) ; // On initialise le biais aléatoirement
2022-04-01 15:18:48 +02:00
}
2022-03-24 13:42:03 +01:00
}
}
2022-04-10 12:32:06 +02:00
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
2022-04-01 15:18:48 +02:00
}
2022-03-25 14:26:46 +01:00
}