From 97823124d84cd2713683a4722316c6afe7979482 Mon Sep 17 00:00:00 2001 From: Shreyash Date: Tue, 2 Sep 2025 23:56:59 +0530 Subject: [PATCH 1/6] feat: add feedforward lib header file --- nn/include/feedforward.h | 14 ++++++++++++++ nn/include/neural_network.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 nn/include/feedforward.h create mode 100644 nn/include/neural_network.h diff --git a/nn/include/feedforward.h b/nn/include/feedforward.h new file mode 100644 index 0000000..fe76aec --- /dev/null +++ b/nn/include/feedforward.h @@ -0,0 +1,14 @@ +#pragma once + +#include "neural_network.h" + +//============================== +// Forward Pass Functions +//============================== + +NeuralNetwork* create_network(int num_layers); + +void free_network(NeuralNetwork* nn); + +// It caches the intermediate results for the backpropagation algorithm. +Matrix* feedforward(NeuralNetwork* nn, const Matrix* input); diff --git a/nn/include/neural_network.h b/nn/include/neural_network.h new file mode 100644 index 0000000..b1adff4 --- /dev/null +++ b/nn/include/neural_network.h @@ -0,0 +1,34 @@ +#pragma once + +#include "activation.h" +#include "cache.h" +#include "linalg.h" + +//============================== +// Neural Network Layer Struct +//============================== + +typedef Matrix* (*ActivationFunc)(Matrix*); + +typedef struct { + Matrix* weights; + Matrix* bias; + + ActivationFunc activation; + + // The leak parameter for the Leaky ReLU activation function. + double leak_parameter; +} Layer; + + +//============================== +// Neural Network Struct +//============================== + +typedef struct { + Layer** layers; + int num_layers; + + // A caching mechanism to store intermediate values from the forward pass. + Cache* cache; +} NeuralNetwork; From 3e96943028f8370a711efbb52338d9532a8784e8 Mon Sep 17 00:00:00 2001 From: Shreyash Date: Wed, 3 Sep 2025 00:01:35 +0530 Subject: [PATCH 2/6] feat: add feedforward lib implementation --- nn/include/neural_network.h | 5 +- nn/src/neural_network.h/feedforward.c | 97 +++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 nn/src/neural_network.h/feedforward.c diff --git a/nn/include/neural_network.h b/nn/include/neural_network.h index b1adff4..e735a93 100644 --- a/nn/include/neural_network.h +++ b/nn/include/neural_network.h @@ -13,14 +13,13 @@ typedef Matrix* (*ActivationFunc)(Matrix*); typedef struct { Matrix* weights; Matrix* bias; - + ActivationFunc activation; // The leak parameter for the Leaky ReLU activation function. double leak_parameter; } Layer; - //============================== // Neural Network Struct //============================== @@ -28,7 +27,7 @@ typedef struct { typedef struct { Layer** layers; int num_layers; - + // A caching mechanism to store intermediate values from the forward pass. Cache* cache; } NeuralNetwork; diff --git a/nn/src/neural_network.h/feedforward.c b/nn/src/neural_network.h/feedforward.c new file mode 100644 index 0000000..7bee239 --- /dev/null +++ b/nn/src/neural_network.h/feedforward.c @@ -0,0 +1,97 @@ +#include "feedforward.h" + +#include +#include +#include + +#include "linalg.h" +#include "neural_network.h" +#include "utils.h" + +// Macro to handle memory allocation checks. +#define CHECK_ALLOC(ptr) \ + if (ptr == NULL) { \ + LOG_ERROR("Memory allocation failed."); \ + return NULL; \ + } + +NeuralNetwork* create_network(int num_layers) { + NeuralNetwork* nn = (NeuralNetwork*)malloc(sizeof(NeuralNetwork)); + CHECK_ALLOC(nn); + + nn->layers = (Layer**)malloc(sizeof(Layer*) * num_layers); + CHECK_ALLOC(nn->layers); + + nn->num_layers = num_layers; + nn->cache = init_cache(); + if (nn->cache == NULL) { + LOG_ERROR("Failed to initialize cache."); + free(nn->layers); + free(nn); + return NULL; + } + return nn; +} + +void free_network(NeuralNetwork* nn) { + if (nn == NULL) { + return; + } + + if (nn->layers != NULL) { + for (int i = 0; i < nn->num_layers; i++) { + if (nn->layers[i] != NULL) { + if (nn->layers[i]->weights != NULL) { + free_matrix(nn->layers[i]->weights); + } + if (nn->layers[i]->bias != NULL) { + free_matrix(nn->layers[i]->bias); + } + free(nn->layers[i]); + } + } + free(nn->layers); + } + if (nn->cache != NULL) { + clear_cache(nn->cache); + free(nn->cache); + } + free(nn); +} + +Matrix* feedforward(NeuralNetwork* nn, const Matrix* input) { + ASSERT(nn != NULL, "Neural Network pointer cannot be NULL."); + ASSERT(input != NULL, "Input matrix cannot be NULL."); + ASSERT(input->rows == nn->layers[0]->weights->cols, + "Input dimensions must match network dimensions."); + + Matrix* current_output = copy_matrix(input); + + // Cache the input for the backpropagation algorithm. + put_matrix(nn->cache, "input", current_output); + + for (int i = 0; i < nn->num_layers; i++) { + Matrix* z = dot_matrix(current_output, nn->layers[i]->weights); + + // Add bias + add_matrix(z, nn->layers[i]->bias); + + // Cache the intermediate value (z). + char z_key[32]; + sprintf(z_key, "z_%d", i); + put_matrix(nn->cache, z_key, z); + + Matrix* a = apply_onto_matrix(nn->layers[i]->activation, z); + + // Cache the activated output (a). + char a_key[32]; + sprintf(a_key, "a_%d", i); + put_matrix(nn->cache, a_key, a); + + free_matrix(z); // We no longer need z, as we have cached it. + free_matrix(current_output); + current_output = a; + } + + return current_output; +} From 7d7ed2acf5455db93812826b33520317f573957c Mon Sep 17 00:00:00 2001 From: Shreyash Date: Wed, 3 Sep 2025 00:08:23 +0530 Subject: [PATCH 3/6] chore: rename nn folder --- nn/src/{neural_network.h => neural_network}/feedforward.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename nn/src/{neural_network.h => neural_network}/feedforward.c (100%) diff --git a/nn/src/neural_network.h/feedforward.c b/nn/src/neural_network/feedforward.c similarity index 100% rename from nn/src/neural_network.h/feedforward.c rename to nn/src/neural_network/feedforward.c From b36de4aef4134385a937489694cec81942a04ec8 Mon Sep 17 00:00:00 2001 From: Shreyash Date: Wed, 3 Sep 2025 23:47:48 +0530 Subject: [PATCH 4/6] chore: move check alloc macro, remove inferable comments --- nn/include/utils.h | 7 +++++++ nn/src/neural_network/feedforward.c | 10 +--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/nn/include/utils.h b/nn/include/utils.h index 5252130..7cc6a70 100644 --- a/nn/include/utils.h +++ b/nn/include/utils.h @@ -29,6 +29,13 @@ typedef enum { // For safe malloc allocations #define CHECK_MALLOC(ptr, message) ASSERT((ptr) != NULL, message); +// Macro to handle memory allocation checks. +#define CHECK_ALLOC(ptr) \ + if (ptr == NULL) { \ + LOG_ERROR("Memory allocation failed."); \ + return NULL; \ + } + // Function prototypes for logging void log_message(LogLevel level, const char* format, ...); diff --git a/nn/src/neural_network/feedforward.c b/nn/src/neural_network/feedforward.c index 7bee239..9bd9181 100644 --- a/nn/src/neural_network/feedforward.c +++ b/nn/src/neural_network/feedforward.c @@ -8,13 +8,6 @@ #include "neural_network.h" #include "utils.h" -// Macro to handle memory allocation checks. -#define CHECK_ALLOC(ptr) \ - if (ptr == NULL) { \ - LOG_ERROR("Memory allocation failed."); \ - return NULL; \ - } - NeuralNetwork* create_network(int num_layers) { NeuralNetwork* nn = (NeuralNetwork*)malloc(sizeof(NeuralNetwork)); CHECK_ALLOC(nn); @@ -73,7 +66,6 @@ Matrix* feedforward(NeuralNetwork* nn, const Matrix* input) { for (int i = 0; i < nn->num_layers; i++) { Matrix* z = dot_matrix(current_output, nn->layers[i]->weights); - // Add bias add_matrix(z, nn->layers[i]->bias); // Cache the intermediate value (z). @@ -88,7 +80,7 @@ Matrix* feedforward(NeuralNetwork* nn, const Matrix* input) { sprintf(a_key, "a_%d", i); put_matrix(nn->cache, a_key, a); - free_matrix(z); // We no longer need z, as we have cached it. + free_matrix(z); free_matrix(current_output); current_output = a; } From 58bab094983b15ed94edfe7ff2f1c913b5cc1045 Mon Sep 17 00:00:00 2001 From: Shreyash Date: Wed, 3 Sep 2025 23:50:14 +0530 Subject: [PATCH 5/6] style: formatting changes --- nn/include/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nn/include/utils.h b/nn/include/utils.h index 7cc6a70..470cf10 100644 --- a/nn/include/utils.h +++ b/nn/include/utils.h @@ -35,7 +35,7 @@ typedef enum { LOG_ERROR("Memory allocation failed."); \ return NULL; \ } - + // Function prototypes for logging void log_message(LogLevel level, const char* format, ...); From 5c7917ae905f2cf4741aa56f4a0eaa28ba71d9e4 Mon Sep 17 00:00:00 2001 From: Shreyash Date: Wed, 3 Sep 2025 23:54:21 +0530 Subject: [PATCH 6/6] fix: graceful error handling --- nn/include/utils.h | 7 +++---- nn/src/neural_network/feedforward.c | 11 +++++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/nn/include/utils.h b/nn/include/utils.h index 470cf10..09572bf 100644 --- a/nn/include/utils.h +++ b/nn/include/utils.h @@ -30,10 +30,9 @@ typedef enum { #define CHECK_MALLOC(ptr, message) ASSERT((ptr) != NULL, message); // Macro to handle memory allocation checks. -#define CHECK_ALLOC(ptr) \ - if (ptr == NULL) { \ - LOG_ERROR("Memory allocation failed."); \ - return NULL; \ +#define CHECK_ALLOC(ptr) \ + if (ptr == NULL) { \ + return NULL; \ } // Function prototypes for logging diff --git a/nn/src/neural_network/feedforward.c b/nn/src/neural_network/feedforward.c index 9bd9181..1e90e50 100644 --- a/nn/src/neural_network/feedforward.c +++ b/nn/src/neural_network/feedforward.c @@ -10,10 +10,17 @@ NeuralNetwork* create_network(int num_layers) { NeuralNetwork* nn = (NeuralNetwork*)malloc(sizeof(NeuralNetwork)); - CHECK_ALLOC(nn); + if (nn == NULL) { + LOG_ERROR("Memory allocation failed for Neural Network struct."); + return NULL; + } nn->layers = (Layer**)malloc(sizeof(Layer*) * num_layers); - CHECK_ALLOC(nn->layers); + if (nn->layers == NULL) { + LOG_ERROR("Memory allocation failed for layers array."); + free(nn); + return NULL; + } nn->num_layers = num_layers; nn->cache = init_cache();