diff --git a/src/mnist/include/neuron.h b/src/mnist/include/neuron.h index 92556a9..5c2691d 100644 --- a/src/mnist/include/neuron.h +++ b/src/mnist/include/neuron.h @@ -4,7 +4,7 @@ typedef struct Neuron { float* weights; // Liste de tous les poids des arêtes sortants du neurone float bias; // Caractérise le bias du neurone - float z; // Sauvegarde des calculs faits sur le neurone (programmation dynamique) + float z; // Sauvegarde des calculs faits sur le neurone float *back_weights; // Changement des poids sortants lors de la backpropagation float *last_back_weights; // Dernier changement de d_poid_sortants diff --git a/src/mnist_cnn/cnn.c b/src/mnist_cnn/cnn.c index afbc8fb..9e51997 100644 --- a/src/mnist_cnn/cnn.c +++ b/src/mnist_cnn/cnn.c @@ -1,16 +1,638 @@ -#define PADING_INPUT 2 +#include +#include +#include +#include +#include -void write_image_in_newtork_32(int** image, int height, int width, float** network) { - /* Ecrit une image 28*28 au centre d'un tableau 32*32 et met à 0 le reste */ +#include "cnn.h" - 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){ - network[i][j] = 0.; +#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 +#include +#include +#include +#include + +#ifndef DEF_CNN_H +#define DEF_CNN_H + + +typedef struct Kernel_cnn { + int k_size; + int rows; + int columns; + int b; + float*** bias; // De dimension columns*k_size*k_size + float*** d_bias; // De dimension columns*k_size*k_size + float**** w; // De dimension rows*columns*k_size*k_size + float**** d_w; // De dimension rows*columns*k_size*k_size +} Kernel_cnn; + +typedef struct Kernel_nn { + int input_units; + int output_units; + float* bias; // De dimension output_units + float* d_bias; // De dimension output_units + float** weights; // De dimension input_units*output_units + float** d_weights; // De dimension input_units*output_units +} Kernel_nn; + +typedef struct Kernel { + Kernel_cnn* cnn; + Kernel_nn* nn; + int activation; // Vaut l'activation sauf pour un pooling où il: vaut kernel_size*100 + activation +} Kernel; + +typedef struct Layer { + +} Layer; + +typedef struct Network{ + int dropout; // Contient la probabilité d'abandon entre 0 et 100 (inclus) + int initialisation; // Contient le type d'initialisation + int max_size; // Taille maximale du réseau après initialisation + int size; // Taille actuelle du réseau + int** dim; // Contient les dimensions de l'input (width*depth) + Kernel* kernel; + float**** input; +} Network; + +float max(float a, float b); +float sigmoid(float x); +float sigmoid_derivative(float x); +float relu(float x); +float relu_derivative(float x); +float tanh_(float x); +float tanh_derivative(float x); +void apply_softmax_input(float ***input, int depth, int rows, int columns); +void apply_function_input(float (*f)(float), float*** input, int depth, int rows, int columns); +void choose_apply_function_input(int activation, float*** input, int depth, int rows, int columns); +int will_be_drop(int dropout_prob); +Network* create_network(int max_size, int dropout, int initialisation, int input_dim, int input_depth); +Network* create_network_lenet5(int dropout, int activation, int initialisation); +void create_a_cube_input_layer(Network* network, int pos, int depth, int dim); +void create_a_line_input_layer(Network* network, int pos, int dim); +void initialisation_1d_matrix(int initialisation, float* matrix, int rows, int n); //NOT FINISHED (UNIFORM AND VARIATIONS) +void initialisation_2d_matrix(int initialisation, float** matrix, int rows, int columns, int n); //NOT FINISHED +void initialisation_3d_matrix(int initialisation, float*** matrix, int depth, int rows, int columns, int n); //NOT FINISHED +void initialisation_4d_matrix(int initialisation, float**** matrix, int rows, int columns, int rows1, int columns1, int n); //NOT FINISHED +void add_average_pooling(Network* network, int kernel_size, int activation); +void add_average_pooling_flatten(Network* network, int kernel_size, int activation); +void add_convolution(Network* network, int nb_filter, int kernel_size, int activation); +void add_dense(Network* network, int input_units, int output_units, int activation); +void write_image_in_newtork_32(int** image, int height, int width, float** input); +void make_convolution(float*** input, Kernel_cnn* kernel, float*** output, int output_dim); +void make_average_pooling(float*** input, float*** output, int size, int output_depth, int output_dim); +void make_average_pooling_flattened(float*** input, float* output, int size, int input_depth, int input_dim); +void make_fully_connected(float* input, Kernel_nn* kernel, float* output, int size_input, int size_output); +void free_a_cube_input_layer(Network* network, int pos, int depth, int dim); +void free_a_line_input_layer(Network* network, int pos); +void free_average_pooling(Network* network, int pos); +void free_average_pooling_flatten(Network* network, int pos); +void free_convolution(Network* network, int pos); +void free_dense(Network* network, int pos); +void free_network_creation(Network* network); +void free_network_lenet5(Network* network); +float compute_cross_entropy_loss(float* output, float* wanted_output, int len); +void forward_propagation(Network* network); +void backward_propagation(Network* network, float wanted_number); //NOT FINISHED +float compute_cross_entropy_loss(float* output, float* wanted_output, int len); +float* generate_wanted_output(float wanted_number); + + +#endif \ No newline at end of file diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..0f25d30 --- /dev/null +++ b/src/test.c @@ -0,0 +1,127 @@ +#include +#include +#include +typedef struct Neuron{ + float bias; // Caractérise le bias du neurone + float z; // Sauvegarde des calculs faits sur le neurone (programmation dynamique) + + float back_bias; // Changement du bias lors de la backpropagation + float last_back_bias; // Dernier changement de back_bias +} Neuron; + +typedef struct Bias{ + float bias; + float back_bias; + float last_back_bias; +} Bias; + +typedef struct Matrix { + int rows; // Nombre de lignes de la matrice + int columns; // Nombre de colonnes de la matrice + float** value; // Tableau 2d comportant les valeurs de matrice +} Matrix; + +typedef struct Matrix_of_neurons { + int rows; // Nombre de lignes de la matrice + int columns; // Nombre de colonnes de la matrice + float** Neuron; // Tableau 2d comportant les valeurs de matrice +} Matrix_of_neurons; + +typedef struct Matrix_of_bias { + int rows; + int columns; + float*** bias; +} Matrix_of_bias; + +typedef struct Layer { + int rows; // Nombre de matrices du tableau de neurones + Matrix** conv; // Tableau de matrices des neurones dans la couche +} Layer; + +typedef struct Filter { + int columns; + int rows; + int dim_bias; + Matrix_of_neurons*** kernel; // De dimension columns*rows + Matrix_of_bias** bias; // De dimension columns +} Filter; + +typedef struct Network{ + int dropout; // Contains the probability of dropout bewteen 0 and 100 + int max_size; + int size; // Taille total du réseau + int size_cnn; // Nombre de couches dans le cnn + int* type_kernel; //De taille size -1 + + Layer** input; // Tableau des couches dans le réseau neuronal + Filter** kernel; +} Network; + +void write_image_in_newtork_32(int** image, int height, int width, float** network) { + /* 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){ + network[i][j] = 0.; + } + else { + network[i][j] = (float)image[i][j] / 255.0f; + } + } + } +} + + + +void make_convolution(Layer* input, Filter* filter, Layer* output){ + /* Effectue une convolution sans stride */ + if (filter->columns != output->rows) { + printf("Erreur, le filtre de la convolution et la sortie ne sont pas compatibles"); + return; + } + if (filter->dim_bias != output->rows) { + printf("Erreur, le biais et la sortie de la convolution n'ont pas les mêmes dimensions"); + return; + } + + // MISS CONDITIONS ON THE CONVOLUTION + int i, j, k; + for (i=0; i < filter->rows; i++) { + for (j=0; j < filter->dim_bias; j++) { + for (int k=0; k < filter->dim_bias; k++) { + //output->conv[j][k] = filter->bias[i]->bias + // COPY BIAS OF FILTERS IN OUTPUT + // POUR CHAQUE COLONNE DANS LE KERNEL + // ON APPLIQUE LE FILTRE SUR CHAQUE LIGNE DE L'INPUT ET LES SOMMES + } + } + } +} + +void make_average_pooling(Layer* input, int dim_pooling, Layer* output){ + /* Effectue un average pooling avec full strides */ + + if (input->rows != output->rows || output->conv[0]->rows*dim_pooling != input->conv[0]->rows || input->rows != output->rows) { + printf("Erreur, dimension de la sortie et de l'entrée ne sont pas compatibles avec l'average pooling"); + return; + } + int i, j, k, a, b, nb=dim_pooling*dim_pooling; + for (i=0; i < input->rows; i++) { + for (j=0; j < output->conv[i]->rows; j++) { + for (k=0; k < output->conv[i]->columns; k++) { + output->conv[i]->value[j][k] = 0; + for (a=0; a < dim_pooling; a++) { + for (b=0; b < dim_pooling; b++) { + output->conv[i]->value[j][k] += input->conv[i]->value[dim_pooling*j + a][dim_pooling*k + b]; + } + } + output->conv[i]->value[j][k] /= nb; + } + } + } +} + +void forward_propagation_cnn() { + /* Effectue une forward propagation d'un cnn */ +} \ No newline at end of file