diff --git a/CMakeLists.txt b/CMakeLists.txt index 847c636..113e5e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,5 +3,5 @@ project(c_net C) set(CMAKE_C_STANDARD 11) -add_executable(c_net main.c matrix.c image.c) +add_executable(c_net main.c matrix.c image.c neuronal_network.c) target_link_libraries(c_net m) diff --git a/image.c b/image.c index e6a6d44..2ff1f67 100644 --- a/image.c +++ b/image.c @@ -4,29 +4,15 @@ #include "image.h" #include "matrix.h" -int endian_swap(int input) { - return ((input >> 24) & 0xff) | // move byte 3 to byte 0 - ((input << 8) & 0xff0000) | // move byte 1 to byte 2 - ((input >> 8) & 0xff00) | // move byte 2 to byte 1 - ((input << 24) & 0xff000000); // byte 0 to byte 3 -} - -int validate_files(FILE* image_file, FILE* label_file) { - - // read magic number from files - int magic_number_label, magic_number_images; - fread(&magic_number_label, 4, 1, label_file); - fread(&magic_number_images, 4, 1, image_file); - - // compare magic numbers with pre-defined value - if(endian_swap(magic_number_label) != 2049 || endian_swap(magic_number_images) != 2051) { - return 0; +void big_endian_to_c_uint(const char * bytes, void * target, int size) { + char* helper = (char*)target; + for(int i = 0; i < size; i++){ + *(helper+i) = *(bytes+size-i-1); } - - return 1; } -Image** import_images(char* image_file_string, char* label_file_string, int number_of_images) { + +Image** import_images(char* image_file_string, char* label_file_string, unsigned int* _number_imported, unsigned int count) { // create file pointer for the image and label data FILE* image_file = fopen(image_file_string, "r"); @@ -39,20 +25,79 @@ Image** import_images(char* image_file_string, char* label_file_string, int numb } // check magic number of the files - if(validate_files(image_file, label_file)) { - printf("ERROR: File validation failed! (validate_files)"); + char word_buffer[4]; + int buffer_size = sizeof(word_buffer); + + unsigned int magic_number_label, magic_number_images, label_count, image_count; + + //Read description of label file + fread(word_buffer, buffer_size, 1, label_file); + big_endian_to_c_uint(word_buffer, &magic_number_label, buffer_size); + + fread(word_buffer, 4, 1, label_file); + big_endian_to_c_uint(word_buffer, &label_count, buffer_size); + + + //Read description of file + fread(word_buffer, 4, 1, image_file); + big_endian_to_c_uint(word_buffer, &magic_number_images, buffer_size); + + fread(word_buffer, 4, 1, image_file); + big_endian_to_c_uint(word_buffer, &image_count, buffer_size); + + // compare magic numbers with pre-defined value + if(magic_number_label != MAGIC_NUMBER_LABEL || magic_number_images != MAGIC_NUMBER_IMAGES) { + printf("TrainingData or Labels are malformed. Exiting..."); + exit(1); + } + if(label_count != image_count){ + printf("Number of images and labels does not match. Exiting..."); exit(1); } + if(count == 0){ + count = image_count; + } - // Jakob Section + if(count > image_count){ + count = image_count; + printf("Number of images exceeds number of available images. Loading all available images"); + } + int image_height, image_width, image_length; + //read image dimensions; + fread(word_buffer, 4, 1, image_file); + big_endian_to_c_uint(word_buffer, &image_height, buffer_size); + + fread(word_buffer, 4, 1, image_file); + big_endian_to_c_uint(word_buffer, &image_width, 4); + + image_length = image_height*image_width; // allocate memory for the storage of images - Image** images = malloc(sizeof(Image) * number_of_images); + Image** images = malloc(sizeof(Image*) * count); + if(!images){ + printf("not enough memory"); + exit(1); + } + + unsigned char byteBuffer[image_length]; + for(int i = 0; i < count; i++){ + images[i] = malloc(sizeof(Image)); + fread(&images[i]->label, 1, 1, label_file); + fread(&byteBuffer, image_width*image_height, 1, image_file); + images[i]->pixel_values = matrix_create(image_height, image_width); + + for(int j = 0; j < image_length; j++) { + images[i]->pixel_values->numbers[j / image_width][j % image_width] = byteBuffer[j] / 255.0; + } + } + + if(_number_imported != NULL)*_number_imported = count; fclose(image_file); fclose(label_file); + return images; } void img_print (Image* img) { @@ -60,7 +105,17 @@ void img_print (Image* img) { //print the image matrix_print(img->pixel_values); //print the number of the image - printf("Number it is supposed to be: %d\n", img->image_label); + printf("Number it is supposed to be: %d\n", img->label); +} + +void img_visualize(Image* img){ + for(int i = 0; i < img->pixel_values->rows; i++){ + for(int j = 0; j < img->pixel_values->columns; j++){ + img->pixel_values->numbers[i][j] > 0.5 ? putc('#', stdout) : putc(' ', stdout); + } + putc('\n', stdout); + } + printf("Should be %d", img->label); } void img_free (Image* img) { diff --git a/image.h b/image.h index b80b4d9..969251a 100644 --- a/image.h +++ b/image.h @@ -5,9 +5,27 @@ typedef struct { Matrix* pixel_values; - int image_label; + char label; } Image; -Image** import_images(char* image_file_string, char* label_file_string, int number_of_images); +typedef struct { + const Image* image; + const size_t size; +} Image_Container; + +static const int MAGIC_NUMBER_LABEL = 2049; + +static const int MAGIC_NUMBER_IMAGES = 2051; + +/** + * reads a specified number of images out of the training dataset + * @param image_file_string Path to the file containing the image data + * @param label_file_string Path to the file containing the image labels + * @param ptr via this pointer, the images can be accessed + * @param count maximum number of images to be loaded. If it is 0, all available images are loaded. + * @return + */ +Image ** import_images(char* image_file_string, char* label_file_string, unsigned int* number_imported, unsigned int count); void img_print (Image* image); +void img_visualize(Image*image); void img_free (Image* image); \ No newline at end of file diff --git a/main.c b/main.c index 82750fe..0330abf 100644 --- a/main.c +++ b/main.c @@ -1,10 +1,12 @@ #include #include +#include #include "matrix.h" #include "image.h" int main() { - Image** images = import_images("../data/train-images.idx3-ubyte", "../data/train-labels.idx1-ubyte", 20); + Image** images = import_images("../data/train-images.idx3-ubyte", "../data/train-labels.idx1-ubyte", NULL, 2); + img_visualize(images[1]); } \ No newline at end of file diff --git a/neuronal_network.c b/neuronal_network.c index 6a352d6..72acda4 100644 --- a/neuronal_network.c +++ b/neuronal_network.c @@ -4,20 +4,20 @@ #include Neural_Network* new_network(int input_size, int hidden_size, int output_size, double learning_rate){ - Neural_Network network = malloc(sizeof(Neural_Network)); + Neural_Network *network = malloc(sizeof(Neural_Network)); // initialize networks variables - network.input_size = input_size; - network.hidden_size = hidden_size; - network.output_size = output_size; - network.learning_rate = learning_rate; + network->hidden_size = hidden_size; + network->input_size = input_size; + network->output_size = output_size; + network->learning_rate = learning_rate; - network.weights_1 = matrix_randomize(matrix_create(hidden_size, input_size)); - network.weights_2 = matrix_randomize(matrix_create(hidden_size, hidden_size)); - network.weights_3 = matrix_randomize(matrix_create(hidden_size, hidden_size)); - network.weights_output = matrix_randomize(matrix_create(output_size, hidden_size)); - network.bias_1 = matrix_randomize(matrix_create(hidden_size, 1)); - network.bias_2 = matrix_randomize(matrix_create(hidden_size, 1)); - network.bias_3 = matrix_randomize(matrix_create(hidden_size, 1)); + network->weights_1 = matrix_create(hidden_size, input_size); + network->weights_2 = matrix_create(hidden_size, hidden_size); + network->weights_3 = matrix_create(hidden_size, hidden_size); + network->weights_output = matrix_create(output_size, hidden_size); + network->bias_1 = matrix_create(hidden_size, 1); + network->bias_2 = matrix_create(hidden_size, 1); + network->bias_3 = matrix_create(hidden_size, 1); //network.bias_output = matrix_create(output_size, 1); // do we need it? return network; @@ -60,7 +60,7 @@ void save_network(Neural_Network* network) { fprintf(save_file, "%d\n", network->output_size); // close the file - fclose(file_name); + fclose(save_file); // save first layer matrix_save(network->bias_1, file_name); @@ -81,40 +81,41 @@ void save_network(Neural_Network* network) { } Neural_Network* load_network(char* file) { - + return NULL; } -double predict_images(Neural_Network* network, Image** images, int amount) { - int num_correct = 0; - for (int i = 0; i < amount; i++) { - Matrix* prediction = predict_image(network, images[i]); - if (matrix_argmax(prediction) == images[i]->image_label) { - num_correct++; - } - matrix_free(prediction); - } - return 1.0 * num_correct / amount; -} -Matrix* predict_image(Neural_Network* network, Image*); +//double predict_images(Neural_Network* network, Image** images, int amount) { +// int num_correct = 0; +// for (int i = 0; i < amount; i++) { +// Matrix* prediction = predict_image(network, images[i]); +// if (matrix_argmax(prediction) == images[i]->label) { +// num_correct++; +// } +// matrix_free(prediction); +// } +// return 1.0 * num_correct / amount; +//} -Matrix* predict(Neural_Network* network, Matrix* image_data) { - Matrix* hidden1_outputs = apply(relu, add(dot(network->weights_1, image_data), network->bias_1)); +//Matrix* predict_image(Neural_Network* network, Image*); - Matrix* hidden2_outputs = apply(relu, add(dot(network->weights_2, hidden1_outputs), network->bias_2)); - - Matrix* hidden3_outputs = apply(relu, add(dot(network->weights_3, hidden2_outputs), network->bias_3)); - - Matrix* final_outputs = apply(relu, dot(network->weights_output, hidden3_outputs)); - - Matrix* result = softmax(final_outputs); - - matrix_free(hidden1_outputs); - matrix_free(hidden2_outputs); - matrix_free(hidden3_outputs); - matrix_free(final_outputs); - - return result; -} +//Matrix* predict(Neural_Network* network, Matrix* image_data) { +// Matrix* hidden1_outputs = apply(relu, add(dot(network->weights_1, image_data), network->bias_1)); +// +// Matrix* hidden2_outputs = apply(relu, add(dot(network->weights_2, hidden1_outputs), network->bias_2)); +// +// Matrix* hidden3_outputs = apply(relu, add(dot(network->weights_3, hidden2_outputs), network->bias_3)); +// +// Matrix* final_outputs = apply(relu, dot(network->weights_output, hidden3_outputs)); +// +// Matrix* result = softmax(final_outputs); +// +// matrix_free(hidden1_outputs); +// matrix_free(hidden2_outputs); +// matrix_free(hidden3_outputs); +// matrix_free(final_outputs); +// +// return result; +//} void train_network(Neural_Network* network, Matrix* input, Matrix* output); void batch_train_network(Neural_Network* network, Image** images, int size); \ No newline at end of file