model.cpp/hpp

I made the model struct to store layers. I'm still missing the backward functions, but it's functional
This commit is contained in:
2026-07-28 19:36:26 +02:00
parent 441540a996
commit c7e87fe191
10 changed files with 552 additions and 107 deletions
View File
+43 -31
View File
@@ -28,7 +28,7 @@
* Author: Michelle Bausager * Author: Michelle Bausager
* *
* Description: * Description:
* Defines the base layers struct used in pther layers in neural network * Defines the base layers struct used in other layers in neural network
* *
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ *++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#pragma once #pragma once
@@ -38,38 +38,57 @@
#include <config/types.hpp> // panic::uint_t, panic::int_t, and panic::real_t #include <config/types.hpp> // panic::uint_t, panic::int_t, and panic::real_t
#include <tensor/matrix.hpp> // panic::tensor::real_matrix (uint_matrix, int_matrix) #include <tensor/matrix.hpp> // panic::tensor::real_matrix (uint_matrix, int_matrix)
//---------------------------------------------------------------------------------------------------------------------------
// DEFINE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
// TYPE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
// Type Name : panic::neural_network::layer
//
// Description:
// A base layer to use in neural networks
//
// Member Variables:
// None.
//
// Notes:
// This base layer should be used in all layers/activations that have a forward and backward function
// This is done so it's easy to make a list of layers in the model to loop over.
// The virtual means it should use derived object's version when called with a pointer.
// The =0 means the derviced object NEEDS to have these functions to work.
//
//---------------------------------------------------------------------------------------------------------------------------
namespace panic{ namespace panic{
namespace neural_network{ namespace neural_network{
/**
* @brief Base layer for the rest of the neural network library to use
*
* This base layer should be used in all layers/activations that have a forward and backward function
* This is done so it's easy to make a list of layers in the model to loop over.
* The virtual means it should use derived object's version when called with a pointer.
* The =0 means the derivative object NEEDS to have these functions to work.
*
* The struct is used for PANIC neural_network library.
*/
struct layer{ struct layer{
/**
* @brief Emphty output matrix to store layer output
*
* Output shape:
* samples x neuron_count
*/
panic::tensor::real_matrix outputs;
/**
* @brief Default de-constructor
*
*/
virtual ~layer() = default; virtual ~layer() = default;
/**
* @brief Virtual forward function for derivative layers
*
* @param inputs Data matrix input for forward function.
*
* @Note It's equal to 0 because it make the derivative
* object NEEDS to have these function to work.
*/
virtual bool forward(const panic::tensor::real_matrix& inputs) = 0; virtual bool forward(const panic::tensor::real_matrix& inputs) = 0;
/**
* @brief Virtual backward function for derivative layers
*
* @param dinputs Data matrix input for backward function.
*
* @Note It's equal to 0 because it make the derivative
* object NEEDS to have these function to work.
*/
virtual bool backward(const panic::tensor::real_matrix& dinputs) = 0; virtual bool backward(const panic::tensor::real_matrix& dinputs) = 0;
}; };
@@ -79,12 +98,5 @@ struct layer{
} // namespace tensor } // namespace tensor
} // namespace panic } // namespace panic
//---------------------------------------------------------------------------------------------------------------------------
// VARIABLE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
// FUNCTION PROTOTYPE
//---------------------------------------------------------------------------------------------------------------------------
+55 -38
View File
@@ -24,7 +24,7 @@
* Module Name: neural_network * Module Name: neural_network
* File Name: layer_dense.hpp * File Name: layer_dense.hpp
* Revision: 0.1.0 * Revision: 0.1.0
* Date: 23-06-2026 * Date: 28-08-2026
* Author: Michelle Bausager * Author: Michelle Bausager
* *
* Description: * Description:
@@ -41,59 +41,76 @@
#include <tensor/vector.hpp> #include <tensor/vector.hpp>
#include <tensor/matrix.hpp> #include <tensor/matrix.hpp>
//---------------------------------------------------------------------------------------------------------------------------
// DEFINE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
// TYPE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------------------
// Function Name : panic::neural_network::layer_dense
//
// Description:
// Dense/fully-connected neural network layer.
//
// Inputs:
// Samples x input size const panic::tensor::real_matrix&
//
// Weight shape:
// input_size x neuron_count
//
// Bias shape:
// 1 x neuron_count
//
// Output shape:
// samples x neuron_count panic::tensor::real_matrix
//
// Notes:
// forward(input) calculates:
//
// outputs = inputs * weights + biases
//--------------------------------------------------------------------------------------------------------------------------
namespace panic{ namespace panic{
namespace neural_network{ namespace neural_network{
/**
* @brief struct for dense layer object used in neural networks
*
* Computes:
* @code
* panic::neural_network::layer_dense myDenseLayer(3, 5);
* myDenseLayer.forward(inputMatrix);
* @endcode
*
* The struct is used in PANIC nural_network library.
*/
struct layer_dense : public layer{ struct layer_dense : public layer{
/**
* @brief Emphty weight matrix to store layer weights
*
* Weight shape:
* input_size x neuron_count
*/
panic::tensor::real_matrix weights; panic::tensor::real_matrix weights;
panic::tensor::real_vector biases;
panic::tensor::real_matrix outputs;
// Empthy contructor /**
* @brief Emphty bias vector to store layer bias
*
* Bias shape:
* 1 x neuron_count
*/
panic::tensor::real_vector biases;
/**
* @brief Empthy constructor
*
*/
layer_dense(); layer_dense();
// Contructor with layer size /**
* @brief Constructor with input size and amount of neurons
*
* @param input_size Input size of data to the network.
* @param neurons Amount of neurons in the layer
*
*/
layer_dense(panic::types::uint_t input_size, panic::types::uint_t neurons); layer_dense(panic::types::uint_t input_size, panic::types::uint_t neurons);
// Decontructor (All internal variables has decontructors, so we can just use default) /**
* @brief Default de-constructor
*
*/
~layer_dense() = default; ~layer_dense() = default;
// Forward function for forward pass /**
* @brief Forward function for layer
*
* @param inputs Data input for forward pass.
*
* @Note Calculates -> outputs = inputs * weights + biases
*/
bool forward(const panic::tensor::real_matrix& inputs); bool forward(const panic::tensor::real_matrix& inputs);
// Backward pass /**
* @brief Backward function for layer
*
* @param inputs Data input for bacward pass.
*
* @Note Calculates derivative of forward function.
*/
bool backward(const panic::tensor::real_matrix& dinpus); bool backward(const panic::tensor::real_matrix& dinpus);
}; };
+178
View File
@@ -0,0 +1,178 @@
/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* PANIC
* Portable Algorithms and Numerics In C++
*
* Scientific computing from scratch, with feeling.
*
* Copyright (c) 2026 Michelle Bausager
*
* This file is part of PANIC.
*
* PANIC is free software licensed under the GNU General Public License v3.0 or later.
* You may redistribute and/or modify it under the terms of the GPL.
*
* PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the LICENSE file for the full license text.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* Project Name: PANIC
* Module Name: neural_network
* File Name: model.hpp
* Revision: 0.1.0
* Date: 25-06-2026
* Author: Michelle Bausager
*
* Description:
* Defines the base model struct used in in neural network
*
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#pragma once
//---------------------------------------------------------------------------------------------------------------------------
// INCLUDE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
#include <config/types.hpp> // panic::types::uint_t, int_t and real_t
#include <tensor/matrix.hpp> // panic::tensor::real_matrix
#include <neural_network/layer/layer.hpp> // Base layer struct
#include <neural_network/layer/layer_dense.hpp> // fully connected dense layer
//---------------------------------------------------------------------------------------------------------------------------
// TYPE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
namespace panic{
namespace neural_network{
/**
* @brief Basic neural network model.
*
* The model owns an array of layer pointers
*
* @note
* layer_count stores how many layers the model currently has.
*
* layers is a "pointer to pointers" -> layer** layers;
* That means it points to an array where each element is a layer*
*
* The struct is used for PANIC neural_network library.
*/
struct model{
/**
* @brief a pointer to a pointer of layers
*
* An example:
* layers[0] points to a layer_dense
* layers[1] points to an actication function
* layers[2] points to another layer_dense
*
* @note The model owns these layers and deletes them in clear().
*
*/
layer** layers;
// Number of layers currently stored in the model.
/**
* @brief Stores the number of layers
*
*/
panic::types::uint_t layer_count;
// model output (may be deleted and also used for debug)
panic::tensor::real_matrix outputs;
/**
* @brief Empthy constructor
*
*/
model();
/**
* @brief De-constructor
*
* @note Calls clear() to delete all layers and releases the layer pointer array
*
*/
~model();
// Add an already-created layer to the model.
// Helper function for e.g. model.add_dense(5,5)
/**
* @brief Helper function for adding layers
*
* Computes:
* @code
* layer_dense* new_layer = new layer_dense(3, 4);
* add(new_layer)
* @endcode
*
* @note it adds an already-inplemented layer to the model.
*
*/
bool add(layer* new_layer);
// Create and add a dense layer.
/**
* @brief Adds a dense layer to the model.
*
* Computes:
* @code
* model.add_layer_dense(3,4);
* @endcode
*
* @param inputs_size Input size of the data.
* @param neuron_count Number of neurons in the layer.
*
* @return true if layer is added
*
* @note This function is convenient, but it allocates a new layer.
*/
bool add_layer_dense(
panic::types::uint_t input_size,
panic::types::uint_t neuron_count
);
/**
* @brief Loops over all layers forward function
*
* Computes:
* @code
* model.forward(input_data_matrix)
* @endcode
*
* @param inputs Input data.
*
* @return true looped over every layer.
*
* @note It takes the privious layer outputs and uses it as
* the next layers input in the forward function.
*
*/
bool forward(const panic::tensor::real_matrix& inputs);
// Delete all layers and reset the model.
/**
* @brief Clears and deletes all layers and resets the model
*
* Computes:
* @code
* model.clear();
* @endcode
*
* @note Primary used in the de-construtor.
*
*/
void clear();
};
} // namespace neural_network
} // namespace panic
-8
View File
@@ -38,12 +38,6 @@
#include <config/types.hpp> // panic::uint_t, panic::int_t, and panic::real_t #include <config/types.hpp> // panic::uint_t, panic::int_t, and panic::real_t
//--------------------------------------------------------------------------------------------------------------------------
// Function Name : panic::random::seed
//
// Description:
// base for random libary
//--------------------------------------------------------------------------------------------------------------------------
namespace panic{ namespace panic{
namespace random{ namespace random{
@@ -77,8 +71,6 @@ struct seed_t{
*/ */
bool set(panic::types::uint_t seed); bool set(panic::types::uint_t seed);
// Creates a deterministic state from the seed and an index.
// This is OMP-friendly because it does not modify shared memory.
/** /**
* @brief Returns a random number based on seed and index * @brief Returns a random number based on seed and index
* *
+21
View File
@@ -45,6 +45,8 @@
#include <neural_network/layer/layer_dense.hpp> #include <neural_network/layer/layer_dense.hpp>
#include <math/add.hpp> #include <math/add.hpp>
#include <random/uniform.hpp> #include <random/uniform.hpp>
#include <neural_network/layer/layer_dense.hpp>
#include <neural_network/model/model.hpp>
@@ -756,6 +758,25 @@ int main(void) {
panic::random::uniform(D3, 100.f, 200.f); panic::random::uniform(D3, 100.f, 200.f);
panic::io::print_matrix(D3); panic::io::print_matrix(D3);
std::cout << "neural_network" << std::endl;
panic::neural_network::layer_dense layer_dense01(3,4);
std::cout << layer_dense01.forward(D1) << std::endl;
panic::io::print_matrix(layer_dense01.outputs);
panic::neural_network::model mymodel;
mymodel.add_layer_dense(3,4);
mymodel.forward(D1);
return 0; return 0;
+1 -2
View File
@@ -51,8 +51,7 @@
* Small vectors and matrices are kept serial because the overhead of starting * Small vectors and matrices are kept serial because the overhead of starting
* worker threads can be larger than the work itself. * worker threads can be larger than the work itself.
*/ */
//static const panic::types::uint_t add_omp_min_work = 10000; static const panic::types::uint_t add_omp_min_work = 500;
static const panic::types::uint_t add_omp_min_work = 0;
//--------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------
// INPLEMENTATION // INPLEMENTATION
//--------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------
View File
+20 -28
View File
@@ -24,7 +24,7 @@
* Module Name: neural_network * Module Name: neural_network
* File Name: layer_dense.cpp * File Name: layer_dense.cpp
* Revision: 0.1.0 * Revision: 0.1.0
* Date: 23-06-2026 * Date: 28-07-2026
* Author: Michelle Bausager * Author: Michelle Bausager
* *
* Description: * Description:
@@ -37,25 +37,25 @@
//--------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------
#include <neural_network/layer/layer_dense.hpp> #include <neural_network/layer/layer_dense.hpp>
#include <config/omp.hpp> #include <config/omp.hpp>
#include <math/matmul.hpp> #include <math/matmul.hpp>
#include <math/add.hpp> #include <math/add.hpp>
#include <random/uniform.hpp>
//--------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------
// DEFINE DESCRIPTION // PRIVATE CONSTANTS
//---------------------------------------------------------------------------------------------------------------------------
/**
* @brief Minimum number of element operations before using the OpenMP-enabled loop.
*
* Small vectors and matrices are kept serial because the overhead of starting
* worker threads can be larger than the work itself.
*/
static const panic::types::uint_t layer_dense_omp_min_size = 500;
//---------------------------------------------------------------------------------------------------------------------------
// INPLEMENTATION
//--------------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
// TYPE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------------------
// VARIABLE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
static const panic::types::uint_t layer_dense_omp_min_size = 10000;
//---------------------------------------------------------------------------------------------------------------------------
// FUNCTION PROTOTYPE
//---------------------------------------------------------------------------------------------------------------------------
namespace panic{ namespace panic{
namespace neural_network{ namespace neural_network{
@@ -76,27 +76,19 @@ layer_dense::layer_dense() {
// Constructor Name : panic::neural_network::layer_dense // Constructor Name : panic::neural_network::layer_dense
// //
// Description: // Description:
// Creates an empty layer. // Creates an empty layer with neurons.
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
layer_dense::layer_dense(panic::types::uint_t input_size, panic::types::uint_t neurons) { layer_dense::layer_dense(panic::types::uint_t input_size, panic::types::uint_t neurons) {
weights.resize(input_size, neurons); weights.resize(input_size, neurons);
panic::random::uniform(weights);
//panic::math::matmul(weights, 0.01f);
biases.resize(neurons); biases.resize(neurons);
panic::random::uniform(biases);
outputs.resize(0,0); outputs.resize(0,0);
} }
//--------------------------------------------------------------------------------------------------------------------------
// Deconstructor Name : panic::tensor::vector::~vector
//
// Description:
// Deletes the data and releases the memory.
//--------------------------------------------------------------------------------------------------------------------------
//template <typename T>
//vector<T>::~vector(){
// delete[] data;
//
// data = 0;
// length = 0;
//}
//-------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------------------------------
// Function Name : panic::neural_network::layer_dense.forward // Function Name : panic::neural_network::layer_dense.forward
+234
View File
@@ -0,0 +1,234 @@
/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* PANIC
* Portable Algorithms and Numerics In C++
*
* Scientific computing from scratch, with feeling.
*
* Copyright (c) 2026 Michelle Bausager
*
* This file is part of PANIC.
*
* PANIC is free software licensed under the GNU General Public License v3.0 or later.
* You may redistribute and/or modify it under the terms of the GPL.
*
* PANIC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the LICENSE file for the full license text.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*
* Project Name: PANIC
* Module Name: neural_network
* File Name: model.cpp
* Revision: 0.1.0
* Date: 25-06-2026
* Author: Michelle Bausager
*
* Description:
* Defines the base model struct used in in neural network
*
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
//---------------------------------------------------------------------------------------------------------------------------
// INCLUDE DESCRIPTION
//---------------------------------------------------------------------------------------------------------------------------
#include <neural_network/model/model.hpp>
#include <config/types.hpp>
#include <tensor/vector.hpp>
#include <tensor/matrix.hpp>
//---------------------------------------------------------------------------------------------------------------------------
// IMPLEMENTATION
//---------------------------------------------------------------------------------------------------------------------------
namespace panic{
namespace neural_network{
//--------------------------------------------------------------------------------------------------------------------------
// Constructor Name : panic::neural_network::model
//
// Description:
// Creates an empty model.
//--------------------------------------------------------------------------------------------------------------------------
model::model(){
// No layers yet.
layers = 0;
// Number of layers is zero.
layer_count = 0;
}
//--------------------------------------------------------------------------------------------------------------------------
// Destructor Name : panic::neural_network::model::~model
//
// Description:
// Deletes all layers owned by the model.
//--------------------------------------------------------------------------------------------------------------------------
model::~model(){
clear();
}
//--------------------------------------------------------------------------------------------------------------------------
// Function Name : panic::neural_network::model::add
//
// Description:
// Adds a layer to the model.
//
// The layer pointer array
// is resized every time a new layer is added.
//--------------------------------------------------------------------------------------------------------------------------
bool model::add(layer* new_layer){
// Do not add a null layer.
if (new_layer == 0){
return false;
}
// The new array needs room for all old layers plus the new one.
const panic::types::uint_t new_layer_count = layer_count + 1;
// Allocate a new array of layer pointers.
//
// layer* means "pointer to one layer"
// layer** means "pointer to many layer pointers"
//
// So this creates:
//
// [ layer* ][ layer* ][ layer* ] ...
//
layer** new_layers = new layer*[new_layer_count];
// Copy the old layer pointers into the new array.
//
// Important:
// This does not copy the layers themselves.
// It only copies the addresses of the layers.
for (panic::types::uint_t i = 0; i < layer_count; ++i){
new_layers[i] = layers[i];
}
// Put the new layer at the end.
new_layers[layer_count] = new_layer;
// Delete the old array of pointers.
//
// Important:
// Do NOT delete layers[i] here.
// The actual layer objects are still used in new_layers.
//
// This only deletes the old pointer array.
delete[] layers;
// Make the model use the new bigger array.
layers = new_layers;
// Update the layer count.
layer_count = new_layer_count;
return true;
}
//--------------------------------------------------------------------------------------------------------------------------
// Function Name : panic::neural_network::model::add_layer_dense
//
// Description:
// Creates a dense layer and adds it to the model.
//
// Example:
// model.add_dense(100, 64);
//--------------------------------------------------------------------------------------------------------------------------
bool model::add_layer_dense(
panic::types::uint_t input_size,
panic::types::uint_t neuron_count){
// Create the dense layer.
layer_dense* new_layer = new layer_dense(input_size, neuron_count);
if (new_layer == 0){
return false;
}
// Add it to the model.
//
// If add() fails, delete the layer so we do not leak memory.
if (!add(new_layer)){
delete new_layer;
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------------------------------
// Function Name : panic::neural_network::model::forward
//
// Description:
// Runs the input through every layer in order.
//--------------------------------------------------------------------------------------------------------------------------
bool model::forward(const panic::tensor::real_matrix& inputs){
// If the model has no layers, just copy inputs to outputs.
if (layer_count == 0){
outputs = inputs;
return true;
}
// First layer receives the original model input.
if (!layers[0]->forward(inputs)){
return false;
}
// Every next layer receives the output from the previous layer.
// If it fails, return false
for (panic::types::uint_t i = 1; i < layer_count; ++i){
if (!layers[i]->forward(layers[i - 1] -> outputs)){
return false;
}
}
// The model output is the output of the last layer.
outputs = layers[layer_count - 1] -> outputs;
return true;
}
//--------------------------------------------------------------------------------------------------------------------------
// Function Name : panic::neural_network::model::clear
//
// Description:
// Deletes all layers and resets the model.
//--------------------------------------------------------------------------------------------------------------------------
void model::clear(){
if (layers != 0){
// Delete each actual layer object.
for (panic::types::uint_t i = 0; i < layer_count; ++i){
delete layers[i];
layers[i] = 0;
}
// Delete the array that stored the layer pointers.
delete[] layers;
}
// Reset to empty state.
layers = 0;
layer_count = 0;
outputs.resize(0, 0);
}
} // namespace neural_network
} // namespace panic