diff --git a/src/cnn/backpropagation.c b/src/cnn/backpropagation.c index 199635d..5950891 100644 --- a/src/cnn/backpropagation.c +++ b/src/cnn/backpropagation.c @@ -82,6 +82,7 @@ void backward_linearisation(Kernel_nn* ker, float*** input, float*** input_z, fl // Weights int cpt = 0; + int nb_elem = depth_input*dim_input*dim_input*size_output; for (int i=0; i < depth_input; i++) { for (int k=0; k < dim_input; k++) { for (int l=0; l < dim_input; l++) { diff --git a/src/cnn/cnn.c b/src/cnn/cnn.c index 13f483b..eeb0f4a 100644 --- a/src/cnn/cnn.c +++ b/src/cnn/cnn.c @@ -76,7 +76,7 @@ void write_image_in_network_260(unsigned char* image, int height, int width, flo } void forward_propagation(Network* network) { - int activation, input_depth, input_width, output_depth, output_width; + int activation, pooling, input_depth, input_width, output_depth, output_width; int n = network->size; float*** input; float*** output; @@ -93,6 +93,7 @@ void forward_propagation(Network* network) { output_depth = network->depth[i+1]; output_width = network->width[i+1]; activation = k_i->activation; + pooling = k_i->pooling; if (k_i->nn) { drop_neurones(input, 1, 1, input_width, network->dropout); @@ -119,7 +120,13 @@ void forward_propagation(Network* network) { printf("Le réseau ne peut pas finir par une pooling layer\n"); return; } else { // Pooling sur une matrice - make_average_pooling(input, output, activation, output_depth, output_width); + if (pooling==1) { + make_average_pooling(input, output, activation, output_depth, output_width); + } else if (pooling==2) { + make_max_pooling(input, output, activation, output_depth, output_width); + } else { + printf("Erreur dans la reconnaissance de la couche de pooling: %d,%d \n", pooling, i); + } } copy_input_to_input_z(output, output_a, output_depth, output_width, output_width); } diff --git a/src/cnn/creation.c b/src/cnn/creation.c index 523b447..a8b328d 100644 --- a/src/cnn/creation.c +++ b/src/cnn/creation.c @@ -24,6 +24,7 @@ Network* create_network(int max_size, float learning_rate, int dropout, int init for (int i=0; i < max_size-1; i++) { network->kernel[i] = (Kernel*)malloc(sizeof(Kernel)); } + network->kernel[0]->linearisation = 0; network->width[0] = input_dim; network->depth[0] = input_depth; network->kernel[0]->nn = NULL; @@ -36,7 +37,6 @@ Network* create_network(int max_size, float learning_rate, int dropout, int init Network* create_network_lenet5(float learning_rate, int dropout, int activation, int initialisation, int input_dim, int input_depth) { Network* network = create_network(8, learning_rate, dropout, initialisation, input_dim, input_depth); network->kernel[0]->activation = activation; - network->kernel[0]->linearisation = 0; add_convolution(network, 6, 28, activation); add_2d_average_pooling(network, 14); add_convolution(network, 16, 10, activation); @@ -50,7 +50,6 @@ Network* create_network_lenet5(float learning_rate, int dropout, int activation, Network* create_simple_one(float learning_rate, int dropout, int activation, int initialisation, int input_dim, int input_depth) { Network* network = create_network(3, learning_rate, dropout, initialisation, input_dim, input_depth); network->kernel[0]->activation = activation; - network->kernel[0]->linearisation = 0; add_dense_linearisation(network, 80, activation); add_dense(network, 10, SOFTMAX); return network; @@ -112,6 +111,29 @@ void add_2d_average_pooling(Network* network, int dim_output) { network->kernel[k_pos]->nn = NULL; network->kernel[k_pos]->activation = IDENTITY; // Ne contient pas de fonction d'activation network->kernel[k_pos]->linearisation = 0; + network->kernel[k_pos]->pooling = 1; + create_a_cube_input_layer(network, n, network->depth[n-1], network->width[n-1]/2); + create_a_cube_input_z_layer(network, n, network->depth[n-1], network->width[n-1]/2); // Will it be used ? + network->size++; +} + +void add_2d_max_pooling(Network* network, int dim_output) { + int n = network->size; + int k_pos = n-1; + int dim_input = network->width[k_pos]; + if (network->max_size == n) { + printf("Impossible de rajouter une couche de max pooling, le réseau est déjà plein\n"); + return; + } + if (dim_input%dim_output != 0) { + printf("Erreur de dimension dans le max pooling\n"); + return; + } + network->kernel[k_pos]->cnn = NULL; + network->kernel[k_pos]->nn = NULL; + network->kernel[k_pos]->activation = IDENTITY; // Ne contient pas de fonction d'activation + network->kernel[k_pos]->linearisation = 0; + network->kernel[k_pos]->pooling = 2; create_a_cube_input_layer(network, n, network->depth[n-1], network->width[n-1]/2); create_a_cube_input_z_layer(network, n, network->depth[n-1], network->width[n-1]/2); // Will it be used ? network->size++; @@ -132,6 +154,7 @@ void add_convolution(Network* network, int depth_output, int dim_output, int act network->kernel[k_pos]->nn = NULL; network->kernel[k_pos]->activation = activation; network->kernel[k_pos]->linearisation = 0; + network->kernel[k_pos]->pooling = 0; network->kernel[k_pos]->cnn = (Kernel_cnn*)malloc(sizeof(Kernel_cnn)); Kernel_cnn* cnn = network->kernel[k_pos]->cnn; @@ -190,6 +213,7 @@ void add_dense(Network* network, int output_units, int activation) { Kernel_nn* nn = network->kernel[k_pos]->nn; network->kernel[k_pos]->activation = activation; network->kernel[k_pos]->linearisation = 0; + network->kernel[k_pos]->pooling = 0; nn->input_units = input_units; nn->output_units = output_units; nn->bias = (float*)malloc(sizeof(float)*output_units); @@ -228,6 +252,7 @@ void add_dense_linearisation(Network* network, int output_units, int activation) Kernel_nn* nn = network->kernel[k_pos]->nn; network->kernel[k_pos]->activation = activation; network->kernel[k_pos]->linearisation = 1; + network->kernel[k_pos]->pooling = 0; nn->input_units = input_units; nn->output_units = output_units; diff --git a/src/cnn/free.c b/src/cnn/free.c index 629b773..11837d7 100644 --- a/src/cnn/free.c +++ b/src/cnn/free.c @@ -25,7 +25,7 @@ void free_a_line_input_layer(Network* network, int pos) { free(network->input_z[pos]); } -void free_2d_average_pooling(Network* network, int pos) { +void free_2d_pooling(Network* network, int pos) { free_a_cube_input_layer(network, pos+1, network->depth[pos+1], network->width[pos+1]); } @@ -123,7 +123,7 @@ void free_network(Network* network) { free_dense_linearisation(network, i); } } else { // Pooling - free_2d_average_pooling(network, i); + free_2d_pooling(network, i); } } free_network_creation(network); diff --git a/src/cnn/include/creation.h b/src/cnn/include/creation.h index dda58b5..f993bb7 100644 --- a/src/cnn/include/creation.h +++ b/src/cnn/include/creation.h @@ -39,6 +39,11 @@ void create_a_line_input_layer(Network* network, int pos, int dim); */ void add_2d_average_pooling(Network* network, int dim_output); +/* +* Ajoute au réseau une couche de max pooling valide de dimension dim*dim +*/ +void add_2d_max_pooling(Network* network, int dim_output); + /* * Ajoute au réseau une couche de convolution dim*dim et initialise les kernels */ diff --git a/src/cnn/include/free.h b/src/cnn/include/free.h index 7551f34..92a5c3a 100644 --- a/src/cnn/include/free.h +++ b/src/cnn/include/free.h @@ -16,9 +16,9 @@ void free_a_cube_input_layer(Network* network, int pos, int depth, int dim); void free_a_line_input_layer(Network* network, int pos); /* -* Libère l'espace mémoire alloué dans 'add_2d_average_pooling' (creation.c) +* Libère l'espace mémoire alloué dans 'add_2d_average_pooling' ou 'add_2d_max_pooling' (creation.c) */ -void free_2d_average_pooling(Network* network, int pos); +void free_2d_pooling(Network* network, int pos); /* * Libère l'espace mémoire dans 'add_convolution' (creation.c) diff --git a/src/cnn/include/make.h b/src/cnn/include/make.h index 5a9dbe1..1c859e9 100644 --- a/src/cnn/include/make.h +++ b/src/cnn/include/make.h @@ -12,11 +12,17 @@ void make_convolution_cpu(Kernel_cnn* kernel, float*** input, float*** output, i * Effectue la convolution sur le CPU ou GPU */ void make_convolution(Kernel_cnn* kernel, float*** input, float*** output, int output_dim); + /* * Effectue un average pooling avec stride=size */ void make_average_pooling(float*** input, float*** output, int size, int output_depth, int output_dim); +/* +* Effectue un max pooling avec stride=size +*/ +void make_max_pooling(float*** input, float*** output, int size, int output_depth, int output_dim); + /* * Effectue une full connection */ diff --git a/src/cnn/include/struct.h b/src/cnn/include/struct.h index 619b7a7..c29d1a4 100644 --- a/src/cnn/include/struct.h +++ b/src/cnn/include/struct.h @@ -25,6 +25,7 @@ typedef struct Kernel { Kernel_nn* nn; // NULL si ce n'est pas un nn int activation; // Vaut l'identifiant de la fonction d'activation int linearisation; // Vaut 1 si c'est la linéarisation d'une couche, 0 sinon + int pooling; // 0 si pas pooling, 1 si average_pooling, 2 si max_pooling } Kernel; diff --git a/src/cnn/include/train.h b/src/cnn/include/train.h index 37ca0fe..7913060 100644 --- a/src/cnn/include/train.h +++ b/src/cnn/include/train.h @@ -6,8 +6,8 @@ #define EPOCHS 10 #define BATCHES 500 -#define USE_MULTITHREADING -#define LEARNING_RATE 0.01 +//#define USE_MULTITHREADING +#define LEARNING_RATE 0.05 /* diff --git a/src/cnn/make.c b/src/cnn/make.c index 29290cf..9aec661 100644 --- a/src/cnn/make.c +++ b/src/cnn/make.c @@ -1,9 +1,17 @@ #include +#include #include "../include/colors.h" #include "include/convolution.h" #include "include/make.h" +float max_flt(float a, float b) { + // Return the max between the two floats + if (a>b) { + return a; + } + return b; +} void make_average_pooling(float*** input, float*** output, int size, int output_depth, int output_dim) { // input[output_depth][output_dim+size-1][output_dim+size-1] @@ -25,6 +33,25 @@ void make_average_pooling(float*** input, float*** output, int size, int output_ } } +void make_max_pooling(float*** input, float*** output, int size, int output_depth, int output_dim) { + // input[output_depth][output_dim+size-1][output_dim+size-1] + // output[output_depth][output_dim][output_dim] + float m; + for (int i=0; i < output_depth; i++) { + for (int j=0; j < output_dim; j++) { + for (int k=0; k < output_dim; k++) { + m = FLT_MIN; + for (int a=0; a < size; a++) { + for (int b=0; b < size; b++) { + m = max_flt(m, input[i][size*j +a][size*k +b]); + } + } + output[i][j][k] = m; + } + } + } +} + void make_dense(Kernel_nn* kernel, float* input, float* output, int size_input, int size_output) { // input[size_input] // output[size_output]