2022-04-07 22:07:32 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2022-04-11 19:57:09 +02:00
|
|
|
#include <float.h>
|
2022-06-23 22:54:49 +02:00
|
|
|
#include <stdbool.h>
|
2022-05-14 10:35:03 +02:00
|
|
|
#include <pthread.h>
|
|
|
|
#include <sys/sysinfo.h>
|
2022-04-07 22:07:32 +02:00
|
|
|
|
2022-11-30 11:24:37 +01:00
|
|
|
#include "include/main.h"
|
2022-09-30 15:44:28 +02:00
|
|
|
#include "include/mnist.h"
|
2023-01-13 15:58:46 +01:00
|
|
|
#include "../include/colors.h"
|
2022-09-30 15:44:28 +02:00
|
|
|
#include "include/neuron_io.h"
|
|
|
|
#include "include/neural_network.h"
|
2022-06-01 21:31:32 +02:00
|
|
|
|
2022-05-13 15:28:45 +02:00
|
|
|
#define EPOCHS 10
|
2022-04-30 09:31:52 +02:00
|
|
|
#define BATCHES 100
|
|
|
|
|
2022-09-30 15:44:28 +02:00
|
|
|
/*
|
2022-10-01 17:53:14 +02:00
|
|
|
* Structure donnée en argument à la fonction 'train_thread'
|
2022-09-30 15:44:28 +02:00
|
|
|
*/
|
|
|
|
typedef struct TrainParameters {
|
|
|
|
Network* network;
|
|
|
|
int*** images;
|
|
|
|
int* labels;
|
2022-11-30 11:24:37 +01:00
|
|
|
int* shuffle_indices;
|
2022-09-30 15:44:28 +02:00
|
|
|
int start;
|
|
|
|
int nb_images;
|
|
|
|
int height;
|
|
|
|
int width;
|
|
|
|
float accuracy;
|
|
|
|
} TrainParameters;
|
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
|
2022-04-26 16:47:43 +02:00
|
|
|
void print_image(unsigned int width, unsigned int height, int** image, float* previsions) {
|
|
|
|
char tab[] = {' ', '.', ':', '%', '#', '\0'};
|
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
for (int i=0; i < (int)height; i++) {
|
|
|
|
for (int j=0; j < (int)width; j++) {
|
2022-04-26 16:47:43 +02:00
|
|
|
printf("%c", tab[image[i][j]/52]);
|
|
|
|
}
|
|
|
|
if (i < 10) {
|
|
|
|
printf("\t%d : %f", i, previsions[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
2022-04-08 15:53:29 +02:00
|
|
|
|
2022-04-10 21:28:54 +02:00
|
|
|
int indice_max(float* tab, int n) {
|
|
|
|
int indice = -1;
|
2022-04-11 19:57:09 +02:00
|
|
|
float maxi = FLT_MIN;
|
2022-04-10 21:28:54 +02:00
|
|
|
|
|
|
|
for (int i=0; i < n; i++) {
|
|
|
|
if (tab[i] > maxi) {
|
|
|
|
maxi = tab[i];
|
|
|
|
indice = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return indice;
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:07:32 +02:00
|
|
|
void help(char* call) {
|
2022-05-03 10:02:47 +02:00
|
|
|
printf("Usage: %s ( train | recognize | test ) [OPTIONS]\n\n", call);
|
2022-04-07 22:07:32 +02:00
|
|
|
printf("OPTIONS:\n");
|
|
|
|
printf("\ttrain:\n");
|
2022-05-19 22:26:19 +02:00
|
|
|
printf("\t\t--epochs | -e [int]\tNombre d'époques (itérations sur tout le set de données).\n");
|
2022-04-30 09:31:52 +02:00
|
|
|
printf("\t\t--couches | -c [int]\tNombres de couches.\n");
|
|
|
|
printf("\t\t--neurones | -n [int]\tNombre de neurones sur la première couche.\n");
|
2022-04-08 19:34:26 +02:00
|
|
|
printf("\t\t--recover | -r [FILENAME]\tRécupérer depuis un modèle existant.\n");
|
2022-04-08 15:53:29 +02:00
|
|
|
printf("\t\t--images | -i [FILENAME]\tFichier contenant les images.\n");
|
|
|
|
printf("\t\t--labels | -l [FILENAME]\tFichier contenant les labels.\n");
|
2022-04-30 09:31:52 +02:00
|
|
|
printf("\t\t--out | -o [FILENAME]\tFichier où écrire le réseau de neurones.\n");
|
2022-05-19 22:26:19 +02:00
|
|
|
printf("\t\t--delta | -d [FILENAME]\tFichier où écrire le réseau différentiel.\n");
|
2022-05-20 19:40:12 +02:00
|
|
|
printf("\t\t--nb-images | -N [int]\tNombres d'images à traiter.\n");
|
|
|
|
printf("\t\t--start | -s [int]\tPremière image à traiter.\n");
|
2022-04-07 22:07:32 +02:00
|
|
|
printf("\trecognize:\n");
|
2022-04-30 09:31:52 +02:00
|
|
|
printf("\t\t--modele | -m [FILENAME]\tFichier contenant le réseau de neurones.\n");
|
2022-04-14 13:02:09 +02:00
|
|
|
printf("\t\t--in | -i [FILENAME]\tFichier contenant les images à reconnaître.\n");
|
|
|
|
printf("\t\t--out | -o (text|json)\tFormat de sortie.\n");
|
|
|
|
printf("\ttest:\n");
|
|
|
|
printf("\t\t--images | -i [FILENAME]\tFichier contenant les images.\n");
|
|
|
|
printf("\t\t--labels | -l [FILENAME]\tFichier contenant les labels.\n");
|
2022-04-30 09:31:52 +02:00
|
|
|
printf("\t\t--modele | -m [FILENAME]\tFichier contenant le réseau de neurones.\n");
|
2022-04-26 16:47:43 +02:00
|
|
|
printf("\t\t--preview-fails | -p\tAfficher les images ayant échoué.\n");
|
2022-04-08 15:53:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-25 14:39:45 +02:00
|
|
|
void write_image_in_network(int** image, Network* network, int height, int width) {
|
2022-04-08 15:53:29 +02:00
|
|
|
for (int i=0; i < height; i++) {
|
|
|
|
for (int j=0; j < width; j++) {
|
2022-04-25 14:39:45 +02:00
|
|
|
network->layers[0]->neurons[i*height+j]->z = (float)image[i][j] / 255.0f;
|
2022-04-08 15:53:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-01 17:53:14 +02:00
|
|
|
void* train_thread(void* parameters) {
|
2022-05-14 10:35:03 +02:00
|
|
|
TrainParameters* param = (TrainParameters*)parameters;
|
|
|
|
Network* network = param->network;
|
|
|
|
Layer* last_layer = network->layers[network->nb_layers-1];
|
|
|
|
int nb_neurons_last_layer = last_layer->nb_neurons;
|
|
|
|
|
|
|
|
int*** images = param->images;
|
|
|
|
int* labels = param->labels;
|
2022-11-30 11:24:37 +01:00
|
|
|
int* shuffle = param->shuffle_indices;
|
2022-05-14 10:35:03 +02:00
|
|
|
|
|
|
|
int start = param->start;
|
|
|
|
int nb_images = param->nb_images;
|
|
|
|
int height = param->height;
|
|
|
|
int width = param->width;
|
|
|
|
float accuracy = 0.;
|
|
|
|
float* sortie = (float*)malloc(sizeof(float)*nb_neurons_last_layer);
|
|
|
|
int* desired_output;
|
|
|
|
|
|
|
|
for (int i=start; i < start+nb_images; i++) {
|
2022-11-30 11:24:37 +01:00
|
|
|
write_image_in_network(images[shuffle[i]], network, height, width);
|
|
|
|
desired_output = desired_output_creation(network, labels[shuffle[i]]);
|
2022-05-14 10:35:03 +02:00
|
|
|
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;
|
|
|
|
}
|
2022-11-30 11:24:37 +01:00
|
|
|
if (indice_max(sortie, nb_neurons_last_layer) == labels[shuffle[i]]) {
|
2022-05-14 10:35:03 +02:00
|
|
|
accuracy += 1.;
|
|
|
|
}
|
|
|
|
free(desired_output);
|
|
|
|
}
|
|
|
|
free(sortie);
|
|
|
|
param->accuracy = accuracy;
|
2022-06-01 17:14:41 +02:00
|
|
|
|
|
|
|
return NULL;
|
2022-05-14 10:35:03 +02:00
|
|
|
}
|
|
|
|
|
2022-04-08 15:53:29 +02:00
|
|
|
|
2022-05-20 19:40:12 +02:00
|
|
|
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) {
|
2022-04-08 16:07:44 +02:00
|
|
|
// Entraînement du réseau sur le set de données MNIST
|
2022-04-25 14:39:45 +02:00
|
|
|
Network* network;
|
2022-05-19 22:26:19 +02:00
|
|
|
Network* delta_network;
|
2022-04-08 15:53:29 +02:00
|
|
|
|
2022-04-25 14:39:45 +02:00
|
|
|
//int* repartition = malloc(sizeof(int)*layers);
|
2022-05-14 10:35:03 +02:00
|
|
|
int nb_neurons_last_layer = 10;
|
2022-11-30 11:24:37 +01:00
|
|
|
int repartition[3] = {neurons, 42, nb_neurons_last_layer};
|
2022-04-10 21:28:54 +02:00
|
|
|
|
|
|
|
float accuracy;
|
2023-01-13 15:58:46 +01:00
|
|
|
float current_accuracy;
|
2022-05-14 10:35:03 +02:00
|
|
|
|
|
|
|
int nb_threads = get_nprocs();
|
|
|
|
pthread_t *tid = (pthread_t *)malloc(nb_threads * sizeof(pthread_t));
|
2022-04-08 15:53:29 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* On repart d'un réseau déjà créée stocké dans un fichier
|
|
|
|
* ou on repart de zéro si aucune backup n'est fournie
|
|
|
|
* */
|
|
|
|
if (! recovery) {
|
2022-05-14 10:35:03 +02:00
|
|
|
network = (Network*)malloc(sizeof(Network));
|
2022-04-25 14:39:45 +02:00
|
|
|
network_creation(network, repartition, layers);
|
|
|
|
network_initialisation(network);
|
2022-04-08 15:53:29 +02:00
|
|
|
} else {
|
2022-04-25 14:39:45 +02:00
|
|
|
network = read_network(recovery);
|
2022-04-08 19:34:26 +02:00
|
|
|
printf("Backup restaurée.\n");
|
2022-04-08 15:53:29 +02:00
|
|
|
}
|
|
|
|
|
2022-05-19 22:26:19 +02:00
|
|
|
if (delta != NULL) {
|
|
|
|
// On initialise un réseau complet mais la seule partie qui nous intéresse est la partie différentielle
|
|
|
|
delta_network = (Network*)malloc(sizeof(Network));
|
|
|
|
|
|
|
|
int* repart = (int*)malloc(sizeof(network->nb_layers));
|
|
|
|
for (int i=0; i < network->nb_layers; i++) {
|
|
|
|
repart[i] = network->layers[i]->nb_neurons;
|
|
|
|
}
|
|
|
|
|
|
|
|
network_creation(delta_network, repart, network->nb_layers);
|
|
|
|
network_initialisation(delta_network);
|
|
|
|
free(repart);
|
|
|
|
}
|
|
|
|
|
2022-04-08 15:53:29 +02:00
|
|
|
// Chargement des images du set de données MNIST
|
|
|
|
int* parameters = read_mnist_images_parameters(image_file);
|
2022-05-14 10:35:03 +02:00
|
|
|
int nb_images_total = parameters[0];
|
|
|
|
int nb_remaining_images = 0; // Nombre d'images restantes dans un batch
|
2022-04-08 15:53:29 +02:00
|
|
|
int height = parameters[1];
|
|
|
|
int width = parameters[2];
|
2022-10-01 17:53:14 +02:00
|
|
|
free(parameters);
|
2022-04-08 15:53:29 +02:00
|
|
|
|
|
|
|
int*** images = read_mnist_images(image_file);
|
|
|
|
unsigned int* labels = read_mnist_labels(label_file);
|
2022-11-30 11:24:37 +01:00
|
|
|
|
|
|
|
int* shuffle_indices = (int*)malloc(sizeof(int)*nb_images_total);
|
|
|
|
for (int i=0; i < nb_images_total; i++) {
|
|
|
|
shuffle_indices[i] = i;
|
|
|
|
}
|
2022-04-08 15:53:29 +02:00
|
|
|
|
2022-05-20 19:40:12 +02:00
|
|
|
if (nb_images_to_process != -1) {
|
|
|
|
nb_images_total = nb_images_to_process;
|
|
|
|
}
|
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
TrainParameters** train_parameters = (TrainParameters**)malloc(sizeof(TrainParameters*)*nb_threads);
|
2022-10-01 17:53:14 +02:00
|
|
|
for (int j=0; j < nb_threads; j++) {
|
|
|
|
train_parameters[j] = (TrainParameters*)malloc(sizeof(TrainParameters));
|
|
|
|
train_parameters[j]->images = (int***)images;
|
|
|
|
train_parameters[j]->labels = (int*)labels;
|
|
|
|
train_parameters[j]->height = height;
|
|
|
|
train_parameters[j]->width = width;
|
|
|
|
train_parameters[j]->nb_images = BATCHES / nb_threads;
|
2022-11-30 11:24:37 +01:00
|
|
|
train_parameters[j]->shuffle_indices = shuffle_indices;
|
2022-10-01 17:53:14 +02:00
|
|
|
}
|
|
|
|
|
2022-05-19 22:26:19 +02:00
|
|
|
for (int i=0; i < epochs; i++) {
|
2022-11-30 11:24:37 +01:00
|
|
|
knuth_shuffle(shuffle_indices, nb_images_total); // Shuffle images between each epoch
|
2022-04-10 21:28:54 +02:00
|
|
|
accuracy = 0.;
|
2022-05-14 10:35:03 +02:00
|
|
|
for (int k=0; k < nb_images_total / BATCHES; k++) {
|
|
|
|
nb_remaining_images = BATCHES;
|
|
|
|
for (int j=0; j < nb_threads; j++) {
|
|
|
|
train_parameters[j]->network = copy_network(network);
|
2022-05-20 19:40:12 +02:00
|
|
|
train_parameters[j]->start = nb_images_total - BATCHES*(nb_images_total / BATCHES - k -1) - nb_remaining_images + start;
|
2022-05-14 10:35:03 +02:00
|
|
|
|
|
|
|
if (j == nb_threads-1) {
|
|
|
|
train_parameters[j]->nb_images = nb_remaining_images;
|
|
|
|
}
|
|
|
|
nb_remaining_images -= train_parameters[j]->nb_images;
|
2022-04-10 21:28:54 +02:00
|
|
|
|
2022-06-01 17:14:41 +02:00
|
|
|
// Création des threads sur le CPU
|
2022-10-01 17:53:14 +02:00
|
|
|
pthread_create( &tid[j], NULL, train_thread, (void*) train_parameters[j]);
|
2022-04-10 21:28:54 +02:00
|
|
|
}
|
2022-05-14 10:35:03 +02:00
|
|
|
for(int j=0; j < nb_threads; j++ ) {
|
2022-11-23 10:41:19 +01:00
|
|
|
// On récupère les threads créés sur le CPU
|
2022-05-14 10:35:03 +02:00
|
|
|
pthread_join( tid[j], NULL );
|
2022-10-21 14:22:57 +02:00
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
accuracy += train_parameters[j]->accuracy / (float) nb_images_total;
|
2022-05-19 22:26:19 +02:00
|
|
|
if (delta != NULL)
|
|
|
|
patch_delta(delta_network, train_parameters[j]->network, train_parameters[j]->nb_images);
|
2022-05-23 11:48:02 +02:00
|
|
|
patch_network(network, train_parameters[j]->network, train_parameters[j]->nb_images);
|
2022-05-14 10:35:03 +02:00
|
|
|
deletion_of_network(train_parameters[j]->network);
|
2022-04-10 21:28:54 +02:00
|
|
|
}
|
2023-01-13 15:58:46 +01:00
|
|
|
current_accuracy = accuracy*(nb_images_total/(BATCHES*(k+1)));
|
|
|
|
printf("\rThreads [%d]\tÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: "YELLOW"%0.1f%%"RESET, nb_threads, i, epochs, BATCHES*(k+1), nb_images_total, current_accuracy*100);
|
2022-11-30 11:24:37 +01:00
|
|
|
fflush(stdout);
|
2022-04-08 15:53:29 +02:00
|
|
|
}
|
2023-01-13 15:58:46 +01:00
|
|
|
printf("\rThreads [%d]\tÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: "GREEN"%0.1f%%"RESET"\n", nb_threads, i, epochs, nb_images_total, nb_images_total, accuracy*100);
|
2022-04-25 14:39:45 +02:00
|
|
|
write_network(out, network);
|
2022-05-19 22:26:19 +02:00
|
|
|
if (delta != NULL)
|
|
|
|
write_delta_network(delta, delta_network);
|
2022-04-08 15:53:29 +02:00
|
|
|
}
|
2022-05-21 18:06:39 +02:00
|
|
|
write_network(out, network);
|
|
|
|
if (delta != NULL) {
|
2022-05-19 22:26:19 +02:00
|
|
|
deletion_of_network(delta_network);
|
2022-05-21 18:06:39 +02:00
|
|
|
}
|
2022-04-25 14:39:45 +02:00
|
|
|
deletion_of_network(network);
|
2022-10-01 17:53:14 +02:00
|
|
|
for (int j=0; j < nb_threads; j++) {
|
|
|
|
free(train_parameters[j]);
|
|
|
|
}
|
2023-01-14 14:52:40 +01:00
|
|
|
|
|
|
|
for (int i=0; i < nb_images_total; i++) {
|
|
|
|
for (int j=0; j < height; j++) {
|
|
|
|
free(images[i][j]);
|
|
|
|
}
|
|
|
|
free(images[i]);
|
|
|
|
}
|
|
|
|
free(images);
|
|
|
|
free(labels);
|
|
|
|
|
2022-12-07 10:44:28 +01:00
|
|
|
free(shuffle_indices);
|
2022-05-19 22:26:19 +02:00
|
|
|
free(train_parameters);
|
2022-06-01 17:14:41 +02:00
|
|
|
// On libère les espaces mémoire utilisés spécialement sur le CPU
|
2022-05-14 10:35:03 +02:00
|
|
|
free(tid);
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
|
|
|
|
2022-11-30 11:24:37 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
float** recognize(char* modele, char* entree) {
|
|
|
|
Network* network = read_network(modele);
|
2022-06-01 17:14:41 +02:00
|
|
|
Layer* last_layer = network->layers[network->nb_layers-1];
|
2022-04-08 16:07:44 +02:00
|
|
|
|
|
|
|
int* parameters = read_mnist_images_parameters(entree);
|
|
|
|
int nb_images = parameters[0];
|
|
|
|
int height = parameters[1];
|
|
|
|
int width = parameters[2];
|
2022-10-01 17:53:14 +02:00
|
|
|
free(parameters);
|
2022-04-08 16:07:44 +02:00
|
|
|
|
|
|
|
int*** images = read_mnist_images(entree);
|
2022-05-14 10:35:03 +02:00
|
|
|
float** results = (float**)malloc(sizeof(float*)*nb_images);
|
2022-04-14 13:02:09 +02:00
|
|
|
|
|
|
|
for (int i=0; i < nb_images; i++) {
|
2022-06-01 17:14:41 +02:00
|
|
|
results[i] = (float*)malloc(sizeof(float)*last_layer->nb_neurons);
|
2022-04-14 13:02:09 +02:00
|
|
|
|
2022-04-25 14:39:45 +02:00
|
|
|
write_image_in_network(images[i], network, height, width);
|
|
|
|
forward_propagation(network);
|
2022-04-14 13:02:09 +02:00
|
|
|
|
2022-06-01 17:14:41 +02:00
|
|
|
for (int j=0; j < last_layer->nb_neurons; j++) {
|
|
|
|
results[i][j] = last_layer->neurons[j]->z;
|
2022-04-14 13:02:09 +02:00
|
|
|
}
|
|
|
|
}
|
2022-04-25 14:39:45 +02:00
|
|
|
deletion_of_network(network);
|
2022-04-14 13:02:09 +02:00
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
void print_recognize(char* modele, char* entree, char* sortie) {
|
|
|
|
Network* network = read_network(modele);
|
|
|
|
int nb_last_layer = network->layers[network->nb_layers-1]->nb_neurons;
|
2022-04-14 13:02:09 +02:00
|
|
|
|
2022-04-25 14:39:45 +02:00
|
|
|
deletion_of_network(network);
|
2022-04-14 13:02:09 +02:00
|
|
|
|
|
|
|
int* parameters = read_mnist_images_parameters(entree);
|
|
|
|
int nb_images = parameters[0];
|
|
|
|
|
2022-06-01 17:14:41 +02:00
|
|
|
float** results = recognize(modele, entree);
|
2022-04-08 16:07:44 +02:00
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
if (! strcmp(sortie, "json")) {
|
2022-04-10 12:01:20 +02:00
|
|
|
printf("{\n");
|
|
|
|
}
|
2022-04-08 16:07:44 +02:00
|
|
|
for (int i=0; i < nb_images; i++) {
|
2022-05-14 10:35:03 +02:00
|
|
|
if (! strcmp(sortie, "text"))
|
2022-04-10 12:01:20 +02:00
|
|
|
printf("Image %d\n", i);
|
|
|
|
else
|
|
|
|
printf("\"%d\" : [", i);
|
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
for (int j=0; j < nb_last_layer; j++) {
|
|
|
|
if (! strcmp(sortie, "json")) {
|
2022-06-01 17:14:41 +02:00
|
|
|
printf("%f", results[i][j]);
|
2022-04-10 21:28:54 +02:00
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
if (j+1 < nb_last_layer) {
|
2022-04-10 12:01:20 +02:00
|
|
|
printf(", ");
|
|
|
|
}
|
|
|
|
} else
|
2022-06-01 17:14:41 +02:00
|
|
|
printf("Probabilité %d: %f\n", j, results[i][j]);
|
2022-04-10 12:01:20 +02:00
|
|
|
}
|
2022-06-01 17:14:41 +02:00
|
|
|
free(results[i]);
|
2022-05-14 10:35:03 +02:00
|
|
|
if (! strcmp(sortie, "json")) {
|
2022-04-10 12:01:20 +02:00
|
|
|
if (i+1 < nb_images) {
|
|
|
|
printf("],\n");
|
|
|
|
} else {
|
|
|
|
printf("]\n");
|
|
|
|
}
|
2022-04-08 16:07:44 +02:00
|
|
|
}
|
|
|
|
}
|
2022-06-01 17:14:41 +02:00
|
|
|
free(results);
|
2022-05-23 17:27:38 +02:00
|
|
|
free(parameters);
|
2022-05-14 10:35:03 +02:00
|
|
|
if (! strcmp(sortie, "json")) {
|
2022-04-11 18:00:32 +02:00
|
|
|
printf("}\n");
|
2022-05-14 10:35:03 +02:00
|
|
|
}
|
2022-04-08 16:07:44 +02:00
|
|
|
}
|
|
|
|
|
2022-05-14 10:35:03 +02:00
|
|
|
void test(char* modele, char* fichier_images, char* fichier_labels, bool preview_fails) {
|
|
|
|
Network* network = read_network(modele);
|
|
|
|
int nb_last_layer = network->layers[network->nb_layers-1]->nb_neurons;
|
2022-04-14 13:02:09 +02:00
|
|
|
|
2022-04-25 14:39:45 +02:00
|
|
|
deletion_of_network(network);
|
2022-04-14 13:02:09 +02:00
|
|
|
|
|
|
|
int* parameters = read_mnist_images_parameters(fichier_images);
|
|
|
|
int nb_images = parameters[0];
|
2022-04-26 17:09:12 +02:00
|
|
|
int width = parameters[1];
|
|
|
|
int height = parameters[2];
|
2022-04-26 16:47:43 +02:00
|
|
|
int*** images = read_mnist_images(fichier_images);
|
2022-04-14 13:02:09 +02:00
|
|
|
|
2022-06-01 17:14:41 +02:00
|
|
|
float** results = recognize(modele, fichier_images);
|
2022-04-14 13:02:09 +02:00
|
|
|
unsigned int* labels = read_mnist_labels(fichier_labels);
|
2022-05-14 10:35:03 +02:00
|
|
|
float accuracy = 0.;
|
2022-04-14 13:02:09 +02:00
|
|
|
|
|
|
|
for (int i=0; i < nb_images; i++) {
|
2022-06-01 17:14:41 +02:00
|
|
|
if (indice_max(results[i], nb_last_layer) == (int)labels[i]) {
|
2022-04-26 16:47:43 +02:00
|
|
|
accuracy += 1. / (float)nb_images;
|
2022-04-26 17:29:25 +02:00
|
|
|
} else if (preview_fails) {
|
2022-06-01 17:14:41 +02:00
|
|
|
printf("--- Image %d, %d --- Prévision: %d ---\n", i, labels[i], indice_max(results[i], nb_last_layer));
|
|
|
|
print_image(width, height, images[i], results[i]);
|
2022-04-14 13:02:09 +02:00
|
|
|
}
|
2022-06-01 17:14:41 +02:00
|
|
|
free(results[i]);
|
2022-04-14 13:02:09 +02:00
|
|
|
}
|
|
|
|
printf("%d Images\tAccuracy: %0.1f%%\n", nb_images, accuracy*100);
|
2022-05-23 17:27:38 +02:00
|
|
|
free(parameters);
|
2022-06-01 17:14:41 +02:00
|
|
|
free(results);
|
2022-04-14 13:02:09 +02:00
|
|
|
}
|
|
|
|
|
2022-04-08 15:53:29 +02:00
|
|
|
|
2022-04-07 22:07:32 +02:00
|
|
|
int main(int argc, char* argv[]) {
|
|
|
|
if (argc < 2) {
|
|
|
|
printf("Pas d'action spécifiée\n");
|
|
|
|
help(argv[0]);
|
2022-10-01 17:53:14 +02:00
|
|
|
return 1;
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
|
|
|
if (! strcmp(argv[1], "train")) {
|
2022-05-19 22:26:19 +02:00
|
|
|
int epochs = EPOCHS;
|
2022-11-30 11:24:37 +01:00
|
|
|
int layers = 3;
|
2022-04-07 22:07:32 +02:00
|
|
|
int neurons = 784;
|
2022-05-20 19:40:12 +02:00
|
|
|
int nb_images = -1;
|
|
|
|
int start = 0;
|
2022-04-07 22:07:32 +02:00
|
|
|
char* images = NULL;
|
|
|
|
char* labels = NULL;
|
2022-04-08 15:53:29 +02:00
|
|
|
char* recovery = NULL;
|
2022-04-07 22:07:32 +02:00
|
|
|
char* out = NULL;
|
2022-05-19 22:26:19 +02:00
|
|
|
char* delta = NULL;
|
2022-04-14 13:02:09 +02:00
|
|
|
int i = 2;
|
2022-04-07 22:07:32 +02:00
|
|
|
while (i < argc) {
|
|
|
|
// Utiliser un switch serait sans doute plus élégant
|
2022-05-19 22:26:19 +02:00
|
|
|
if ((! strcmp(argv[i], "--epochs"))||(! strcmp(argv[i], "-e"))) {
|
|
|
|
epochs = strtol(argv[i+1], NULL, 10);
|
2022-04-07 22:07:32 +02:00
|
|
|
i += 2;
|
|
|
|
} else
|
2022-04-30 09:31:52 +02:00
|
|
|
if ((! strcmp(argv[i], "--couches"))||(! strcmp(argv[i], "-c"))) {
|
2022-04-25 14:39:45 +02:00
|
|
|
layers = strtol(argv[i+1], NULL, 10);
|
2022-04-07 22:07:32 +02:00
|
|
|
i += 2;
|
2022-04-30 09:31:52 +02:00
|
|
|
} else if ((! strcmp(argv[i], "--neurones"))||(! strcmp(argv[i], "-n"))) {
|
2022-04-07 22:07:32 +02:00
|
|
|
neurons = strtol(argv[i+1], NULL, 10);
|
|
|
|
i += 2;
|
|
|
|
} else if ((! strcmp(argv[i], "--images"))||(! strcmp(argv[i], "-i"))) {
|
|
|
|
images = argv[i+1];
|
|
|
|
i += 2;
|
|
|
|
} else if ((! strcmp(argv[i], "--labels"))||(! strcmp(argv[i], "-l"))) {
|
|
|
|
labels = argv[i+1];
|
|
|
|
i += 2;
|
2022-04-08 15:53:29 +02:00
|
|
|
} else if ((! strcmp(argv[i], "--recover"))||(! strcmp(argv[i], "-r"))) {
|
|
|
|
recovery = argv[i+1];
|
|
|
|
i += 2;
|
2022-04-07 22:07:32 +02:00
|
|
|
} else if ((! strcmp(argv[i], "--out"))||(! strcmp(argv[i], "-o"))) {
|
|
|
|
out = argv[i+1];
|
|
|
|
i += 2;
|
2022-05-19 22:26:19 +02:00
|
|
|
} else if ((! strcmp(argv[i], "--delta"))||(! strcmp(argv[i], "-d"))) {
|
|
|
|
delta = argv[i+1];
|
|
|
|
i += 2;
|
2022-05-20 19:40:12 +02:00
|
|
|
} else if ((! strcmp(argv[i], "--nb-images"))||(! strcmp(argv[i], "-N"))) {
|
|
|
|
nb_images = strtol(argv[i+1], NULL, 10);
|
|
|
|
i += 2;
|
|
|
|
} else if ((! strcmp(argv[i], "--start"))||(! strcmp(argv[i], "-s"))) {
|
|
|
|
start = strtol(argv[i+1], NULL, 10);
|
|
|
|
i += 2;
|
2022-04-07 22:07:32 +02:00
|
|
|
} else {
|
|
|
|
printf("%s : Argument non reconnu\n", argv[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! images) {
|
|
|
|
printf("Pas de fichier d'images spécifié\n");
|
2022-10-01 17:53:14 +02:00
|
|
|
return 1;
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
|
|
|
if (! labels) {
|
|
|
|
printf("Pas de fichier de labels spécifié\n");
|
2022-10-01 17:53:14 +02:00
|
|
|
return 1;
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
|
|
|
if (! out) {
|
|
|
|
printf("Pas de fichier de sortie spécifié, default: out.bin\n");
|
|
|
|
out = "out.bin";
|
|
|
|
}
|
|
|
|
// Entraînement en sourçant neural_network.c
|
2022-05-20 19:40:12 +02:00
|
|
|
train(epochs, layers, neurons, recovery, images, labels, out, delta, nb_images, start);
|
2022-10-01 17:53:14 +02:00
|
|
|
return 0;
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
|
|
|
if (! strcmp(argv[1], "recognize")) {
|
|
|
|
char* in = NULL;
|
2022-05-14 10:35:03 +02:00
|
|
|
char* modele = NULL;
|
2022-04-07 22:07:32 +02:00
|
|
|
char* out = NULL;
|
2022-04-14 13:02:09 +02:00
|
|
|
int i = 2;
|
2022-04-07 22:07:32 +02:00
|
|
|
while(i < argc) {
|
|
|
|
if ((! strcmp(argv[i], "--in"))||(! strcmp(argv[i], "-i"))) {
|
|
|
|
in = argv[i+1];
|
|
|
|
i += 2;
|
|
|
|
} else if ((! strcmp(argv[i], "--modele"))||(! strcmp(argv[i], "-m"))) {
|
2022-05-14 10:35:03 +02:00
|
|
|
modele = argv[i+1];
|
2022-04-07 22:07:32 +02:00
|
|
|
i += 2;
|
|
|
|
} else if ((! strcmp(argv[i], "--out"))||(! strcmp(argv[i], "-o"))) {
|
|
|
|
out = argv[i+1];
|
|
|
|
i += 2;
|
|
|
|
} else {
|
|
|
|
printf("%s : Argument non reconnu\n", argv[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! in) {
|
|
|
|
printf("Pas d'entrée spécifiée\n");
|
2022-10-01 17:53:14 +02:00
|
|
|
return 1;
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
2022-05-14 10:35:03 +02:00
|
|
|
if (! modele) {
|
2022-04-07 22:07:32 +02:00
|
|
|
printf("Pas de modèle spécifié\n");
|
2022-10-01 17:53:14 +02:00
|
|
|
return 1;
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
|
|
|
if (! out) {
|
|
|
|
out = "text";
|
|
|
|
}
|
2022-05-14 10:35:03 +02:00
|
|
|
print_recognize(modele, in, out);
|
2022-04-07 22:07:32 +02:00
|
|
|
// Reconnaissance puis affichage des données sous le format spécifié
|
2022-10-01 17:53:14 +02:00
|
|
|
return 0;
|
2022-04-07 22:07:32 +02:00
|
|
|
}
|
2022-04-14 13:02:09 +02:00
|
|
|
if (! strcmp(argv[1], "test")) {
|
2022-05-14 10:35:03 +02:00
|
|
|
char* modele = NULL;
|
2022-04-14 13:02:09 +02:00
|
|
|
char* images = NULL;
|
|
|
|
char* labels = NULL;
|
2022-04-26 16:47:43 +02:00
|
|
|
bool preview_fails = false;
|
2022-04-14 13:02:09 +02:00
|
|
|
int i = 2;
|
|
|
|
while (i < argc) {
|
|
|
|
if ((! strcmp(argv[i], "--images"))||(! strcmp(argv[i], "-i"))) {
|
|
|
|
images = argv[i+1];
|
|
|
|
i += 2;
|
|
|
|
} else if ((! strcmp(argv[i], "--labels"))||(! strcmp(argv[i], "-l"))) {
|
|
|
|
labels = argv[i+1];
|
|
|
|
i += 2;
|
|
|
|
} else if ((! strcmp(argv[i], "--modele"))||(! strcmp(argv[i], "-m"))) {
|
2022-05-14 10:35:03 +02:00
|
|
|
modele = argv[i+1];
|
2022-04-14 13:02:09 +02:00
|
|
|
i += 2;
|
2022-04-26 16:47:43 +02:00
|
|
|
} else if ((! strcmp(argv[i], "--preview-fails"))||(! strcmp(argv[i], "-p"))) {
|
|
|
|
preview_fails = true;
|
|
|
|
i++;
|
2022-04-14 13:02:09 +02:00
|
|
|
}
|
|
|
|
}
|
2022-05-14 10:35:03 +02:00
|
|
|
test(modele, images, labels, preview_fails);
|
2022-10-01 17:53:14 +02:00
|
|
|
return 0;
|
2022-04-14 13:02:09 +02:00
|
|
|
}
|
2022-04-07 22:07:32 +02:00
|
|
|
printf("Option choisie non reconnue: %s\n", argv[1]);
|
|
|
|
help(argv[0]);
|
|
|
|
return 1;
|
2022-05-14 10:35:03 +02:00
|
|
|
}
|