HolyFuckItsAlive #13
5 changed files with 148 additions and 72 deletions
|
|
@ -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)
|
||||
|
|
|
|||
105
image.c
105
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) {
|
||||
|
|
|
|||
22
image.h
22
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);
|
||||
4
main.c
4
main.c
|
|
@ -1,10 +1,12 @@
|
|||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#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]);
|
||||
|
||||
}
|
||||
|
|
@ -4,20 +4,20 @@
|
|||
#include <time.h>
|
||||
|
||||
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);
|
||||
Reference in a new issue