2022-03-24 13:42:03 +01:00
# include <stdio.h>
# include <stdlib.h>
2022-04-22 14:22:45 +02:00
# include <stdbool.h>
# include <stdint.h>
2022-03-24 13:42:03 +01:00
# include <string.h>
# include <math.h>
# include <time.h>
2022-04-26 11:39:29 +02:00
# include "include/neuron.h"
2022-03-24 13:42:03 +01:00
2022-04-18 17:49:50 +02:00
// Définit le taux d'apprentissage du réseau neuronal, donc la rapidité d'adaptation du modèle (compris entre 0 et 1)
2022-04-25 14:39:45 +02:00
// Cette valeur peut évoluer au fur et à mesure des époques (linéaire c'est mieux)
# define LEARNING_RATE 0.5
2022-04-18 17:49:50 +02:00
//Retourne un nombre aléatoire entre 0 et 1
2022-04-16 17:02:57 +02:00
# define RAND_DOUBLE() ((double)rand()) / ((double)RAND_MAX)
2022-04-18 17:49:50 +02:00
//Coefficient leaking ReLU
# define COEFF_LEAKY_RELU 0.2
2022-04-22 14:22:45 +02:00
# define MAX_RESEAU 100000
2022-04-25 10:09:47 +02:00
# define INT_MIN -2147483648
2022-04-22 14:22:45 +02:00
# define PRINT_POIDS false
# define PRINT_BIAIS false
2022-03-24 13:42:03 +01:00
2022-04-05 09:08:39 +02:00
float max ( float a , float b ) {
2022-04-21 12:09:35 +02:00
return a < b ? b : a ;
2022-04-05 09:08:39 +02:00
}
float sigmoid ( float x ) {
2022-04-22 14:22:45 +02:00
return 1 / ( 1 + exp ( - x ) ) ;
2022-04-05 09:08:39 +02:00
}
2022-04-25 14:39:45 +02:00
float sigmoid_derivative ( float x ) {
2022-04-21 12:09:35 +02:00
float tmp = exp ( - x ) ;
return tmp / ( ( 1 + tmp ) * ( 1 + tmp ) ) ;
2022-04-05 09:08:39 +02:00
}
2022-04-18 17:49:50 +02:00
float leaky_ReLU ( float x ) {
2022-04-22 14:22:45 +02:00
if ( x > 0 )
2022-04-18 17:49:50 +02:00
return x ;
2022-04-22 14:22:45 +02:00
return COEFF_LEAKY_RELU ;
2022-04-18 17:49:50 +02:00
}
2022-04-25 14:39:45 +02:00
float leaky_ReLU_derivative ( float x ) {
2022-04-22 14:22:45 +02:00
if ( x > 0 )
2022-04-18 17:49:50 +02:00
return 1 ;
return COEFF_LEAKY_RELU ;
2022-04-05 09:08:39 +02:00
}
2022-03-24 13:42:03 +01:00
2022-04-25 14:39:45 +02:00
void network_creation ( Network * network , int * neurons_per_layer , int nb_layers ) {
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-25 14:39:45 +02:00
Layer * layer ;
2022-04-05 09:08:39 +02:00
2022-04-25 14:39:45 +02:00
network - > nb_layers = nb_layers ;
network - > layers = ( Layer * * ) malloc ( sizeof ( Layer * ) * nb_layers ) ;
2022-04-01 15:18:48 +02:00
2022-04-25 14:39:45 +02:00
for ( int i = 0 ; i < nb_layers ; i + + ) {
network - > layers [ i ] = ( Layer * ) malloc ( sizeof ( Layer ) ) ;
layer = network - > layers [ i ] ;
layer - > nb_neurons = neurons_per_layer [ i ] ; // Nombre de neurones pour la layer
layer - > neurons = ( Neuron * * ) malloc ( sizeof ( Neuron * ) * network - > layers [ i ] - > nb_neurons ) ; // Création des différents neurones dans la couche
2022-04-01 15:18:48 +02:00
2022-04-25 14:39:45 +02:00
for ( int j = 0 ; j < layer - > nb_neurons ; j + + ) {
layer - > neurons [ j ] = ( Neuron * ) malloc ( sizeof ( Neuron ) ) ;
2022-04-10 12:32:06 +02:00
2022-04-25 14:39:45 +02:00
if ( i ! = network - > nb_layers - 1 ) { // On exclut la dernière couche dont les neurones ne contiennent pas de poids sortants
layer - > neurons [ j ] - > weights = ( float * ) malloc ( sizeof ( float ) * neurons_per_layer [ i + 1 ] ) ; // Création des poids sortants du neurone
layer - > neurons [ j ] - > back_weights = ( float * ) malloc ( sizeof ( float ) * neurons_per_layer [ i + 1 ] ) ;
layer - > neurons [ j ] - > last_back_weights = ( float * ) malloc ( sizeof ( float ) * neurons_per_layer [ i + 1 ] ) ;
2022-04-01 15:18:48 +02:00
}
2022-03-24 13:42:03 +01:00
}
}
}
2022-04-25 14:39:45 +02:00
void deletion_of_network ( Network * network ) {
2022-03-24 13:42:03 +01:00
/* Libère l'espace mémoire alloué aux différentes variables dans la fonction
2022-04-25 14:39:45 +02:00
' creation_du_network ' */
Layer * layer ;
Neuron * neuron ;
for ( int i = 0 ; i < network - > nb_layers ; i + + ) {
layer = network - > layers [ i ] ;
if ( i ! = network - > nb_layers - 1 ) { // On exclut la dernière couche dont les neurons ne contiennent pas de poids sortants
for ( int j = 0 ; j < network - > layers [ i ] - > nb_neurons ; j + + ) {
neuron = layer - > neurons [ j ] ;
free ( neuron - > weights ) ;
free ( neuron - > back_weights ) ;
2022-03-24 13:42:03 +01:00
}
}
2022-04-25 14:39:45 +02:00
free ( layer - > neurons ) ; // On libère enfin la liste des neurones de la couche
2022-03-24 13:42:03 +01:00
}
2022-04-25 14:39:45 +02:00
free ( network ) ; // Pour finir, on libère le réseau neuronal contenant la liste des couches
2022-03-24 13:42:03 +01:00
}
2022-04-25 14:39:45 +02:00
void forward_propagation ( Network * network ) {
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 */
2022-04-25 14:39:45 +02:00
Layer * layer ; // Couche actuelle
Layer * pre_layer ; // Couche précédente
Neuron * neuron ;
2022-04-25 10:09:47 +02:00
float sum ;
float max_z ;
2022-04-10 12:32:06 +02:00
2022-04-25 14:39:45 +02:00
for ( int i = 1 ; i < network - > nb_layers ; i + + ) { // La première couche contient déjà des valeurs
2022-04-25 10:09:47 +02:00
sum = 0 ;
max_z = INT_MIN ;
2022-04-25 14:39:45 +02:00
layer = network - > layers [ i ] ;
pre_layer = network - > layers [ i - 1 ] ;
2022-04-10 12:32:06 +02:00
2022-04-25 14:39:45 +02:00
for ( int j = 0 ; j < layer - > nb_neurons ; j + + ) {
neuron = layer - > neurons [ j ] ;
neuron - > z = neuron - > bias ;
2022-04-10 12:32:06 +02:00
2022-04-25 14:39:45 +02:00
for ( int k = 0 ; k < pre_layer - > nb_neurons ; k + + ) {
neuron - > z + = pre_layer - > neurons [ k ] - > z * pre_layer - > neurons [ k ] - > weights [ j ] ;
2022-03-24 13:42:03 +01:00
}
2022-04-25 14:39:45 +02:00
if ( i < network - > nb_layers - 1 ) { // Pour toutes les couches sauf la dernière on utilise la fonction leaky_ReLU (a*z si z<0, z sinon)
neuron - > z = leaky_ReLU ( neuron - > z ) ;
} else { // Pour la dernière layer on utilise la fonction sigmoid permettant d'obtenir un résultat entre 0 et 1 à savoir une probabilité
max_z = max ( max_z , neuron - > z ) ;
2022-03-24 13:42:03 +01:00
}
}
}
2022-04-25 14:39:45 +02:00
layer = network - > layers [ network - > nb_layers - 1 ] ;
int size_last_layer = layer - > nb_neurons ;
2022-04-25 10:09:47 +02:00
for ( int j = 0 ; j < size_last_layer ; j + + ) {
2022-04-25 14:39:45 +02:00
neuron = layer - > neurons [ j ] ;
neuron - > z = exp ( neuron - > z - max_z ) ;
sum + = neuron - > z ;
2022-04-25 10:09:47 +02:00
}
for ( int j = 0 ; j < size_last_layer ; j + + ) {
2022-04-25 14:39:45 +02:00
neuron = layer - > neurons [ j ] ;
neuron - > z = neuron - > z / sum ;
2022-04-25 10:09:47 +02:00
}
2022-03-24 13:42:03 +01:00
}
2022-04-25 14:39:45 +02:00
int * desired_output_creation ( Network * network , int wanted_number ) {
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-25 14:39:45 +02:00
int nb_neurons = network - > layers [ network - > nb_layers - 1 ] - > nb_neurons ;
2022-03-24 13:42:03 +01:00
2022-04-25 14:39:45 +02:00
int * desired_output = ( int * ) malloc ( sizeof ( int ) * nb_neurons ) ;
2022-04-08 15:53:29 +02:00
2022-04-25 14:39:45 +02:00
for ( int i = 0 ; i < nb_neurons ; i + + ) // On initialise toutes les sorties à 0 par défaut
desired_output [ i ] = 0 ;
2022-04-08 15:53:29 +02:00
2022-04-25 14:39:45 +02:00
desired_output [ wanted_number ] = 1 ; // Seule la sortie voulue vaut 1
return desired_output ;
2022-03-24 13:42:03 +01:00
}
2022-04-25 14:39:45 +02:00
void backward_propagation ( Network * network , int * desired_output ) {
2022-04-05 09:08:39 +02:00
/* Effectue une propagation en arrière du réseau neuronal */
2022-04-25 14:39:45 +02:00
Neuron * neuron ;
Neuron * neuron2 ;
2022-04-18 17:49:50 +02:00
float changes ;
2022-04-25 10:09:47 +02:00
float tmp ;
2022-03-24 13:42:03 +01:00
2022-04-25 14:39:45 +02:00
int i = network - > nb_layers - 2 ;
int neurons_nb = network - > layers [ i + 1 ] - > nb_neurons ;
2022-03-24 13:42:03 +01:00
// On commence par parcourir tous les neurones de la couche finale
2022-04-25 14:39:45 +02:00
for ( int j = 0 ; j < network - > layers [ i + 1 ] - > nb_neurons ; j + + ) {
neuron = network - > layers [ i + 1 ] - > neurons [ j ] ;
tmp = ( desired_output [ j ] = = 1 ) ? neuron - > z - 1 : neuron - > z ;
for ( int k = 0 ; k < network - > layers [ i ] - > nb_neurons ; k + + ) {
neuron2 = network - > layers [ i ] - > neurons [ k ] ;
neuron2 - > back_weights [ j ] + = neuron2 - > z * tmp ;
neuron2 - > last_back_weights [ j ] = neuron2 - > z * tmp ;
2022-03-24 13:42:03 +01:00
}
2022-04-25 14:39:45 +02:00
neuron - > last_back_bias = tmp ;
neuron - > back_bias + = tmp ;
2022-04-22 14:22:45 +02:00
}
2022-04-25 14:39:45 +02:00
for ( i - - ; i > = 0 ; i - - ) {
neurons_nb = network - > layers [ i + 1 ] - > nb_neurons ;
for ( int j = 0 ; j < neurons_nb ; j + + ) {
neuron = network - > layers [ i + 1 ] - > neurons [ j ] ;
2022-04-22 14:22:45 +02:00
changes = 0 ;
2022-04-25 14:39:45 +02:00
for ( int k = 0 ; k < network - > layers [ i + 2 ] - > nb_neurons ; k + + ) {
changes + = ( neuron - > weights [ k ] * neuron - > last_back_weights [ k ] ) / neurons_nb ;
2022-04-22 14:22:45 +02:00
}
2022-04-25 14:39:45 +02:00
changes = changes * leaky_ReLU_derivative ( neuron - > z ) ;
neuron - > back_bias + = changes ;
neuron - > last_back_bias = changes ;
for ( int l = 0 ; l < network - > layers [ i ] - > nb_neurons ; l + + ) {
neuron2 = network - > layers [ i ] - > neurons [ l ] ;
neuron2 - > back_weights [ j ] + = neuron2 - > weights [ j ] * changes ;
neuron2 - > last_back_weights [ j ] = neuron2 - > weights [ j ] * changes ;
2022-03-24 13:42:03 +01:00
}
}
}
}
2022-04-25 14:39:45 +02:00
void network_modification ( Network * network , uint32_t nb_modifs ) {
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-25 14:39:45 +02:00
Neuron * neuron ;
for ( int i = 0 ; i < network - > nb_layers ; i + + ) { // on exclut la dernière couche
for ( int j = 0 ; j < network - > layers [ i ] - > nb_neurons ; j + + ) {
neuron = network - > layers [ i ] - > neurons [ j ] ;
if ( neuron - > bias ! = 0 & & PRINT_BIAIS )
printf ( " C %d \t N %d \t b: %f \t Db: %f \n " , i , j , neuron - > bias , ( LEARNING_RATE / nb_modifs ) * neuron - > back_bias ) ;
neuron - > bias - = ( LEARNING_RATE / nb_modifs ) * neuron - > back_bias ; // On modifie le biais du neurone à partir des données de la propagation en arrière
neuron - > back_bias = 0 ;
if ( neuron - > bias > MAX_RESEAU )
neuron - > bias = MAX_RESEAU ;
else if ( neuron - > bias < - MAX_RESEAU )
neuron - > bias = - MAX_RESEAU ;
if ( i ! = network - > nb_layers - 1 ) {
for ( int k = 0 ; k < network - > layers [ i + 1 ] - > nb_neurons ; k + + ) {
if ( neuron - > weights [ k ] ! = 0 & & PRINT_POIDS )
printf ( " C %d \t N %d -> %d \t p: %f \t Dp: %f \n " , i , j , k , neuron - > weights [ k ] , ( LEARNING_RATE / nb_modifs ) * neuron - > back_weights [ k ] ) ;
neuron - > weights [ k ] - = ( LEARNING_RATE / nb_modifs ) * neuron - > back_weights [ k ] ; // On modifie le poids du neurone à partir des données de la propagation en arrière
neuron - > back_weights [ k ] = 0 ;
if ( neuron - > weights [ k ] > MAX_RESEAU ) {
neuron - > weights [ k ] = MAX_RESEAU ;
2022-04-25 10:09:47 +02:00
printf ( " Erreur, max du réseau atteint " ) ;
}
2022-04-25 14:39:45 +02:00
else if ( neuron - > weights [ k ] < - MAX_RESEAU ) {
neuron - > weights [ k ] = - MAX_RESEAU ;
2022-04-25 10:09:47 +02:00
printf ( " Erreur, min du réseau atteint " ) ;
}
}
2022-03-24 13:42:03 +01:00
}
}
}
}
2022-04-25 14:39:45 +02:00
void network_initialisation ( Network * network ) {
/* Initialise les variables du réseau neuronal (bias, poids, ...)
en suivant de la méthode de Xavier . . . . . . à partir du nombre de couches et de la liste du nombre de neurone par couches */
Neuron * neuron ;
double upper_bound ;
double lower_bound ;
double bound_gap ;
2022-04-10 12:32:06 +02:00
2022-04-25 14:39:45 +02:00
int nb_layers_loop = network - > nb_layers - 1 ;
upper_bound = 1 / sqrt ( ( double ) network - > layers [ nb_layers_loop ] - > nb_neurons ) ;
lower_bound = - upper_bound ;
bound_gap = upper_bound - lower_bound ;
2022-03-24 13:42:03 +01:00
srand ( time ( 0 ) ) ;
2022-04-25 14:39:45 +02:00
for ( int i = 0 ; i < nb_layers_loop ; i + + ) { // On exclut la dernière couche
for ( int j = 0 ; j < network - > layers [ i ] - > nb_neurons ; j + + ) {
2022-04-10 12:32:06 +02:00
2022-04-25 14:39:45 +02:00
neuron = network - > layers [ i ] - > neurons [ j ] ;
2022-03-25 14:26:46 +01:00
// Initialisation des bornes supérieure et inférieure
2022-04-25 14:39:45 +02:00
if ( i ! = nb_layers_loop ) {
for ( int k = 0 ; k < network - > layers [ i + 1 ] - > nb_neurons ; k + + ) {
neuron - > weights [ k ] = lower_bound + RAND_DOUBLE ( ) * bound_gap ;
neuron - > back_weights [ k ] = 0 ;
neuron - > last_back_weights [ k ] = 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-25 14:39:45 +02:00
neuron - > bias = lower_bound + RAND_DOUBLE ( ) * bound_gap ;
neuron - > back_bias = 0 ;
neuron - > last_back_bias = 0 ;
2022-04-01 15:18:48 +02:00
}
2022-03-24 13:42:03 +01:00
}
}
2022-04-12 18:28:19 +02:00
}
2022-04-25 14:39:45 +02:00
float loss_computing ( Network * network , int numero_voulu ) {
2022-04-12 18:28:19 +02:00
/* Renvoie l'erreur du réseau neuronal pour une sortie */
float erreur = 0 ;
2022-04-25 14:39:45 +02:00
float neuron_value ;
2022-04-12 18:28:19 +02:00
2022-04-25 14:39:45 +02:00
for ( int i = 0 ; i < network - > nb_layers - 1 ; i + + ) {
neuron_value = network - > layers [ network - > nb_layers - 1 ] - > neurons [ i ] - > z ;
2022-04-12 18:33:28 +02:00
2022-04-22 14:22:45 +02:00
if ( i = = numero_voulu ) {
2022-04-25 14:39:45 +02:00
erreur + = ( 1 - neuron_value ) * ( 1 - neuron_value ) ;
2022-04-12 18:28:19 +02:00
}
else {
2022-04-25 14:39:45 +02:00
erreur + = neuron_value * neuron_value ;
2022-04-12 18:28:19 +02:00
}
}
2022-04-12 18:33:28 +02:00
2022-04-12 18:28:19 +02:00
return erreur ;
2022-04-12 18:19:09 +02:00
}