#include #include #include #include #include #include "cnn.h" #define PADING_INPUT 2 // Augmente les dimensions de l'image d'entrée #define RAND_FLT() ((float)rand())/((float)RAND_MAX) // Génère un flotant entre 0 et 1 // Les dérivées sont l'opposé #define TANH 1 #define SIGMOID 2 #define RELU 3 #define SOFTMAX 4 #define ZERO 0 #define GLOROT_NORMAL 1 #define GLOROT_UNIFROM 2 #define HE_NORMAL 3 #define HE_UNIFORM 4 // Penser à mettre srand(time(NULL)); (pour les proba de dropout) float max(float a, float b) { return a 0) return 1; return 0; } float tanh_(float x) { return tanh(x); } float tanh_derivative(float x) { float a = tanh(x); return 1 - a*a; } void apply_softmax_input(float ***input, int depth, int rows, int columns) { int i, j, k; float m = FLT_MIN; float sum=0; for (i=0; i100) { printf("Erreur, la probabilité de dropout n'est pas respecté, elle doit être comprise entre 0 et 100\n"); } Network* network = malloc(sizeof(Network)); network->max_size = max_size; network->dropout = dropout; network->initialisation = initialisation; network->size = 1; network->input = malloc(sizeof(float***)*max_size); network->kernel = malloc(sizeof(Kernel)*(max_size-1)); create_a_cube_input_layer(network, 0, input_depth, input_dim); int i, j; network->dim = malloc(sizeof(int*)*max_size); for (i=0; idim[i] = malloc(sizeof(int)*2); } network->dim[0][0] = input_dim; network->dim[0][1] = input_depth; return network; } Network* create_network_lenet5(int dropout, int activation, int initialisation) { /* Renvoie un réseau suivant l'architecture LeNet5 */ Network* network; network = create_network(8, dropout, initialisation, 32, 1); add_convolution(network, 6, 5, activation); add_average_pooling(network, 2, activation); add_convolution(network, 16, 5, activation); add_average_pooling_flatten(network, 2, activation); add_dense(network, 120, 84, activation); add_dense(network, 84, 10, activation); add_dense(network, 10, 10, SOFTMAX); return network; } void create_a_cube_input_layer(Network* network, int pos, int depth, int dim) { /* Créé et alloue de la mémoire à une couche de type input cube */ int i, j; network->input[pos] = malloc(sizeof(float**)*depth); for (i=0; iinput[pos][i] = malloc(sizeof(float*)*dim); for (j=0; jinput[pos][i][j] = malloc(sizeof(float)*dim); } } network->dim[pos][0] = dim; network->dim[pos][1] = depth; } void create_a_line_input_layer(Network* network, int pos, int dim) { /* Créé et alloue de la mémoire à une couche de type ligne */ int i; network->input[pos] = malloc(sizeof(float**)); network->input[pos][0] = malloc(sizeof(float*)); network->input[pos][0][0] = malloc(sizeof(float)*dim); } void initialisation_1d_matrix(int initialisation, float* matrix, int rows, int n) { //NOT FINISHED /* Initialise une matrice 1d rows de float en fonction du type d'initialisation */ int i; float lower_bound = -6/sqrt((double)n); float distance = -lower_bound-lower_bound; for (i=0; isize; if (network->max_size == n) { printf("Impossible de rajouter une couche d'average pooling, le réseau est déjà plein\n"); return; } network->kernel[n].cnn = NULL; network->kernel[n].nn = NULL; network->kernel[n].activation = activation + 100*kernel_size; create_a_cube_input_layer(network, n, network->dim[n-1][1], network->dim[n-1][0]/2); network->size++; } void add_average_pooling_flatten(Network* network, int kernel_size, int activation) { /* Ajoute au réseau une couche d'average pooling valide de dimension dim*dim qui aplatit */ int n = network->size; if (network->max_size == n) { printf("Impossible de rajouter une couche d'average pooling, le réseau est déjà plein\n"); return; } network->kernel[n].cnn = NULL; network->kernel[n].nn = NULL; network->kernel[n].activation = activation + 100*kernel_size; int dim = (network->dim[n-1][0]*network->dim[n-1][0]*network->dim[n-1][1])/(kernel_size*kernel_size); create_a_line_input_layer(network, n, dim); network->size++; } void add_convolution(Network* network, int nb_filter, int kernel_size, int activation) { /* Ajoute une couche de convolution dim*dim au réseau et initialise les kernels */ int n = network->size, i, j, k; if (network->max_size == n) { printf("Impossible de rajouter une couche de convolution, le réseau est déjà plein\n"); return; } int r = network->dim[n-1][1]; int c = nb_filter; network->kernel[n].nn = NULL; network->kernel[n].cnn = malloc(sizeof(Kernel_cnn)); network->kernel[n].activation = activation; network->kernel[n].cnn->k_size = kernel_size; network->kernel[n].cnn->rows = r; network->kernel[n].cnn->columns = c; network->kernel[n].cnn->w = malloc(sizeof(float***)*r); network->kernel[n].cnn->d_w = malloc(sizeof(float***)*r); for (i=0; ikernel[n].cnn->w[i] = malloc(sizeof(float**)*c); network->kernel[n].cnn->d_w[i] = malloc(sizeof(float**)*c); for (j=0; jkernel[n].cnn->w[i][j] = malloc(sizeof(float*)*kernel_size); network->kernel[n].cnn->d_w[i][j] = malloc(sizeof(float*)*kernel_size); for (k=0; kkernel[n].cnn->w[i][j][k] = malloc(sizeof(float)*kernel_size); network->kernel[n].cnn->d_w[i][j][k] = malloc(sizeof(float)*kernel_size); } } } network->kernel[n].cnn->bias = malloc(sizeof(float**)*c); network->kernel[n].cnn->d_bias = malloc(sizeof(float**)*c); for (i=0; ikernel[n].cnn->bias[i] = malloc(sizeof(float*)*kernel_size); network->kernel[n].cnn->d_bias[i] = malloc(sizeof(float*)*kernel_size); for (j=0; jkernel[n].cnn->bias[i][j] = malloc(sizeof(float)*kernel_size); network->kernel[n].cnn->d_bias[i][j] = malloc(sizeof(float)*kernel_size); } } create_a_cube_input_layer(network, n, c, network->dim[n-1][0] - 2*(kernel_size/2)); int n_int = network->dim[n-1][0]*network->dim[n-1][0]*network->dim[n-1][1]; int n_out = network->dim[n][0]*network->dim[n][0]*network->dim[n][1]; initialisation_3d_matrix(network->initialisation, network->kernel[n].cnn->bias, c, kernel_size, kernel_size, n_int+n_out); initialisation_3d_matrix(ZERO, network->kernel[n].cnn->d_bias, c, kernel_size, kernel_size, n_int+n_out); initialisation_4d_matrix(network->initialisation, network->kernel[n].cnn->w, r, c, kernel_size, kernel_size, n_int+n_out); initialisation_4d_matrix(ZERO, network->kernel[n].cnn->d_w, r, c, kernel_size, kernel_size, n_int+n_out); network->size++; } void add_dense(Network* network, int input_units, int output_units, int activation) { /* Ajoute une couche dense au réseau et initialise les poids et les biais*/ int n = network->size; if (network->max_size == n) { printf("Impossible de rajouter une couche dense, le réseau est déjà plein\n"); return; } network->kernel[n].cnn = NULL; network->kernel[n].nn = malloc(sizeof(Kernel_nn)); network->kernel[n].activation = activation; network->kernel[n].nn->input_units = input_units; network->kernel[n].nn->output_units = output_units; network->kernel[n].nn->bias = malloc(sizeof(float)*output_units); network->kernel[n].nn->d_bias = malloc(sizeof(float)*output_units); network->kernel[n].nn->weights = malloc(sizeof(float*)*input_units); network->kernel[n].nn->d_weights = malloc(sizeof(float*)*input_units); for (int i=0; ikernel[n].nn->weights[i] = malloc(sizeof(float)*output_units); network->kernel[n].nn->d_weights[i] = malloc(sizeof(float)*output_units); } initialisation_1d_matrix(network->initialisation, network->kernel[n].nn->bias, output_units, output_units+input_units); initialisation_1d_matrix(ZERO, network->kernel[n].nn->d_bias, output_units, output_units+input_units); initialisation_2d_matrix(network->initialisation, network->kernel[n].nn->weights, input_units, output_units, output_units+input_units); initialisation_2d_matrix(ZERO, network->kernel[n].nn->d_weights, input_units, output_units, output_units+input_units); create_a_line_input_layer(network, n, output_units); network->size++; } void write_image_in_newtork_32(int** image, int height, int width, float** input) { /* Ecrit une image 28*28 au centre d'un tableau 32*32 et met à 0 le reste */ for (int i=0; i < height+2*PADING_INPUT; i++) { for (int j=PADING_INPUT; j < width+2*PADING_INPUT; j++) { if (iheight+PADING_INPUT || jwidth+PADING_INPUT) { input[i][j] = 0.; } else { input[i][j] = (float)image[i][j] / 255.0f; } } } } void make_convolution(float*** input, Kernel_cnn* kernel, float*** output, int output_dim) { /* Effectue une convolution sans stride */ //NOT FINISHED, MISS CONDITIONS ON THE CONVOLUTION float f; int i, j, k, a, b, c, n=kernel->k_size; for (i=0; icolumns; i++) { for (j=0; jbias[i][j][k]; for (a=0; arows; a++) { for (b=0; bw[a][i][b][c]*input[a][j+a][k+b]; } } } output[i][j][k] = f; } } } } void make_average_pooling(float*** input, float*** output, int size, int output_depth, int output_dim) { /* Effecute un average pooling avec stride=size */ //NOT FINISHED, MISS CONDITIONS ON THE POOLING float average; int i, j, k, a, b, n=size*size; for (i=0; ibias[i]; for (j=0; jweights[i][j]*input[j]; } output[i] = f; } } void free_a_cube_input_layer(Network* network, int pos, int depth, int dim) { /* Libère la mémoire allouée à une couche de type input cube */ int i, j, k; for (i=0; iinput[pos][i][j]); } free(network->input[pos][i]); } free(network->input[pos]); } void free_a_line_input_layer(Network* network, int pos) { /* Libère la mémoire allouée à une couche de type input line */ free(network->input[pos][0][0]); free(network->input[pos][0]); free(network->input[pos]); } void free_average_pooling(Network* network, int pos) { /* Libère l'espace mémoie et supprime une couche d'average pooling classique */ free_a_cube_input_layer(network, pos, network->dim[pos-1][1], network->dim[pos-1][0]/2); } void free_average_pooling_flatten(Network* network, int pos) { /* Libère l'espace mémoie et supprime une couche d'average pooling flatten */ free_a_line_input_layer(network, pos); } void free_convolution(Network* network, int pos) { /* Libère l'espace mémoire et supprime une couche de convolution */ int i, j, k, c = network->kernel[pos].cnn->columns; int k_size = network->kernel[pos].cnn->k_size; int r = network->kernel[pos].cnn->rows; free_a_cube_input_layer(network, pos, c, network->dim[pos-1][0] - 2*(k_size/2)); for (i=0; ikernel[pos].cnn->bias[i][j]); free(network->kernel[pos].cnn->d_bias[i][j]); } free(network->kernel[pos].cnn->bias[i]); free(network->kernel[pos].cnn->d_bias[i]); } free(network->kernel[pos].cnn->bias); free(network->kernel[pos].cnn->d_bias); for (i=0; ikernel[pos].cnn->w[i][j][k]); free(network->kernel[pos].cnn->d_w[i][j][k]); } free(network->kernel[pos].cnn->w[i][j]); free(network->kernel[pos].cnn->d_w[i][j]); } free(network->kernel[pos].cnn->w[i]); free(network->kernel[pos].cnn->d_w[i]); } free(network->kernel[pos].cnn->w); free(network->kernel[pos].cnn->d_w); free(network->kernel[pos].cnn); } void free_dense(Network* network, int pos) { /* Libère l'espace mémoire et supprime une couche dense */ free_a_line_input_layer(network, pos); int i, dim = network->kernel[pos].nn->output_units; for (int i=0; ikernel[pos].nn->weights[i]); free(network->kernel[pos].nn->d_weights[i]); } free(network->kernel[pos].nn->weights); free(network->kernel[pos].nn->d_weights); free(network->kernel[pos].nn->bias); free(network->kernel[pos].nn->d_bias); free(network->kernel[pos].nn); } void free_network_creation(Network* network) { /* Libère l'espace alloué dans la fonction 'create_network' */ free_a_cube_input_layer(network, 0, network->dim[0][1], network->dim[0][0]); for (int i=0; imax_size; i++) { free(network->dim[i]); } free(network->dim); free(network->kernel); free(network->input); free(network); } void free_network_lenet5(Network* network) { /* Libère l'espace alloué dans la fonction 'create_network_lenet5' */ free_dense(network, 6); free_dense(network, 5); free_dense(network, 4); free_average_pooling_flatten(network, 3); free_convolution(network, 2); free_average_pooling(network, 1); free_convolution(network, 0); free_network_creation(network); if (network->size != network->max_size) { printf("Attention, le réseau LeNet5 n'est pas complet"); } } void forward_propagation(Network* network) { /* Propage en avant le cnn */ for (int i=0; i < network->size-1; i++) { if (network->kernel[i].nn==NULL && network->kernel[i].cnn!=NULL) { make_convolution(network->input[i], network->kernel[i].cnn, network->input[i+1], network->dim[i+1][0]); choose_apply_function_input(network->kernel[i].activation, network->input[i+1], network->dim[i+1][1], network->dim[i+1][0], network->dim[i+1][0]); } else if (network->kernel[i].nn!=NULL && network->kernel[i].cnn==NULL) { make_fully_connected(network->input[i][0][0], network->kernel[i].nn, network->input[i+1][0][0], network->dim[i][0], network->dim[i+1][0]); choose_apply_function_input(network->kernel[i].activation, network->input[i+1], 1, 1, network->dim[i+1][0]); } else { if (network->size-2==i) { printf("Le réseau ne peut pas finir par une pooling layer"); return; } if (network->kernel[i+1].nn!=NULL && network->kernel[i+1].cnn==NULL) { make_average_pooling_flattened(network->input[i], network->input[i+1][0][0], network->kernel[i].activation/100, network->dim[i][1], network->dim[i][0]); choose_apply_function_input(network->kernel[i].activation%100, network->input[i+1], 1, 1, network->dim[i+1][0]); } else if (network->kernel[i+1].nn==NULL && network->kernel[i+1].cnn!=NULL) { make_average_pooling(network->input[i], network->input[i+1], network->kernel[i].activation/100, network->dim[i+1][1], network->dim[i+1][0]); choose_apply_function_input(network->kernel[i].activation%100, network->input[i+1], network->dim[i+1][1], network->dim[i+1][0], network->dim[i+1][0]); } else { printf("Le réseau ne peut pas contenir deux poolings layers collées"); return; } } } } void backward_propagation(Network* network, float wanted_number) { /* Propage en arrière le cnn */ float* wanted_output = generate_wanted_output(wanted_number); int n = network->size-1; float loss = compute_cross_entropy_loss(network->input[n][0][0], wanted_output, network->dim[n][0]); int i, j; for (i=n; i>=0; i--) { if (i==n) { if (network->kernel[i].activation == SOFTMAX) { int l2 = network->dim[i][0]; // Taille de la dernière couche int l1 = network->dim[i-1][0]; for (j=0; jkernel[i].activation == SIGMOID) { } else if (network->kernel[i].activation == TANH) { } else if (network->kernel[i].activation == RELU) { } } } free(wanted_output); } float compute_cross_entropy_loss(float* output, float* wanted_output, int len) { /* Renvoie l'erreur du réseau neuronal pour une sortie */ float loss=0.; for (int i=0; i