This commit is contained in:
julienChemillier 2022-12-07 10:27:52 +01:00
commit c74d3f574b
12 changed files with 403 additions and 60 deletions

View File

@ -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; 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) $(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 ifndef NVCC_INSTALLED
@echo "$(NVCC) not found, skipping" @echo "$(NVCC) not found, skipping"
else else
@ -105,7 +105,7 @@ endif
# #
run-tests: build-tests run-tests: build-tests
$(foreach file, $(wildcard $(TEST_SRCDIR)/*.sh), $(file);) $(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 build-tests: prepare-tests $(TESTS_OBJ) $(BUILDDIR)/test-cnn_matrix_multiplication $(BUILDDIR)/test-cnn_convolution

View File

@ -16,6 +16,19 @@
// Augmente les dimensions de l'image d'entrée // Augmente les dimensions de l'image d'entrée
#define PADDING_INPUT 2 #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) { int will_be_drop(int dropout_prob) {
return (rand() % 100) < dropout_prob; return (rand() % 100) < dropout_prob;
} }

View File

@ -3,6 +3,11 @@
#ifndef DEF_MAIN_H #ifndef DEF_MAIN_H
#define 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é * Renvoie si oui ou non (1 ou 0) le neurone va être abandonné

View File

@ -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

View File

@ -27,11 +27,6 @@ typedef struct TrainParameters {
} 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 * Fonction auxiliaire d'entraînement destinée à être exécutée sur plusieurs threads à la fois
*/ */

View File

@ -2,9 +2,11 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <stdbool.h>
#include <float.h> #include <float.h>
#include "include/initialisation.h" #include "include/initialisation.h"
#include "include/test_network.h"
#include "../include/colors.h" #include "../include/colors.h"
#include "include/function.h" #include "include/function.h"
#include "include/creation.h" #include "include/creation.h"
@ -15,10 +17,8 @@
void help(char* call) { 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("OPTIONS:\n");
printf("\tdev:\n");
printf("\t\t--conv | -c\tTester la fonction dev_conv().\n");
printf("\ttrain:\n"); printf("\ttrain:\n");
printf("\t\t--dataset | -d (mnist|jpg)\tFormat du set de données.\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--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 (jpg) \t--datadir | -dd [FOLDER]\tDossier contenant les images.\n");
printf("\t\t--epochs | -e [int]\t\tNombre d'époques.\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"); printf("\t\t--out | -o [FILENAME]\tFichier où écrire le réseau de neurones.\n");
} 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");
void dev_conv() { printf("\t\t--input | -i [FILENAME]\tImage jpeg ou fichier binaire à reconnaître.\n");
Network* network = create_network_lenet5(0, 0, TANH, GLOROT, 32, 1); printf("\ttest:\n");
forward_propagation(network); 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]); help(argv[0]);
return 1; 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")) { if (! strcmp(argv[1], "train")) {
char* dataset = NULL; char* dataset = NULL;
char* images_file = 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); train(dataset_type, images_file, labels_file, data_dir, epochs, out);
return 0; 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]); printf("Option choisie non reconnue: %s\n", argv[1]);
help(argv[0]); help(argv[0]);
return 1; return 1;

View File

@ -185,6 +185,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); fclose(ptr);
return network; return network;
} }

158
src/cnn/test_network.c Normal file
View File

@ -0,0 +1,158 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#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);
}

View File

@ -19,18 +19,8 @@
#include "include/train.h" #include "include/train.h"
int div_up(int a, int b) { // Partie entière supérieure de a/b
int indice_max(float* tab, int n) { return ((a % b) != 0) ? (a / b + 1) : (a / b);
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;
} }
@ -91,7 +81,9 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di
float accuracy; float accuracy;
float current_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; int*** images;
unsigned int* labels; 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 // 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. // et donnera donc des résultats différents sur les mêmes images.
accuracy = 0.; 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 #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++) { for (int k=0; k < nb_threads; k++) {
if (k == nb_threads-1) { if (k == nb_threads-1) {
@ -191,8 +191,9 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di
} else { } else {
nb_remaining_images -= BATCHES / nb_threads; 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]->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]); pthread_create( &tid[k], NULL, train_thread, (void*) train_parameters[k]);
} }
for (int k=0; k < nb_threads; 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); 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); 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 #else
train_params->start = j*BATCHES; train_params->start = j*BATCHES;

View File

@ -1,3 +1,5 @@
#include "neural_network.h"
#ifndef DEF_MAIN_H #ifndef DEF_MAIN_H
#define 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); 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 * Reconnaissance d'un set d'images, renvoie un tableau de float contentant les prédictions
* modele: nom du fichier contenant le réseau neuronal * modele: nom du fichier contenant le réseau neuronal

View File

@ -6,6 +6,7 @@
#include <pthread.h> #include <pthread.h>
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#include "include/main.h"
#include "include/mnist.h" #include "include/mnist.h"
#include "include/neuron_io.h" #include "include/neuron_io.h"
#include "include/neural_network.h" #include "include/neural_network.h"
@ -20,6 +21,7 @@ typedef struct TrainParameters {
Network* network; Network* network;
int*** images; int*** images;
int* labels; int* labels;
int* shuffle_indices;
int start; int start;
int nb_images; int nb_images;
int height; int height;
@ -97,6 +99,7 @@ void* train_thread(void* parameters) {
int*** images = param->images; int*** images = param->images;
int* labels = param->labels; int* labels = param->labels;
int* shuffle = param->shuffle_indices;
int start = param->start; int start = param->start;
int nb_images = param->nb_images; int nb_images = param->nb_images;
@ -107,15 +110,15 @@ void* train_thread(void* parameters) {
int* desired_output; int* desired_output;
for (int i=start; i < start+nb_images; i++) { for (int i=start; i < start+nb_images; i++) {
write_image_in_network(images[i], network, height, width); write_image_in_network(images[shuffle[i]], network, height, width);
desired_output = desired_output_creation(network, labels[i]); desired_output = desired_output_creation(network, labels[shuffle[i]]);
forward_propagation(network); forward_propagation(network);
backward_propagation(network, desired_output); backward_propagation(network, desired_output);
for (int k=0; k < nb_neurons_last_layer; k++) { for (int k=0; k < nb_neurons_last_layer; k++) {
sortie[k] = last_layer->neurons[k]->z; 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.; accuracy += 1.;
} }
free(desired_output); 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* repartition = malloc(sizeof(int)*layers);
int nb_neurons_last_layer = 10; 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; float accuracy;
@ -179,6 +182,11 @@ void train(int epochs, int layers, int neurons, char* recovery, char* image_file
int*** images = read_mnist_images(image_file); int*** images = read_mnist_images(image_file);
unsigned int* labels = read_mnist_labels(label_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) { if (nb_images_to_process != -1) {
nb_images_total = nb_images_to_process; 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]->height = height;
train_parameters[j]->width = width; train_parameters[j]->width = width;
train_parameters[j]->nb_images = BATCHES / nb_threads; train_parameters[j]->nb_images = BATCHES / nb_threads;
train_parameters[j]->shuffle_indices = shuffle_indices;
} }
for (int i=0; i < epochs; i++) { for (int i=0; i < epochs; i++) {
knuth_shuffle(shuffle_indices, nb_images_total); // Shuffle images between each epoch
accuracy = 0.; accuracy = 0.;
for (int k=0; k < nb_images_total / BATCHES; k++) { for (int k=0; k < nb_images_total / BATCHES; k++) {
nb_remaining_images = BATCHES; 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); 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); 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); 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); write_network(out, network);
@ -239,6 +250,18 @@ void train(int epochs, int layers, int neurons, char* recovery, char* image_file
free(tid); 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) { float** recognize(char* modele, char* entree) {
Network* network = read_network(modele); Network* network = read_network(modele);
Layer* last_layer = network->layers[network->nb_layers-1]; Layer* last_layer = network->layers[network->nb_layers-1];
@ -351,7 +374,7 @@ int main(int argc, char* argv[]) {
} }
if (! strcmp(argv[1], "train")) { if (! strcmp(argv[1], "train")) {
int epochs = EPOCHS; int epochs = EPOCHS;
int layers = 2; int layers = 3;
int neurons = 784; int neurons = 784;
int nb_images = -1; int nb_images = -1;
int start = 0; int start = 0;

View File

@ -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) // 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) // 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 // Retourne un nombre aléatoire entre 0 et 1
#define RAND_DOUBLE() ((double)rand())/((double)RAND_MAX) #define RAND_DOUBLE() ((double)rand())/((double)RAND_MAX)
//Coefficient leaking ReLU //Coefficient leaking ReLU