From 88227a38fc18dc29f7ae8f00106f7c84ddd7203b Mon Sep 17 00:00:00 2001 From: Michelle Date: Fri, 3 Oct 2025 20:54:37 +0200 Subject: [PATCH] Neural Network Started on implementing neural network from NNFS. I've done ReLU and stopped at p.104. Softmax is not ready. --- bin/abc_lab | Bin 22672 -> 37320 bytes .../activation_functions/ReLU.h | 28 +++ .../activation_functions/Softmax.h | 28 +++ .../modules/neural_networks/datasets/spiral.h | 61 +++++ .../neural_networks/layers/dense_layer.h | 42 ++++ .../modules/neural_networks/neural_networks.h | 9 + include/numerics/matadd.h | 229 ++++++++++++++++++ include/numerics/matmul.h | 5 +- include/numerics/max.h | 29 +++ include/numerics/numerics.h | 1 + include/numerics/transpose.h | 5 +- include/utils/matrix.h | 84 +++++++ include/utils/random.h | 37 +++ include/utils/utils.h | 3 +- include/utils/vector.h | 12 + makefile | 2 +- obj/main.d | 27 ++- obj/main.o | Bin 21184 -> 39712 bytes src/main.cpp | 39 ++- 19 files changed, 626 insertions(+), 15 deletions(-) create mode 100644 include/modules/neural_networks/activation_functions/ReLU.h create mode 100644 include/modules/neural_networks/activation_functions/Softmax.h create mode 100644 include/modules/neural_networks/datasets/spiral.h create mode 100644 include/modules/neural_networks/layers/dense_layer.h create mode 100644 include/modules/neural_networks/neural_networks.h create mode 100644 include/numerics/matadd.h create mode 100644 include/utils/random.h diff --git a/bin/abc_lab b/bin/abc_lab index ac1a151b0e2aaeec911d8fa9b9c5f6ef40bf16ca..0c1f68d28d8200914149f20e9183347dfe5032b8 100755 GIT binary patch literal 37320 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 diff --git a/include/modules/neural_networks/activation_functions/ReLU.h b/include/modules/neural_networks/activation_functions/ReLU.h new file mode 100644 index 0000000..9e38e10 --- /dev/null +++ b/include/modules/neural_networks/activation_functions/ReLU.h @@ -0,0 +1,28 @@ +#pragma once + +#include "./core/omp_config.h" + +#include "./utils/vector.h" +#include "./utils/matrix.h" +#include "./utils/random.h" + + +namespace neural_networks{ + + template + struct activation_ReLU{ + + utils::Matrix outputs; + + void forward(utils::Matrix inputs){ + outputs = numerics::max(inputs, T{0}); + //outputs.print(); + } + + + + }; + + + +} // end namespace neural_networks \ No newline at end of file diff --git a/include/modules/neural_networks/activation_functions/Softmax.h b/include/modules/neural_networks/activation_functions/Softmax.h new file mode 100644 index 0000000..837b91c --- /dev/null +++ b/include/modules/neural_networks/activation_functions/Softmax.h @@ -0,0 +1,28 @@ +#pragma once + +#include "./core/omp_config.h" + +#include "./utils/vector.h" +#include "./utils/matrix.h" +#include "./utils/random.h" + + +namespace neural_networks{ + + template + struct activation_softmax{ + + utils::Matrix outputs; + + void forward(utils::Matrix inputs){ + //outputs = numerics::max(inputs, T{0}); + //outputs.print(); + } + + + + }; + + + +} // end namespace neural_networks \ No newline at end of file diff --git a/include/modules/neural_networks/datasets/spiral.h b/include/modules/neural_networks/datasets/spiral.h new file mode 100644 index 0000000..d0dd473 --- /dev/null +++ b/include/modules/neural_networks/datasets/spiral.h @@ -0,0 +1,61 @@ +#pragma once + +#include "./core/omp_config.h" +#include "./utils/matrix.h" +#include "./utils/vector.h" +#include "./utils/random.h" + +//#include + + +namespace neural_networks{ + + 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; + uint64_t row_idx; + + + if ((rows != X.rows()) || (X.cols() != 2)){ + X.resize(samples*classes, 2); + } + if (rows != y.size()){ + y.resize(rows); + } + + 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); + 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; + } + } + + + + /* + + 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]; + } + }*/ + } + + +} // end namesoace NN \ No newline at end of file diff --git a/include/modules/neural_networks/layers/dense_layer.h b/include/modules/neural_networks/layers/dense_layer.h new file mode 100644 index 0000000..28aa973 --- /dev/null +++ b/include/modules/neural_networks/layers/dense_layer.h @@ -0,0 +1,42 @@ +#pragma once + +#include "./core/omp_config.h" + +#include "./utils/vector.h" +#include "./utils/matrix.h" +#include "./utils/random.h" + + +namespace neural_networks{ + + template + struct dense_layer{ + utils::Matrix weights; + utils::Vector biases; + utils::Matrix outputs; + + // Default Constructor + dense_layer() = default; + + // Constructor + dense_layer(const uint64_t n_inputs, const uint64_t n_neurons){ + + weights.random(n_inputs, n_neurons, -1, 1); + biases.resize(n_neurons, T{0}); + weights.print(); + //outputs.resize() + + } + + + void forward(utils::Matrix inputs){ + outputs = numerics::matadd(numerics::matmul_auto(inputs, (weights)), biases, "row"); + } + + + + }; + + + +} // 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 new file mode 100644 index 0000000..f905c20 --- /dev/null +++ b/include/modules/neural_networks/neural_networks.h @@ -0,0 +1,9 @@ +// #include "./modules/neural_networks/neural_networks.h" +#pragma once + +#include "datasets/spiral.h" + +#include "layers/dense_layer.h" + + +#include "activation_functions/ReLU.h" \ No newline at end of file diff --git a/include/numerics/matadd.h b/include/numerics/matadd.h new file mode 100644 index 0000000..58853e8 --- /dev/null +++ b/include/numerics/matadd.h @@ -0,0 +1,229 @@ +#ifndef _matadd_n_ +#define _matadd_n_ + + +#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) { + + 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]; + } + } + } + + template + void inplace_matadd_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_matadd_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 matadd_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_matadd_colvec(B, x); + + return B; + } + + template + utils::Matrix matadd_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_matadd_rowvec(B, x); + + return B; + } + + template + utils::Matrix matadd(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("matadd: too many options for dimensions"); + } else if (rows == N){ + return matadd_rowvec(A, x); + } else if (cols == N){ + return matadd_colvec(A, x); + }else{ + throw std::runtime_error("matadd: undefined fault - auto"); + } + }else if(method=="row"){ + return matadd_rowvec(A, x); + } else if (method=="col"){ + return matadd_colvec(A, x); + }else{ + throw std::runtime_error("matadd: undefined fault - defined method"); + } + } + + + + + /* + // -------------- Collapse(2) OpenMP ---------------- + template + utils::Vector matvec_omp(const utils::Matrix& A, const utils::Vector& x) { + if (A.cols() != x.size()) { + throw std::runtime_error("matvec: dimension mismatch"); + } + + const uint64_t m = A.rows(); + const uint64_t n = A.cols(); + + utils::Vector y(m, T{0}); // <-- y has length m (rows) + + + const T* xptr = x.data(); + const T* Aptr = A.data(); // row-major: A(i,j) == Aptr[i*n + j] + + // Each row i is an independent dot product: y[i] = dot(A[i,*], x) + #pragma omp parallel for schedule(static) + for (uint64_t i = 0; i < m; ++i) { + const T* row = Aptr + i * n; // contiguous row i + T acc = T{0}; + #pragma omp simd reduction(+:acc) + for (uint64_t j = 0; j < n; ++j) { + acc += row[j] * xptr[j]; + } + y[i] = acc; + } + + return y; + } + + // -------------- Auto OpenMP ---------------- + template + utils::Vector matvec_auto(const utils::Matrix& A, + const utils::Vector& x) { + + + uint64_t work = A.rows() * A.cols(); + + bool can_parallel = omp_config::omp_parallel_allowed(); + #ifdef _OPENMP + int threads = omp_get_max_threads(); + #else + int threads = 1; + #endif + + if (can_parallel || work > static_cast(threads) * 4ull) { + return matvec_omp(A,x); + } + else{ + // Safe fallback + return matvec(A,x); + } + + } + +// ================================================= +// y = x * A (Vector–Matrix product) +// ================================================= + template + utils::Vector vecmat(const utils::Vector& x, const utils::Matrix& A) { + if (x.size() != A.rows()) { + throw std::runtime_error("vecmat: dimension mismatch"); + } + const uint64_t m = A.rows(); + const uint64_t n = A.cols(); + + utils::Vector y(n, T{0}); + + for (uint64_t j = 0; j < n; ++j) { + for (uint64_t i = 0; i < m; ++i) { + y[j] += x[i] * A(i, j); + } + } + return y; + } + + // -------------- Collapse(2) OpenMP ---------------- + template + utils::Vector vecmat_omp(const utils::Vector& x, const utils::Matrix& A) { + if (x.size() != A.rows()) { + throw std::runtime_error("vecmat: dimension mismatch"); + } + const uint64_t m = A.rows(); + const uint64_t n = A.cols(); + + utils::Vector y(n, T{0}); + #pragma omp parallel for schedule(static) + for (uint64_t j = 0; j < n; ++j) { + T acc = T{0}; + for (uint64_t i = 0; i < m; ++i) { + acc += x[i] * A(i, j); + } + y[j] = acc; + } + return y; + } + + // -------------- Auto OpenMP ---------------- + template + utils::Vector vecmat_auto(const utils::Vector& x, + const utils::Matrix& A) { + + uint64_t work = A.rows() * A.cols(); + + bool can_parallel = omp_config::omp_parallel_allowed(); + #ifdef _OPENMP + int threads = omp_get_max_threads(); + #else + int threads = 1; + #endif + + if (can_parallel || work > static_cast(threads) * 4ull) { + return vecmat_omp(x,A); + } + else{ + // Safe fallback + return vecmat(x,A); + } + + } +*/ + +} // namespace numerics + +#endif // _matadd_n_ \ No newline at end of file diff --git a/include/numerics/matmul.h b/include/numerics/matmul.h index 6461e31..c2a25a7 100644 --- a/include/numerics/matmul.h +++ b/include/numerics/matmul.h @@ -11,11 +11,11 @@ namespace numerics{ // ---------------- Serial baseline ---------------- template utils::Matrix matmul(const utils::Matrix& A, const utils::Matrix& B){ - + if(A.cols() != B.rows()){ throw std::runtime_error("matmul: dimension mismatch"); } - + const uint64_t m = A.rows(); const uint64_t n = A.cols(); // also B.rows() const uint64_t p = B.cols(); @@ -98,6 +98,7 @@ utils::Matrix matmul_auto(const utils::Matrix& A, // Tiny problems: serial is cheapest. if (!can_parallel || work < threads*4ull) { + return matmul(A,B); } // Plenty of (i,j) work → collapse(2) is a great default. diff --git a/include/numerics/max.h b/include/numerics/max.h index ca3797b..3f8402f 100644 --- a/include/numerics/max.h +++ b/include/numerics/max.h @@ -17,6 +17,35 @@ namespace numerics{ } } + template + void inplace_max(utils::Matrix& A, const T b){ + + const uint64_t rows = A.rows(); + const uint64_t cols = A.cols(); + + for (uint64_t i = 0; i < rows; ++i){ + for (uint64_t j = 0; j < cols; ++j){ + + if (b > A(i,j)){ + //std::cout << A(i,j) << std::endl; + A(i,j) = b; + //std::cout << A(i,j) << std::endl; + } + } + } + } + + template + utils::Matrix max(const utils::Matrix& A, const T b){ + + utils::Matrix B = A; + + inplace_max(B, b); + + + return B; + } + } // namespace numerics diff --git a/include/numerics/numerics.h b/include/numerics/numerics.h index bb4760e..fb5d2b7 100644 --- a/include/numerics/numerics.h +++ b/include/numerics/numerics.h @@ -7,6 +7,7 @@ #include "./numerics/inverse.h" #include "./numerics/matmul.h" #include "./numerics/matvec.h" +#include "./numerics/matadd.h" #include "./numerics/min.h" #include "./numerics/max.h" #include "./numerics/abs.h" diff --git a/include/numerics/transpose.h b/include/numerics/transpose.h index 3052e56..d4fd38a 100644 --- a/include/numerics/transpose.h +++ b/include/numerics/transpose.h @@ -103,6 +103,7 @@ namespace numerics{ uint64_t threads = 1; #endif + if (can_parallel && work > threads * 4ull) { inplace_transpose_square_omp(A); }else { @@ -118,8 +119,10 @@ namespace numerics{ uint64_t work = A.rows() * A.cols(); + + if (rows==cols){ - utils::Matrix B(rows, cols, T{0}); + utils::Matrix B = A; inplace_transpose_square_auto(B); return B; } diff --git a/include/utils/matrix.h b/include/utils/matrix.h index ad72e9d..c13cb3d 100644 --- a/include/utils/matrix.h +++ b/include/utils/matrix.h @@ -2,12 +2,16 @@ #define _matrix_n_ #include "./utils/vector.h" +#include "./utils/random.h" #ifdef _OPENMP #include #endif +#include + + #include namespace utils{ @@ -25,6 +29,72 @@ public: : rows_(rows), cols_(cols), data_(rows * cols, value) {} + // Construct from list-of-lists: + // utils::Mf A{{1,2,3}, {4,5,6}}; + Matrix(std::initializer_list> init) { + rows_ = static_cast(init.size()); + if (rows_ > 0) { + cols_ = static_cast(init.begin()->size()); + } else { + cols_ = 0; + } + + // Validate all rows have the same length + for (const auto& row : init) { + if (row.size() != cols_) { + throw std::runtime_error("Matrix(list of lists): ragged rows"); + } + } + + data_.resize(rows_ * cols_); + uint64_t r = 0; + for (uint64_t i = 0; i < init.size(); ++i, ++r){ + const std::initializer_list& row = *(init.begin() + i); + + uint64_t c = 0; + for (uint64_t j = 0; j < row.size(); ++j, ++c){ + const T& val = *(row.begin() + j); + data_[r * cols_ + c] = val; + } + } + } + + + // Assign from list-of-lists after default construction: + // utils::Md M; M = {{1,2},{3,4}}; + Matrix& operator=(std::initializer_list> init) { + // Set sizes + rows_ = static_cast(init.size()); + if (rows_ > 0) { + cols_ = static_cast((init.begin())->size()); + } else { + cols_ = 0; + } + + // Validate: all rows must have same length + for (uint64_t i = 0; i < rows_; ++i) { + const std::initializer_list& row = *(init.begin() + i); + if (row.size() != cols_) { + throw std::runtime_error("Matrix(list of lists): ragged rows"); + } + } + + // Allocate storage + data_.resize(rows_ * cols_); + + // Copy data row by row + for (uint64_t i = 0; i < rows_; ++i) { + const std::initializer_list& row = *(init.begin() + i); + for (uint64_t j = 0; j < cols_; ++j) { + const T& val = *(row.begin() + j); + data_[i * cols_ + j] = val; + } + } + + return *this; + } + + //# MATRIX: basic properties # uint64_t rows() const noexcept {return rows_;} uint64_t cols() const noexcept {return cols_;} @@ -45,6 +115,20 @@ public: } + void random(uint64_t rows, uint64_t cols, const T& lower, const T& higher){ + rows_ = rows; + cols_ = cols; + data_.resize(rows_*cols_, 0); + + // Copy data row by row + for (uint64_t i = 0; i < rows_; ++i) { + for (uint64_t j = 0; j < cols_; ++j) { + data_[i * cols_ + j] = utils::random(lower, higher); + } + } + + } + //# MATRIX: row helpers (copy out) # // Read whole row as an owning Vector diff --git a/include/utils/random.h b/include/utils/random.h new file mode 100644 index 0000000..8540982 --- /dev/null +++ b/include/utils/random.h @@ -0,0 +1,37 @@ +#pragma once + +#include "./core/omp_config.h" +#include + +namespace utils{ + + // Shared engine + inline std::mt19937& rng() { + static std::random_device rd; + static std::mt19937 gen(rd()); + return gen; + } + + // Integral overload + template < + typename T, + typename std::enable_if::value, int>::type = 0 + > + T random(T low, T high) { + std::uniform_int_distribution dist(low, high); + return dist(rng()); + } + + // Floating-point overload + template < + typename T, + typename std::enable_if::value, int>::type = 0 + > + T random(T low, T high) { + std::uniform_real_distribution dist(low, high); + return dist(rng()); + } + + +} // end namespace utils + diff --git a/include/utils/utils.h b/include/utils/utils.h index 86904a4..5b7b8bf 100644 --- a/include/utils/utils.h +++ b/include/utils/utils.h @@ -3,4 +3,5 @@ #include "./utils/vector.h" #include "./utils/matrix.h" -#include "./utils/generators.h" \ No newline at end of file +#include "./utils/generators.h" +#include "./utils/random.h" diff --git a/include/utils/vector.h b/include/utils/vector.h index 9b71ac1..5780b19 100644 --- a/include/utils/vector.h +++ b/include/utils/vector.h @@ -5,6 +5,8 @@ #include #include +#include + #include #include @@ -31,6 +33,9 @@ public: v.resize(size, value); } + // Construct from a braced list: utils::Vf v{1,2,3}; + Vector(std::initializer_list init) : v(init) {} + //########################################################## @@ -47,6 +52,13 @@ public: // a = vector[2]; const T& operator[](uint64_t idx) const { return v[idx]; } + + // Assign from a braced list after default construction: + Vector& operator=(std::initializer_list init) { + v = init; + return *this; + } + // vector.size(); uint64_t size() const noexcept { return v.size(); } diff --git a/makefile b/makefile index 3d04849..fb36b99 100644 --- a/makefile +++ b/makefile @@ -51,7 +51,7 @@ OMP_MAX_LEVELS ?= 1 # 1 = no nested teams; set 2+ to allow nesting OMP_THREADS ?= 16 # e.g. "16" or "8,4" for nested (outer,inner) OMP_DYNAMIC ?= TRUE # TRUE/FALSE: let runtime adjust threads OMP_SCHEDULE ?= STATIC # STATIC recommended for matvec/matmul -OMP_DISPLAY_ENV ?= TRUE # TRUE to print runtime config at startup +OMP_DISPLAY_ENV ?= FALSE # TRUE to print runtime config at startup # Export OMP defaults so child makes or tools see them (not strictly required) export OMP_PROC_BIND diff --git a/obj/main.d b/obj/main.d index be73496..2f70e92 100644 --- a/obj/main.d +++ b/obj/main.d @@ -1,15 +1,16 @@ obj/main.o: src/main.cpp include/./core/omp_config.h \ include/./utils/utils.h include/./utils/vector.h \ - include/./utils/matrix.h include/./utils/generators.h \ - include/./utils/generators/linspace.h include/utils/vector.h \ - include/./numerics/numerics.h include/./numerics/initializers/eye.h \ - include/./numerics/matequal.h include/./numerics/abs.h \ - include/./numerics/transpose.h include/./numerics/inverse.h \ + include/./utils/matrix.h include/./utils/random.h \ + include/./utils/generators.h include/./utils/generators/linspace.h \ + include/utils/vector.h include/./numerics/numerics.h \ + include/./numerics/initializers/eye.h include/./numerics/matequal.h \ + include/./numerics/abs.h include/./numerics/transpose.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/min.h include/./numerics/max.h \ - include/./numerics/interpolation1d.h \ + include/./numerics/matadd.h include/./numerics/min.h \ + include/./numerics/max.h include/./numerics/interpolation1d.h \ include/./numerics/interpolation1d/interpolation1d_barycentric.h \ include/./numerics/interpolation1d/interpolation1d_base.h \ include/./numerics/interpolation1d/interpolation1d_cubic_spline.h \ @@ -19,11 +20,16 @@ obj/main.o: src/main.cpp include/./core/omp_config.h \ include/./decomp/decomp.h include/./modules/mesh/mesh.h \ include/modules/mesh/mesh1d.h include/modules/fluids/fluids.h \ include/modules/fluids/diffusion1d.h include/core/global_config.h \ - include/utils/matrix.h + include/utils/matrix.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/./core/omp_config.h: include/./utils/utils.h: include/./utils/vector.h: include/./utils/matrix.h: +include/./utils/random.h: include/./utils/generators.h: include/./utils/generators/linspace.h: include/utils/vector.h: @@ -38,6 +44,7 @@ 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: @@ -54,3 +61,7 @@ include/modules/fluids/fluids.h: include/modules/fluids/diffusion1d.h: include/core/global_config.h: include/utils/matrix.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: diff --git a/obj/main.o b/obj/main.o index 15bd2270574a5600f23fe359c812761fda8c12c1..debce121562ab963a63cbd029b1ac9f911383945 100644 GIT binary patch literal 39712 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 literal 21184 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 @@ -19,7 +21,40 @@ int main(int argc, char const *argv[]) -{ +{ + + utils::Mf X(10,2, 0); + utils::Vf y(10, 0); + neural_networks::create_spital_data(100, 3, X, y); + + neural_networks::dense_layer layer(2, 3); + + neural_networks::activation_ReLU RelU; + + layer.forward(X); + RelU.forward(layer.outputs); + + for (int i = 0; i < 5; ++i){ + std::cout << RelU.outputs.get_row(i) << std::endl; + } + + //layer1_output.print(); + //layer2_output.print(); + + //std::cout << output << std::endl; + + + + + + + + + + + + + /* utils::Vd a = utils::linspace(1, 10, 10, true); a.print(); mesh::Mesh1D mesh(a); @@ -40,7 +75,7 @@ int main(int argc, char const *argv[]) fluids::Diffusion1D diffusion(cfg, mesh, Gamma); diffusion.assemble(A, b, s); - +*/ return 0; } \ No newline at end of file