diff --git a/Makefile b/Makefile index 2e01f9f..79a8140 100644 --- a/Makefile +++ b/Makefile @@ -65,10 +65,10 @@ $(BUILDDIR)/mnist_%.o: $(MNIST_SRCDIR)/%.c $(MNIST_SRCDIR)/include/%.h # cnn: $(BUILDDIR)/cnn-main $(BUILDDIR)/cnn-main-cuda $(BUILDDIR)/cnn-preview; -$(BUILDDIR)/cnn-main: $(CNN_SRCDIR)/main.c $(BUILDDIR)/cnn_train.o $(BUILDDIR)/cnn_cnn.o $(BUILDDIR)/cnn_creation.o $(BUILDDIR)/cnn_initialisation.o $(BUILDDIR)/cnn_make.o $(BUILDDIR)/cnn_neuron_io.o $(BUILDDIR)/cnn_function.o $(BUILDDIR)/cnn_utils.o $(BUILDDIR)/cnn_update.o $(BUILDDIR)/cnn_free.o $(BUILDDIR)/cnn_jpeg.o $(BUILDDIR)/cnn_convolution.o $(BUILDDIR)/cnn_backpropagation.o $(BUILDDIR)/colors.o $(BUILDDIR)/mnist.o +$(BUILDDIR)/cnn-main: $(CNN_SRCDIR)/main.c $(BUILDDIR)/cnn_train.o $(BUILDDIR)/cnn_test_network.o $(BUILDDIR)/cnn_cnn.o $(BUILDDIR)/cnn_creation.o $(BUILDDIR)/cnn_initialisation.o $(BUILDDIR)/cnn_make.o $(BUILDDIR)/cnn_neuron_io.o $(BUILDDIR)/cnn_function.o $(BUILDDIR)/cnn_utils.o $(BUILDDIR)/cnn_update.o $(BUILDDIR)/cnn_free.o $(BUILDDIR)/cnn_jpeg.o $(BUILDDIR)/cnn_convolution.o $(BUILDDIR)/cnn_backpropagation.o $(BUILDDIR)/colors.o $(BUILDDIR)/mnist.o $(CC) $^ -o $@ $(CFLAGS) -$(BUILDDIR)/cnn-main-cuda: $(BUILDDIR)/cnn_main.o $(BUILDDIR)/cnn_train.o $(BUILDDIR)/cnn_cnn.o $(BUILDDIR)/cnn_creation.o $(BUILDDIR)/cnn_initialisation.o $(BUILDDIR)/cnn_make.o $(BUILDDIR)/cnn_neuron_io.o $(BUILDDIR)/cnn_function.o $(BUILDDIR)/cnn_utils.o $(BUILDDIR)/cnn_update.o $(BUILDDIR)/cnn_free.o $(BUILDDIR)/cnn_jpeg.o $(BUILDDIR)/cnn_cuda_convolution.o $(BUILDDIR)/cnn_backpropagation.o $(BUILDDIR)/cuda_utils.o $(BUILDDIR)/colors.o $(BUILDDIR)/mnist.o +$(BUILDDIR)/cnn-main-cuda: $(BUILDDIR)/cnn_main.o $(BUILDDIR)/cnn_train.o $(BUILDDIR)/cnn_test_network.o $(BUILDDIR)/cnn_cnn.o $(BUILDDIR)/cnn_creation.o $(BUILDDIR)/cnn_initialisation.o $(BUILDDIR)/cnn_make.o $(BUILDDIR)/cnn_neuron_io.o $(BUILDDIR)/cnn_function.o $(BUILDDIR)/cnn_utils.o $(BUILDDIR)/cnn_update.o $(BUILDDIR)/cnn_free.o $(BUILDDIR)/cnn_jpeg.o $(BUILDDIR)/cnn_cuda_convolution.o $(BUILDDIR)/cnn_backpropagation.o $(BUILDDIR)/cuda_utils.o $(BUILDDIR)/colors.o $(BUILDDIR)/mnist.o ifndef NVCC_INSTALLED @echo "$(NVCC) not found, skipping" else @@ -105,7 +105,7 @@ endif # run-tests: build-tests $(foreach file, $(wildcard $(TEST_SRCDIR)/*.sh), $(file);) - @echo "$$(for file in build/test-*; do echo -e \\033[33m#####\\033[0m $$file \\033[33m#####\\033[0m; $$file; done)" + @echo "$$(for file in build/test-*; do echo -e \\033[33m#####\\033[0m $$file \\033[33m#####\\033[0m; $$file || echo "Erreur sur $$file"; done)" build-tests: prepare-tests $(TESTS_OBJ) $(BUILDDIR)/test-cnn_matrix_multiplication $(BUILDDIR)/test-cnn_convolution diff --git a/src/cnn/cnn.c b/src/cnn/cnn.c index 5feb795..9ebfbe9 100644 --- a/src/cnn/cnn.c +++ b/src/cnn/cnn.c @@ -16,6 +16,19 @@ // Augmente les dimensions de l'image d'entrée #define PADDING_INPUT 2 +int indice_max(float* tab, int n) { + int indice = -1; + float maxi = FLT_MIN; + + for (int i=0; i < n; i++) { + if (tab[i] > maxi) { + maxi = tab[i]; + indice = i; + } + } + return indice; +} + int will_be_drop(int dropout_prob) { return (rand() % 100) < dropout_prob; } diff --git a/src/cnn/include/cnn.h b/src/cnn/include/cnn.h index 0764257..884d13a 100644 --- a/src/cnn/include/cnn.h +++ b/src/cnn/include/cnn.h @@ -3,6 +3,11 @@ #ifndef DEF_MAIN_H #define DEF_MAIN_H +/* +* Renvoie l'indice de l'élément de valeur maximale dans un tableau de flottants +* Utilisé pour trouver le neurone le plus activé de la dernière couche (résultat de la classification) +*/ +int indice_max(float* tab, int n); /* * Renvoie si oui ou non (1 ou 0) le neurone va être abandonné diff --git a/src/cnn/include/test_network.h b/src/cnn/include/test_network.h new file mode 100644 index 0000000..1c924e9 --- /dev/null +++ b/src/cnn/include/test_network.h @@ -0,0 +1,25 @@ +#include "struct.h" + +#ifndef DEF_TEST_NETWORK_H +#define DEF_TEST_NETWORK_H + +/* +* Renvoie le taux de réussite d'un réseau sur des données de test +*/ +void test_network(int dataset_type, char* modele, char* images_file, char* labels_file, char* data_dir, bool preview_fails); + +/* +* Classifie un fichier d'images sous le format MNIST à partir d'un réseau préalablement entraîné +*/ +void recognize_mnist(Network* network, char* input_file); + +/* +* Classifie une image jpg à partir d'un réseau préalablement entraîné +*/ +void recognize_jpg(Network* network, char* input_file); + +/* +* Classifie une image à partir d'un réseau préalablement entraîné +*/ +void recognize(int dataset_type, char* modele, char* input_file); +#endif \ No newline at end of file diff --git a/src/cnn/include/train.h b/src/cnn/include/train.h index 2afc718..2cfe564 100644 --- a/src/cnn/include/train.h +++ b/src/cnn/include/train.h @@ -27,11 +27,6 @@ typedef struct TrainParameters { } TrainParameters; -/* -* Renvoie l'indice maximal d'un tableau tab de taille n -*/ -int indice_max(float* tab, int n); - /* * Fonction auxiliaire d'entraînement destinée à être exécutée sur plusieurs threads à la fois */ diff --git a/src/cnn/main.c b/src/cnn/main.c index e9cd7f4..07915df 100644 --- a/src/cnn/main.c +++ b/src/cnn/main.c @@ -2,9 +2,11 @@ #include #include #include +#include #include #include "include/initialisation.h" +#include "include/test_network.h" #include "../include/colors.h" #include "include/function.h" #include "include/creation.h" @@ -15,10 +17,8 @@ void help(char* call) { - printf("Usage: %s ( train | dev ) [OPTIONS]\n\n", call); + printf("Usage: %s ( train | recognize | test ) [OPTIONS]\n\n", call); printf("OPTIONS:\n"); - printf("\tdev:\n"); - printf("\t\t--conv | -c\tTester la fonction dev_conv().\n"); printf("\ttrain:\n"); printf("\t\t--dataset | -d (mnist|jpg)\tFormat du set de données.\n"); printf("\t(mnist)\t--images | -i [FILENAME]\tFichier contenant les images.\n"); @@ -26,12 +26,17 @@ void help(char* call) { printf("\t (jpg) \t--datadir | -dd [FOLDER]\tDossier contenant les images.\n"); printf("\t\t--epochs | -e [int]\t\tNombre d'époques.\n"); printf("\t\t--out | -o [FILENAME]\tFichier où écrire le réseau de neurones.\n"); -} - - -void dev_conv() { - Network* network = create_network_lenet5(0, 0, TANH, GLOROT, 32, 1); - forward_propagation(network); + printf("\trecognize:\n"); + printf("\t\t--dataset | -d (mnist|jpg)\tFormat de l'image à reconnaître.\n"); + printf("\t\t--modele | -m [FILENAME]\tFichier contenant le réseau entraîné.\n"); + printf("\t\t--input | -i [FILENAME]\tImage jpeg ou fichier binaire à reconnaître.\n"); + printf("\ttest:\n"); + printf("\t\t--modele | -m [FILENAME]\tFichier contenant le réseau entraîné.\n"); + printf("\t\t--dataset | -d (mnist|jpg)\tFormat du set de données.\n"); + printf("\t(mnist)\t--images | -i [FILENAME]\tFichier contenant les images.\n"); + printf("\t(mnist)\t--labels | -l [FILENAME]\tFichier contenant les labels.\n"); + printf("\t (jpg) \t--datadir | -dd [FOLDER]\tDossier contenant les images.\n"); + printf("\t\t--preview-fails | -p\t\tAfficher les images ayant échoué.\n"); } @@ -42,27 +47,6 @@ int main(int argc, char* argv[]) { help(argv[0]); return 1; } - if (! strcmp(argv[1], "dev")) { - int option = 0; - // 0 pour la fonction dev_conv() - int i = 2; - while (i < argc) { - // Utiliser un switch serait sans doute plus élégant - if ((! strcmp(argv[i], "--conv"))||(! strcmp(argv[i], "-c"))) { - option = 0; - i++; - } else { - printf("Option choisie inconnue: %s\n", argv[i]); - i++; - } - } - if (option == 0) { - dev_conv(); - return 0; - } - printf("Option choisie inconnue: dev %d\n", option); - return 1; - } if (! strcmp(argv[1], "train")) { char* dataset = NULL; char* images_file = NULL; @@ -130,6 +114,118 @@ int main(int argc, char* argv[]) { train(dataset_type, images_file, labels_file, data_dir, epochs, out); return 0; } + if (! strcmp(argv[1], "test")) { + char* dataset = NULL; // mnist ou jpg + char* modele = NULL; // Fichier contenant le modèle + char* images_file = NULL; // Fichier d'images (mnist) + char* labels_file = NULL; // Fichier de labels (mnist) + char* data_dir = NULL; // Dossier d'images (jpg) + int dataset_type; // Type de dataset (0 pour mnist, 1 pour jpg) + bool preview_fails = false; + int i = 2; + while (i < argc) { + if ((! strcmp(argv[i], "--dataset"))||(! strcmp(argv[i], "-d"))) { + dataset = argv[i+1]; + i += 2; + } + else if ((! strcmp(argv[i], "--modele"))||(! strcmp(argv[i], "-m"))) { + modele = argv[i+1]; + i += 2; + } + else if ((! strcmp(argv[i], "--images"))||(! strcmp(argv[i], "-i"))) { + images_file = argv[i+1]; + i += 2; + } + else if ((! strcmp(argv[i], "--labels"))||(! strcmp(argv[i], "-l"))) { + labels_file = argv[i+1]; + i += 2; + } + else if ((! strcmp(argv[i], "--datadir"))||(! strcmp(argv[i], "-dd"))) { + data_dir = argv[i+1]; + i += 2; + } + else if ((! strcmp(argv[i], "--preview-fails"))||(! strcmp(argv[i], "-p"))) { + preview_fails = true; + i++; + } + else { + printf("Option choisie inconnue: %s\n", argv[i]); + i++; + } + } + if ((dataset!=NULL) && !strcmp(dataset, "mnist")) { + dataset_type = 0; + if (!images_file) { + printf("Pas de fichier d'images spécifié\n"); + return 1; + } + if (!labels_file) { + printf("Pas de fichier de labels spécifié\n"); + return 1; + } + } + else if ((dataset!=NULL) && !strcmp(dataset, "jpg")) { + dataset_type = 1; + if (!data_dir) { + printf("Pas de dossier de données spécifié.\n"); + return 1; + } + } + else { + printf("Pas de type de dataset spécifié.\n"); + return 1; + } + + if (!modele) { + printf("Pas de modèle à utiliser spécifié.\n"); + return 1; + } + test_network(dataset_type, modele, images_file, labels_file, data_dir, preview_fails); + return 0; + } + if (! strcmp(argv[1], "recognize")) { + char* dataset = NULL; // mnist ou jpg + char* modele = NULL; // Fichier contenant le modèle + char* input_file = NULL; // Image à reconnaître + int dataset_type; + int i = 2; + while (i < argc) { + if ((! strcmp(argv[i], "--dataset"))||(! strcmp(argv[i], "-d"))) { + dataset = argv[i+1]; + i += 2; + } + else if ((! strcmp(argv[i], "--modele"))||(! strcmp(argv[i], "-m"))) { + modele = argv[i+1]; + i += 2; + } + else if ((! strcmp(argv[i], "--input"))||(! strcmp(argv[i], "-i"))) { + input_file = argv[i+1]; + i += 2; + } else { + printf("Option choisie inconnue: %s\n", argv[i]); + i++; + } + } + if ((dataset!=NULL) && !strcmp(dataset, "mnist")) { + dataset_type = 0; + } else if ((dataset!=NULL) && !strcmp(dataset, "jpg")) { + dataset_type = 1; + } + else { + printf("Pas de type de dataset spécifié.\n"); + return 1; + } + if (!input_file) { + printf("Pas de fichier d'entrée spécifié, rien à faire.\n"); + return 1; + } + if (!modele) { + printf("Pas de modèle à utiliser spécifié.\n"); + return 1; + } + recognize(dataset_type, modele, input_file); + return 0; + } printf("Option choisie non reconnue: %s\n", argv[1]); help(argv[0]); return 1; diff --git a/src/cnn/neuron_io.c b/src/cnn/neuron_io.c index 3b65560..b25865b 100644 --- a/src/cnn/neuron_io.c +++ b/src/cnn/neuron_io.c @@ -184,6 +184,20 @@ Network* read_network(char* filename) { } } } + + network->input_z = (float****)malloc(sizeof(float***)*size); + for (int i=0; i < (int)size; i++) { // input[size][couche->depth][couche->dim][couche->dim] + network->input_z[i] = (float***)malloc(sizeof(float**)*network->depth[i]); + for (int j=0; j < network->depth[i]; j++) { + network->input_z[i][j] = (float**)malloc(sizeof(float*)*network->width[i]); + for (int k=0; k < network->width[i]; k++) { + network->input_z[i][j][k] = (float*)malloc(sizeof(float)*network->width[i]); + for (int l=0; l < network->width[i]; l++) { + network->input_z[i][j][k][l] = 0.; + } + } + } + } fclose(ptr); return network; diff --git a/src/cnn/test_network.c b/src/cnn/test_network.c new file mode 100644 index 0000000..70b778b --- /dev/null +++ b/src/cnn/test_network.c @@ -0,0 +1,158 @@ +#include +#include +#include + +#include "../mnist/include/mnist.h" +#include "include/neuron_io.h" +#include "include/struct.h" +#include "include/jpeg.h" +#include "include/free.h" +#include "include/cnn.h" + + +void test_network_mnist(Network* network, char* images_file, char* labels_file, bool preview_fails) { + (void)preview_fails; // Inutilisé pour le moment + int width, height; // Dimensions des images + int nb_elem; // Nombre d'éléments + int maxi; // Catégorie reconnue + + int accuracy = 0; // Nombre d'images reconnues + + // Load image + int* mnist_parameters = read_mnist_images_parameters(images_file); + + int*** images = read_mnist_images(images_file); + unsigned int* labels = read_mnist_labels(labels_file); + + nb_elem = mnist_parameters[0]; + + width = mnist_parameters[1]; + height = mnist_parameters[2]; + free(mnist_parameters); + + // Load image in the first layer of the Network + for (int i=0; i < nb_elem; i++) { + if(i %(nb_elem/100) == 0) { + printf("Avancement: %.0f%%\r", 100*i/(float)nb_elem); + fflush(stdout); + } + write_image_in_network_32(images[i], height, width, network->input[0][0]); + forward_propagation(network); + maxi = indice_max(network->input[network->size-1][0][0], 10); + + if (maxi == (int)labels[i]) { + accuracy++; + } + + for (int j=0; j < height; j++) { + free(images[i][j]); + } + free(images[i]); + } + free(images); + printf("%d Images. Taux de réussite: %.2f%%\n", nb_elem, 100*accuracy/(float)nb_elem); +} + + +void test_network_jpg(Network* network, char* data_dir, bool preview_fails) { + (void)preview_fails; // Inutilisé pour le moment + jpegDataset* dataset = loadJpegDataset(data_dir); + + int accuracy = 0; + int maxi; + + for (int i=0; i < (int)dataset->numImages; i++) { + if(i %(dataset->numImages/100) == 0) { + printf("Avancement: %.1f%%\r", 1000*i/(float)dataset->numImages); + fflush(stdout); + } + write_image_in_network_260(dataset->images[i], dataset->height, dataset->height, network->input[0]); + forward_propagation(network); + maxi = indice_max(network->input[network->size-1][0][0], 50); + + if (maxi == (int)dataset->labels[i]) { + accuracy++; + } + + free(dataset->images[i]); + } + + printf("%d Images. Taux de réussite: %.2f%%\n", dataset->numImages, 100*accuracy/(float)dataset->numImages); + free(dataset->images); + free(dataset->labels); + free(dataset); +} + + +void test_network(int dataset_type, char* modele, char* images_file, char* labels_file, char* data_dir, bool preview_fails) { + Network* network = read_network(modele); + + if (dataset_type == 0) { + test_network_mnist(network, images_file, labels_file, preview_fails); + } else { + test_network_jpg(network, data_dir, preview_fails); + } + + free_network(network); +} + + +void recognize_mnist(Network* network, char* input_file) { + int width, height; // Dimensions de l'image + int nb_elem; // Nombre d'éléments + int maxi; // Catégorie reconnue + + // Load image + int* mnist_parameters = read_mnist_images_parameters(input_file); + int*** images = read_mnist_images(input_file); + nb_elem = mnist_parameters[0]; + + width = mnist_parameters[1]; + height = mnist_parameters[2]; + free(mnist_parameters); + + printf("Image\tCatégorie détectée\n"); + // Load image in the first layer of the Network + for (int i=0; i < nb_elem; i++) { + write_image_in_network_32(images[i], height, width, network->input[0][0]); + forward_propagation(network); + maxi = indice_max(network->input[network->size-1][0][0], 10); + + printf("%d\t%d\n", i, maxi); + + for (int j=0; j < height; j++) { + free(images[i][j]); + } + free(images[i]); + } + free(images); +} + +void recognize_jpg(Network* network, char* input_file) { + int width, height; // Dimensions de l'image + int maxi; + + imgRawImage* image = loadJpegImageFile(input_file); + width = image->width; + height = image->height; + + write_image_in_network_260(image->lpData, height, width, network->input[0]); + forward_propagation(network); + maxi = indice_max(network->input[network->size-1][0][0], 50); + + printf("Catégorie reconnue: %d\n", maxi); + free(image->lpData); + free(image); +} + +void recognize(int dataset_type, char* modele, char* input_file) { + Network* network = read_network(modele); + + if (dataset_type == 0) { + recognize_mnist(network, input_file); + } else { + recognize_jpg(network, input_file); + } + + free_network(network); +} \ No newline at end of file diff --git a/src/cnn/train.c b/src/cnn/train.c index a5bcf02..b7761b0 100644 --- a/src/cnn/train.c +++ b/src/cnn/train.c @@ -19,18 +19,8 @@ #include "include/train.h" - -int indice_max(float* tab, int n) { - int indice = -1; - float maxi = FLT_MIN; - - for (int i=0; i < n; i++) { - if (tab[i] > maxi) { - maxi = tab[i]; - indice = i; - } - } - return indice; +int div_up(int a, int b) { // Partie entière supérieure de a/b + return ((a % b) != 0) ? (a / b + 1) : (a / b); } @@ -91,7 +81,9 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di float accuracy; float current_accuracy; - int nb_images_total; + int nb_images_total; // Images au total + int nb_images_total_remaining; // Images restantes dans un batch + int batches_epoques; // Batches par époque int*** images; unsigned int* labels; @@ -180,9 +172,17 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di // du multi-threading car chaque copie du réseau initiale sera légèrement différente // et donnera donc des résultats différents sur les mêmes images. accuracy = 0.; - for (int j=0; j < nb_images_total / BATCHES; j++) { + batches_epoques = div_up(nb_images_total, BATCHES); + nb_images_total_remaining = nb_images_total; + for (int j=0; j < batches_epoques; j++) { #ifdef USE_MULTITHREADING - nb_remaining_images = BATCHES; + if (j == batches_epoques-1) { + nb_remaining_images = nb_images_total_remaining; + nb_images_total_remaining = 0; + } else { + nb_images_total_remaining -= BATCHES; + nb_remaining_images = BATCHES; + } for (int k=0; k < nb_threads; k++) { if (k == nb_threads-1) { @@ -191,8 +191,9 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di } else { nb_remaining_images -= BATCHES / nb_threads; } + train_parameters[k]->start = BATCHES*j + (BATCHES/nb_threads)*k; train_parameters[k]->network = copy_network(network); - train_parameters[k]->start = BATCHES*j + (nb_images_total/BATCHES)*k; + pthread_create( &tid[k], NULL, train_thread, (void*) train_parameters[k]); } for (int k=0; k < nb_threads; k++) { @@ -206,6 +207,7 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di } current_accuracy = accuracy * nb_images_total/((j+1)*BATCHES); printf("\rThreads [%d]\tÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: "YELLOW"%0.1f%%"RESET" ", nb_threads, i, epochs, BATCHES*(j+1), nb_images_total, current_accuracy*100); + fflush(stdout); #else train_params->start = j*BATCHES; diff --git a/src/mnist/include/main.h b/src/mnist/include/main.h index fb69e8c..57718e8 100644 --- a/src/mnist/include/main.h +++ b/src/mnist/include/main.h @@ -1,3 +1,5 @@ +#include "neural_network.h" + #ifndef DEF_MAIN_H #define DEF_MAIN_H @@ -49,6 +51,16 @@ void* train_thread(void* parameters); */ void train(int epochs, int layers, int neurons, char* recovery, char* image_file, char* label_file, char* out, char* delta, int nb_images_to_process, int start); +/* +* Échange deux éléments d'un tableau +*/ +void swap(int* tab, int i, int j); + +/* +* Mélange un tableau avec le mélange de Knuth +*/ +void knuth_shuffle(int* tab, int n); + /* * Reconnaissance d'un set d'images, renvoie un tableau de float contentant les prédictions * modele: nom du fichier contenant le réseau neuronal diff --git a/src/mnist/main.c b/src/mnist/main.c index 9d4cb57..3a199dc 100644 --- a/src/mnist/main.c +++ b/src/mnist/main.c @@ -6,6 +6,7 @@ #include #include +#include "include/main.h" #include "include/mnist.h" #include "include/neuron_io.h" #include "include/neural_network.h" @@ -20,6 +21,7 @@ typedef struct TrainParameters { Network* network; int*** images; int* labels; + int* shuffle_indices; int start; int nb_images; int height; @@ -97,6 +99,7 @@ void* train_thread(void* parameters) { int*** images = param->images; int* labels = param->labels; + int* shuffle = param->shuffle_indices; int start = param->start; int nb_images = param->nb_images; @@ -107,15 +110,15 @@ void* train_thread(void* parameters) { int* desired_output; for (int i=start; i < start+nb_images; i++) { - write_image_in_network(images[i], network, height, width); - desired_output = desired_output_creation(network, labels[i]); + write_image_in_network(images[shuffle[i]], network, height, width); + desired_output = desired_output_creation(network, labels[shuffle[i]]); forward_propagation(network); backward_propagation(network, desired_output); for (int k=0; k < nb_neurons_last_layer; k++) { sortie[k] = last_layer->neurons[k]->z; } - if (indice_max(sortie, nb_neurons_last_layer) == labels[i]) { + if (indice_max(sortie, nb_neurons_last_layer) == labels[shuffle[i]]) { accuracy += 1.; } free(desired_output); @@ -134,7 +137,7 @@ void train(int epochs, int layers, int neurons, char* recovery, char* image_file //int* repartition = malloc(sizeof(int)*layers); int nb_neurons_last_layer = 10; - int repartition[2] = {neurons, nb_neurons_last_layer}; + int repartition[3] = {neurons, 42, nb_neurons_last_layer}; float accuracy; @@ -178,6 +181,11 @@ void train(int epochs, int layers, int neurons, char* recovery, char* image_file int*** images = read_mnist_images(image_file); unsigned int* labels = read_mnist_labels(label_file); + + int* shuffle_indices = (int*)malloc(sizeof(int)*nb_images_total); + for (int i=0; i < nb_images_total; i++) { + shuffle_indices[i] = i; + } if (nb_images_to_process != -1) { nb_images_total = nb_images_to_process; @@ -191,9 +199,11 @@ void train(int epochs, int layers, int neurons, char* recovery, char* image_file train_parameters[j]->height = height; train_parameters[j]->width = width; train_parameters[j]->nb_images = BATCHES / nb_threads; + train_parameters[j]->shuffle_indices = shuffle_indices; } for (int i=0; i < epochs; i++) { + knuth_shuffle(shuffle_indices, nb_images_total); // Shuffle images between each epoch accuracy = 0.; for (int k=0; k < nb_images_total / BATCHES; k++) { nb_remaining_images = BATCHES; @@ -220,6 +230,7 @@ void train(int epochs, int layers, int neurons, char* recovery, char* image_file deletion_of_network(train_parameters[j]->network); } printf("\rThreads [%d]\tÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: %0.1f%%", nb_threads, i, epochs, BATCHES*(k+1), nb_images_total, accuracy*100); + fflush(stdout); } printf("\rThreads [%d]\tÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: %0.1f%%\n", nb_threads, i, epochs, nb_images_total, nb_images_total, accuracy*100); write_network(out, network); @@ -239,6 +250,18 @@ void train(int epochs, int layers, int neurons, char* recovery, char* image_file free(tid); } +void swap(int* tab, int i, int j) { + int tmp = tab[i]; + tab[i] = tab[j]; + tab[j] = tmp; +} + +void knuth_shuffle(int* tab, int n) { + for(int i=1; i < n; i++) { + swap(tab, i, rand() %i); + } +} + float** recognize(char* modele, char* entree) { Network* network = read_network(modele); Layer* last_layer = network->layers[network->nb_layers-1]; @@ -351,7 +374,7 @@ int main(int argc, char* argv[]) { } if (! strcmp(argv[1], "train")) { int epochs = EPOCHS; - int layers = 2; + int layers = 3; int neurons = 784; int nb_images = -1; int start = 0; diff --git a/src/mnist/neural_network.c b/src/mnist/neural_network.c index 652aa82..6e40ccd 100644 --- a/src/mnist/neural_network.c +++ b/src/mnist/neural_network.c @@ -10,7 +10,7 @@ // Définit le taux d'apprentissage du réseau neuronal, donc la rapidité d'adaptation du modèle (compris entre 0 et 1) // Cette valeur peut évoluer au fur et à mesure des époques (linéaire c'est mieux) -#define LEARNING_RATE 0.5 +#define LEARNING_RATE 0.1 // Retourne un nombre aléatoire entre 0 et 1 #define RAND_DOUBLE() ((double)rand())/((double)RAND_MAX) //Coefficient leaking ReLU