Compare commits

..

22 commits

Author SHA1 Message Date
Jakob Stornig
aa58f99045 minor changes 2023-09-25 11:11:07 +02:00
Jakob Stornig
ac35897396 Merge remote-tracking branch 'origin/main' 2023-09-24 22:36:51 +02:00
Jakob Stornig
746f4cf3bd deleted unused functions 2023-09-24 22:36:40 +02:00
jastornig
754d170616 Update .gitlab-ci.yml file 2023-09-24 20:36:11 +00:00
jastornig
8b4f2e2ccd Merge branch 'ci-testing' into 'main'
Ci testing

See merge request jastornig/c-net!12
2023-09-24 20:31:36 +00:00
Jakob Stornig
1cfdf93f7c (fix) evaluation
trained with 50000 images
evaluated with 10000
2023-09-24 22:29:41 +02:00
jastornig
e821afdbd5 Update .gitlab-ci.yml file 2023-09-24 20:23:22 +00:00
jastornig
a681833712 Update .gitlab-ci.yml file 2023-09-24 20:19:40 +00:00
jastornig
77b67aa949 Update .gitlab-ci.yml file 2023-09-24 20:12:14 +00:00
Jakob Stornig
38fafa672c minor changes for pgm files 2023-09-24 21:27:59 +02:00
jastornig
b9c3e93564 Update .gitlab-ci.yml file 2023-09-24 19:20:20 +00:00
jastornig
8ba83737f5 Merge branch 'merge-me' into 'main'
Update file README.md

See merge request jastornig/c-net!11
2023-09-24 19:07:59 +00:00
rawalcher
2d7fe49598 Update file README.md 2023-09-24 19:07:24 +00:00
jastornig
7bf2b88902 Merge branch 'lass-mi-de-drecks-readme-mergen' into 'main'
Lass mi de drecks readme mergen

See merge request jastornig/c-net!10
2023-09-24 19:02:24 +00:00
Raphael Walcher
eec607f7dd picture 2023-09-24 21:00:37 +02:00
jastornig
61339556c7 Merge branch 'Demonstration' into 'main'
!(feat) cli implemented

See merge request jastornig/c-net!9
2023-09-24 18:59:58 +00:00
Raphael Walcher
2019d56122 picture 2023-09-24 20:58:34 +02:00
Jakob Stornig
e9881ed2b3 !(feat) cli implemented
breaking changes.
save_network in neuronal_network.c now takes a second parameter file_name
2023-09-24 20:56:44 +02:00
jastornig
a282601751 Merge branch 'lass-mi-de-drecks-readme-mergen' into 'main'
readme

See merge request jastornig/c-net!8
2023-09-24 18:54:55 +00:00
Raphael Walcher
b9dba1a92b readme 2023-09-24 20:51:27 +02:00
jastornig
f13d3950b0 (fix) image loader windows 2023-09-23 20:30:25 +00:00
jastornig
dce3e264d9 Merge branch 'Delta-Error-Test' into 'main'
HolyFuckItsAlive

See merge request jastornig/c-net!6
2023-09-23 20:27:53 +00:00
14 changed files with 460 additions and 330 deletions

56
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,56 @@
# This file is a template, and might need editing before it works on your project.
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
#
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/C++.gitlab-ci.yml
# use the official gcc image, based on debian
# can use versions as well, like gcc:5.2
# see https://hub.docker.com/_/gcc/
image: gcc
stages:
- build
- release
build:
stage: build
# instead of calling g++ directly you can also use some build toolkit like make
# install the necessary build tools when needed
before_script:
- apt update && apt -y install cmake
script:
- echo BUILD_JOB_ID=$CI_JOB_ID >> CI_JOB_ID.env
- echo "Compiling the code..."
- cmake .
- cmake --build .
artifacts:
paths:
- c_net
reports:
dotenv: CI_JOB_ID.env
release:
image: registry.gitlab.com/gitlab-org/release-cli:latest
stage: release
needs:
- job: build
release:
tag_name: $CI_COMMIT_SHORT_SHA'
description: "latest"
assets:
links:
- name: c_net linux download (precompiled)
url: '${CI_PROJECT_URL}/-/jobs/${BUILD_JOB_ID}/artifacts/file/c_net'
script: echo "Define your deployment script!"

View file

@ -3,5 +3,5 @@ project(c_net C)
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
add_executable(c_net main.c matrix/matrix.c image/image.c neuronal_network.c util.c matrix/operations.c) add_executable(c_net main.c matrix.c image.c neuronal_network.c util.c util.h)
target_link_libraries(c_net m) target_link_libraries(c_net m)

View file

@ -1,10 +1,10 @@
# C-net ඞ # C-net ඞ
## Description ## Description
C-net ඞ is a Python project designed to read and predict numbers from the MNIST dataset using neural networks. C-net ඞ is a C project designed to read and predict numbers from the MNIST dataset using neural networks.
## Visuals ## Visuals
![Insert GIF or Screenshot here](link_to_visual.gif) ![Insert GIF or Screenshot here](https://camo.githubusercontent.com/b308207b5c5ce0970b13c21609350fab21aa61a2fae56da2a6418d6fdcdbc079/68747470733a2f2f7777772e776f6c6672616d2e636f6d2f6d617468656d61746963612f6e65772d696e2d31302f656e68616e6365642d696d6167652d70726f63657373696e672f48544d4c496d616765732e656e2f68616e647772697474656e2d6469676974732d636c617373696669636174696f6e2f736d616c6c7468756d625f31302e676966)
## Roadmap ## Roadmap
@ -23,8 +23,14 @@ This project was brought to you by the following contributors:
- Dworski, Daniel - Dworski, Daniel
- Walcher, Raphael - Walcher, Raphael
We would like to express our gratitude to the following project, which served as an inspiration and reference: We would like to express our gratitude to the following sources, which served as an inspiration and reference:
- [MNIST from Scratch](https://github.com/markkraay/mnist-from-scratch) by markkraay - [MNIST from Scratch](https://github.com/markkraay/mnist-from-scratch) by markkraay
- [Neural Network Framework in C](https://medium.com/analytics-vidhya/building-neural-network-framework-in-c-using-backpropagation-8ad589a0752d)
- [Simple Neural Network Implementation in C](https://towardsdatascience.com/simple-neural-network-implementation-in-c-663f51447547)
- [3Blue1Brown Neural Network Series](https://www.youtube.com/watch?v=aircAruvnKk&list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi)
- [Brotcrunsher's YouTube Videos](https://www.youtube.com/watch?v=oCPT87SvkPM&pp=ygUbYnJvdCBjcnVzaGVyIG5ldXJhbCBuZXp3ZXJr), [Video 2](https://www.youtube.com/watch?v=YIqYBxpv53A&pp=ygUbYnJvdCBjcnVzaGVyIG5ldXJhbCBuZXp3ZXJr), [Video 3](https://youtu.be/EAtQCut6Qno)
## Project Status ## Project Status
The project is considered finished, but ongoing optimizations and improvements may still be in progress. The project is considered finished, but ongoing optimizations and improvements may still be in progress.
![amogus](https://media.tenor.com/7kpsm7kU330AAAAd/sussy-among-us.gif)

View file

@ -2,8 +2,8 @@
#include <stdlib.h> #include <stdlib.h>
#include "image.h" #include "image.h"
#include "../matrix/matrix.h" #include "matrix.h"
#include "../util.h" #include "util.h"
void big_endian_to_c_uint(const char * bytes, void * target, int size) { void big_endian_to_c_uint(const char * bytes, void * target, int size) {
char* helper = (char*)target; char* helper = (char*)target;
@ -14,23 +14,27 @@ void big_endian_to_c_uint(const char * bytes, void * target, int size) {
void read_until_space_or_newline(char * buff, int maxCount, FILE * fptr){ void read_until_space_or_newline(char * buff, int maxCount, FILE * fptr){
int bufferOffset = 0; int bufferOffset = 0;
char c = -1; char c;
int counter = 0;
do{ do{
c = (char)getc(fptr); c = (char)getc(fptr);
buff[bufferOffset++] = c; buff[bufferOffset++] = c;
}while(!feof(fptr) && c != 0 && c != ' ' && c !='\n'); }while(!feof(fptr) && c != 0 && c != ' ' && c !='\n' && counter++ < maxCount);
buff[bufferOffset-1] = 0; buff[bufferOffset-1] = 0;
} }
Image * load_pgm_image(char * image_file_string){ Image * load_pgm_image(char * image_file_string){
FILE * fptr = fopen(image_file_string, "r"); FILE * fptr = fopen(image_file_string, "r");
if(!fptr){
printf("could not open image file. exit\n");
exit(1);
}
Image *image = malloc(sizeof(Image)); Image *image = malloc(sizeof(Image));
image->label = -1; image->label = -1;
char buffer[100]; char buffer[2048];
int magic_number = 0;
fgets(buffer, 4, fptr); fgets(buffer, 4, fptr);
if(buffer[0] != 'P' || buffer[1] != '5'){ if(buffer[0] != 'P' || buffer[1] != '5'){
printf("Wrong file Format"); printf("Wrong file Format");
@ -40,17 +44,16 @@ Image * load_pgm_image(char * image_file_string){
fgets(buffer, 1024, fptr); fgets(buffer, 1024, fptr);
} }
int image_width, image_height, image_length, image_white ; int image_width, image_height, image_white ;
read_until_space_or_newline(buffer, 10, fptr); read_until_space_or_newline(buffer, 10, fptr);
image_width = strtol(buffer, NULL, 10); image_width = (int)strtol(buffer, NULL, 10);
read_until_space_or_newline(buffer, 10, fptr); read_until_space_or_newline(buffer, 10, fptr);
image_height = strtol(buffer, NULL, 10); image_height = (int)strtol(buffer, NULL, 10);
read_until_space_or_newline(buffer, 10, fptr); read_until_space_or_newline(buffer, 10, fptr);
image_white = strtol(buffer, NULL, 10); image_white = (int)strtol(buffer, NULL, 10);
image_length = image_width * image_height;
image->pixel_values = matrix_create(image_height, image_width); image->pixel_values = matrix_create(image_height, image_width);
for(int i = 0; i < image_height; i++){ for(int i = 0; i < image_height; i++){
@ -159,6 +162,7 @@ Image** import_images(char* image_file_string, char* label_file_string, int* _nu
} }
void img_print (Image* img) { void img_print (Image* img) {
//print the image //print the image
matrix_print(img->pixel_values); matrix_print(img->pixel_values);
//print the number of the image //print the number of the image

32
image.h Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include "matrix.h"
#include "matrix.h"
typedef struct {
Matrix* pixel_values;
char label;
} Image;
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, int* number_imported, int count);
Image * load_pgm_image(char * image_file_string);
void img_print (Image* image);
void img_visualize(Image*image);
void img_free (Image* image);

View file

@ -1,21 +0,0 @@
#include "../matrix/matrix.h"
typedef struct {
Matrix* pixel_values;
char label;
} Image;
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;
Image ** import_images(char* image_file_string, char* label_file_string, int* number_imported, int count);
Image * load_pgm_image(char * image_file_string);
void img_print (Image* image);
void img_visualize(Image*image);
void img_free (Image* image);
void images_free (Image** images, int quantity);

156
main.c
View file

@ -1,64 +1,122 @@
#include <stdio.h> #include <stdio.h>
#include "image/image.h" #include "image.h"
#include "neuronal_network.h" #include "neuronal_network.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "util.h"
int main() { void parsingErrorPrintHelp(){
printf("Syntax: c_net [train | predict]\n");
const int amount_of_images_to_load = 60000; printf("commands:\n");
const int amount_of_images_used_to_train = 30000; printf("train\t train the network\n");
const int amount_of_images_used_to_test = 1000; printf("predict\t load a pgm image and predict_demo the number\n");
const int input_size = 28*28; exit(1);
const int hidden_layer_size = 50;
const int hidden_layer_count = 3;
const double learning_rate = 0.1;
/*
* Loading Images from Dataset
*/
Image** images = import_images("../data/train-images.idx3-ubyte", "../data/train-labels.idx1-ubyte", NULL, amount_of_images_to_load);
// img_visualize(images[0]);
// img_print(images[0]);
/*
* Create a new network and randomize the weights
*/
Neural_Network* network = new_network(input_size, hidden_layer_size, hidden_layer_count, 10, learning_rate);
randomize_network(network, 1);
/*
* Training
*/
for (int i = 0; i < amount_of_images_used_to_train; i++) {
train_network(network, images[i], images[i]->label);
} }
// Batch training works if you change the train_network method, but the results are not that good (needs further testing) void parsingErrorTrain(){
// batch_train(nn, images, 30000, 2); printf("invalid syntax\n");
printf("Syntax: c_net train [path_to_train-images.idx3-ubyte] [path_to_train-labels.idx1-ubyte] [hidden_layer_count] [neurons_per_layer] [epochs] [learning_rate] [path_to_save_network]\n");
exit(1);
}
printf("Trinaing Done!\n"); void parsingErrorDetect(){
printf("invalid syntax\n");
printf("Syntax: c_net predict_demo [path_to_network] [image_file]\n");
}
/* void predict_demo(int argc, char** arguments){
* Saving and Loading if(argc != 2) parsingErrorDetect();
*/ char * network_file = arguments[0];
char * image_file = arguments[1];
// save_network(network); Neural_Network * nn = load_network(network_file);
// Neural_Network* network = load_network("../networks/newest_network.txt"); Image * image = load_pgm_image(image_file);
Matrix * result = predict_image(nn, image);
int predicted = matrix_argmax(result);
printf("prediction result %d\n", predicted);
matrix_print(result);
matrix_free(result);
}
/* void train(int argc, char** arguments) {
* Measure Accuracy & predict single images if (argc != 7) parsingErrorTrain();
*/ char *image_file = arguments[0];
char *label_file = arguments[1];
int hidden_count = (int) strtol(arguments[2], NULL, 10);
int neurons_per_layer = (int) strtol(arguments[3], NULL, 10);
int epochs = (int) strtol(arguments[4], NULL, 10);
if (errno != 0) {
printf("hidden_count, neurons_per_layer or epochs could not be parsed!\n");
exit(1);
}
double learning_rate = strtod(arguments[5], NULL);
if (errno != 0) {
printf("learning_rate could not be parsed!\n");
exit(1);
}
char *save_path = arguments[6];
int imported = 0;
Image ** images = import_images(image_file, label_file, &imported, 60000);
Image ** evaluation_images = images+50000;
printf("Accuracy: %lf\n", measure_network_accuracy(network, images, amount_of_images_used_to_test)); int training_image_count = 50000;
int testing_image_count = 10000;
// matrix_print(predict_image(network, images[0])); Neural_Network *nn = new_network(28 * 28, neurons_per_layer, hidden_count, 10, learning_rate);
randomize_network(nn, 1);
images_free(images, amount_of_images_to_load); printf("training_network\n");
free_network(network); for(int epoch = 1; epoch <= epochs; epoch++){
printf("epoch %d\n", epoch);
for (int i = 0; i < training_image_count; i++) {
if (i % 1000 == 0) {
updateBar(i * 100 / imported);
}
train_network(nn, images[i], images[i]->label);
}
updateBar(100);
printf("\n");
printf("accuracy %lf\n", measure_network_accuracy(nn, evaluation_images, testing_image_count));
}
printf("done training!\n");
save_network(nn, save_path);
}
int main(int argc, char** argv) {
// Image** images = import_images("../data/train-images.idx3-ubyte", "../data/train-labels.idx1-ubyte", NULL, 60000);
//// img_visualize(images[0]);
//// img_visualize(images[1]);
//
//// matrix_print(images[0]->pixel_values);
//// matrix_print(images[1]->pixel_values);
//
// Neural_Network* nn = new_network(28*28, 40, 5, 10, 0.08);
// randomize_network(nn, 1);
//// Neural_Network* nn = load_network("../networks/newest_network.txt");
//// printf("Done loading!\n");
//
//// batch_train(nn, images, 20000, 20);
//
// for (int i = 0; i < 30000; ++i) {
// train_network(nn, images[i], images[i]->label);
// }
//
// save_network(nn);
//
// printf("%lf\n", measure_network_accuracy(nn, images, 10000));
if(argc < 2){
parsingErrorPrintHelp();
exit(1);
}
if(strcmp(argv[1], "train") == 0){
train(argc-2, argv+2);
return 0; return 0;
} }
if(strcmp(argv[1], "predict") == 0){
predict_demo(argc - 2, argv + 2);
return 0;
}
parsingErrorPrintHelp();
}

View file

@ -1,10 +1,92 @@
#include <process.h> #include "matrix.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h> #include <time.h>
#include "math.h" #define MAX_BYTES 100
#include "operations.h"
static int RANDOMIZED = 0; static int RANDOMIZED = 0;
// operational functions
Matrix* matrix_create(int rows, int columns) {
// allocate memory for the matrix
Matrix* matrix = malloc(sizeof(Matrix));
// set size variables to the correct size
matrix->rows = rows;
matrix->columns = columns;
// allocate memory for the numbers (2D-Array)
matrix->numbers = malloc(sizeof(double*) * rows);
for (int i = 0; i < rows; i++) {
matrix->numbers[i] = calloc(sizeof(double), columns);
}
// return the pointer to the allocated memory
return matrix;
}
void matrix_fill(Matrix* matrix, double value) {
// simple for loop to populate the 2D-array with a value
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->columns; j++) {
matrix->numbers[i][j] = value;
}
}
}
void matrix_free(Matrix* matrix) {
// de-allocate every column
for (int i = 0; i < matrix->rows; i++) {
free(matrix->numbers[i]);
}
// de-allocate the rows
free(matrix->numbers);
// de-allocate the matrix
free(matrix);
}
void matrix_print(Matrix *matrix) {
// print the dimensions of the matrix
printf("Rows: %d, Columns: %d\n", matrix->rows, matrix->columns);
// loop through all values and format them into the correct matrix representation
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->columns; j++) {
printf("%lf ", matrix->numbers[i][j]);
}
printf("\n");
}
}
Matrix* matrix_copy(Matrix *matrix) {
// create another matrix of the same size
Matrix* copy_of_matrix = matrix_create(matrix->rows, matrix->columns);
// copy the values from the original matrix into the copy
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->columns; j++) {
copy_of_matrix->numbers[i][j] = matrix->numbers[i][j];
}
}
// return the pointer to the copy
return copy_of_matrix;
}
// mathematical functions
/*
* These methods won't change or free the input matrix.
* It creates a new matrix, which is modified and then returned.
* If we don't need the original matrix, we should consider just changing the original matrix and changing the method signature to void.
*/
Matrix* multiply(Matrix* matrix1, Matrix* matrix2) { Matrix* multiply(Matrix* matrix1, Matrix* matrix2) {
@ -134,6 +216,7 @@ Matrix* scale(Matrix* matrix, double value) {
return result_matrix; return result_matrix;
} }
Matrix* transpose(Matrix* matrix) { Matrix* transpose(Matrix* matrix) {
// create a new matrix of the size n-m, based on the original matrix of size m-n // create a new matrix of the size n-m, based on the original matrix of size m-n
@ -151,6 +234,67 @@ Matrix* transpose(Matrix* matrix) {
} }
void matrix_save(Matrix* matrix, char* file_string){
// open the file in append mode
FILE *file = fopen(file_string, "a");
// check if the file could be found
if(file == NULL) {
printf("ERROR: Unable to get handle for \"%s\"! (matrix_save)", file_string);
exit(1);
}
// save the size of the matrix
fprintf(file, "%d\n", matrix->rows);
fprintf(file, "%d\n", matrix->columns);
// save all the numbers of the matrix into the file
for(int i = 0; i < matrix->rows; i++){
for(int j = 0; j < matrix->columns; j++){
fprintf(file, "%.10f\n", matrix->numbers[i][j]);
}
}
// close the file
fclose(file);
}
Matrix* matrix_load(char* file_string){
FILE *fptr = fopen(file_string, "r");
if(!fptr){
printf("Could not open \"%s\"", file_string);
exit(1);
}
Matrix * m = load_next_matrix(fptr);
fclose(fptr);
return m;
}
Matrix* load_next_matrix(FILE *save_file){
char buffer[MAX_BYTES];
fgets(buffer, MAX_BYTES, save_file);
int rows = (int)strtol(buffer, NULL, 10);
fgets(buffer, MAX_BYTES, save_file);
int cols = (int)strtol(buffer, NULL, 10);
Matrix *matrix = matrix_create(rows, cols);
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
fgets(buffer, MAX_BYTES, save_file);
matrix->numbers[i][j] = strtod(buffer, NULL);
}
}
return matrix;
}
Matrix* matrix_flatten(Matrix* matrix, int axis) { Matrix* matrix_flatten(Matrix* matrix, int axis) {
// Axis = 0 -> Column Vector, Axis = 1 -> Row Vector // Axis = 0 -> Column Vector, Axis = 1 -> Row Vector
Matrix* result_matrix; Matrix* result_matrix;
@ -174,10 +318,10 @@ Matrix* matrix_flatten(Matrix* matrix, int axis) {
return result_matrix; return result_matrix;
} }
int argmax(Matrix* matrix) { int matrix_argmax(Matrix* matrix) {
// Expects a Mx1 matrix // Expects a Mx1 matrix
if (matrix->columns != 1){ if (matrix->columns != 1){
printf("ERROR: Matrix is not Mx1 (argmax)"); printf("ERROR: Matrix is not Mx1 (matrix_argmax)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }

39
matrix.h Normal file
View file

@ -0,0 +1,39 @@
#pragma once
#include <stdio.h>
typedef struct {
int rows, columns;
double **numbers;
} Matrix;
static const int scaling_value = 10000;
// operational functions
Matrix* matrix_create(int rows, int columns);
void matrix_fill(Matrix* matrix, double value);
void matrix_free(Matrix* matrix);
void matrix_print(Matrix *matrix);
Matrix* matrix_copy(Matrix *matrix);
void matrix_save(Matrix* matrix, char* file_string);
Matrix* matrix_load(char* file_string);
Matrix* load_next_matrix(FILE * save_file);
void matrix_randomize(Matrix* matrix, int n); // don't understand the usage of the n
int matrix_argmax(Matrix* matrix);
Matrix* matrix_flatten(Matrix* matrix, int axis);
Matrix* matrix_add_bias(Matrix* matrix);
/*
* These methods won't change or free the input matrix.
* It creates a new matrix, which is modified and then returned.
* If we don't need the original matrix, we should consider just changing the original matrix and changing the method signature to void.
*/
// mathematical functions
Matrix* multiply(Matrix* matrix1, Matrix* matrix2);
Matrix* add(Matrix* matrix1, Matrix* matrix2);
Matrix* subtract(Matrix* matrix1, Matrix* matrix2);
Matrix* dot(Matrix* matrix1, Matrix* matrix2);
Matrix* apply(double (*function)(double), Matrix* matrix);
Matrix* scale(Matrix* matrix, double value);
Matrix* transpose(Matrix* matrix);

View file

@ -1,139 +0,0 @@
#include "matrix.h"
#include <stdlib.h>
#include <stdio.h>
#define MAX_BYTES 100
Matrix* matrix_create(int rows, int columns) {
// allocate memory for the matrix
Matrix* matrix = malloc(sizeof(Matrix));
// set size variables to the correct size
matrix->rows = rows;
matrix->columns = columns;
// allocate memory for the numbers (2D-Array)
matrix->numbers = malloc(sizeof(double*) * rows);
for (int i = 0; i < rows; i++) {
matrix->numbers[i] = calloc(sizeof(double), columns);
}
// return the pointer to the allocated memory
return matrix;
}
void matrix_fill(Matrix* matrix, double value) {
// simple for loop to populate the 2D-array with a value
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->columns; j++) {
matrix->numbers[i][j] = value;
}
}
}
void matrix_free(Matrix* matrix) {
// de-allocate every column
for (int i = 0; i < matrix->rows; i++) {
free(matrix->numbers[i]);
}
// de-allocate the rows
free(matrix->numbers);
// de-allocate the matrix
free(matrix);
}
void matrix_print(Matrix *matrix) {
// print the dimensions of the matrix
printf("Rows: %d, Columns: %d\n", matrix->rows, matrix->columns);
// loop through all values and format them into the correct matrix representation
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->columns; j++) {
printf("%lf ", matrix->numbers[i][j]);
}
printf("\n");
}
}
Matrix* matrix_copy(Matrix *matrix) {
// create another matrix of the same size
Matrix* copy_of_matrix = matrix_create(matrix->rows, matrix->columns);
// copy the values from the original matrix into the copy
for (int i = 0; i < matrix->rows; i++) {
for (int j = 0; j < matrix->columns; j++) {
copy_of_matrix->numbers[i][j] = matrix->numbers[i][j];
}
}
// return the pointer to the copy
return copy_of_matrix;
}
void matrix_save(Matrix* matrix, char* file_string){
// open the file in append mode
FILE *file = fopen(file_string, "a");
// check if the file could be found
if(file == NULL) {
printf("ERROR: Unable to get handle for \"%s\"! (matrix_save)", file_string);
exit(1);
}
// save the size of the matrix
fprintf(file, "%d\n", matrix->rows);
fprintf(file, "%d\n", matrix->columns);
// save all the numbers of the matrix into the file
for(int i = 0; i < matrix->rows; i++){
for(int j = 0; j < matrix->columns; j++){
fprintf(file, "%.10f\n", matrix->numbers[i][j]);
}
}
// close the file
fclose(file);
}
Matrix* matrix_load(char* file_string){
FILE *fptr = fopen(file_string, "r");
if(!fptr){
printf("Could not open \"%s\"", file_string);
exit(1);
}
Matrix * m = load_next_matrix(fptr);
fclose(fptr);
return m;
}
Matrix* load_next_matrix(FILE *save_file){
char buffer[MAX_BYTES];
fgets(buffer, MAX_BYTES, save_file);
int rows = (int)strtol(buffer, NULL, 10);
fgets(buffer, MAX_BYTES, save_file);
int cols = (int)strtol(buffer, NULL, 10);
Matrix *matrix = matrix_create(rows, cols);
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
fgets(buffer, MAX_BYTES, save_file);
matrix->numbers[i][j] = strtod(buffer, NULL);
}
}
return matrix;
}

View file

@ -1,15 +0,0 @@
#include <stdio.h>
typedef struct {
int rows, columns;
double **numbers;
} Matrix;
Matrix* matrix_create(int rows, int columns);
void matrix_fill(Matrix* matrix, double value);
void matrix_free(Matrix* matrix);
void matrix_print(Matrix *matrix);
Matrix* matrix_copy(Matrix *matrix);
void matrix_save(Matrix* matrix, char* file_string);
Matrix* matrix_load(char* file_string);
Matrix* load_next_matrix(FILE * save_file);

View file

@ -1,25 +0,0 @@
#include "matrix.h"
static const int scaling_value = 10000;
Matrix* multiply(Matrix* matrix1, Matrix* matrix2);
Matrix* add(Matrix* matrix1, Matrix* matrix2); //only used in the batch_training method
Matrix* subtract(Matrix* matrix1, Matrix* matrix2);
Matrix* dot(Matrix* matrix1, Matrix* matrix2);
Matrix* apply(double (*function)(double), Matrix* matrix);
Matrix* scale(Matrix* matrix, double value);
Matrix* transpose(Matrix* matrix);
Matrix* matrix_flatten(Matrix* matrix, int axis);
int argmax(Matrix* matrix);
void matrix_randomize(Matrix* matrix, int n);
Matrix* matrix_add_bias(Matrix* matrix);

View file

@ -1,14 +1,14 @@
#include <stdlib.h> #include <stdlib.h>
#include "neuronal_network.h" #include "neuronal_network.h"
#include "matrix\operations.h"
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include "util.h"
double sigmoid(double input); double sigmoid(double input);
Matrix* predict(Neural_Network* network, Matrix* image_data); Matrix* predict(Neural_Network* network, Matrix* image_data);
Matrix* sigmoid_derivative(Matrix* matrix); Matrix* sigmoid_derivative(Matrix* matrix);
Matrix *calculate_weights_delta(Matrix *previous_layer_output, Matrix *delta_matrix); Matrix *calculate_weights_delta(Matrix *previous_layer_output, Matrix *delta_matrix, double learning_rate);
void apply_weights(Neural_Network *network, Matrix *delta_weights_matrix, int index, double learning_rate); void apply_weights(Neural_Network* network, Matrix* delta_weights_matrix, int index);
Matrix* calculate_delta_hidden(Matrix* next_layer_delta, Matrix* weights, Matrix* current_layer_output); Matrix* calculate_delta_hidden(Matrix* next_layer_delta, Matrix* weights, Matrix* current_layer_output);
Neural_Network* new_network(int input_size, int hidden_size, int hidden_amount, int output_size, double learning_rate){ Neural_Network* new_network(int input_size, int hidden_size, int hidden_amount, int output_size, double learning_rate){
@ -46,9 +46,7 @@ void free_network(Neural_Network* network){
free(network); free(network);
} }
void save_network(Neural_Network* network) { void save_network(Neural_Network* network, char * file_name) {
char* file_name = "../networks/newest_network.txt";
// create file // create file
FILE* save_file = fopen(file_name, "w"); FILE* save_file = fopen(file_name, "w");
@ -118,10 +116,13 @@ void print_network(Neural_Network* network) {
double measure_network_accuracy(Neural_Network* network, Image** images, int amount) { double measure_network_accuracy(Neural_Network* network, Image** images, int amount) {
int num_correct = 0; int num_correct = 0;
printf("evaluating network\n");
if(amount > 10000) amount = 10000;
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
updateBar(i*100/amount);
Matrix* prediction = predict_image(network, images[i]); Matrix* prediction = predict_image(network, images[i]);
int guess = argmax(prediction); int guess = matrix_argmax(prediction);
int answer = (unsigned char) images[i]->label; int answer = (unsigned char) images[i]->label;
if (guess == answer) { if (guess == answer) {
@ -130,6 +131,7 @@ double measure_network_accuracy(Neural_Network* network, Image** images, int amo
matrix_free(prediction); matrix_free(prediction);
} }
updateBar(100);
return ((double) num_correct) / amount; return ((double) num_correct) / amount;
} }
@ -168,26 +170,22 @@ Matrix* predict(Neural_Network* network, Matrix* image_data) {
//void batch_train(Neural_Network* network, Image** images, int amount, int batch_size) { //void batch_train(Neural_Network* network, Image** images, int amount, int batch_size) {
// //
// if(amount % batch_size != 0) { // for (int i = 0; i < amount; ++i) {
// printf("ERROR: Batch Size is not compatible with image amount! (batch_train)"); //
// exit(1); // if(amount % 1000 == 0) {
// printf("1k pics!\n");
// } // }
// //
// int image_index = 0;
//
// for (int i = 0; i < amount / batch_size; ++i) {
//
// Matrix* batch_weights[network->hidden_amount + 1]; // Matrix* batch_weights[network->hidden_amount + 1];
// //
// for (int j = 0; j < network->hidden_amount + 1; j++) {
// batch_weights[j] = matrix_create(network->weights[j]->rows, network->weights[j]->columns);
// matrix_fill(batch_weights[j], 0);
// }
//
// for (int j = 0; j < batch_size; ++j) { // for (int j = 0; j < batch_size; ++j) {
// Matrix** delta_weights = train_network(network, images[image_index], images[image_index]->label); // Matrix** delta_weights = train_network(network, images[i], images[i]->label);
// //
// for (int k = 0; k < network->hidden_amount + 1; k++) { // for (int k = 0; k < network->hidden_amount + 1; k++) {
// if(j == 0) {
// batch_weights[k] = delta_weights[k];
// continue;
// }
// //
// Matrix* temp_result = add(batch_weights[k], delta_weights[k]); // Matrix* temp_result = add(batch_weights[k], delta_weights[k]);
// //
@ -198,16 +196,14 @@ Matrix* predict(Neural_Network* network, Matrix* image_data) {
// } // }
// //
// free(delta_weights); // free(delta_weights);
//
// image_index++;
// } // }
// //
// for (int j = 0; j < network->hidden_amount + 1; j++) { // for (int j = 0; j < network->hidden_amount + 1; ++j) {
// Matrix* average_delta_weight = scale(batch_weights[j], (1.0 / batch_size)); // Matrix* average_delta_weight = scale(batch_weights[j], (1.0 / batch_size));
// apply_weights(network, average_delta_weight, j, network->learning_rate); // apply_weights(network, average_delta_weight, j);
// //
// matrix_free(batch_weights[j]);
// matrix_free(average_delta_weight); // matrix_free(average_delta_weight);
// matrix_free(batch_weights[j]);
// } // }
// } // }
//} //}
@ -246,13 +242,13 @@ void train_network(Neural_Network* network, Image *image, int label) {
Matrix* delta = multiply(sigmoid_prime, error); Matrix* delta = multiply(sigmoid_prime, error);
//calculate and apply the delta for all weights in out-put layer //calculate and apply the delta for all weights in out-put layer
delta_weights[network->hidden_amount] = calculate_weights_delta(output[network->hidden_amount - 1], delta); delta_weights[network->hidden_amount] = calculate_weights_delta(output[network->hidden_amount - 1], delta, network->learning_rate);
//hidden layers //hidden layers
Matrix* previous_delta = delta; Matrix* previous_delta = delta;
for (int i = network->hidden_amount; i > 1; i--) { for (int i = network->hidden_amount; i > 1; i--) {
delta = calculate_delta_hidden(previous_delta, network->weights[i], output[i - 1]); delta = calculate_delta_hidden(previous_delta, network->weights[i], output[i - 1]);
delta_weights[i - 1] = calculate_weights_delta(output[i - 2], delta); delta_weights[i - 1] = calculate_weights_delta(output[i - 2], delta, network->learning_rate);
matrix_free(previous_delta); matrix_free(previous_delta);
previous_delta = delta; previous_delta = delta;
@ -260,16 +256,10 @@ void train_network(Neural_Network* network, Image *image, int label) {
// Input Layer // Input Layer
delta = calculate_delta_hidden(previous_delta, network->weights[1], output[0]); delta = calculate_delta_hidden(previous_delta, network->weights[1], output[0]);
delta_weights[0] = calculate_weights_delta(image_data, delta); delta_weights[0] = calculate_weights_delta(image_data, delta, network->learning_rate);
// if you want to use this method as a standalone method this part needs to be uncommented
for (int i = 0; i < network->hidden_amount + 1; ++i) {
apply_weights(network, delta_weights[i], i, network->learning_rate);
}
for (int i = 0; i < network->hidden_amount + 1; ++i) { for (int i = 0; i < network->hidden_amount + 1; ++i) {
matrix_free(delta_weights[i]); apply_weights(network, delta_weights[i], i);
} }
// De-allocate stuff // De-allocate stuff
@ -280,7 +270,9 @@ void train_network(Neural_Network* network, Image *image, int label) {
matrix_free(output[i]); matrix_free(output[i]);
} }
for (int i = 0; i < network->hidden_amount + 1; ++i) {
matrix_free(delta_weights[i]);
}
matrix_free(sigmoid_prime); matrix_free(sigmoid_prime);
matrix_free(wanted_output); matrix_free(wanted_output);
@ -319,7 +311,7 @@ Matrix* calculate_delta_hidden(Matrix* next_layer_delta, Matrix* weights, Matrix
return new_deltas; return new_deltas;
} }
void apply_weights(Neural_Network *network, Matrix *delta_weights_matrix, int index, double learning_rate) { void apply_weights(Neural_Network* network, Matrix* delta_weights_matrix, int index) {
if(index > network->hidden_amount || index < 0) { if(index > network->hidden_amount || index < 0) {
printf("ERROR: Index out of range! (apply_weights)"); printf("ERROR: Index out of range! (apply_weights)");
@ -331,28 +323,27 @@ void apply_weights(Neural_Network *network, Matrix *delta_weights_matrix, int in
exit(1); exit(1);
} }
// scale by learning rate
Matrix* scaled_delta_weights_matrix = scale(delta_weights_matrix, learning_rate);
for (int i = 0; i < delta_weights_matrix->rows; i++) { for (int i = 0; i < delta_weights_matrix->rows; i++) {
for (int j = 0; j < scaled_delta_weights_matrix->columns; j++) { for (int j = 0; j < delta_weights_matrix->columns; j++) {
network->weights[index]->numbers[i][j] += scaled_delta_weights_matrix->numbers[i][j]; // multiply delta_weights_matrix with learning rate AND - instead of + because soll-ist network->weights[index]->numbers[i][j] += delta_weights_matrix->numbers[i][j]; // multiply delta_weights_matrix with learning rate AND - instead of + because soll-ist
}
} }
} }
matrix_free(scaled_delta_weights_matrix); Matrix *calculate_weights_delta(Matrix *previous_layer_output, Matrix *delta_matrix, double learning_rate) {
}
Matrix *calculate_weights_delta(Matrix *previous_layer_output, Matrix *delta_matrix) {
Matrix* previous_out_with_one = matrix_add_bias(previous_layer_output); Matrix* previous_out_with_one = matrix_add_bias(previous_layer_output);
Matrix* transposed_previous_out_with_bias = transpose(previous_out_with_one); Matrix* transposed_previous_out_with_bias = transpose(previous_out_with_one);
Matrix* weights_delta_matrix = dot(delta_matrix, transposed_previous_out_with_bias); Matrix* weights_delta_matrix = dot(delta_matrix, transposed_previous_out_with_bias);
// scale by learning rate
Matrix* result = scale(weights_delta_matrix, learning_rate);
matrix_free(previous_out_with_one); matrix_free(previous_out_with_one);
matrix_free(transposed_previous_out_with_bias); matrix_free(transposed_previous_out_with_bias);
matrix_free(weights_delta_matrix);
return weights_delta_matrix; return result;
} }
Matrix* sigmoid_derivative(Matrix* matrix) { Matrix* sigmoid_derivative(Matrix* matrix) {

View file

@ -1,6 +1,6 @@
#include "matrix/matrix.h" #include "matrix.h"
#include "image/image.h" #include "image.h"
typedef struct { typedef struct {
int input_size; int input_size;
@ -21,7 +21,7 @@ Neural_Network* new_network(int input_size, int hidden_size, int hidden_amount,
void randomize_network(Neural_Network* network, int scope); void randomize_network(Neural_Network* network, int scope);
void free_network(Neural_Network* network); void free_network(Neural_Network* network);
void save_network(Neural_Network* network); void save_network(Neural_Network* network, char * file_name);
Neural_Network* load_network(char* file); Neural_Network* load_network(char* file);
void print_network(Neural_Network* network); void print_network(Neural_Network* network);