From ea359f3b097e91295ebf471ae7d461e6762b3060 Mon Sep 17 00:00:00 2001 From: Michelle Date: Sun, 5 Oct 2025 19:45:37 +0200 Subject: [PATCH] Started Loss, done softmax, up to p.125 I've implemented alot of support functions that needs to be refactored, optimised and tested; mean.h, exponential.h, matdiv.h matsum.h matsubtract.h. Maybe we need to have a look at if matdiv/matmul should be in the same. Same with matadd/matsubtract and if some of it should be in matvec.h. --- bin/abc_lab | Bin 37320 -> 50856 bytes .../activation_functions/Softmax.h | 21 ++-- .../modules/neural_networks/datasets/spiral.h | 35 ++---- .../neural_networks/layers/dense_layer.h | 2 +- .../loss/Loss _CategoricalCrossentrophy.h | 34 ++++++ include/modules/neural_networks/loss/loss.h | 34 ++++++ .../modules/neural_networks/neural_networks.h | 5 +- include/numerics/exponential.h | 39 +++++++ include/numerics/matadd.h | 5 +- include/numerics/matdiv.h | 38 +++++++ include/numerics/matsubtract.h | 102 ++++++++++++++++++ include/numerics/matsum.h | 39 +++++++ include/numerics/max.h | 30 +++++- include/numerics/mean.h | 31 ++++++ include/numerics/numerics.h | 5 + obj/main.d | 20 +++- obj/main.o | Bin 39712 -> 58768 bytes src/main.cpp | 23 ++-- 18 files changed, 407 insertions(+), 56 deletions(-) create mode 100644 include/modules/neural_networks/loss/Loss _CategoricalCrossentrophy.h create mode 100644 include/modules/neural_networks/loss/loss.h create mode 100644 include/numerics/exponential.h create mode 100644 include/numerics/matdiv.h create mode 100644 include/numerics/matsubtract.h create mode 100644 include/numerics/matsum.h create mode 100644 include/numerics/mean.h diff --git a/bin/abc_lab b/bin/abc_lab index 0c1f68d28d8200914149f20e9183347dfe5032b8..31c11c2fd4be94ae201bea2ce79303a6d8adb0f7 100755 GIT binary patch literal 50856 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

9{l~v3Rz#ogc%h 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 struct activation_softmax{ + utils::Matrix exp_values; + utils::Matrix probabilities; utils::Matrix outputs; - void forward(utils::Matrix inputs){ - //outputs = numerics::max(inputs, T{0}); - //outputs.print(); + void forward(const utils::Matrix inputs){ + + + exp_values = numerics::exponential(numerics::matsubtract(inputs, numerics::max(inputs, "rows"), "col")); + probabilities = numerics::matdiv(exp_values, numerics::matsum(exp_values, "col"), "col"); + + outputs = probabilities; + } - - }; diff --git a/include/modules/neural_networks/datasets/spiral.h b/include/modules/neural_networks/datasets/spiral.h index d0dd473..4b95a8b 100644 --- a/include/modules/neural_networks/datasets/spiral.h +++ b/include/modules/neural_networks/datasets/spiral.h @@ -10,11 +10,11 @@ namespace neural_networks{ - template - void create_spital_data(const uint64_t samples, const uint64_t classes, utils::Matrix& X, utils::Vector& y) { + template + void create_spital_data(const uint64_t samples, const uint64_t classes, utils::Matrix& X, utils::Vector& y) { const uint64_t rows = samples*classes; - T r, t; + TX r, t; uint64_t row_idx; @@ -27,34 +27,15 @@ namespace neural_networks{ for (uint64_t i = 0; i < classes; ++i){ for (uint64_t j = 0; j < samples; ++j){ - r = static_cast(j)/static_cast(samples); - t = static_cast(i)*4.0 + (4.0+r); + r = static_cast(j)/static_cast(samples); + t = static_cast(i)*4.0 + (4.0+r); row_idx = (i*samples) + j; - X(row_idx, 0) = r*std::cos(t*2.5) + utils::random(T{-0.15}, T{0.15}); - X(row_idx, 1) = r*std::sin(t*2.5) + utils::random(T{-0.15}, T{0.15}); - y[row_idx] = i; + X(row_idx, 0) = r*std::cos(t*2.5) + utils::random(TX{-0.15}, TX{0.15}); + X(row_idx, 1) = r*std::sin(t*2.5) + utils::random(TX{-0.15}, TX{0.15}); + y[row_idx] = static_cast(i); } } - - - - /* - - utils::Matrix X(static_cast(samples*classes), 3, T{0}); - - const uint64_t rows = A.rows(); - const uint64_t cols = A.cols(); - - if (rows != x.size()) { - throw std::runtime_error("inplace_matadd_colvec: dimension mismatch"); - } - - for (uint64_t i = 0; i < cols; ++i) { - for (uint64_t j = 0; j < rows; ++j) { - A(j, i) += x[j]; - } - }*/ } diff --git a/include/modules/neural_networks/layers/dense_layer.h b/include/modules/neural_networks/layers/dense_layer.h index 28aa973..51a8ba7 100644 --- a/include/modules/neural_networks/layers/dense_layer.h +++ b/include/modules/neural_networks/layers/dense_layer.h @@ -23,7 +23,7 @@ namespace neural_networks{ weights.random(n_inputs, n_neurons, -1, 1); biases.resize(n_neurons, T{0}); - weights.print(); + //weights.print(); //outputs.resize() } diff --git a/include/modules/neural_networks/loss/Loss _CategoricalCrossentrophy.h b/include/modules/neural_networks/loss/Loss _CategoricalCrossentrophy.h new file mode 100644 index 0000000..fa4c6c2 --- /dev/null +++ b/include/modules/neural_networks/loss/Loss _CategoricalCrossentrophy.h @@ -0,0 +1,34 @@ +#pragma once + +#include "./core/omp_config.h" + +#include "./utils/vector.h" +#include "./utils/matrix.h" + + +namespace neural_networks{ + + template + struct Loss{ + + utils::Matrix sample_losses; + Td data_losses; + + virtual utils::Vector forward(const utils::Matrix& output, const utils::Matrix& y) = 0; + + Td calculate(const utils::Matrix& output, const utils::Matrix& y){ + // Calculate sample losses + sample_losses = forward(output, y); + + // Calculate mean loss + data_losses = numerics::mean(sample_losses); + return data_losses; + + } + + + }; + + + +} // end namespace neural_networks \ No newline at end of file diff --git a/include/modules/neural_networks/loss/loss.h b/include/modules/neural_networks/loss/loss.h new file mode 100644 index 0000000..fa4c6c2 --- /dev/null +++ b/include/modules/neural_networks/loss/loss.h @@ -0,0 +1,34 @@ +#pragma once + +#include "./core/omp_config.h" + +#include "./utils/vector.h" +#include "./utils/matrix.h" + + +namespace neural_networks{ + + template + struct Loss{ + + utils::Matrix sample_losses; + Td data_losses; + + virtual utils::Vector forward(const utils::Matrix& output, const utils::Matrix& y) = 0; + + Td calculate(const utils::Matrix& output, const utils::Matrix& y){ + // Calculate sample losses + sample_losses = forward(output, y); + + // Calculate mean loss + data_losses = numerics::mean(sample_losses); + return data_losses; + + } + + + }; + + + +} // end namespace neural_networks \ No newline at end of file diff --git a/include/modules/neural_networks/neural_networks.h b/include/modules/neural_networks/neural_networks.h index f905c20..c0d32ab 100644 --- a/include/modules/neural_networks/neural_networks.h +++ b/include/modules/neural_networks/neural_networks.h @@ -6,4 +6,7 @@ #include "layers/dense_layer.h" -#include "activation_functions/ReLU.h" \ No newline at end of file +#include "activation_functions/ReLU.h" +#include "activation_functions/Softmax.h" + +#include "loss/loss.h" \ No newline at end of file diff --git a/include/numerics/exponential.h b/include/numerics/exponential.h new file mode 100644 index 0000000..cfe59a7 --- /dev/null +++ b/include/numerics/exponential.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include "./utils/vector.h" +#include "./utils/matrix.h" + + +namespace numerics{ + + template + T exponential(const T a){ + return std::exp(a); + } + + template + utils::Vector exponential(const utils::Vector& a){ + utils::Vector b = a; + for (uint64_t i = 0; i < a.size(); ++i){ + b[i] = numerics::exponential(a[i]); + } + return b; + } + + template + utils::Matrix exponential(const utils::Matrix& A){ + utils::Matrix B = A; + for (uint64_t i = 0; i < A.rows(); ++i){ + for (uint64_t j = 0; j < A.cols(); ++j){ + B(i,j) = numerics::exponential(A(i,j)); + } + } + return B; + } + + + +} // namespace numerics + diff --git a/include/numerics/matadd.h b/include/numerics/matadd.h index 58853e8..d3890c8 100644 --- a/include/numerics/matadd.h +++ b/include/numerics/matadd.h @@ -1,15 +1,12 @@ #ifndef _matadd_n_ #define _matadd_n_ - +#include "./utils/vector.h" #include "./utils/matrix.h" #include "./core/omp_config.h" namespace numerics{ -// ================================================= -// y = A * x (Matrix–Vector product) -// ================================================= template void inplace_matadd_colvec(utils::Matrix& A, const utils::Vector& x) { diff --git a/include/numerics/matdiv.h b/include/numerics/matdiv.h new file mode 100644 index 0000000..c8e1312 --- /dev/null +++ b/include/numerics/matdiv.h @@ -0,0 +1,38 @@ +#ifndef _matdiv_n_ +#define _matdiv_n_ + + +#include "./utils/matrix.h" +#include "./core/omp_config.h" + + +namespace numerics{ + +// ---------------- Serial baseline ---------------- + template + utils::Matrix matdiv(const utils::Matrix& A, const utils::Vector& b, std::string method){ + + utils::Matrix C = A; + + if (method == "row"){ + for (uint64_t i = 0; i < A.rows(); ++i){ + for (uint64_t j = 0; j < A.cols(); ++j){ + C(i,j) /= b[j]; + } + } + }else if (method == "col"){ + for (uint64_t i = 0; i < A.rows(); ++i){ + for (uint64_t j = 0; j < A.cols(); ++j){ + C(i,j) /= b[i]; + } + } + }else{ + throw std::runtime_error("matdiv: choose div by: 'row' or 'col'"); + } + return C; + } + + +} // namespace numerics + +#endif // _matdiv_n_ \ No newline at end of file diff --git a/include/numerics/matsubtract.h b/include/numerics/matsubtract.h new file mode 100644 index 0000000..b58e881 --- /dev/null +++ b/include/numerics/matsubtract.h @@ -0,0 +1,102 @@ +#ifndef _matsubtract_n_ +#define _matsubtract_n_ + +#include "./utils/vector.h" +#include "./utils/matrix.h" +#include "./core/omp_config.h" + +namespace numerics{ + + template + void inplace_matsubtract_colvec(utils::Matrix& A, const utils::Vector& x) { + + const uint64_t rows = A.rows(); + const uint64_t cols = A.cols(); + + if (rows != x.size()) { + throw std::runtime_error("inplace_matsubtract_colvec: dimension mismatch"); + } + + for (uint64_t i = 0; i < cols; ++i) { + for (uint64_t j = 0; j < rows; ++j) { + A(j, i) -= x[j]; + } + } + } + + template + void inplace_matsubtract_rowvec(utils::Matrix& A, const utils::Vector& x) { + + const uint64_t rows = A.rows(); + const uint64_t cols = A.cols(); + + if (cols != x.size()) { + throw std::runtime_error("inplace_matsubtract_rowvec: dimension mismatch"); + } + + for (uint64_t i = 0; i < cols; ++i) { + for (uint64_t j = 0; j < rows; ++j) { + A(j, i) -= x[i]; + } + } + } + + template + utils::Matrix matsubtract_colvec(const utils::Matrix& A, const utils::Vector& x) { + + //const uint64_t rows = A.rows(); + //const uint64_t cols = A.cols(); + + utils::Matrix B = A; + + inplace_matsubtract_colvec(B, x); + + return B; + } + + template + utils::Matrix matsubtract_rowvec(const utils::Matrix& A, const utils::Vector& x) { + + //const uint64_t rows = A.rows(); + //const uint64_t cols = A.cols(); + + utils::Matrix B = A; + + inplace_matsubtract_rowvec(B, x); + + return B; + } + + template + utils::Matrix matsubtract(const utils::Matrix& A, const utils::Vector& x, std::string method = "auto"){ + + const uint64_t rows = A.rows(); + const uint64_t cols = A.cols(); + const uint64_t N = x.size(); + + if (method=="auto"){ + + if (rows==cols){ + throw std::runtime_error("matsubtract: too many options for dimensions"); + } else if (rows == N){ + return matsubtract_rowvec(A, x); + } else if (cols == N){ + return matsubtract_colvec(A, x); + }else{ + throw std::runtime_error("matsubtract: undefined fault - auto"); + } + }else if(method=="row"){ + return matsubtract_rowvec(A, x); + } else if (method=="col"){ + return matsubtract_colvec(A, x); + }else{ + throw std::runtime_error("matsubtract: undefined fault - defined method"); + } + } + + + + +} // namespace numerics + +#endif // _matsubtract_n_ \ No newline at end of file diff --git a/include/numerics/matsum.h b/include/numerics/matsum.h new file mode 100644 index 0000000..9bf0ebd --- /dev/null +++ b/include/numerics/matsum.h @@ -0,0 +1,39 @@ +#ifndef _matsum_n_ +#define _matsum_n_ + +#include "./utils/vector.h" +#include "./utils/matrix.h" +#include "./core/omp_config.h" + +namespace numerics{ + + template + utils::Vector matsum(utils::Matrix& A, std::string method) { + + utils::Vector b; + + if (method == "row"){ + b.resize(A.cols(), T{0}); + for (uint64_t i = 0; i < A.cols(); ++i){ + for (uint64_t j = 0; j < A.rows(); ++j){ + b[i] += A(j, i); + } + } + }else if (method == "col"){ + b.resize(A.rows(), T{0}); + + for (uint64_t i = 0; i < A.cols(); ++i){ + for (uint64_t j = 0; j < A.rows(); ++j){ + b[j] += A(j, i); + } + } + }else{ + throw std::runtime_error("matsum: choose sum by: 'row' or 'col'"); + } + return b; + } + + +} // namespace numerics + +#endif // _matadd_n_ \ No newline at end of file diff --git a/include/numerics/max.h b/include/numerics/max.h index 3f8402f..4e0db24 100644 --- a/include/numerics/max.h +++ b/include/numerics/max.h @@ -39,13 +39,37 @@ namespace numerics{ utils::Matrix max(const utils::Matrix& A, const T b){ utils::Matrix B = A; - inplace_max(B, b); - - return B; } + template + utils::Vector max(const utils::Matrix& A, std::string method){ + + utils::Vector b; + + if (method == "cols"){ + b.resize(A.cols(), T{0}); + for (uint64_t i = 0; i < A.cols(); ++i){ + for (uint64_t j = 0; j < A.rows(); ++j){ + b[i] = max(A(j, i), b[i]); + } + } + }else if (method == "rows"){ + b.resize(A.rows(), T{0}); + for (uint64_t i = 0; i < A.rows(); ++i){ + for (uint64_t j = 0; j < A.cols(); ++j){ + //std::cout << i << ":" << j << std::endl; + b[i] = max(A(i, j), b[i]); + } + } + }else{ + throw std::runtime_error("max: choose 'rows or 'cols'"); + } + return b; + + } + } // namespace numerics diff --git a/include/numerics/mean.h b/include/numerics/mean.h new file mode 100644 index 0000000..b8166a4 --- /dev/null +++ b/include/numerics/mean.h @@ -0,0 +1,31 @@ +#ifndef _mean_n_ +#define _mean_n_ + +#include "./utils/vector.h" +#include "./utils/matrix.h" +#include "./core/omp_config.h" + +namespace numerics{ + + template + T mean(utils::Vector& A) { + + T mean(T{0}); + + const uint64_t rows = A.rows(); + const uint64_t cols = A.cols(); + + + for (uint64_t i = 0; i < cols; ++i) { + for (uint64_t j = 0; j < rows; ++j) { + mean += A(j, i); + } + } + mean /= (static_cast(rows)* static_cast(cols)); + return mean; + } + + +} // namespace numerics + +#endif // _mean_n_ \ No newline at end of file diff --git a/include/numerics/numerics.h b/include/numerics/numerics.h index fb5d2b7..1c0d2e3 100644 --- a/include/numerics/numerics.h +++ b/include/numerics/numerics.h @@ -6,11 +6,16 @@ #include "./numerics/transpose.h" #include "./numerics/inverse.h" #include "./numerics/matmul.h" +#include "./numerics/matdiv.h" #include "./numerics/matvec.h" #include "./numerics/matadd.h" +#include "./numerics/matsubtract.h" +#include "./numerics/matsum.h" #include "./numerics/min.h" #include "./numerics/max.h" #include "./numerics/abs.h" +#include "./numerics/mean.h" +#include "./numerics/exponential.h" #include "./numerics/interpolation1d.h" // base diff --git a/obj/main.d b/obj/main.d index 2f70e92..c672385 100644 --- a/obj/main.d +++ b/obj/main.d @@ -8,9 +8,12 @@ obj/main.o: src/main.cpp include/./core/omp_config.h \ include/./numerics/inverse.h \ include/./numerics/inverse/inverse_gauss_jordan.h \ include/./numerics/inverse/inverse_lu.h include/./decomp/lu.h \ - include/./numerics/matmul.h include/./numerics/matvec.h \ - include/./numerics/matadd.h include/./numerics/min.h \ - include/./numerics/max.h include/./numerics/interpolation1d.h \ + include/./numerics/matmul.h include/./numerics/matdiv.h \ + include/./numerics/matvec.h include/./numerics/matadd.h \ + include/./numerics/matsubtract.h include/./numerics/matsum.h \ + include/./numerics/min.h include/./numerics/max.h \ + include/./numerics/mean.h include/./numerics/exponential.h \ + include/./numerics/interpolation1d.h \ include/./numerics/interpolation1d/interpolation1d_barycentric.h \ include/./numerics/interpolation1d/interpolation1d_base.h \ include/./numerics/interpolation1d/interpolation1d_cubic_spline.h \ @@ -24,7 +27,9 @@ obj/main.o: src/main.cpp include/./core/omp_config.h \ include/./modules/neural_networks/neural_networks.h \ include/./modules/neural_networks/datasets/spiral.h \ include/./modules/neural_networks/layers/dense_layer.h \ - include/./modules/neural_networks/activation_functions/ReLU.h + include/./modules/neural_networks/activation_functions/ReLU.h \ + include/./modules/neural_networks/activation_functions/Softmax.h \ + include/./modules/neural_networks/loss/loss.h include/./core/omp_config.h: include/./utils/utils.h: include/./utils/vector.h: @@ -43,10 +48,15 @@ include/./numerics/inverse/inverse_gauss_jordan.h: include/./numerics/inverse/inverse_lu.h: include/./decomp/lu.h: include/./numerics/matmul.h: +include/./numerics/matdiv.h: include/./numerics/matvec.h: include/./numerics/matadd.h: +include/./numerics/matsubtract.h: +include/./numerics/matsum.h: include/./numerics/min.h: include/./numerics/max.h: +include/./numerics/mean.h: +include/./numerics/exponential.h: include/./numerics/interpolation1d.h: include/./numerics/interpolation1d/interpolation1d_barycentric.h: include/./numerics/interpolation1d/interpolation1d_base.h: @@ -65,3 +75,5 @@ include/./modules/neural_networks/neural_networks.h: include/./modules/neural_networks/datasets/spiral.h: include/./modules/neural_networks/layers/dense_layer.h: include/./modules/neural_networks/activation_functions/ReLU.h: +include/./modules/neural_networks/activation_functions/Softmax.h: +include/./modules/neural_networks/loss/loss.h: diff --git a/obj/main.o b/obj/main.o index debce121562ab963a63cbd029b1ac9f911383945..d2232b615da5a634f41558e685eb0f24c718425c 100644 GIT binary patch literal 58768 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

wHmradBVP?WkmKn>5 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 literal 39712 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 diff --git a/src/main.cpp b/src/main.cpp index 83b8280..5b09871 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,24 +24,27 @@ int main(int argc, char const *argv[]) { utils::Mf X(10,2, 0); - utils::Vf y(10, 0); + utils::Vd y(10, 0); + + neural_networks::create_spital_data(100, 3, X, y); - neural_networks::dense_layer layer(2, 3); + neural_networks::dense_layer dense1(2, 3); + neural_networks::activation_ReLU activation1; + neural_networks::dense_layer dense2(3, 3); + neural_networks::activation_softmax activation2; - neural_networks::activation_ReLU RelU; + dense1.forward(X); + activation1.forward(dense1.outputs); + dense2.forward(activation1.outputs); + activation2.forward(dense2.outputs); - layer.forward(X); - RelU.forward(layer.outputs); + for (int i = 0; i < 5; ++i){ - std::cout << RelU.outputs.get_row(i) << std::endl; + std::cout << activation2.outputs.get_row(i) << std::endl; } - //layer1_output.print(); - //layer2_output.print(); - - //std::cout << output << std::endl;