Add recognize option

This commit is contained in:
augustin64 2022-11-25 15:17:47 +01:00
parent 88bec19189
commit 7da3544d8b
8 changed files with 250 additions and 51 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;
$(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

View File

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

View File

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

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;
/*
* 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
*/

View File

@ -2,9 +2,11 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <float.h>
#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;

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

@ -0,0 +1,75 @@
#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(int dataset_type, char* modele, char* images_file, char* labels_file, char* data_dir, bool preview_fails) {
}
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"
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);
}
@ -182,7 +172,7 @@ 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.;
batches_epoques = nb_images_total / BATCHES;
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