feat: added AI and working on loading dataset
This commit is contained in:
739
src/utils/AI/neural_utils.c
Normal file
739
src/utils/AI/neural_utils.c
Normal file
@ -0,0 +1,739 @@
|
|||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
#include "neural_utils.h"
|
||||||
|
#include "../Application/ApplicationUtils.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
double sigmoid(double x)
|
||||||
|
{
|
||||||
|
return 1.0 / (1.0 + exp(-x));
|
||||||
|
}
|
||||||
|
|
||||||
|
double sigmoid_derivate(double x)
|
||||||
|
{
|
||||||
|
double s = sigmoid(x);
|
||||||
|
return s*(1-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
double double_rand(double size)
|
||||||
|
{
|
||||||
|
return ((double)rand() / (double)RAND_MAX) * size - (size / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double clamp(double value, double min, double max)
|
||||||
|
{
|
||||||
|
if (value < min)
|
||||||
|
return min;
|
||||||
|
if (value > max)
|
||||||
|
return max;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_neuron(neuron* n, size_t nb_connection)
|
||||||
|
{
|
||||||
|
n->bias = double_rand(12.0 / (double)nb_connection);
|
||||||
|
n->activation = 0.0;
|
||||||
|
|
||||||
|
double* weights = calloc( nb_connection, sizeof(double));
|
||||||
|
|
||||||
|
if (weights == NULL)
|
||||||
|
errx(1, "init_neuron: Cannot allocate memory!");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nb_connection; i++)
|
||||||
|
{
|
||||||
|
weights[i] = double_rand(10.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
n->weights = weights;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_neuron(neuron* n)
|
||||||
|
{
|
||||||
|
free(n->weights);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_neural_network(neural_network* network)
|
||||||
|
{
|
||||||
|
if (network->nb_input <= 0)
|
||||||
|
errx(EXIT_FAILURE, "init_neural_network: cannot allocate neural network with 0 or less input neurons");
|
||||||
|
neuron* in = (neuron*)calloc(network->nb_input, sizeof(neuron));
|
||||||
|
if (in == NULL)
|
||||||
|
errx(1, "init_neural_network: Cannot allocate memory!");
|
||||||
|
if (network->nb_output <= 0)
|
||||||
|
errx(EXIT_FAILURE, "init_neural_network: cannot allocate neural network with 0 or less output neurons");
|
||||||
|
neuron* out = (neuron*)calloc(network->nb_output, sizeof(neuron));
|
||||||
|
if (out == NULL)
|
||||||
|
errx(1, "init_neural_network: Cannot allocate memory!");
|
||||||
|
|
||||||
|
if (network->hidden_depth <= 0)
|
||||||
|
errx(EXIT_FAILURE, "init_neural_network: cannot allocate neural network with 0 or less hidden neurons");
|
||||||
|
neuron** hid = (neuron**)calloc(network->hidden_depth, sizeof(neuron));
|
||||||
|
if (hid == NULL)
|
||||||
|
errx(1, "init_neural_network: Cannot allocate memory!");
|
||||||
|
|
||||||
|
if (network->hidden_height <= 0)
|
||||||
|
errx(EXIT_FAILURE, "init_neural_network: cannot allocate neural network with 0 or less hidden neurons");
|
||||||
|
for (size_t i = 0; i < network->hidden_depth; i++)
|
||||||
|
{
|
||||||
|
neuron* val = (neuron*)calloc(network->hidden_height, sizeof(neuron));
|
||||||
|
if (val == NULL)
|
||||||
|
errx(1, "init_neural_network: Cannot allocate memory!");
|
||||||
|
hid[i] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
network->inputs = in;
|
||||||
|
network->outputs = out;
|
||||||
|
network->hidden = hid;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < network->nb_input; i++)
|
||||||
|
{
|
||||||
|
init_neuron(&network->inputs[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < network->nb_output; i++)
|
||||||
|
{
|
||||||
|
init_neuron(&network->outputs[i], network->hidden_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t x = 0; x < network->hidden_depth; x++)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++)
|
||||||
|
{
|
||||||
|
if (x == 0)
|
||||||
|
init_neuron(&network->hidden[x][y], network->nb_input);
|
||||||
|
else
|
||||||
|
init_neuron(&network->hidden[x][y], network->hidden_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_neural_network(neural_network* network)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < network->nb_input; i++)
|
||||||
|
{
|
||||||
|
free_neuron(&network->inputs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < network->nb_output; i++)
|
||||||
|
{
|
||||||
|
free_neuron(&network->outputs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t x = 0; x < network->hidden_depth; x++)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++)
|
||||||
|
{
|
||||||
|
free_neuron(&network->hidden[x][y]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < network->hidden_depth; i++)
|
||||||
|
{
|
||||||
|
free(network->hidden + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//free(network->hidden);
|
||||||
|
free(network->inputs);
|
||||||
|
free(network->outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_neural_network(neural_network* network, const char* file_path)
|
||||||
|
{
|
||||||
|
FILE *fptr;
|
||||||
|
|
||||||
|
fptr = fopen(file_path, "w");
|
||||||
|
|
||||||
|
fprintf(fptr, "%li,%li,%li,%li\n", network->nb_input, network->hidden_depth, network->hidden_height, network->nb_output);
|
||||||
|
|
||||||
|
for (size_t x = 0; x < network->hidden_depth; x++)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++)
|
||||||
|
{
|
||||||
|
if (x == 0)
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->nb_input; h++)
|
||||||
|
{
|
||||||
|
fprintf(fptr, "%f,", network->hidden[x][y].weights[h]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
fprintf(fptr, "%f,", network->hidden[x][y].weights[h]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fptr, "%f,", network->hidden[x][y].bias);
|
||||||
|
}
|
||||||
|
fprintf(fptr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < network->nb_output; i++)
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
fprintf(fptr, "%f,", network->outputs[i].weights[h]);
|
||||||
|
}
|
||||||
|
fprintf(fptr, "%f,", network->outputs[i].bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
char** string_split(const char* string, char separator, size_t* res_len)
|
||||||
|
{
|
||||||
|
size_t sep_nb = 0;
|
||||||
|
|
||||||
|
for (int i = 0; string[i] != '\0'; i++)
|
||||||
|
{
|
||||||
|
if (string[i] == separator)
|
||||||
|
sep_nb++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sep_nb++;
|
||||||
|
|
||||||
|
char** res = calloc(sep_nb, sizeof(char*));
|
||||||
|
|
||||||
|
if (res == NULL)
|
||||||
|
errx(EXIT_FAILURE, "string_split: malloc error");
|
||||||
|
|
||||||
|
*res_len = sep_nb;
|
||||||
|
|
||||||
|
const char* str_pos = string;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < sep_nb; j++)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (str_pos[j+len] != separator && str_pos[j+len] != '\0')
|
||||||
|
{
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* str = calloc(len+1, sizeof(char));
|
||||||
|
|
||||||
|
if (str == NULL)
|
||||||
|
errx(EXIT_FAILURE, "string_split: malloc error");
|
||||||
|
|
||||||
|
str[len] = '\0';
|
||||||
|
|
||||||
|
memcpy(str, str_pos + j, len);
|
||||||
|
|
||||||
|
res[j] = str;
|
||||||
|
|
||||||
|
str_pos += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_neural_network(neural_network* network, const char* content)
|
||||||
|
{
|
||||||
|
size_t lines_len;
|
||||||
|
char** lines = string_split(content, '\n', &lines_len);
|
||||||
|
|
||||||
|
size_t first_line_len;
|
||||||
|
char** first_line = string_split(lines[0], ',', &first_line_len);
|
||||||
|
|
||||||
|
network->nb_input = atoi(strtok(first_line[0], ","));
|
||||||
|
network->hidden_depth = atoi(strtok(first_line[1], ","));
|
||||||
|
network->hidden_height = atoi(strtok(first_line[2], ","));
|
||||||
|
network->nb_output = atoi(strtok(first_line[3], ","));
|
||||||
|
|
||||||
|
free(first_line[0]);
|
||||||
|
free(first_line[1]);
|
||||||
|
free(first_line[2]);
|
||||||
|
free(first_line[3]);
|
||||||
|
free(first_line);
|
||||||
|
|
||||||
|
init_neural_network(network);
|
||||||
|
|
||||||
|
for (size_t x = 0; x < network->hidden_depth; x++)
|
||||||
|
{
|
||||||
|
size_t line_len;
|
||||||
|
char** line = string_split(lines[x + 1], ',', &line_len);
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++)
|
||||||
|
{
|
||||||
|
if (x == 0)
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->nb_input; h++)
|
||||||
|
{
|
||||||
|
network->hidden[x][y].weights[h] = atof(line[pos]);
|
||||||
|
free(line[pos]);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
network->hidden[x][y].weights[h] = atof(line[pos]);
|
||||||
|
free(line[pos]);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
network->hidden[x][y].bias = atof(line[pos]);
|
||||||
|
free(line[pos]);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t last_line_len;
|
||||||
|
char** last_line = string_split(lines[network->hidden_depth + 1], ',', &last_line_len);
|
||||||
|
|
||||||
|
size_t last_pos = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < network->nb_output; i++)
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
network->outputs[i].weights[h] = atof(last_line[last_pos]);
|
||||||
|
free(last_line[last_pos]);
|
||||||
|
last_pos++;
|
||||||
|
}
|
||||||
|
network->outputs[i].bias = atof(last_line[last_pos]);
|
||||||
|
free(last_line[last_pos]);
|
||||||
|
last_pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(last_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* read_file(const char* file)
|
||||||
|
{
|
||||||
|
FILE * stream = fopen( file, "r" );
|
||||||
|
|
||||||
|
size_t str_len = 0;
|
||||||
|
|
||||||
|
char* buff = calloc(1, sizeof(char));
|
||||||
|
|
||||||
|
if (buff == NULL)
|
||||||
|
errx(EXIT_FAILURE, "read_file: malloc error");
|
||||||
|
|
||||||
|
char* pos = buff;
|
||||||
|
|
||||||
|
while (fread(pos, sizeof(char), 1, stream) > 0)
|
||||||
|
{
|
||||||
|
str_len++;
|
||||||
|
buff = realloc(buff, (str_len + 1) * sizeof(char));
|
||||||
|
pos = buff + str_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
buff[str_len] = '\0';
|
||||||
|
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_hidden_layer(neural_network* network)
|
||||||
|
{
|
||||||
|
for (size_t x = 0; x < network->hidden_depth; x++)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++)
|
||||||
|
{
|
||||||
|
neuron* curr = &network->hidden[x][y];
|
||||||
|
double sum = 0.0;
|
||||||
|
|
||||||
|
if (x == 0){
|
||||||
|
for (size_t h = 0; h < network->nb_input; h++) //Sum with inputs
|
||||||
|
{
|
||||||
|
double w = curr->weights[h];
|
||||||
|
sum += w * network->inputs[h].activation;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++) //Sum with previous layer
|
||||||
|
{
|
||||||
|
double w = curr->weights[h];
|
||||||
|
sum += w * network->hidden[x-1][h].activation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curr->activation_input = sum + curr->bias;
|
||||||
|
curr->activation = sigmoid(curr->activation_input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_output_layer(neural_network* network)
|
||||||
|
{
|
||||||
|
for (size_t o = 0; o < network->nb_output; o++)
|
||||||
|
{
|
||||||
|
neuron* curr = &network->outputs[o];
|
||||||
|
double sum = 0.0;
|
||||||
|
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
double w = curr->weights[h];
|
||||||
|
sum += w * network->hidden[network->hidden_depth-1][h].activation;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr->activation_input = sum + curr->bias;
|
||||||
|
curr->activation = sigmoid(sum + curr->bias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_network(neural_network* network)
|
||||||
|
{
|
||||||
|
process_hidden_layer(network);
|
||||||
|
process_output_layer(network);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_network_cost(neural_network* network, training_data* expected_data, size_t data_len)
|
||||||
|
{
|
||||||
|
double cost = 0.0;
|
||||||
|
for (size_t d = 0; d < data_len; d++)
|
||||||
|
{
|
||||||
|
/*for (size_t i = 0; i < network->nb_input; i++)
|
||||||
|
{
|
||||||
|
network->inputs[i].activation = expected_data[d].inputs[i];
|
||||||
|
}*/
|
||||||
|
|
||||||
|
network_set_input_data(network, expected_data[d]);
|
||||||
|
|
||||||
|
process_network(network);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < network->nb_output; i++)
|
||||||
|
{
|
||||||
|
neuron* curr = &network->outputs[i];
|
||||||
|
|
||||||
|
double err = expected_data[d].outputs[i] - curr->activation;
|
||||||
|
|
||||||
|
cost += err * err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0/2.0 * cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
double calculate_hidden_local_gradiant(neural_network* network, size_t x, size_t y)
|
||||||
|
{
|
||||||
|
neuron* curr = &network->hidden[x][y];
|
||||||
|
|
||||||
|
double local_gradient_sum = 0.0;
|
||||||
|
|
||||||
|
if (x == network->hidden_depth-1)
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->nb_output; h++)
|
||||||
|
{
|
||||||
|
neuron* target = &network->outputs[h];
|
||||||
|
|
||||||
|
local_gradient_sum += target->local_gradient * target->weights[h];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
neuron* target = &network->hidden[x+1][h];
|
||||||
|
|
||||||
|
local_gradient_sum += target->local_gradient * target->weights[h];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return local_gradient_sum * sigmoid_derivate(curr->activation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_hidden_back_propagation(neural_network* network, double learning_rate)
|
||||||
|
{
|
||||||
|
for (long int x = ((long int)network->hidden_depth-1); x >= 0; x--)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++)
|
||||||
|
{
|
||||||
|
neuron* curr = &network->hidden[x][y];
|
||||||
|
|
||||||
|
curr->local_gradient = calculate_hidden_local_gradiant(network, x, y);
|
||||||
|
|
||||||
|
if (x == 0)
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->nb_input; h++)
|
||||||
|
{
|
||||||
|
neuron* connect = &network->inputs[h];
|
||||||
|
|
||||||
|
double total_error_w = curr->local_gradient * connect->activation;
|
||||||
|
|
||||||
|
curr->weights[h] -= learning_rate * total_error_w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
neuron* connect = &network->hidden[x-1][h];
|
||||||
|
|
||||||
|
double total_error_w = curr->local_gradient * connect->activation;
|
||||||
|
|
||||||
|
curr->weights[h] -= learning_rate * total_error_w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curr->bias -= learning_rate * curr->local_gradient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_output_back_propagation(neural_network* network, double* expected_data, double learning_rate)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < network->nb_output; i++)
|
||||||
|
{
|
||||||
|
neuron* curr = &network->outputs[i];
|
||||||
|
|
||||||
|
curr->local_gradient = (curr->activation - expected_data[i]) * sigmoid_derivate(curr->activation_input);
|
||||||
|
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++)
|
||||||
|
{
|
||||||
|
neuron* connect = &network->hidden[network->hidden_depth-1][h];
|
||||||
|
|
||||||
|
double total_error_w = curr->local_gradient * connect->activation;
|
||||||
|
|
||||||
|
curr->weights[h] -= learning_rate * total_error_w;
|
||||||
|
}
|
||||||
|
|
||||||
|
curr->bias -= learning_rate * curr->local_gradient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_back_propagation(neural_network* network, double* expected_data, double learning_rate)
|
||||||
|
{
|
||||||
|
network_output_back_propagation(network, expected_data, learning_rate);
|
||||||
|
network_hidden_back_propagation(network, learning_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_set_input_data(neural_network* network, training_data data)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < network->nb_input; i++)
|
||||||
|
{
|
||||||
|
network->inputs[i].activation = data.inputs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_train_data(neural_network* network, training_data data, double learning_rate)
|
||||||
|
{
|
||||||
|
network_set_input_data(network, data);
|
||||||
|
|
||||||
|
process_network(network);
|
||||||
|
|
||||||
|
network_back_propagation(network, data.outputs, learning_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_process_epoche(neural_network* network, training_data* data, size_t data_len, double learning_rate)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < data_len; i++)
|
||||||
|
{
|
||||||
|
network_train_data(network, data[i], learning_rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_network_total_cost(neural_network* network, training_data* datas, size_t data_len)
|
||||||
|
{
|
||||||
|
double cost = 0;
|
||||||
|
for (size_t i = 0; i < data_len; i++)
|
||||||
|
{
|
||||||
|
network_set_input_data(network, datas[i]);
|
||||||
|
|
||||||
|
process_network(network);
|
||||||
|
|
||||||
|
cost += get_network_cost(network, datas, data_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
void train_network(neural_network* network, training_data* datas, size_t data_len, float learning_rate, size_t warmup, size_t warmup_iterations, size_t iterations)
|
||||||
|
{
|
||||||
|
if (warmup > 0)
|
||||||
|
{
|
||||||
|
neural_network networks[warmup];
|
||||||
|
double min_net_cost = -1;
|
||||||
|
size_t min_net = 0;
|
||||||
|
|
||||||
|
for (size_t n = 0; n < warmup; n++)
|
||||||
|
{
|
||||||
|
networks[n].nb_input = network->nb_input;
|
||||||
|
networks[n].nb_output = network->nb_output;
|
||||||
|
networks[n].hidden_depth = network->hidden_depth;
|
||||||
|
networks[n].hidden_height = network->hidden_height;
|
||||||
|
|
||||||
|
init_neural_network(networks + n);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < warmup_iterations; i++)
|
||||||
|
{
|
||||||
|
network_process_epoche(&(networks[n]), datas, data_len, learning_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
double cost = get_network_total_cost(&networks[n], datas, data_len);
|
||||||
|
|
||||||
|
if (min_net_cost < 0 || cost < min_net_cost)
|
||||||
|
{
|
||||||
|
min_net_cost = cost;
|
||||||
|
min_net = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("MinNet: %li with cost: %f\n", min_net, min_net_cost);
|
||||||
|
|
||||||
|
memcpy(network, networks + min_net, sizeof(neural_network));
|
||||||
|
|
||||||
|
for (size_t n = 0; n < warmup; n++)
|
||||||
|
{
|
||||||
|
if (n != min_net)
|
||||||
|
free_neural_network(networks + n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
network_process_epoche(network, datas, data_len, learning_rate);
|
||||||
|
|
||||||
|
if (i % (iterations / 100) == 0) //Debug
|
||||||
|
{
|
||||||
|
printf("Training %i%% (ETA: %s)\n", (int)(((float)i / (float)iterations) * 100), "1 m");
|
||||||
|
/*printf("----------------------------------------\n");
|
||||||
|
printf("\t\tEpoche %li:\n", i);
|
||||||
|
print_training_debug(network, datas, 4);*/
|
||||||
|
//print_network_state(&network);
|
||||||
|
//printf("NetCost: %f\n", get_network_cost(&network, datas, 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_success_rate(neural_network* network, training_data* datas, size_t data_len)
|
||||||
|
{
|
||||||
|
int success = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data_len; i++)
|
||||||
|
{
|
||||||
|
network_set_input_data(network, datas[i]);
|
||||||
|
|
||||||
|
process_network(network);
|
||||||
|
|
||||||
|
if ((int)datas[i].outputs[0] == (int)round(network->outputs[0].activation))
|
||||||
|
success++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (double)success / (double)data_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
training_data* load_dataset(const char* directory)
|
||||||
|
{
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *dir;
|
||||||
|
|
||||||
|
d = opendir(directory);
|
||||||
|
|
||||||
|
if (d)
|
||||||
|
{
|
||||||
|
while ((dir = readdir(d)) != NULL)
|
||||||
|
{
|
||||||
|
if(dir->d_type==DT_REG)
|
||||||
|
{
|
||||||
|
int len = strlen(dir->d_name);
|
||||||
|
|
||||||
|
if (len < 5)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dir->d_name[len-1] != 'g' || dir->d_name[len-2] != 'n' || dir->d_name[len-3] != 'p' || dir->d_name[len-4] != '.')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char* file = combine_path(directory, dir->d_name);
|
||||||
|
|
||||||
|
char letter = dir->d_name[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_network_activations(neural_network* network)
|
||||||
|
{
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++)
|
||||||
|
{
|
||||||
|
if (y < network->nb_input)
|
||||||
|
printf("input%li: %f|", y, network->inputs[y].activation);
|
||||||
|
for (size_t x = 0; x < network->hidden_depth; x++)
|
||||||
|
{
|
||||||
|
printf("%f--", network->hidden[x][y].activation);
|
||||||
|
}
|
||||||
|
if (y < network->nb_output)
|
||||||
|
printf("|output%li: %f", y, network->outputs[y].activation);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_network_state(neural_network *network) {
|
||||||
|
printf("Network State:\n");
|
||||||
|
for (size_t x = 0; x < network->hidden_depth; x++) {
|
||||||
|
for (size_t y = 0; y < network->hidden_height; y++) {
|
||||||
|
printf("Hidden[%li][%li] Input: %f, Activation: %f, Bias: %f\n",
|
||||||
|
x, y, network->hidden[x][y].activation_input, network->hidden[x][y].activation, network->hidden[x][y].bias);
|
||||||
|
for (size_t h = 0; h < network->nb_input; h++) {
|
||||||
|
printf(" Weight[%li]: %f\n", h, network->hidden[x][y].weights[h]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t o = 0; o < network->nb_output; o++) {
|
||||||
|
printf("Output[%li] Input: %f, Activation: %f, Bias: %f\n",
|
||||||
|
o, network->outputs[o].activation_input, network->outputs[o].activation, network->outputs[o].bias);
|
||||||
|
for (size_t h = 0; h < network->hidden_height; h++) {
|
||||||
|
printf(" Weight[%li]: %f\n", h, network->outputs[o].weights[h]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void print_training_debug(neural_network* network, training_data* data, size_t data_len)
|
||||||
|
{
|
||||||
|
size_t debug_height;
|
||||||
|
|
||||||
|
if (network->nb_output < network->nb_input)
|
||||||
|
{
|
||||||
|
debug_height = network->nb_input;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug_height = network->nb_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t data_i = 0; data_i < data_len; data_i++)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < network->nb_input; i++)
|
||||||
|
{
|
||||||
|
network->inputs[i].activation = data[data_i].inputs[i];
|
||||||
|
}
|
||||||
|
process_network(network);
|
||||||
|
|
||||||
|
printf("----------------------------------------\n");
|
||||||
|
for (size_t line = 0; line < debug_height; line++)
|
||||||
|
{
|
||||||
|
if (line < network->nb_input)
|
||||||
|
{
|
||||||
|
if (line < network->nb_output)
|
||||||
|
{
|
||||||
|
printf("input%02li:%i | output%02li:%f expected:%i\n", line, (int)data[data_i].inputs[line], line, network->outputs[line].activation, (int)data[data_i].outputs[line]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("input%02li:%i |\n", line, (int)data[data_i].inputs[line]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf(" | output%02li:%f expected:%i\n", line, network->outputs[line].activation, (int)data[data_i].outputs[line]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
71
src/utils/AI/neural_utils.h
Normal file
71
src/utils/AI/neural_utils.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include <aio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#ifndef NEURAL_UTILS_H
|
||||||
|
#define NEURAL_UTILS_H
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double activation;
|
||||||
|
double activation_input;
|
||||||
|
double local_gradient;
|
||||||
|
double bias;
|
||||||
|
double* weights;
|
||||||
|
}neuron;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
size_t nb_input;
|
||||||
|
size_t hidden_height;
|
||||||
|
size_t hidden_depth;
|
||||||
|
size_t nb_output;
|
||||||
|
|
||||||
|
double learning_rate;
|
||||||
|
|
||||||
|
neuron* inputs;
|
||||||
|
neuron** hidden;
|
||||||
|
neuron* outputs;
|
||||||
|
}neural_network;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double* inputs;
|
||||||
|
double* outputs;
|
||||||
|
}training_data;
|
||||||
|
|
||||||
|
double sigmoid(double x);
|
||||||
|
|
||||||
|
double double_rand();
|
||||||
|
|
||||||
|
void init_neuron(neuron* n, size_t nb_connection);
|
||||||
|
|
||||||
|
void init_neural_network(neural_network* network);
|
||||||
|
|
||||||
|
void save_neural_network(neural_network* network, const char* file_path);
|
||||||
|
|
||||||
|
void load_neural_network(neural_network* network, const char* content);
|
||||||
|
|
||||||
|
char* read_file(const char* file);
|
||||||
|
|
||||||
|
void process_network(neural_network* network);
|
||||||
|
|
||||||
|
double get_network_cost(neural_network* network, training_data* expected_data, size_t data_len);
|
||||||
|
|
||||||
|
void network_back_propagation(neural_network* network, double* expected_data, double learning_rate);
|
||||||
|
|
||||||
|
void network_process_epoche(neural_network* network, training_data* data, size_t data_len, double learning_rate);
|
||||||
|
|
||||||
|
double get_network_total_cost(neural_network* network, training_data* datas, size_t data_len);
|
||||||
|
|
||||||
|
void train_network(neural_network* network, training_data* datas, size_t data_len, float learning_rate, size_t warmup, size_t warmup_iterations, size_t iterations);
|
||||||
|
|
||||||
|
double get_success_rate(neural_network* network, training_data* datas, size_t data_len);
|
||||||
|
|
||||||
|
void print_network_activations(neural_network* network);
|
||||||
|
|
||||||
|
void network_set_input_data(neural_network* network, training_data data);
|
||||||
|
|
||||||
|
void print_network_state(neural_network *network);
|
||||||
|
|
||||||
|
void print_training_debug(neural_network* network, training_data* data, size_t data_len);
|
||||||
|
|
||||||
|
#endif
|
@ -30,7 +30,7 @@ char* path_get_directory(char* path)
|
|||||||
return n_str;
|
return n_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* combine_path(char* first_path, char* second_path)
|
char* combine_path(const char* first_path, const char* second_path)
|
||||||
{
|
{
|
||||||
size_t f_len = strlen(first_path);
|
size_t f_len = strlen(first_path);
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
char* path_get_directory(char* path);
|
char* path_get_directory(char* path);
|
||||||
|
|
||||||
char* combine_path(char* first_path, char* second_path);
|
char* combine_path(const char* first_path, const char* second_path);
|
||||||
|
|
||||||
void mkpath(const char* file_path);
|
void mkpath(const char* file_path);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user