From e813ed29571cd73a28f3e850a7f15c828e37f3cb Mon Sep 17 00:00:00 2001 From: anon Date: Sun, 10 Mar 2024 13:48:34 +0100 Subject: [PATCH] Neural Network in C --- cnn.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 cnn.c diff --git a/cnn.c b/cnn.c new file mode 100644 index 0000000..c29af6c --- /dev/null +++ b/cnn.c @@ -0,0 +1,126 @@ +/* @BAKE gcc $@ -o n.out -lm && ./n.out + */ +/* + # CNN + > Simple Neural Network from scratch in C, emulating logic gates. +*/ +#include +#include +#include + +typedef struct { + double input[3]; + double output; +} sample_t; + +sample_t OR[] = { + {{0.0, 0.0, 1.0}, 0.0}, + {{1.0, 0.0, 1.0}, 1.0}, + {{0.0, 1.0, 1.0}, 1.0}, + {{1.0, 1.0, 1.0}, 1.0}, +}; + +sample_t AND[] = { + {{0.0, 0.0, 1.0}, 0.0}, + {{1.0, 0.0, 1.0}, 0.0}, + {{0.0, 1.0, 1.0}, 0.0}, + {{1.0, 1.0, 1.0}, 1.0}, +}; + +sample_t XOR[] = { + {{0.0, 0.0, 1.0}, 0.0}, + {{1.0, 0.0, 1.0}, 1.0}, + {{0.0, 1.0, 1.0}, 1.0}, + {{1.0, 1.0, 1.0}, 0.0}, +}; + +typedef struct { + size_t n_layers; + double * layer_width; + double * * weights; +} network_t; + +double activation(double x) { + return 1.0/(1.0 + exp(-x)); +} + +double deactivation(double y) { + return y * (1.0 - y); +} + +void new_network(network_t * n) { + n->n_layers = 5; + n->layer_width = (double*)malloc(n->n_layers*sizeof(double)); + n->layer_width[0] = 3; + n->layer_width[1] = 3; + n->layer_width[2] = 3; + n->layer_width[3] = 3; + n->layer_width[4] = 1; + n->weights = (double**)malloc((n->n_layers-1)*sizeof(double)); + for (int i = 0; i < n->n_layers-1; i++) { + size_t synapse_count = n->layer_width[i] * n->layer_width[i+1]; + n->weights[i] = (double*)malloc(synapse_count*sizeof(double)); + for (int h = 0; h < synapse_count; h++) { + n->weights[i][h] = (double)rand() / (double)RAND_MAX; + } + } +} + +double oracle(network_t * n, double * input) { + double r; + int sum = 0; + for (int i = 0; i < n->n_layers-1; i++) { + size_t synapse_count = n->layer_width[i] * n->layer_width[i+1]; + for (int h = 0; h < synapse_count; h++) { + sum += (input[h] * n->weights[i][h]); + } + } + r = activation(sum); + //printf("The network oracles %d!\n", (int)round(r)); + return r; +} + +double adjust(network_t * n, double response, sample_t s) { + double error = s.output - response; + double delta = error * deactivation(response); + for (int i = 0; i < n->n_layers-1; i++) { + size_t synapse_count = n->layer_width[i] * n->layer_width[i+1]; + for (int h = 0; h < synapse_count; h++) { + n->weights[i][h] += 0.8 * delta * s.input[h]; + } + } + return error; +} + +void train(network_t * n, sample_t * s, size_t c) { + for (int i = 0; i < c; i++) { + double sumerr = 0; + for (int h = 0; h < 4; h++) { + double network_response = oracle(n, s[h].input); + double error = adjust(n, network_response, s[h]); + sumerr += pow(error, 2); + } + printf("%d: %lf\n", i, sumerr); + } +} + +void print_sample(sample_t * s) { + printf("{%d, %d, %d} -> %d\n", + (int)s->input[0], (int)s->input[1], (int)s->input[2], (int)s->output + ); +} + +void test(network_t * n, sample_t * s) { + for (int i = 0; i < 4; i++) { + fputs("\033[1mfor: ", stdout); + print_sample(s + i); + printf("\033[0;33mThe Network oracles: %d\033[0m\n", (int)round(oracle(n, s[i].input))); + } +} + +signed main() { + network_t n; + new_network(&n); + train(&n, AND, 100); + test(&n, AND); +}