Add random offset to mnist images during learning

This commit is contained in:
augustin64 2023-03-22 13:03:19 +01:00
parent 1bd92074ab
commit b893f11da0
6 changed files with 131 additions and 25 deletions

View File

@ -1,7 +1,8 @@
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <math.h>
#include <float.h> // Is it used ? #include <float.h> // Is it used ?
#include <math.h>
#include "include/backpropagation.h" #include "include/backpropagation.h"
#include "include/initialisation.h" #include "include/initialisation.h"
@ -33,7 +34,80 @@ int will_be_drop(int dropout_prob) {
return (rand() % 100) < dropout_prob; return (rand() % 100) < dropout_prob;
} }
void write_image_in_network_32(int** image, int height, int width, float** input) { void write_image_in_network_32(int** image, int height, int width, float** input, bool random_offset) {
int i_offset = 0;
int j_offset = 0;
int min_col = 0;
int min_ligne = 0;
if (random_offset) {
/*
<-- min_ligne
.%%:.
######%%%%%%%%%.
.:.:%##########:
. .... ##:
.##
##.
:##
.##.
:#%
%#.
:#%
.##.
##%
%##
##.
##:
:##.
.###.
:###
:#%
<-- max_ligne
^-- min_col
^-- max_col
*/
int sum_colonne[width];
int sum_ligne[height];
for (int i=0; i < width; i++) {
sum_colonne[i] = 0;
}
for (int j=0; j < height; j++) {
sum_ligne[j] = 0;
}
for (int i=0; i < width; i++) {
for (int j=0; j < height; j++) {
sum_ligne[i] += image[i][j];
sum_colonne[j] += image[i][j];
}
}
min_ligne = -1;
while (sum_ligne[min_ligne+1] == 0 && min_ligne < width+1) {
min_ligne++;
}
int max_ligne = width;
while (sum_ligne[max_ligne-1] == 0 && max_ligne > 0) {
max_ligne--;
}
min_col = -1;
while (sum_colonne[min_col+1] == 0 && min_col < height+1) {
min_col++;
}
int max_col = height;
while (sum_colonne[max_col-1] == 0 && max_col > 0) {
max_col--;
}
i_offset = rand()%(27-max_ligne+min_ligne);
j_offset = rand()%(27-max_col+min_col);
}
int padding = (32 - height)/2; int padding = (32 - height)/2;
for (int i=0; i < padding; i++) { for (int i=0; i < padding; i++) {
for (int j=0; j < 32; j++) { for (int j=0; j < 32; j++) {
@ -46,7 +120,10 @@ void write_image_in_network_32(int** image, int height, int width, float** input
for (int i=0; i < width; i++) { for (int i=0; i < width; i++) {
for (int j=0; j < height; j++) { for (int j=0; j < height; j++) {
input[i+2][j+2] = (float)image[i][j] / 255.0f; int adjusted_i = i + min_ligne - i_offset;
int adjusted_j = j + min_col - j_offset;
// Make sure not to be out of the image
input[i+2][j+2] = adjusted_i < height && adjusted_j < width && adjusted_i >= 0 && adjusted_j >= 0 ? (float)image[adjusted_i][adjusted_j] / 255.0f : 0.;
} }
} }
} }

View File

@ -17,7 +17,7 @@ int will_be_drop(int dropout_prob);
/* /*
* Écrit une image 28*28 au centre d'un tableau 32*32 et met à 0 le reste * Écrit une image 28*28 au centre d'un tableau 32*32 et met à 0 le reste
*/ */
void write_image_in_network_32(int** image, int height, int width, float** input); void write_image_in_network_32(int** image, int height, int width, float** input, bool random_offset);
/* /*
* Écrit une image linéarisée de 256*256*3 pixels dans un tableau de taille 260*260*3 * Écrit une image linéarisée de 256*256*3 pixels dans un tableau de taille 260*260*3

View File

@ -6,7 +6,7 @@
/* /*
* Renvoie le taux de réussite d'un réseau sur des données de test * 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); float* test_network(int dataset_type, char* modele, char* images_file, char* labels_file, char* data_dir, bool preview_fails, bool to_stdout, bool with_offset);
/* /*
* Classifie un fichier d'images sous le format MNIST à partir d'un réseau préalablement entraîné * Classifie un fichier d'images sous le format MNIST à partir d'un réseau préalablement entraîné

View File

@ -188,7 +188,7 @@ int main(int argc, char* argv[]) {
printf_error("Pas de modèle à utiliser spécifié.\n"); printf_error("Pas de modèle à utiliser spécifié.\n");
return 1; return 1;
} }
test_network(dataset_type, modele, images_file, labels_file, data_dir, preview_fails); (void)test_network(dataset_type, modele, images_file, labels_file, data_dir, preview_fails, true, false);
return 0; return 0;
} }
if (! strcmp(argv[1], "recognize")) { if (! strcmp(argv[1], "recognize")) {

View File

@ -12,7 +12,7 @@
#include "include/cnn.h" #include "include/cnn.h"
void test_network_mnist(Network* network, char* images_file, char* labels_file, bool preview_fails) { float* test_network_mnist(Network* network, char* images_file, char* labels_file, bool preview_fails, bool to_stdout, bool with_offset) {
(void)preview_fails; // Inutilisé pour le moment (void)preview_fails; // Inutilisé pour le moment
int width, height; // Dimensions des images int width, height; // Dimensions des images
int nb_elem; // Nombre d'éléments int nb_elem; // Nombre d'éléments
@ -36,11 +36,11 @@ void test_network_mnist(Network* network, char* images_file, char* labels_file,
// Load image in the first layer of the Network // Load image in the first layer of the Network
for (int i=0; i < nb_elem; i++) { for (int i=0; i < nb_elem; i++) {
if(i %(nb_elem/100) == 0) { if(i %(nb_elem/100) == 0 && to_stdout) {
printf("Avancement: %.0f%%\r", 100*i/(float)nb_elem); printf("Avancement: %.0f%%\r", 100*i/(float)nb_elem);
fflush(stdout); fflush(stdout);
} }
write_image_in_network_32(images[i], height, width, network->input[0][0]); write_image_in_network_32(images[i], height, width, network->input[0][0], with_offset);
forward_propagation(network); forward_propagation(network);
maxi = indice_max(network->input[network->size-1][0][0], 10); maxi = indice_max(network->input[network->size-1][0][0], 10);
@ -59,11 +59,15 @@ void test_network_mnist(Network* network, char* images_file, char* labels_file,
free(images[i]); free(images[i]);
} }
free(images); free(images);
printf("%d Images. Taux de réussite: %.2f%%\tLoss: %lf\n", nb_elem, 100*accuracy/(float)nb_elem, loss/nb_elem);
float* results = malloc(sizeof(float)*2);
results[0] = 100*accuracy/(float)nb_elem;
results[1] = loss/(float)nb_elem;
return results;
} }
void test_network_jpg(Network* network, char* data_dir, bool preview_fails) { float* test_network_jpg(Network* network, char* data_dir, bool preview_fails, bool to_stdout) {
(void)preview_fails; // Inutilisé pour le moment (void)preview_fails; // Inutilisé pour le moment
jpegDataset* dataset = loadJpegDataset(data_dir); jpegDataset* dataset = loadJpegDataset(data_dir);
@ -71,7 +75,7 @@ void test_network_jpg(Network* network, char* data_dir, bool preview_fails) {
int maxi; int maxi;
for (int i=0; i < (int)dataset->numImages; i++) { for (int i=0; i < (int)dataset->numImages; i++) {
if(i %(dataset->numImages/100) == 0) { if(i %(dataset->numImages/100) == 0 && to_stdout) {
printf("Avancement: %.1f%%\r", 1000*i/(float)dataset->numImages); printf("Avancement: %.1f%%\r", 1000*i/(float)dataset->numImages);
fflush(stdout); fflush(stdout);
} }
@ -86,23 +90,35 @@ void test_network_jpg(Network* network, char* data_dir, bool preview_fails) {
free(dataset->images[i]); free(dataset->images[i]);
} }
printf("%d Images. Taux de réussite: %.2f%%\n", dataset->numImages, 100*accuracy/(float)dataset->numImages); float* results = malloc(sizeof(float)*2);
results[0] = 100*accuracy/(float)dataset->numImages;
results[1] = 0;
free(dataset->images); free(dataset->images);
free(dataset->labels); free(dataset->labels);
free(dataset); free(dataset);
return results;
} }
void test_network(int dataset_type, char* modele, char* images_file, char* labels_file, char* data_dir, bool preview_fails) { float* test_network(int dataset_type, char* modele, char* images_file, char* labels_file, char* data_dir, bool preview_fails, bool to_stdout, bool with_offset) {
Network* network = read_network(modele); Network* network = read_network(modele);
float* results;
if (dataset_type == 0) { if (dataset_type == 0) {
test_network_mnist(network, images_file, labels_file, preview_fails); results = test_network_mnist(network, images_file, labels_file, preview_fails, to_stdout, with_offset);
} else { } else {
test_network_jpg(network, data_dir, preview_fails); results = test_network_jpg(network, data_dir, preview_fails, to_stdout);
} }
free_network(network); free_network(network);
if (to_stdout) {
printf("Accuracy: %lf\tLoss: %lf\n", results[0], results[1]);
free(results); // Will not be used if to_stdout is used
}
return results;
} }
@ -130,7 +146,7 @@ void recognize_mnist(Network* network, char* input_file, char* out) {
printf("\"%d\" : [", i); printf("\"%d\" : [", i);
} }
write_image_in_network_32(images[i], height, width, network->input[0][0]); write_image_in_network_32(images[i], height, width, network->input[0][0], false);
forward_propagation(network); forward_propagation(network);

View File

@ -51,7 +51,7 @@ void* train_thread(void* parameters) {
for (int i=start; i < start+nb_images; i++) { for (int i=start; i < start+nb_images; i++) {
if (dataset_type == 0) { if (dataset_type == 0) {
write_image_in_network_32(images[index[i]], height, width, network->input[0][0]); write_image_in_network_32(images[index[i]], height, width, network->input[0][0], true);
forward_propagation(network); forward_propagation(network);
maxi = indice_max(network->input[network->size-1][0][0], 10); maxi = indice_max(network->input[network->size-1][0][0], 10);
if (maxi == -1) { if (maxi == -1) {
@ -106,6 +106,7 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di
srand(time(NULL)); srand(time(NULL));
float loss; float loss;
float batch_loss; // May be redundant with loss, but gives more informations float batch_loss; // May be redundant with loss, but gives more informations
float test_accuracy = 0.; // Used to decrease Learning rate
float accuracy; float accuracy;
float batch_accuracy; float batch_accuracy;
float current_accuracy; float current_accuracy;
@ -233,7 +234,7 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di
end_time = omp_get_wtime(); end_time = omp_get_wtime();
elapsed_time = end_time - start_time; elapsed_time = end_time - start_time;
printf("Taux d'apprentissage initial: %lf\n", network->learning_rate); printf("Taux d'apprentissage initial: %0.2e\n", network->learning_rate);
printf("Initialisation: "); printf("Initialisation: ");
printf_time(elapsed_time); printf_time(elapsed_time);
printf("\n\n"); printf("\n\n");
@ -308,7 +309,6 @@ 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.2f%%" RESET " \tBatch Accuracy: " YELLOW "%0.2f%%" RESET, nb_threads, i, epochs, BATCHES*(j+1), nb_images_total, current_accuracy*100, batch_accuracy*100); printf("\rThreads [%d]\tÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: " YELLOW "%0.2f%%" RESET " \tBatch Accuracy: " YELLOW "%0.2f%%" RESET, nb_threads, i, epochs, BATCHES*(j+1), nb_images_total, current_accuracy*100, batch_accuracy*100);
fflush(stdout);
#else #else
(void)nb_images_total_remaining; // Juste pour enlever un warning (void)nb_images_total_remaining; // Juste pour enlever un warning
@ -331,7 +331,6 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di
update_bias(network, network); update_bias(network, network);
printf("\rÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: " YELLOW "%0.4f%%" RESET "\tBatch Accuracy: " YELLOW "%0.2f%%" RESET, i, epochs, BATCHES*(j+1), nb_images_total, current_accuracy*100, batch_accuracy*100); printf("\rÉpoque [%d/%d]\tImage [%d/%d]\tAccuracy: " YELLOW "%0.4f%%" RESET "\tBatch Accuracy: " YELLOW "%0.2f%%" RESET, i, epochs, BATCHES*(j+1), nb_images_total, current_accuracy*100, batch_accuracy*100);
fflush(stdout);
#endif #endif
} }
//* Fin d'une époque: affichage des résultats et sauvegarde du réseau //* Fin d'une époque: affichage des résultats et sauvegarde du réseau
@ -347,11 +346,25 @@ void train(int dataset_type, char* images_file, char* labels_file, char* data_di
printf("\n"); printf("\n");
#endif #endif
write_network(out, network); write_network(out, network);
// If you want to test the network between each epoch, uncomment the following line: // If you want to test the network between each epoch, uncomment the following lines:
test_network(0, out, "data/mnist/t10k-images-idx3-ubyte", "data/mnist/t10k-labels-idx1-ubyte", NULL, false); /*
float* test_results = test_network(0, out, "data/mnist/t10k-images-idx3-ubyte", "data/mnist/t10k-labels-idx1-ubyte", NULL, false, false, true);
printf("Tests: Accuracy: %0.2lf%%\tLoss: %lf\n", test_results[0], test_results[1]);
if (test_results[0] < test_accuracy) {
network->learning_rate *= 0.1;
printf("Decreased learning rate to %0.2e\n", network->learning_rate);
}
if (test_results[0] == test_accuracy) {
network->learning_rate *= 2;
printf("Increased learning rate to %0.2e\n", network->learning_rate);
}
test_accuracy = test_results[0];
free(test_results);
// Learning Rate decay test_results = test_network(0, out, "data/mnist/t10k-images-idx3-ubyte", "data/mnist/t10k-labels-idx1-ubyte", NULL, false, false, false);
network->learning_rate -= LEARNING_RATE*(1./(float)(epochs+1)); printf("Tests sans offset: Accuracy: %0.2lf%%\tLoss: %lf\n", test_results[0], test_results[1]);
free(test_results);
*/
} }
//* Fin de l'algo //* Fin de l'algo