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"
2023-03-13 13:55:09 +01:00
# include "include/neural_network.h"
2022-03-24 13:42:03 +01:00
2022-04-22 14:22:45 +02:00
2022-03-24 13:42:03 +01:00
2022-06-01 17:14:16 +02:00
# ifndef __CUDACC__
// The functions and macros below are already defined when using NVCC
# define INT_MIN -2147483648
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
}
2022-06-01 17:14:16 +02:00
# endif
2023-03-13 13:55:09 +01:00
bool drop ( float prob ) {
return ( rand ( ) % 100 ) > 100 * prob ;
}
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 ) {
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 ] ;
2022-06-30 10:25:04 +02:00
layer - > nb_neurons = neurons_per_layer [ i ] ;
layer - > neurons = ( Neuron * * ) malloc ( sizeof ( Neuron * ) * network - > layers [ i ] - > nb_neurons ) ;
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
2022-06-30 10:25:04 +02:00
layer - > neurons [ j ] - > weights = ( float * ) malloc ( sizeof ( float ) * neurons_per_layer [ i + 1 ] ) ;
2022-04-25 14:39:45 +02:00
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 ) {
Layer * layer ;
Neuron * neuron ;
2022-05-14 14:46:48 +02:00
for ( int i = 0 ; i < network - > nb_layers ; i + + ) {
2022-04-25 14:39:45 +02:00
layer = network - > layers [ i ] ;
2023-01-14 14:52:40 +01:00
for ( int j = 0 ; j < network - > layers [ i ] - > nb_neurons ; j + + ) {
neuron = layer - > neurons [ j ] ;
if ( i ! = network - > nb_layers - 1 ) { // On exclut la dernière couche dont les neurones ne contiennent pas de poids sortants
2022-04-25 14:39:45 +02:00
free ( neuron - > weights ) ;
free ( neuron - > back_weights ) ;
2022-05-14 14:46:48 +02:00
free ( neuron - > last_back_weights ) ;
2022-03-24 13:42:03 +01:00
}
2023-01-14 14:52:40 +01:00
free ( neuron ) ;
2022-03-24 13:42:03 +01:00
}
2022-06-30 10:25:04 +02:00
free ( layer - > neurons ) ;
2022-05-23 17:27:38 +02:00
free ( network - > layers [ i ] ) ;
2022-03-24 13:42:03 +01:00
}
2022-05-14 10:28:40 +02:00
free ( network - > layers ) ;
2022-06-30 10:25:04 +02:00
free ( network ) ;
2022-03-24 13:42:03 +01:00
}
2023-03-13 13:55:09 +01:00
void forward_propagation ( Network * network , bool is_training ) {
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 ;
2023-03-13 13:55:09 +01:00
float max_z = INT_MIN ;
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-06-30 10:25:04 +02:00
if ( i < network - > nb_layers - 1 ) {
2023-03-13 13:55:09 +01:00
if ( ! is_training ) {
if ( j = = 0 ) {
neuron - > z = ENTRY_DROPOUT * leaky_ReLU ( neuron - > z ) ;
} else {
neuron - > z = DROPOUT * leaky_ReLU ( neuron - > z ) ;
}
} else if ( ! drop ( DROPOUT ) ) {
neuron - > z = leaky_ReLU ( neuron - > z ) ;
} else {
neuron - > z = 0. ;
}
2022-06-30 10:25:04 +02:00
} else { // Softmax seulement pour la dernière couche
2022-04-25 14:39:45 +02:00
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 ) {
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 ;
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 ) {
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-06-30 10:25:04 +02:00
for ( int j = 0 ; j < network - > layers [ i + 1 ] - > nb_neurons ; j + + ) { // Dernière couche en première
2022-04-25 14:39:45 +02:00
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-06-30 10:25:04 +02:00
for ( i - - ; i > = 0 ; i - - ) { // Autres couches ensuite
2022-04-25 14:39:45 +02:00
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 ) ;
2023-03-13 13:55:09 +01:00
if ( neuron - > z ! = 0 ) {
neuron - > back_bias + = changes ;
neuron - > last_back_bias = changes ;
}
2022-04-25 14:39:45 +02:00
for ( int l = 0 ; l < network - > layers [ i ] - > nb_neurons ; l + + ) {
neuron2 = network - > layers [ i ] - > neurons [ l ] ;
2023-03-13 13:55:09 +01:00
if ( neuron - > z ! = 0 ) {
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 ) {
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 ) ;
2022-06-30 10:25:04 +02:00
neuron - > bias - = ( LEARNING_RATE / nb_modifs ) * neuron - > back_bias ;
2022-04-25 14:39:45 +02:00
neuron - > back_bias = 0 ;
if ( neuron - > bias > MAX_RESEAU )
neuron - > bias = MAX_RESEAU ;
else if ( neuron - > bias < - MAX_RESEAU )
neuron - > bias = - MAX_RESEAU ;
2022-05-14 10:28:40 +02:00
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 ] ) ;
2022-06-30 10:25:04 +02:00
neuron - > weights [ k ] - = ( LEARNING_RATE / nb_modifs ) * neuron - > back_weights [ k ] ;
2022-05-14 10:28:40 +02:00
neuron - > back_weights [ k ] = 0 ;
2022-04-25 14:39:45 +02:00
2022-05-14 10:28:40 +02:00
if ( neuron - > weights [ k ] > MAX_RESEAU ) {
neuron - > weights [ k ] = MAX_RESEAU ;
printf ( " Erreur, max du réseau atteint " ) ;
}
else if ( neuron - > weights [ k ] < - MAX_RESEAU ) {
neuron - > weights [ k ] = - MAX_RESEAU ;
printf ( " Erreur, min du réseau atteint " ) ;
}
2022-04-25 10:09:47 +02:00
}
2022-03-24 13:42:03 +01:00
}
}
}
}
2022-04-25 14:39:45 +02:00
void network_initialisation ( Network * network ) {
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 ] ;
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-06-30 10:25:04 +02:00
if ( i > 0 ) { // On exclut 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-05-14 10:28:40 +02:00
void patch_network ( Network * network , Network * delta , uint32_t nb_modifs ) {
Neuron * neuron ;
Neuron * dneuron ;
for ( int i = 0 ; i < network - > nb_layers ; i + + ) {
for ( int j = 0 ; j < network - > layers [ i ] - > nb_neurons ; j + + ) {
neuron = network - > layers [ i ] - > neurons [ j ] ;
dneuron = delta - > layers [ i ] - > neurons [ j ] ;
neuron - > bias - = ( LEARNING_RATE / nb_modifs ) * dneuron - > back_bias ;
dneuron - > back_bias = 0 ;
if ( i ! = network - > nb_layers - 1 ) {
for ( int k = 0 ; k < network - > layers [ i + 1 ] - > nb_neurons ; k + + ) {
neuron - > weights [ k ] - = ( LEARNING_RATE / nb_modifs ) * dneuron - > back_weights [ k ] ; // On modifie le poids du neurone à partir des données de la propagation en arrière
dneuron - > back_weights [ k ] = 0 ;
}
}
}
}
}
2022-05-19 22:26:19 +02:00
void patch_delta ( Network * network , Network * delta , uint32_t nb_modifs ) {
Neuron * neuron ;
Neuron * dneuron ;
for ( int i = 0 ; i < network - > nb_layers ; i + + ) {
for ( int j = 0 ; j < network - > layers [ i ] - > nb_neurons ; j + + ) {
neuron = network - > layers [ i ] - > neurons [ j ] ;
dneuron = delta - > layers [ i ] - > neurons [ j ] ;
neuron - > back_bias + = dneuron - > back_bias / nb_modifs ;
if ( i ! = network - > nb_layers - 1 ) {
for ( int k = 0 ; k < network - > layers [ i + 1 ] - > nb_neurons ; k + + ) {
neuron - > back_weights [ k ] + = dneuron - > back_weights [ k ] / nb_modifs ;
}
}
}
}
}
2022-05-14 10:28:40 +02:00
Network * copy_network ( Network * network ) {
Network * network2 = ( Network * ) malloc ( sizeof ( Network ) ) ;
Layer * layer ;
Neuron * neuron1 ;
Neuron * neuron ;
2022-04-12 18:28:19 +02:00
2022-05-14 10:28:40 +02:00
network2 - > nb_layers = network - > nb_layers ;
network2 - > layers = ( Layer * * ) malloc ( sizeof ( Layer * ) * network - > nb_layers ) ;
for ( int i = 0 ; i < network2 - > nb_layers ; i + + ) {
layer = ( Layer * ) malloc ( sizeof ( Layer ) ) ;
layer - > nb_neurons = network - > layers [ i ] - > nb_neurons ;
layer - > neurons = ( Neuron * * ) malloc ( sizeof ( Neuron * ) * layer - > nb_neurons ) ;
for ( int j = 0 ; j < layer - > nb_neurons ; j + + ) {
neuron = ( Neuron * ) malloc ( sizeof ( Neuron ) ) ;
neuron1 = network - > layers [ i ] - > neurons [ j ] ;
neuron - > bias = neuron1 - > bias ;
neuron - > z = neuron1 - > z ;
neuron - > back_bias = neuron1 - > back_bias ;
neuron - > last_back_bias = neuron1 - > last_back_bias ;
if ( i ! = network2 - > nb_layers - 1 ) {
( void ) network2 - > layers [ i + 1 ] - > nb_neurons ;
neuron - > weights = ( float * ) malloc ( sizeof ( float ) * network - > layers [ i + 1 ] - > nb_neurons ) ;
neuron - > back_weights = ( float * ) malloc ( sizeof ( float ) * network - > layers [ i + 1 ] - > nb_neurons ) ;
neuron - > last_back_weights = ( float * ) malloc ( sizeof ( float ) * network - > layers [ i + 1 ] - > nb_neurons ) ;
for ( int k = 0 ; k < network - > layers [ i + 1 ] - > nb_neurons ; k + + ) {
neuron - > weights [ k ] = neuron1 - > weights [ k ] ;
neuron - > back_weights [ k ] = neuron1 - > back_weights [ k ] ;
neuron - > last_back_weights [ k ] = neuron1 - > last_back_weights [ k ] ;
}
}
layer - > neurons [ j ] = neuron ;
}
network2 - > layers [ i ] = layer ;
}
return network2 ;
}
2022-04-12 18:28:19 +02:00
2022-06-30 10:25:04 +02:00
float loss_computing ( Network * network , int wanted_number ) {
2022-04-12 18:28:19 +02:00
float erreur = 0 ;
2022-04-25 14:39:45 +02:00
float neuron_value ;
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-06-30 10:25:04 +02:00
if ( i = = wanted_number ) {
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
}
}
return erreur ;
2022-10-21 14:22:57 +02:00
}