From 6b4e0fc3ca0a4cec35764dc96782e55cf18cc210 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Mon, 25 Nov 2024 17:29:19 +0100 Subject: [PATCH 01/12] feat: Add CPU backend for heaviside operator --- include/aidge/backend/cpu.hpp | 1 + unit_tests/operator/Test_Heaviside.cpp | 86 ++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 unit_tests/operator/Test_Heaviside.cpp diff --git a/include/aidge/backend/cpu.hpp b/include/aidge/backend/cpu.hpp index 5db19a2b..17f3b832 100644 --- a/include/aidge/backend/cpu.hpp +++ b/include/aidge/backend/cpu.hpp @@ -36,6 +36,7 @@ #include "aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp" #include "aidge/backend/cpu/operator/HeavisideImpl.hpp" #include "aidge/backend/cpu/operator/LRNImpl.hpp" +#include "aidge/backend/cpu/operator/HeavisideImpl.hpp" #include "aidge/backend/cpu/operator/LeakyReLUImpl.hpp" #include "aidge/backend/cpu/operator/LnImpl.hpp" #include "aidge/backend/cpu/operator/MatMulImpl.hpp" diff --git a/unit_tests/operator/Test_Heaviside.cpp b/unit_tests/operator/Test_Heaviside.cpp new file mode 100644 index 00000000..1a11ff2b --- /dev/null +++ b/unit_tests/operator/Test_Heaviside.cpp @@ -0,0 +1,86 @@ +#include <aidge/operator/Heaviside.hpp> +#include <aidge/utils/TensorUtils.hpp> +#include <catch2/catch_test_macros.hpp> +#include <memory> +#include <cstdlib> +#include <random> + +#include "aidge/data/Tensor.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/operator/AvgPooling.hpp" + +namespace Aidge +{ + +TEST_CASE("[cpu/operator] Heaviside(forward)", "[Heaviside][CPU]") { + + // Create a random number generator + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<float> valueDist(-1.0f, 1.0f); + std::uniform_int_distribution<std::size_t> dimSizeDist(std::size_t(2), std::size_t(10)); + std::uniform_int_distribution<std::size_t> nbDimsDist(std::size_t(1), std::size_t(5)); + std::uniform_int_distribution<int> boolDist(0,1); + + SECTION("1D Tensor") { + + std::shared_ptr<Tensor> input0 = std::make_shared<Tensor>(Array1D<float,10> { + {0, 1, 2,-3, 4,-5,-6, 7, 8, 9} + }); + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array1D<float,10> { + {0.5, 1, 1, 0, 1, 0, 0, 1, 1, 1} + }); + + std::shared_ptr<Aidge::Node> hs = Aidge::Heaviside(0.5); + auto op = std::static_pointer_cast<Aidge::OperatorTensor>(hs -> getOperator()); + op->associateInput(0, input0); + op->setBackend("cpu"); + op->setDataType(DataType::Float32); + + op->forward(); + REQUIRE(approxEq<float>(*op->getOutput(0),*expectedOutput)); + } + + SECTION("Random Tensor") + { + auto dims = std::vector<std::size_t>(); + auto nbDims = nbDimsDist(gen); + + for (std::size_t i = 0; i < nbDims; ++i) { + dims.push_back(dimSizeDist(gen)); + } + + auto numberOfElements = std::accumulate(dims.cbegin(), dims.cend(), std::size_t(1), std::multiplies<std::size_t>()); + float* array0 = new float[numberOfElements]; + float* array1 = new float[numberOfElements]; + + for(auto i = 0u; i < numberOfElements; ++i) + { + array0[i] = valueDist(gen); + array1[i] = array0[i] > 0 ? 1 : (array0[i] == 0 ? 0.5 : 0); + } + + auto T0 = std::make_shared<Tensor>(); + T0->setDataType(DataType::Float32); + T0->setBackend("cpu"); + + auto T1 = std::make_shared<Tensor>(); + T1->setDataType(DataType::Float32); + T1->setBackend("cpu"); + + T0->resize(dims); + T0->getImpl()->setRawPtr(array0, numberOfElements); + T1->resize(dims); + T1->getImpl()->setRawPtr(array1, numberOfElements); + + std::shared_ptr<Aidge::Node> hs = Aidge::Heaviside(0.5); + auto op = std::static_pointer_cast<Aidge::OperatorTensor>(hs -> getOperator()); + op->associateInput(0, T0); + op->setBackend("cpu"); + op->setDataType(DataType::Float32); + op->forward(); + + REQUIRE(approxEq<float>(*T0, *T1)); + } +} +} -- GitLab From 134704eddd0917fb1195a3faac110c0d42058e97 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Mon, 25 Nov 2024 17:45:11 +0100 Subject: [PATCH 02/12] chore: format and clean files --- unit_tests/operator/Test_Heaviside.cpp | 86 -------------------------- 1 file changed, 86 deletions(-) delete mode 100644 unit_tests/operator/Test_Heaviside.cpp diff --git a/unit_tests/operator/Test_Heaviside.cpp b/unit_tests/operator/Test_Heaviside.cpp deleted file mode 100644 index 1a11ff2b..00000000 --- a/unit_tests/operator/Test_Heaviside.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include <aidge/operator/Heaviside.hpp> -#include <aidge/utils/TensorUtils.hpp> -#include <catch2/catch_test_macros.hpp> -#include <memory> -#include <cstdlib> -#include <random> - -#include "aidge/data/Tensor.hpp" -#include "aidge/graph/Node.hpp" -#include "aidge/operator/AvgPooling.hpp" - -namespace Aidge -{ - -TEST_CASE("[cpu/operator] Heaviside(forward)", "[Heaviside][CPU]") { - - // Create a random number generator - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_real_distribution<float> valueDist(-1.0f, 1.0f); - std::uniform_int_distribution<std::size_t> dimSizeDist(std::size_t(2), std::size_t(10)); - std::uniform_int_distribution<std::size_t> nbDimsDist(std::size_t(1), std::size_t(5)); - std::uniform_int_distribution<int> boolDist(0,1); - - SECTION("1D Tensor") { - - std::shared_ptr<Tensor> input0 = std::make_shared<Tensor>(Array1D<float,10> { - {0, 1, 2,-3, 4,-5,-6, 7, 8, 9} - }); - std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array1D<float,10> { - {0.5, 1, 1, 0, 1, 0, 0, 1, 1, 1} - }); - - std::shared_ptr<Aidge::Node> hs = Aidge::Heaviside(0.5); - auto op = std::static_pointer_cast<Aidge::OperatorTensor>(hs -> getOperator()); - op->associateInput(0, input0); - op->setBackend("cpu"); - op->setDataType(DataType::Float32); - - op->forward(); - REQUIRE(approxEq<float>(*op->getOutput(0),*expectedOutput)); - } - - SECTION("Random Tensor") - { - auto dims = std::vector<std::size_t>(); - auto nbDims = nbDimsDist(gen); - - for (std::size_t i = 0; i < nbDims; ++i) { - dims.push_back(dimSizeDist(gen)); - } - - auto numberOfElements = std::accumulate(dims.cbegin(), dims.cend(), std::size_t(1), std::multiplies<std::size_t>()); - float* array0 = new float[numberOfElements]; - float* array1 = new float[numberOfElements]; - - for(auto i = 0u; i < numberOfElements; ++i) - { - array0[i] = valueDist(gen); - array1[i] = array0[i] > 0 ? 1 : (array0[i] == 0 ? 0.5 : 0); - } - - auto T0 = std::make_shared<Tensor>(); - T0->setDataType(DataType::Float32); - T0->setBackend("cpu"); - - auto T1 = std::make_shared<Tensor>(); - T1->setDataType(DataType::Float32); - T1->setBackend("cpu"); - - T0->resize(dims); - T0->getImpl()->setRawPtr(array0, numberOfElements); - T1->resize(dims); - T1->getImpl()->setRawPtr(array1, numberOfElements); - - std::shared_ptr<Aidge::Node> hs = Aidge::Heaviside(0.5); - auto op = std::static_pointer_cast<Aidge::OperatorTensor>(hs -> getOperator()); - op->associateInput(0, T0); - op->setBackend("cpu"); - op->setDataType(DataType::Float32); - op->forward(); - - REQUIRE(approxEq<float>(*T0, *T1)); - } -} -} -- GitLab From 6bdcbbeddba449b4eb7aaebead9a1aceb089baa7 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Tue, 3 Dec 2024 17:38:12 +0100 Subject: [PATCH 03/12] save changes - wip tests for leaky --- src/operator/SubImpl.cpp | 3 + unit_tests/operator/Test_MetaOperator.cpp | 1035 ++++++++++++--------- 2 files changed, 614 insertions(+), 424 deletions(-) diff --git a/src/operator/SubImpl.cpp b/src/operator/SubImpl.cpp index e36abe2a..5c842c26 100644 --- a/src/operator/SubImpl.cpp +++ b/src/operator/SubImpl.cpp @@ -29,6 +29,9 @@ void Aidge::SubImpl_cpu::forward() { // Find the correct kernel type const auto impl = Registrar<SubImpl_cpu>::create(getBestMatch(getRequiredSpec())); + Log::info("Sub Operator Kernel"); + op_.getInput(0)->print(); + op_.getInput(1)->print(); // Call kernel impl.forward(op_.getInput(0)->dims(), diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index 271a1e2f..9c25795f 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -14,7 +14,6 @@ #include <cstdlib> #include <memory> -#include "aidge/utils/TensorUtils.hpp" #include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/PadImpl.hpp" #include "aidge/data/Tensor.hpp" @@ -23,56 +22,60 @@ #include "aidge/operator/MetaOperatorDefs.hpp" #include "aidge/operator/Pad.hpp" #include "aidge/operator/Pop.hpp" -#include "aidge/scheduler/SequentialScheduler.hpp" +#include "aidge/operator/Stack.hpp" #include "aidge/scheduler/ParallelScheduler.hpp" +#include "aidge/scheduler/SequentialScheduler.hpp" +#include "aidge/utils/TensorUtils.hpp" using namespace Aidge; TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { SECTION("PaddedConv(forward)") { - std::shared_ptr<Tensor> myWeights = std::make_shared<Tensor>( - Array4D<double, 4, 3, 3, 3>{{{{{6.20986394e-01, 1.19775136e-03, 7.22876095e-02}, - {1.16492919e-01, 8.21634093e-02, 1.17413265e-01}, - {2.23743494e-01, 3.99495413e-01, 5.55552411e-01}}, - {{6.64970077e-01, 9.62199940e-01, 4.87531967e-01}, - {6.12586558e-01, 8.09918671e-02, 8.40649383e-01}, - {4.15264406e-01, 8.28247138e-01, 1.52301135e-01}}, - {{1.76992844e-02, 7.78697112e-01, 8.14531592e-01}, - {1.36960611e-01, 4.64806728e-01, 4.85150000e-01}, - {4.34776520e-01, 9.51740977e-01, 9.05793799e-01}}}, - - {{{1.71925246e-02, 1.91082720e-01, 3.67982644e-01}, - {1.56806559e-01, 6.22280998e-01, 3.15827594e-01}, - {6.04359038e-01, 2.83095947e-01, 6.11168892e-01}}, - {{2.76942832e-01, 1.89768419e-01, 8.07988176e-01}, - {1.67925807e-01, 2.68356150e-01, 6.28875602e-01}, - {1.69093357e-04, 9.64788636e-01, 7.29254981e-01}}, - {{6.34030122e-01, 1.32087038e-01, 3.33857107e-01}, - {7.63047502e-01, 5.12539506e-02, 9.77400493e-01}, - {8.06151288e-01, 2.60237147e-01, 3.93729313e-01}}}, - - {{{5.84605240e-01, 4.74648725e-01, 8.54111741e-01}, - {7.10897067e-02, 5.02579011e-01, 3.35236224e-01}, - {9.08637408e-01, 8.02903830e-01, 2.83929907e-01}}, - {{3.68206999e-01, 9.18579021e-02, 7.33168098e-01}, - {1.59875539e-01, 9.13163381e-01, 3.59806060e-01}, - {1.41295882e-01, 7.00312185e-01, 5.63728289e-01}}, - {{9.39513546e-01, 1.91704891e-01, 1.11454944e-01}, - {5.46298282e-01, 2.89698587e-01, 2.62612651e-01}, - {1.18554992e-01, 4.32147376e-02, 7.53016994e-01}}}, - - {{{9.53179175e-01, 2.05041054e-02, 1.11318451e-01}, - {8.67878485e-01, 2.93263422e-01, 8.03912714e-01}, - {8.93620255e-01, 1.37831128e-01, 3.83640583e-01}}, - {{3.96020188e-01, 6.24959320e-01, 1.90709175e-01}, - {5.80538620e-01, 6.63031275e-01, 2.07247191e-01}, - {5.65672171e-01, 5.57014317e-01, 9.26909496e-01}}, - {{3.43901418e-01, 4.47741636e-01, 6.59249367e-01}, - {7.34639028e-01, 2.84957200e-02, 9.70225217e-01}, - {1.33578790e-02, 6.12054702e-01, 9.36685235e-02}}}}}); + std::shared_ptr<Tensor> myWeights = + std::make_shared<Tensor>(Array4D<double, 4, 3, 3, 3>{ + {{{{6.20986394e-01, 1.19775136e-03, 7.22876095e-02}, + {1.16492919e-01, 8.21634093e-02, 1.17413265e-01}, + {2.23743494e-01, 3.99495413e-01, 5.55552411e-01}}, + {{6.64970077e-01, 9.62199940e-01, 4.87531967e-01}, + {6.12586558e-01, 8.09918671e-02, 8.40649383e-01}, + {4.15264406e-01, 8.28247138e-01, 1.52301135e-01}}, + {{1.76992844e-02, 7.78697112e-01, 8.14531592e-01}, + {1.36960611e-01, 4.64806728e-01, 4.85150000e-01}, + {4.34776520e-01, 9.51740977e-01, 9.05793799e-01}}}, + + {{{1.71925246e-02, 1.91082720e-01, 3.67982644e-01}, + {1.56806559e-01, 6.22280998e-01, 3.15827594e-01}, + {6.04359038e-01, 2.83095947e-01, 6.11168892e-01}}, + {{2.76942832e-01, 1.89768419e-01, 8.07988176e-01}, + {1.67925807e-01, 2.68356150e-01, 6.28875602e-01}, + {1.69093357e-04, 9.64788636e-01, 7.29254981e-01}}, + {{6.34030122e-01, 1.32087038e-01, 3.33857107e-01}, + {7.63047502e-01, 5.12539506e-02, 9.77400493e-01}, + {8.06151288e-01, 2.60237147e-01, 3.93729313e-01}}}, + + {{{5.84605240e-01, 4.74648725e-01, 8.54111741e-01}, + {7.10897067e-02, 5.02579011e-01, 3.35236224e-01}, + {9.08637408e-01, 8.02903830e-01, 2.83929907e-01}}, + {{3.68206999e-01, 9.18579021e-02, 7.33168098e-01}, + {1.59875539e-01, 9.13163381e-01, 3.59806060e-01}, + {1.41295882e-01, 7.00312185e-01, 5.63728289e-01}}, + {{9.39513546e-01, 1.91704891e-01, 1.11454944e-01}, + {5.46298282e-01, 2.89698587e-01, 2.62612651e-01}, + {1.18554992e-01, 4.32147376e-02, 7.53016994e-01}}}, + + {{{9.53179175e-01, 2.05041054e-02, 1.11318451e-01}, + {8.67878485e-01, 2.93263422e-01, 8.03912714e-01}, + {8.93620255e-01, 1.37831128e-01, 3.83640583e-01}}, + {{3.96020188e-01, 6.24959320e-01, 1.90709175e-01}, + {5.80538620e-01, 6.63031275e-01, 2.07247191e-01}, + {5.65672171e-01, 5.57014317e-01, 9.26909496e-01}}, + {{3.43901418e-01, 4.47741636e-01, 6.59249367e-01}, + {7.34639028e-01, 2.84957200e-02, 9.70225217e-01}, + {1.33578790e-02, 6.12054702e-01, 9.36685235e-02}}}}}); std::shared_ptr<Tensor> myBias = std::make_shared<Tensor>( - Array1D<double, 4>{{0.16884905, 0.27994487, 0.57227465, 0.06435205}}); - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>(Array4D<double, 2, 3, 5, 5>{ + Array1D<double, 4>{{0.16884905, 0.27994487, 0.57227465, 0.06435205}}); + std::shared_ptr<Tensor> myInput = + std::make_shared<Tensor>(Array4D<double, 2, 3, 5, 5>{ // NCHW {{{{0.43224481, 0.9047832, 0.18402257, 0.06162838, 0.52490127}, {0.27773404, 0.55402353, 0.9485062, 0.31197083, 0.80328607}, @@ -110,61 +113,63 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { {0.02332061, 0.74270703, 0.59415632, 0.08195934, 0.46295434}, {0.71426058, 0.85032931, 0.90750818, 0.28768431, 0.4401146}}}}}); - std::shared_ptr<Tensor> myOutput = std::make_shared<Tensor>( - Array4D<double, 2, 4, 5, 5>{{{{{3.40294218, 3.74021220, 4.02050114, 4.07054710, 2.46286273}, - {4.61770582, 6.70517588, 6.50356627, 6.29688787, 3.53332567}, - {5.47480106, 5.92094421, 6.64605665, 7.95090199, 4.28721523}, - {4.01485729, 6.06748962, 7.52447891, 7.37980652, 5.28401136}, - {2.83065438, 3.62033439, 3.56222963, 5.56103945, 3.23335814}}, - - {{3.30230498, 4.92814112, 4.34710836, 3.96262765, 2.97987890}, - {4.49693012, 6.68929291, 5.53603029, 5.68874264, 4.28756475}, - {4.20528078, 6.82776880, 6.70569849, 7.12809610, 4.40845442}, - {4.31169367, 6.73352146, 6.30962515, 7.45826864, 4.99164438}, - {2.18136287, 4.28968000, 4.20080042, 4.89814138, 2.87394023}}, - - {{3.54787683, 4.35851812, 4.63881302, 4.23359537, 3.16992092}, - {5.25099468, 7.54282856, 6.69849157, 5.64309788, 4.56919575}, - {4.71914101, 7.52830601, 6.71450949, 7.81113863, 5.84658146}, - {4.97893143, 7.39293909, 6.89905310, 8.14430809, 5.62998581}, - {2.79735112, 4.80967140, 5.57630205, 5.38828325, 4.57078695}}, - - {{3.03048635, 5.04540300, 4.21824932, 4.87323284, 2.35113740}, - {4.45167351, 6.47721338, 7.40922976, 6.70445728, 3.60700107}, - {3.77927423, 6.82826376, 7.41777134, 7.57402420, 5.13131523}, - {4.08747244, 7.07994175, 7.57206821, 8.51897335, 5.26987123}, - {2.34426999, 4.60127831, 4.86486769, 6.01579571, 3.97803569}}}, - - - {{{3.84700942, 4.25972605, 3.05269003, 3.78043652, 2.08771229}, - {6.00459957, 6.05633259, 4.45951605, 4.54089880, 4.03066444}, - {5.41579390, 7.29543972, 6.18680000, 5.58812714, 3.45964241}, - {6.04531050, 7.70924091, 5.52207708, 5.02131319, 4.09403706}, - {3.18092418, 4.45422697, 4.04294252, 3.86577177, 2.18776536}}, - - {{4.02600670, 4.27603531, 3.81011319, 4.03631020, 2.57254648}, - {5.33471155, 5.72588634, 5.12079763, 5.11733150, 3.76836705}, - {5.62947607, 5.92492962, 6.24170446, 6.44130468, 3.44276404}, - {5.38414621, 6.02679539, 5.88985586, 5.90263271, 3.15044069}, - {3.31261086, 4.44371319, 3.47660780, 4.15411520, 1.48961508}}, - - {{3.95879412, 4.17324543, 3.70114422, 3.27447152, 3.09713888}, - {5.78258181, 6.57920837, 4.99913597, 6.20961237, 4.98552179}, - {5.84685421, 7.19971228, 6.66386652, 6.68013430, 4.90963316}, - {5.24417877, 7.06430531, 6.58512402, 6.02492285, 4.48986387}, - {3.64294529, 5.00678444, 5.04760027, 4.72895622, 2.67990756}}, - - {{3.48610687, 4.12853813, 4.07563591, 3.51327014, 2.44217038}, - {4.80529881, 7.33211374, 5.14774036, 4.77281189, 4.44612408}, - {5.11703110, 7.55168772, 7.14374542, 6.43696356, 4.10621357}, - {5.41270018, 6.85949135, 6.73503923, 5.74601364, 4.46150303}, - {3.16612267, 4.38248920, 5.23248482, 4.21292210, 2.86031270}}}}}); + std::shared_ptr<Tensor> myOutput = + std::make_shared<Tensor>(Array4D<double, 2, 4, 5, 5>{ + {{{{3.40294218, 3.74021220, 4.02050114, 4.07054710, 2.46286273}, + {4.61770582, 6.70517588, 6.50356627, 6.29688787, 3.53332567}, + {5.47480106, 5.92094421, 6.64605665, 7.95090199, 4.28721523}, + {4.01485729, 6.06748962, 7.52447891, 7.37980652, 5.28401136}, + {2.83065438, 3.62033439, 3.56222963, 5.56103945, 3.23335814}}, + + {{3.30230498, 4.92814112, 4.34710836, 3.96262765, 2.97987890}, + {4.49693012, 6.68929291, 5.53603029, 5.68874264, 4.28756475}, + {4.20528078, 6.82776880, 6.70569849, 7.12809610, 4.40845442}, + {4.31169367, 6.73352146, 6.30962515, 7.45826864, 4.99164438}, + {2.18136287, 4.28968000, 4.20080042, 4.89814138, 2.87394023}}, + + {{3.54787683, 4.35851812, 4.63881302, 4.23359537, 3.16992092}, + {5.25099468, 7.54282856, 6.69849157, 5.64309788, 4.56919575}, + {4.71914101, 7.52830601, 6.71450949, 7.81113863, 5.84658146}, + {4.97893143, 7.39293909, 6.89905310, 8.14430809, 5.62998581}, + {2.79735112, 4.80967140, 5.57630205, 5.38828325, 4.57078695}}, + + {{3.03048635, 5.04540300, 4.21824932, 4.87323284, 2.35113740}, + {4.45167351, 6.47721338, 7.40922976, 6.70445728, 3.60700107}, + {3.77927423, 6.82826376, 7.41777134, 7.57402420, 5.13131523}, + {4.08747244, 7.07994175, 7.57206821, 8.51897335, 5.26987123}, + {2.34426999, 4.60127831, 4.86486769, 6.01579571, 3.97803569}}}, + + {{{3.84700942, 4.25972605, 3.05269003, 3.78043652, 2.08771229}, + {6.00459957, 6.05633259, 4.45951605, 4.54089880, 4.03066444}, + {5.41579390, 7.29543972, 6.18680000, 5.58812714, 3.45964241}, + {6.04531050, 7.70924091, 5.52207708, 5.02131319, 4.09403706}, + {3.18092418, 4.45422697, 4.04294252, 3.86577177, 2.18776536}}, + + {{4.02600670, 4.27603531, 3.81011319, 4.03631020, 2.57254648}, + {5.33471155, 5.72588634, 5.12079763, 5.11733150, 3.76836705}, + {5.62947607, 5.92492962, 6.24170446, 6.44130468, 3.44276404}, + {5.38414621, 6.02679539, 5.88985586, 5.90263271, 3.15044069}, + {3.31261086, 4.44371319, 3.47660780, 4.15411520, 1.48961508}}, + + {{3.95879412, 4.17324543, 3.70114422, 3.27447152, 3.09713888}, + {5.78258181, 6.57920837, 4.99913597, 6.20961237, 4.98552179}, + {5.84685421, 7.19971228, 6.66386652, 6.68013430, 4.90963316}, + {5.24417877, 7.06430531, 6.58512402, 6.02492285, 4.48986387}, + {3.64294529, 5.00678444, 5.04760027, 4.72895622, 2.67990756}}, + + {{3.48610687, 4.12853813, 4.07563591, 3.51327014, 2.44217038}, + {4.80529881, 7.33211374, 5.14774036, 4.77281189, 4.44612408}, + {5.11703110, 7.55168772, 7.14374542, 6.43696356, 4.10621357}, + {5.41270018, 6.85949135, 6.73503923, 5.74601364, 4.46150303}, + {3.16612267, 4.38248920, 5.23248482, 4.21292210, + 2.86031270}}}}}); std::shared_ptr<Node> myConv = Conv<2>(3, 4, {3, 3}, "myconv"); - auto convOp = std::static_pointer_cast<OperatorTensor>(myConv->getOperator()); + auto convOp = + std::static_pointer_cast<OperatorTensor>(myConv->getOperator()); std::shared_ptr<Node> myPad = - Pad<2>({1, 1, 1, 1}, "myPad", PadBorderType::Constant, 0.0); + Pad<2>({1, 1, 1, 1}, "myPad", PadBorderType::Constant, 0.0); auto padOp = std::static_pointer_cast<OperatorTensor>(myPad->getOperator()); convOp->setInput(1, myWeights); @@ -180,343 +185,525 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { myPad->forward(); myConv->forward(); - convOp -> getOutput(0) -> print(); + convOp->getOutput(0)->print(); - double* computedOutput = static_cast<double*>(convOp->getOutput(0)->getImpl()->rawPtr()); - double* expectedOutput = static_cast<double*>(myOutput->getImpl()->rawPtr()); + double *computedOutput = + static_cast<double *>(convOp->getOutput(0)->getImpl()->rawPtr()); + double *expectedOutput = + static_cast<double *>(myOutput->getImpl()->rawPtr()); for (std::size_t i = 0; i < myOutput->size(); ++i) { - REQUIRE(std::abs(computedOutput[i] - expectedOutput[i]) < 1e-5); + REQUIRE(std::abs(computedOutput[i] - expectedOutput[i]) < 1e-5); } std::shared_ptr<Node> myPaddedConv = - PaddedConv(3, 4, {3, 3}, "myPaddedConv", {1, 1}, {1, 1, 1, 1}); + PaddedConv(3, 4, {3, 3}, "myPaddedConv", {1, 1}, {1, 1, 1, 1}); + } + SECTION("LSTM(forward)") { + auto pop = Pop(); + auto myLSTM = LSTM(32, 64, 0, true, "ltsm"); + auto op = std::dynamic_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); + + auto microGraph = op->getMicroGraph(); + microGraph->save("lstm", false, true); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + } + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = + std::make_shared<Tensor>(Array2D<float, 16, 32>{}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 32, 64>{}); + std::shared_ptr<Tensor> myInitW = + std::make_shared<Tensor>(Array2D<float, 64, 32>{}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 64, 64>{}); + + pop->addChild(myLSTM, 0, 0); + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); + // Weights H + myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); + + auto g = getConnectedGraphView(myLSTM); + g->setDataType(DataType::Float32); + g->setBackend("cpu"); + + auto scheduler = SequentialScheduler(g); + scheduler.forward(true); + + g->save("lstm_outside_dims", true, true); + + microGraph->save("lstm_dims", true, true); + REQUIRE(op->dimsForwarded()); + + auto microGraphScheduler = std::dynamic_pointer_cast<MetaOperator_Op>(op) + ->getMicroGraphScheduler(); + microGraphScheduler->saveSchedulingDiagram("lstm_scheduling"); + + REQUIRE(op->getNbConsumedData(0).data == 512); + REQUIRE(op->getNbConsumedData(1).data == 32768); + REQUIRE(op->getNbProducedData(0).data == 34816); + REQUIRE(op->getNbProducedData(1).data == 34816); + REQUIRE(microGraphScheduler->getStaticScheduling(0).size() == 26); + REQUIRE(microGraphScheduler->getStaticScheduling(1).size() == 24); + REQUIRE(microGraphScheduler->getStaticScheduling(15).size() == 24); } - SECTION("LSTM(forward)") { - auto pop = Pop(); - auto myLSTM = LSTM(32, 64, 0, true, "ltsm"); - auto op = std::dynamic_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); - - auto microGraph = op->getMicroGraph(); - microGraph->save("lstm", false, true); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); - } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array2D<float, 16, 32>{}); - std::shared_ptr<Tensor> myInit = std::make_shared<Tensor>( - Array2D<float, 32, 64>{}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 64, 32>{}); - std::shared_ptr<Tensor> myInitR = std::make_shared<Tensor>( - Array2D<float, 64, 64>{}); - - pop->addChild(myLSTM, 0, 0); - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); - // Weights H - myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); - - auto g = getConnectedGraphView(myLSTM); - g->setDataType(DataType::Float32); - g->setBackend("cpu"); - - auto scheduler = SequentialScheduler(g); - scheduler.forward(true); - - g->save("lstm_outside_dims", true, true); - - microGraph->save("lstm_dims", true, true); - REQUIRE(op->dimsForwarded()); - - auto microGraphScheduler = std::dynamic_pointer_cast<MetaOperator_Op>(op)->getMicroGraphScheduler(); - microGraphScheduler->saveSchedulingDiagram("lstm_scheduling"); - - REQUIRE(op->getNbConsumedData(0).data == 512); - REQUIRE(op->getNbConsumedData(1).data == 32768); - REQUIRE(op->getNbProducedData(0).data == 34816); - REQUIRE(op->getNbProducedData(1).data == 34816); - REQUIRE(microGraphScheduler->getStaticScheduling(0).size() == 26); - REQUIRE(microGraphScheduler->getStaticScheduling(1).size() == 24); - REQUIRE(microGraphScheduler->getStaticScheduling(15).size() == 24); + SECTION("LSTM(forward_values)") { + auto myLSTM = LSTM(2, 3, 0, true, "ltsm"); + auto op = std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); + + auto microGraph = + std::dynamic_pointer_cast<MetaOperator_Op>(op)->getMicroGraph(); + microGraph->save("lstm", false, false); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); } - SECTION("LSTM(forward_values)") { - auto myLSTM = LSTM(2, 3, 0, true, "ltsm"); - auto op = std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); - - auto microGraph = std::dynamic_pointer_cast<MetaOperator_Op>(op)->getMicroGraph(); - microGraph->save("lstm", false, false); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); - } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}}); - std::shared_ptr<Tensor> myInit = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - op->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); - // Weights H - myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); - - auto g = getConnectedGraphView(myLSTM); - g->setDataType(DataType::Float32); - g->setBackend("cpu"); - - auto scheduler = SequentialScheduler(g); - scheduler.forward(); - - microGraph->save("lstm_values_dims", false, true); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.0952412, 0.0952412, 0.0952412}, - {0.25606447, 0.25606447, 0.25606447}, - {0.40323776, 0.40323776, 0.40323776}}}); - - - auto microGraphScheduler = std::dynamic_pointer_cast<MetaOperator_Op>(op)->getMicroGraphScheduler(); - microGraphScheduler->saveSchedulingDiagram("lstm_values_scheduling"); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); } - SECTION("LSTM(forward_values_seq)") { - auto pop = Pop(); - auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); - auto myGraph = Sequential({pop, myLSTM}); - auto op = std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); - } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - std::shared_ptr<Tensor> myInit = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); - // Weights H - myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); - - auto g = getConnectedGraphView(myLSTM); - g->compile("cpu", DataType::Float32); - - g->save("lstm_seq", true, true); - - auto scheduler = SequentialScheduler(g); - scheduler.forward(); - scheduler.saveSchedulingDiagram("lstm_seq_schedule"); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, - {0.49801484, 0.49801484, 0.49801484}, - {0.67162132, 0.67162132, 0.67162132}}}); - - myGraph->save("lstm_seq_mygraph", true, true); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + op->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); + // Weights H + myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); + + auto g = getConnectedGraphView(myLSTM); + g->setDataType(DataType::Float32); + g->setBackend("cpu"); + + auto scheduler = SequentialScheduler(g); + scheduler.forward(); + + microGraph->save("lstm_values_dims", false, true); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.0952412, 0.0952412, 0.0952412}, + {0.25606447, 0.25606447, 0.25606447}, + {0.40323776, 0.40323776, 0.40323776}}}); + + auto microGraphScheduler = std::dynamic_pointer_cast<MetaOperator_Op>(op) + ->getMicroGraphScheduler(); + microGraphScheduler->saveSchedulingDiagram("lstm_values_scheduling"); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + } + SECTION("LSTM(forward_values_seq)") { + auto pop = Pop(); + auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); + auto myGraph = Sequential({pop, myLSTM}); + auto op = std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); } - SECTION("LSTM(forward_values_seq_flatten)(sequential)") { - auto pop = Pop(); - auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); - auto op = std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); - - // Here we test LSTM as it is was flatten in the graph. - // We just borrow its micro-graph into our larger myGraph graph. - auto myGraph = std::make_shared<GraphView>(); - pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - myGraph->add(op->getMicroGraph()); - myGraph->add(pop); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); - } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - std::shared_ptr<Tensor> myInit = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - auto prodX = Producer(myInitW); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, 0, 1); - // Weights H - auto prodH = Producer(myInitR); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, 0, 1); - myGraph->add({prodX, prodH}); - - myGraph->setDataType(DataType::Float32); - myGraph->setBackend("cpu"); - myGraph->save("lstm_seq_flatten", true, true); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, - {0.49801484, 0.49801484, 0.49801484}, - {0.67162132, 0.67162132, 0.67162132}}}); - - auto scheduler = SequentialScheduler(myGraph); - scheduler.generateScheduling(); - scheduler.saveStaticSchedulingDiagram("lstm_static_schedule"); - scheduler.forward(true); - scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_seq"); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); + // Weights H + myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); + + auto g = getConnectedGraphView(myLSTM); + g->compile("cpu", DataType::Float32); + + g->save("lstm_seq", true, true); + + auto scheduler = SequentialScheduler(g); + scheduler.forward(); + scheduler.saveSchedulingDiagram("lstm_seq_schedule"); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, + {0.49801484, 0.49801484, 0.49801484}, + {0.67162132, 0.67162132, 0.67162132}}}); + + myGraph->save("lstm_seq_mygraph", true, true); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + } + SECTION("LSTM(forward_values_seq_flatten)(sequential)") { + auto pop = Pop(); + auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); + auto op = std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + myGraph->add(op->getMicroGraph()); + myGraph->add(pop); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); } - SECTION("LSTM(forward_values_seq_flatten)(parallel)") { - auto pop = Pop(); - auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); - auto op = std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); - - // Here we test LSTM as it is was flatten in the graph. - // We just borrow its micro-graph into our larger myGraph graph. - auto myGraph = std::make_shared<GraphView>(); - pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - myGraph->add(op->getMicroGraph()); - myGraph->add(pop); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); - } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - std::shared_ptr<Tensor> myInit = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - auto prodX = Producer(myInitW); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, 0, 1); - // Weights H - auto prodH = Producer(myInitR); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, 0, 1); - myGraph->add({prodX, prodH}); - - myGraph->setDataType(DataType::Float32); - myGraph->setBackend("cpu"); - myGraph->save("lstm_seq_flatten", true, true); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, - {0.49801484, 0.49801484, 0.49801484}, - {0.67162132, 0.67162132, 0.67162132}}}); - - auto scheduler = ParallelScheduler(myGraph); - scheduler.generateScheduling(); - scheduler.forward(true); - scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_par"); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); } -} \ No newline at end of file + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + auto prodX = Producer(myInitW); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, 0, 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, 0, 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, 0, 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, 0, 1); + // Weights H + auto prodH = Producer(myInitR); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, 0, 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, 0, 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, 0, 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, 0, 1); + myGraph->add({prodX, prodH}); + + myGraph->setDataType(DataType::Float32); + myGraph->setBackend("cpu"); + myGraph->save("lstm_seq_flatten", true, true); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, + {0.49801484, 0.49801484, 0.49801484}, + {0.67162132, 0.67162132, 0.67162132}}}); + + auto scheduler = SequentialScheduler(myGraph); + scheduler.generateScheduling(); + scheduler.saveStaticSchedulingDiagram("lstm_static_schedule"); + scheduler.forward(true); + scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_seq"); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + } + SECTION("LSTM(forward_values_seq_flatten)(parallel)") { + auto pop = Pop(); + auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); + auto op = std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + myGraph->add(op->getMicroGraph()); + myGraph->add(pop); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + } + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + auto prodX = Producer(myInitW); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, 0, 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, 0, 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, 0, 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, 0, 1); + // Weights H + auto prodH = Producer(myInitR); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, 0, 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, 0, 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, 0, 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, 0, 1); + myGraph->add({prodX, prodH}); + + myGraph->setDataType(DataType::Float32); + myGraph->setBackend("cpu"); + myGraph->save("lstm_seq_flatten", true, true); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, + {0.49801484, 0.49801484, 0.49801484}, + {0.67162132, 0.67162132, 0.67162132}}}); + + auto scheduler = ParallelScheduler(myGraph); + scheduler.generateScheduling(); + scheduler.forward(true); + scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_par"); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); + } + + SECTION("Leaky") { + + // First we need to test the spikes without pop operator. + + // TODO: Compare with real result + auto pop = Pop(); + auto myLeaky = Leaky("leaky"); + auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + myGraph->add(op->getMicroGraph()); + myGraph->add(pop); + + // 3 outputs + REQUIRE(myLeaky->nbInputs() == 3); + REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); + REQUIRE(myLeaky->nbOutputs() == 3); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + // Compute expected output + // for i in range(num_steps) + + pop->getOperator()->associateInput(0, myInput); + + myLeaky->input(1).first->getOperator()->setOutput(0, myInitW); + myLeaky->input(2).first->getOperator()->setOutput(0, myInitW); + + myGraph->setDataType(DataType::Float32); + myGraph->setBackend("cpu"); + + auto scheduler = SequentialScheduler(myGraph); + scheduler.generateScheduling(); + REQUIRE_NOTHROW(scheduler.forward(true)); + + op->getOutput(0)->print(); + } + + SECTION("Leaky1") { + auto myLeaky = Leaky("leaky"); + auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + myGraph->add(op->getMicroGraph()); + + // 3 outputs + REQUIRE(myLeaky->nbInputs() == 3); + REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); + REQUIRE(myLeaky->nbOutputs() == 3); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}}); + + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + op->associateInput(0, myInput); + myLeaky->input(1).first->getOperator()->setOutput(0, myInitW); + myLeaky->input(2).first->getOperator()->setOutput(0, myInitW); + + myGraph->setDataType(DataType::Float32); + myGraph->setBackend("cpu"); + + auto scheduler = SequentialScheduler(myGraph); + scheduler.generateScheduling(); + + // Results Looking good. + REQUIRE_NOTHROW(scheduler.forward(true)); + op->getOutput(0)->print(); + + REQUIRE_NOTHROW(scheduler.forward(true)); + op->getOutput(0)->print(); + + Log::info("Test Done."); + } + + SECTION("Leaky2") { + auto myLeaky = Leaky("leaky"); + auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); + //auto stack = Stack(2); + auto stack = Pop("popout"); + auto pop = Pop("popinput"); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + + pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(stack, 0, 0); + for(auto node : op->getMicroGraph()->getOrderedOutputs()) + { + Log::info("name of output {}", node.first->name()); + } + + myGraph->add(pop); + myGraph->add(op->getMicroGraph()); + myGraph->add(stack); + myGraph->save("mg", true, true); + + // 3 outputs + REQUIRE(myLeaky->nbInputs() == 3); + REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); + REQUIRE(myLeaky->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + pop->getOperator()->associateInput(0, myInput); + + //myLeaky->input(1).first->getOperator()->setOutput(0, myInitW); + //myLeaky->input(2).first->getOperator()->setOutput(0, myInitW); + op->associateInput(1, myInitW); + op->associateInput(2, myInitW); + + myGraph->setDataType(DataType::Float32); + myGraph->setBackend("cpu"); + myGraph->forwardDims(); + + auto scheduler = SequentialScheduler(myGraph); + scheduler.generateScheduling(); + + scheduler.saveStaticSchedulingDiagram("leaky"); + scheduler.graphView()->save("schedgraph"); + + auto microGraph = op->getMicroGraph(); + microGraph->save("Micro", false, false); + + REQUIRE_NOTHROW(scheduler.forward(true)); + + auto sop = std::static_pointer_cast<OperatorTensor>(stack->getOperator()); + sop->getOutput(0)->print(); + op->getOutput(0)->print(); + Log::info("Test Done."); + } +} -- GitLab From e16e98684ad575f3faf5fb6709af3f7aee7e4bfa Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Thu, 5 Dec 2024 16:08:37 +0100 Subject: [PATCH 04/12] [WIP] chore: Improve leaky tests --- unit_tests/operator/Test_MetaOperator.cpp | 152 +++++++++++++++++++++- 1 file changed, 145 insertions(+), 7 deletions(-) diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index 9c25795f..3efbdc73 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -22,6 +22,7 @@ #include "aidge/operator/MetaOperatorDefs.hpp" #include "aidge/operator/Pad.hpp" #include "aidge/operator/Pop.hpp" +#include "aidge/operator/Identity.hpp" #include "aidge/operator/Stack.hpp" #include "aidge/scheduler/ParallelScheduler.hpp" #include "aidge/scheduler/SequentialScheduler.hpp" @@ -642,7 +643,8 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { auto myLeaky = Leaky("leaky"); auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); //auto stack = Stack(2); - auto stack = Pop("popout"); + auto mem_rec = Stack(3, "mem_rec"); + auto spk_rec = Stack(3, "spk_rec"); auto pop = Pop("popinput"); // Here we test LSTM as it is was flatten in the graph. @@ -650,7 +652,9 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { auto myGraph = std::make_shared<GraphView>(); pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(stack, 0, 0); + // 0 for mem 1 for stack + op->getMicroGraph()->getOrderedOutputs()[1].first->addChild(mem_rec, 0, 0); + op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(spk_rec, 0, 0); for(auto node : op->getMicroGraph()->getOrderedOutputs()) { Log::info("name of output {}", node.first->name()); @@ -658,13 +662,15 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { myGraph->add(pop); myGraph->add(op->getMicroGraph()); - myGraph->add(stack); + myGraph->add(mem_rec); + myGraph->add(spk_rec); myGraph->save("mg", true, true); // 3 outputs REQUIRE(myLeaky->nbInputs() == 3); REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); - REQUIRE(myLeaky->nbOutputs() == 2); + // Two spikes connected to nothing, + the Add node real output + REQUIRE(myLeaky->nbOutputs() == 4); std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, @@ -701,9 +707,141 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { REQUIRE_NOTHROW(scheduler.forward(true)); - auto sop = std::static_pointer_cast<OperatorTensor>(stack->getOperator()); - sop->getOutput(0)->print(); - op->getOutput(0)->print(); + auto mem_op = std::static_pointer_cast<OperatorTensor>(mem_rec->getOperator()); + auto spk_op = std::static_pointer_cast<OperatorTensor>(spk_rec->getOperator()); + Log::info("Output of stack node and spike : "); + mem_op->getOutput(0)->print(); + Log::info("Output of stack node and spike : "); + spk_op->getOutput(0)->print(); Log::info("Test Done."); } + + //SECTION("Accumulate") + //{ + // auto meta = Accumulate(2, "leaky"); + // auto op = std::static_pointer_cast<MetaOperator_Op>(meta->getOperator()); + + // //auto stack = Stack(2); + // //auto stack = Stack(3,"popout"); + // auto stack = Identity("popout"); + // auto pop = Pop("pop_input"); + + // //auto myGraph = std::make_shared<GraphView>(); + // //pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + // //Log::info("added child : {}", op->getMicroGraph()->getOrderedInputs()[0].first->name()); + // //op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(stack, 0, 0); + + + + // //myGraph->add(pop); + // //myGraph->add(op->getMicroGraph()); + // //myGraph->add(meta); + // //myGraph->add(stack); + // //myGraph->save("mg", true, true); + + // // 3 outputs + // REQUIRE(meta->nbInputs() == 2); + // REQUIRE(meta->nbOutputs() == 1); + + // std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + // Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + // {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + + // std::shared_ptr<Tensor> myInit = + // std::make_shared<Tensor>(Array2D<float, 3, 3>{ + // {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + + // std::shared_ptr<Tensor> myInit2 = + // std::make_shared<Tensor>(Array2D<float, 1, 2>{{{0.0, 0.0}}}); + + // std::shared_ptr<Tensor> myInit3 = + // std::make_shared<Tensor>(Array2D<float, 3, 2>{ + // {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); + + // std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + // Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); + + // std::shared_ptr<Tensor> myInitR = + // std::make_shared<Tensor>(Array2D<float, 3, 3>{ + // {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + + // //pop->getOperator()->associateInput(0, myInput); + // //op->associateInput(1, myInitW); + + // pop->addChild(meta, 0, 0); + // meta->addChild(stack, 0, 0); + // pop->getOperator()->associateInput(0, myInput); + // op->associateInput(1, myInit3); + // //op->associateInput(18, meta); + + // //myGraph->setDataType(DataType::Float32); + // //myGraph->setBackend("cpu"); + // //myGraph->forwardDims(); + + // //auto scheduler = SequentialScheduler(myGraph); + // //scheduler.generateScheduling(); + // //scheduler.graphView()->save("scheduled_graph"); + + // //REQUIRE_NOTHROW(scheduler.forward(true)); + + // //auto sop = std::static_pointer_cast<OperatorTensor>(stack->getOperator()); + // //sop->getOutput(0)->print(); + // //op->getOutput(0)->print(); + // //Log::info("Test Done."); + + // auto g = getConnectedGraphView(meta); + // g->setDataType(DataType::Float32); + // g->setBackend("cpu"); + + // g->forwardDims({}, true); + // g->save("connected"); + + // auto scheduler = SequentialScheduler(g); + // scheduler.forward(); + + + //} + + //SECTION("Issue") + //{ + + // std::shared_ptr<Tensor> Input = std::make_shared<Tensor>( + // Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + // {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + + // std::shared_ptr<Tensor> MemInit = + // std::make_shared<Tensor>(Array2D<float, 3, 2>{ + // {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); + + // auto meta = Accumulate(2, "accumulate"); + // auto op = std::static_pointer_cast<MetaOperator_Op>(meta->getOperator()); + // auto pop_i = Pop("pop_input"); + // auto pop_o = Identity("pop_output"); + + // pop_i->getOperator()->associateInput(0, Input); + // pop_i->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + // op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(pop_o, 0, 0); + + // op->associateInput(1, MemInit); + + // // Build the graph. + // auto myGraph = std::make_shared<GraphView>(); + // myGraph->add(pop_i); + // myGraph->add(op->getMicroGraph()); + // myGraph->add(pop_o); + // myGraph->compile("cpu", DataType::Float32); + + // // Schedule and run + // auto scheduler = SequentialScheduler(myGraph); + // scheduler.generateScheduling(); + // scheduler.graphView()->save("scheduled_graph"); + // REQUIRE_NOTHROW(scheduler.forward(true)); + + // // Print output + // std::static_pointer_cast<OperatorTensor>(pop_o->getOperator())->getOutput(0)->print(); + // // Print spike + // Log::info("Spike : "); + // op->getOutput(1)->print(); + //} } -- GitLab From 57b7de20259130453e46866550615d7a841aa351 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Thu, 5 Dec 2024 17:59:01 +0100 Subject: [PATCH 05/12] chore: Improve Leaky Tests --- unit_tests/operator/Test_MetaOperator.cpp | 267 +++------------------- 1 file changed, 38 insertions(+), 229 deletions(-) diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index 3efbdc73..b3450d27 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -541,110 +541,15 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); } - SECTION("Leaky") { + SECTION("Leaky(forward)") { - // First we need to test the spikes without pop operator. + const auto nbTimeSteps = 2; - // TODO: Compare with real result - auto pop = Pop(); - auto myLeaky = Leaky("leaky"); - auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); - - // Here we test LSTM as it is was flatten in the graph. - // We just borrow its micro-graph into our larger myGraph graph. - auto myGraph = std::make_shared<GraphView>(); - pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - myGraph->add(op->getMicroGraph()); - myGraph->add(pop); - - // 3 outputs - REQUIRE(myLeaky->nbInputs() == 3); - REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); - REQUIRE(myLeaky->nbOutputs() == 3); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - // Compute expected output - // for i in range(num_steps) - - pop->getOperator()->associateInput(0, myInput); - - myLeaky->input(1).first->getOperator()->setOutput(0, myInitW); - myLeaky->input(2).first->getOperator()->setOutput(0, myInitW); - - myGraph->setDataType(DataType::Float32); - myGraph->setBackend("cpu"); - - auto scheduler = SequentialScheduler(myGraph); - scheduler.generateScheduling(); - REQUIRE_NOTHROW(scheduler.forward(true)); - - op->getOutput(0)->print(); - } - - SECTION("Leaky1") { - auto myLeaky = Leaky("leaky"); - auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); - - // Here we test LSTM as it is was flatten in the graph. - // We just borrow its micro-graph into our larger myGraph graph. - auto myGraph = std::make_shared<GraphView>(); - myGraph->add(op->getMicroGraph()); - - // 3 outputs - REQUIRE(myLeaky->nbInputs() == 3); - REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); - REQUIRE(myLeaky->nbOutputs() == 3); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}}); - - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - op->associateInput(0, myInput); - myLeaky->input(1).first->getOperator()->setOutput(0, myInitW); - myLeaky->input(2).first->getOperator()->setOutput(0, myInitW); - - myGraph->setDataType(DataType::Float32); - myGraph->setBackend("cpu"); - - auto scheduler = SequentialScheduler(myGraph); - scheduler.generateScheduling(); - - // Results Looking good. - REQUIRE_NOTHROW(scheduler.forward(true)); - op->getOutput(0)->print(); - - REQUIRE_NOTHROW(scheduler.forward(true)); - op->getOutput(0)->print(); - - Log::info("Test Done."); - } - - SECTION("Leaky2") { - auto myLeaky = Leaky("leaky"); + auto myLeaky = Leaky(nbTimeSteps, 1.0, 0.9, "leaky"); auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); //auto stack = Stack(2); - auto mem_rec = Stack(3, "mem_rec"); - auto spk_rec = Stack(3, "spk_rec"); + auto mem_rec = Stack(nbTimeSteps, "mem_rec"); + auto spk_rec = Stack(nbTimeSteps, "spk_rec"); auto pop = Pop("popinput"); // Here we test LSTM as it is was flatten in the graph. @@ -676,6 +581,37 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + + float array[12] = {1,2,3,4,5,6,2,3,4,5,6,7}; + float* result = new float[expectedOutput->size()]; + + // Elements popped at each time step + auto nbElements = expectedOutput->size() / nbTimeSteps; + + // Init + for(int i = 0; i < nbElements; ++i) + { + result[i] = array[i]; + } + + // Reccurence + for(int i = 1 ; i < nbTimeSteps; ++i) + { + auto offset = nbElements * i; + auto prev = nbElements * (i-1); + for(int j = 0; j < nbElements; ++j) + { + result[offset+j] = result[prev+j] * 0.9 + array[offset+j]; + } + } + + + expectedOutput->getImpl()->setRawPtr(result, expectedOutput->size()); + expectedOutput->print(); + std::shared_ptr<Tensor> myInit = std::make_shared<Tensor>(Array2D<float, 3, 3>{ {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); @@ -707,141 +643,14 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { REQUIRE_NOTHROW(scheduler.forward(true)); + // TODO: Naming is wrong auto mem_op = std::static_pointer_cast<OperatorTensor>(mem_rec->getOperator()); auto spk_op = std::static_pointer_cast<OperatorTensor>(spk_rec->getOperator()); Log::info("Output of stack node and spike : "); mem_op->getOutput(0)->print(); + REQUIRE(approxEq<float>(*(spk_op->getOutput(0)), *(expectedOutput))); Log::info("Output of stack node and spike : "); spk_op->getOutput(0)->print(); Log::info("Test Done."); } - - //SECTION("Accumulate") - //{ - // auto meta = Accumulate(2, "leaky"); - // auto op = std::static_pointer_cast<MetaOperator_Op>(meta->getOperator()); - - // //auto stack = Stack(2); - // //auto stack = Stack(3,"popout"); - // auto stack = Identity("popout"); - // auto pop = Pop("pop_input"); - - // //auto myGraph = std::make_shared<GraphView>(); - // //pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - // //Log::info("added child : {}", op->getMicroGraph()->getOrderedInputs()[0].first->name()); - // //op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(stack, 0, 0); - - - - // //myGraph->add(pop); - // //myGraph->add(op->getMicroGraph()); - // //myGraph->add(meta); - // //myGraph->add(stack); - // //myGraph->save("mg", true, true); - - // // 3 outputs - // REQUIRE(meta->nbInputs() == 2); - // REQUIRE(meta->nbOutputs() == 1); - - // std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - // Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - // {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - - // std::shared_ptr<Tensor> myInit = - // std::make_shared<Tensor>(Array2D<float, 3, 3>{ - // {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - - // std::shared_ptr<Tensor> myInit2 = - // std::make_shared<Tensor>(Array2D<float, 1, 2>{{{0.0, 0.0}}}); - - // std::shared_ptr<Tensor> myInit3 = - // std::make_shared<Tensor>(Array2D<float, 3, 2>{ - // {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); - - // std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - // Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); - - // std::shared_ptr<Tensor> myInitR = - // std::make_shared<Tensor>(Array2D<float, 3, 3>{ - // {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - - // //pop->getOperator()->associateInput(0, myInput); - // //op->associateInput(1, myInitW); - - // pop->addChild(meta, 0, 0); - // meta->addChild(stack, 0, 0); - // pop->getOperator()->associateInput(0, myInput); - // op->associateInput(1, myInit3); - // //op->associateInput(18, meta); - - // //myGraph->setDataType(DataType::Float32); - // //myGraph->setBackend("cpu"); - // //myGraph->forwardDims(); - - // //auto scheduler = SequentialScheduler(myGraph); - // //scheduler.generateScheduling(); - // //scheduler.graphView()->save("scheduled_graph"); - - // //REQUIRE_NOTHROW(scheduler.forward(true)); - - // //auto sop = std::static_pointer_cast<OperatorTensor>(stack->getOperator()); - // //sop->getOutput(0)->print(); - // //op->getOutput(0)->print(); - // //Log::info("Test Done."); - - // auto g = getConnectedGraphView(meta); - // g->setDataType(DataType::Float32); - // g->setBackend("cpu"); - - // g->forwardDims({}, true); - // g->save("connected"); - - // auto scheduler = SequentialScheduler(g); - // scheduler.forward(); - - - //} - - //SECTION("Issue") - //{ - - // std::shared_ptr<Tensor> Input = std::make_shared<Tensor>( - // Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - // {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - - // std::shared_ptr<Tensor> MemInit = - // std::make_shared<Tensor>(Array2D<float, 3, 2>{ - // {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); - - // auto meta = Accumulate(2, "accumulate"); - // auto op = std::static_pointer_cast<MetaOperator_Op>(meta->getOperator()); - // auto pop_i = Pop("pop_input"); - // auto pop_o = Identity("pop_output"); - - // pop_i->getOperator()->associateInput(0, Input); - // pop_i->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - // op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(pop_o, 0, 0); - - // op->associateInput(1, MemInit); - - // // Build the graph. - // auto myGraph = std::make_shared<GraphView>(); - // myGraph->add(pop_i); - // myGraph->add(op->getMicroGraph()); - // myGraph->add(pop_o); - // myGraph->compile("cpu", DataType::Float32); - - // // Schedule and run - // auto scheduler = SequentialScheduler(myGraph); - // scheduler.generateScheduling(); - // scheduler.graphView()->save("scheduled_graph"); - // REQUIRE_NOTHROW(scheduler.forward(true)); - - // // Print output - // std::static_pointer_cast<OperatorTensor>(pop_o->getOperator())->getOutput(0)->print(); - // // Print spike - // Log::info("Spike : "); - // op->getOutput(1)->print(); - //} } -- GitLab From 5282cb87703f5ae83fe9dd70e9dc70cbdfc252d1 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Thu, 5 Dec 2024 19:08:14 +0100 Subject: [PATCH 06/12] Reset node as output --- unit_tests/operator/Test_MetaOperator.cpp | 121 +++++++++++++++------- 1 file changed, 84 insertions(+), 37 deletions(-) diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index b3450d27..effb95bd 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -9,10 +9,12 @@ * ********************************************************************************/ +#include <aidge/filler/Filler.hpp> #include <catch2/catch_test_macros.hpp> #include <cmath> #include <cstdlib> #include <memory> +#include <random> #include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/PadImpl.hpp" @@ -543,7 +545,28 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { SECTION("Leaky(forward)") { - const auto nbTimeSteps = 2; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<float> valueDist(0.1f, 1.1f); // Random float distribution between 0 and 1 + std::uniform_int_distribution<std::size_t> dimSizeDist(std::size_t(2), std::size_t(4)); + std::uniform_int_distribution<std::size_t> nbDimsDist(std::size_t(3), std::size_t(3)); + std::uniform_int_distribution<int> boolDist(0,1); + + const std::size_t nbDims = nbDimsDist(gen); + Log::info("Nbdims : {}", nbDims); + std::vector<std::size_t> dims; + for (std::size_t i = 0; i < nbDims; ++i) { + dims.push_back(dimSizeDist(gen)); + } + Log::info("timesteps : {}", dims[0]); + Log::info("dimensions : "); + for(auto dim: dims) { + Log::info("{}", dim); + } + + + const auto nbTimeSteps = dims[0]; + auto myLeaky = Leaky(nbTimeSteps, 1.0, 0.9, "leaky"); auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); @@ -581,76 +604,100 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + //std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>( + // Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + // {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + - float array[12] = {1,2,3,4,5,6,2,3,4,5,6,7}; - float* result = new float[expectedOutput->size()]; + // Generate input + std::shared_ptr<Tensor> T0 = std::make_shared<Tensor>(); + T0->setDataType(DataType::Float32); + T0->setBackend("cpu"); + + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(); + expectedOutput->setDataType(DataType::Float32); + expectedOutput->setBackend("cpu"); + + + const auto nb_elements = std::accumulate(dims.cbegin(), dims.cend(), std::size_t(1), std::multiplies<std::size_t>()); + float* input = new float[nb_elements]; + float* result = new float[nb_elements]; + + for (std::size_t i = 0; i < nb_elements; ++i) { + input[i] = valueDist(gen); + } + T0->resize(dims); + T0->getImpl()->setRawPtr(input, nb_elements); + T0->print(); // Elements popped at each time step - auto nbElements = expectedOutput->size() / nbTimeSteps; + auto nbElementsPerTimeStep = nb_elements / dims[0]; // Init - for(int i = 0; i < nbElements; ++i) + for(int i = 0; i < nbElementsPerTimeStep; ++i) { - result[i] = array[i]; + result[i] = input[i]; } // Reccurence - for(int i = 1 ; i < nbTimeSteps; ++i) + for(int i = 1 ; i < dims[0]; ++i) { - auto offset = nbElements * i; - auto prev = nbElements * (i-1); - for(int j = 0; j < nbElements; ++j) + auto offset = nbElementsPerTimeStep * i; + auto prev = nbElementsPerTimeStep * (i-1); + for(int j = 0; j < nbElementsPerTimeStep; ++j) { - result[offset+j] = result[prev+j] * 0.9 + array[offset+j]; + auto reset = (result[prev+j] > 1.0 ? 1 : 0); + result[offset+j] = result[prev+j] * 0.9 + input[offset+j] - reset; + } } - expectedOutput->getImpl()->setRawPtr(result, expectedOutput->size()); + expectedOutput->resize(dims); + expectedOutput->getImpl()->setRawPtr(result, nb_elements); + Log::info("Expected ouptut : "); expectedOutput->print(); std::shared_ptr<Tensor> myInit = std::make_shared<Tensor>(Array2D<float, 3, 3>{ {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + + auto initMemdims = std::vector<std::size_t>(dims.begin()+1, dims.end()); + Log::info("dimensions : "); + for(auto dim: initMemdims) { + Log::info("{}", dim); + } std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - pop->getOperator()->associateInput(0, myInput); + std::shared_ptr<Tensor> myInitR = std::make_shared<Tensor>(initMemdims); + myInitR->setDataType(DataType::Float32); + myInitR->setBackend("cpu"); + uniformFiller<float>(myInitR, 0, 0); - //myLeaky->input(1).first->getOperator()->setOutput(0, myInitW); - //myLeaky->input(2).first->getOperator()->setOutput(0, myInitW); - op->associateInput(1, myInitW); - op->associateInput(2, myInitW); + pop->getOperator()->associateInput(0, T0); + op->associateInput(1, myInitR); + op->associateInput(2, myInitR); - myGraph->setDataType(DataType::Float32); - myGraph->setBackend("cpu"); - myGraph->forwardDims(); + myGraph->compile("cpu", DataType::Float32); auto scheduler = SequentialScheduler(myGraph); - scheduler.generateScheduling(); - - scheduler.saveStaticSchedulingDiagram("leaky"); - scheduler.graphView()->save("schedgraph"); - - auto microGraph = op->getMicroGraph(); - microGraph->save("Micro", false, false); - + REQUIRE_NOTHROW(scheduler.generateScheduling()); REQUIRE_NOTHROW(scheduler.forward(true)); // TODO: Naming is wrong auto mem_op = std::static_pointer_cast<OperatorTensor>(mem_rec->getOperator()); auto spk_op = std::static_pointer_cast<OperatorTensor>(spk_rec->getOperator()); - Log::info("Output of stack node and spike : "); - mem_op->getOutput(0)->print(); + //Log::info("Output of stack node and spike : "); + //mem_op->getOutput(0)->print(); + Log::info("----- Input -----"); + T0->print(); + Log::info("----- Results (expected) -----"); + expectedOutput->print(); + Log::info("----- Results -----"); + spk_op->getOutput(0)->print(); REQUIRE(approxEq<float>(*(spk_op->getOutput(0)), *(expectedOutput))); Log::info("Output of stack node and spike : "); - spk_op->getOutput(0)->print(); Log::info("Test Done."); } } -- GitLab From 4b89662afe461aef77f8684dcdd06dd44862c49b Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Mon, 9 Dec 2024 18:45:59 +0100 Subject: [PATCH 07/12] chore: format files and reflect changes to Leaky constructor --- unit_tests/operator/Test_MetaOperator.cpp | 1180 +++++++++++---------- 1 file changed, 626 insertions(+), 554 deletions(-) diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index effb95bd..17064385 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -20,11 +20,11 @@ #include "aidge/backend/cpu/operator/PadImpl.hpp" #include "aidge/data/Tensor.hpp" #include "aidge/operator/Conv.hpp" +#include "aidge/operator/Identity.hpp" #include "aidge/operator/MetaOperator.hpp" #include "aidge/operator/MetaOperatorDefs.hpp" #include "aidge/operator/Pad.hpp" #include "aidge/operator/Pop.hpp" -#include "aidge/operator/Identity.hpp" #include "aidge/operator/Stack.hpp" #include "aidge/scheduler/ParallelScheduler.hpp" #include "aidge/scheduler/SequentialScheduler.hpp" @@ -33,52 +33,53 @@ using namespace Aidge; TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { - SECTION("PaddedConv(forward)") { - std::shared_ptr<Tensor> myWeights = - std::make_shared<Tensor>(Array4D<double, 4, 3, 3, 3>{ - {{{{6.20986394e-01, 1.19775136e-03, 7.22876095e-02}, - {1.16492919e-01, 8.21634093e-02, 1.17413265e-01}, - {2.23743494e-01, 3.99495413e-01, 5.55552411e-01}}, - {{6.64970077e-01, 9.62199940e-01, 4.87531967e-01}, - {6.12586558e-01, 8.09918671e-02, 8.40649383e-01}, - {4.15264406e-01, 8.28247138e-01, 1.52301135e-01}}, - {{1.76992844e-02, 7.78697112e-01, 8.14531592e-01}, - {1.36960611e-01, 4.64806728e-01, 4.85150000e-01}, - {4.34776520e-01, 9.51740977e-01, 9.05793799e-01}}}, - - {{{1.71925246e-02, 1.91082720e-01, 3.67982644e-01}, - {1.56806559e-01, 6.22280998e-01, 3.15827594e-01}, - {6.04359038e-01, 2.83095947e-01, 6.11168892e-01}}, - {{2.76942832e-01, 1.89768419e-01, 8.07988176e-01}, - {1.67925807e-01, 2.68356150e-01, 6.28875602e-01}, - {1.69093357e-04, 9.64788636e-01, 7.29254981e-01}}, - {{6.34030122e-01, 1.32087038e-01, 3.33857107e-01}, - {7.63047502e-01, 5.12539506e-02, 9.77400493e-01}, - {8.06151288e-01, 2.60237147e-01, 3.93729313e-01}}}, - - {{{5.84605240e-01, 4.74648725e-01, 8.54111741e-01}, - {7.10897067e-02, 5.02579011e-01, 3.35236224e-01}, - {9.08637408e-01, 8.02903830e-01, 2.83929907e-01}}, - {{3.68206999e-01, 9.18579021e-02, 7.33168098e-01}, - {1.59875539e-01, 9.13163381e-01, 3.59806060e-01}, - {1.41295882e-01, 7.00312185e-01, 5.63728289e-01}}, - {{9.39513546e-01, 1.91704891e-01, 1.11454944e-01}, - {5.46298282e-01, 2.89698587e-01, 2.62612651e-01}, - {1.18554992e-01, 4.32147376e-02, 7.53016994e-01}}}, - - {{{9.53179175e-01, 2.05041054e-02, 1.11318451e-01}, - {8.67878485e-01, 2.93263422e-01, 8.03912714e-01}, - {8.93620255e-01, 1.37831128e-01, 3.83640583e-01}}, - {{3.96020188e-01, 6.24959320e-01, 1.90709175e-01}, - {5.80538620e-01, 6.63031275e-01, 2.07247191e-01}, - {5.65672171e-01, 5.57014317e-01, 9.26909496e-01}}, - {{3.43901418e-01, 4.47741636e-01, 6.59249367e-01}, - {7.34639028e-01, 2.84957200e-02, 9.70225217e-01}, - {1.33578790e-02, 6.12054702e-01, 9.36685235e-02}}}}}); - std::shared_ptr<Tensor> myBias = std::make_shared<Tensor>( - Array1D<double, 4>{{0.16884905, 0.27994487, 0.57227465, 0.06435205}}); - std::shared_ptr<Tensor> myInput = - std::make_shared<Tensor>(Array4D<double, 2, 3, 5, 5>{ + SECTION("PaddedConv(forward)") { + std::shared_ptr<Tensor> myWeights = + std::make_shared<Tensor>(Array4D<double, 4, 3, 3, 3>{ + {{{{6.20986394e-01, 1.19775136e-03, 7.22876095e-02}, + {1.16492919e-01, 8.21634093e-02, 1.17413265e-01}, + {2.23743494e-01, 3.99495413e-01, 5.55552411e-01}}, + {{6.64970077e-01, 9.62199940e-01, 4.87531967e-01}, + {6.12586558e-01, 8.09918671e-02, 8.40649383e-01}, + {4.15264406e-01, 8.28247138e-01, 1.52301135e-01}}, + {{1.76992844e-02, 7.78697112e-01, 8.14531592e-01}, + {1.36960611e-01, 4.64806728e-01, 4.85150000e-01}, + {4.34776520e-01, 9.51740977e-01, 9.05793799e-01}}}, + + {{{1.71925246e-02, 1.91082720e-01, 3.67982644e-01}, + {1.56806559e-01, 6.22280998e-01, 3.15827594e-01}, + {6.04359038e-01, 2.83095947e-01, 6.11168892e-01}}, + {{2.76942832e-01, 1.89768419e-01, 8.07988176e-01}, + {1.67925807e-01, 2.68356150e-01, 6.28875602e-01}, + {1.69093357e-04, 9.64788636e-01, 7.29254981e-01}}, + {{6.34030122e-01, 1.32087038e-01, 3.33857107e-01}, + {7.63047502e-01, 5.12539506e-02, 9.77400493e-01}, + {8.06151288e-01, 2.60237147e-01, 3.93729313e-01}}}, + + {{{5.84605240e-01, 4.74648725e-01, 8.54111741e-01}, + {7.10897067e-02, 5.02579011e-01, 3.35236224e-01}, + {9.08637408e-01, 8.02903830e-01, 2.83929907e-01}}, + {{3.68206999e-01, 9.18579021e-02, 7.33168098e-01}, + {1.59875539e-01, 9.13163381e-01, 3.59806060e-01}, + {1.41295882e-01, 7.00312185e-01, 5.63728289e-01}}, + {{9.39513546e-01, 1.91704891e-01, 1.11454944e-01}, + {5.46298282e-01, 2.89698587e-01, 2.62612651e-01}, + {1.18554992e-01, 4.32147376e-02, 7.53016994e-01}}}, + + {{{9.53179175e-01, 2.05041054e-02, 1.11318451e-01}, + {8.67878485e-01, 2.93263422e-01, 8.03912714e-01}, + {8.93620255e-01, 1.37831128e-01, 3.83640583e-01}}, + {{3.96020188e-01, 6.24959320e-01, 1.90709175e-01}, + {5.80538620e-01, 6.63031275e-01, 2.07247191e-01}, + {5.65672171e-01, 5.57014317e-01, 9.26909496e-01}}, + {{3.43901418e-01, 4.47741636e-01, 6.59249367e-01}, + {7.34639028e-01, 2.84957200e-02, 9.70225217e-01}, + {1.33578790e-02, 6.12054702e-01, 9.36685235e-02}}}}}); + std::shared_ptr<Tensor> myBias = + std::make_shared<Tensor>(Array1D<double, 4>{ + {0.16884905, 0.27994487, 0.57227465, 0.06435205}}); + std::shared_ptr<Tensor> myInput = std::make_shared< + Tensor>(Array4D<double, 2, 3, 5, 5>{ // NCHW {{{{0.43224481, 0.9047832, 0.18402257, 0.06162838, 0.52490127}, {0.27773404, 0.55402353, 0.9485062, 0.31197083, 0.80328607}, @@ -114,10 +115,14 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { {0.95873236, 0.6742374, 0.55679676, 0.6323497, 0.34072958}, {0.49694061, 0.79173045, 0.19738225, 0.14755281, 0.80818177}, {0.02332061, 0.74270703, 0.59415632, 0.08195934, 0.46295434}, - {0.71426058, 0.85032931, 0.90750818, 0.28768431, 0.4401146}}}}}); - - std::shared_ptr<Tensor> myOutput = - std::make_shared<Tensor>(Array4D<double, 2, 4, 5, 5>{ + {0.71426058, + 0.85032931, + 0.90750818, + 0.28768431, + 0.4401146}}}}}); + + std::shared_ptr<Tensor> myOutput = std::make_shared< + Tensor>(Array4D<double, 2, 4, 5, 5>{ {{{{3.40294218, 3.74021220, 4.02050114, 4.07054710, 2.46286273}, {4.61770582, 6.70517588, 6.50356627, 6.29688787, 3.53332567}, {5.47480106, 5.92094421, 6.64605665, 7.95090199, 4.28721523}, @@ -164,540 +169,607 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { {4.80529881, 7.33211374, 5.14774036, 4.77281189, 4.44612408}, {5.11703110, 7.55168772, 7.14374542, 6.43696356, 4.10621357}, {5.41270018, 6.85949135, 6.73503923, 5.74601364, 4.46150303}, - {3.16612267, 4.38248920, 5.23248482, 4.21292210, + {3.16612267, + 4.38248920, + 5.23248482, + 4.21292210, 2.86031270}}}}}); - std::shared_ptr<Node> myConv = Conv<2>(3, 4, {3, 3}, "myconv"); - auto convOp = - std::static_pointer_cast<OperatorTensor>(myConv->getOperator()); + std::shared_ptr<Node> myConv = Conv<2>(3, 4, {3, 3}, "myconv"); + auto convOp = + std::static_pointer_cast<OperatorTensor>(myConv->getOperator()); - std::shared_ptr<Node> myPad = - Pad<2>({1, 1, 1, 1}, "myPad", PadBorderType::Constant, 0.0); - auto padOp = std::static_pointer_cast<OperatorTensor>(myPad->getOperator()); + std::shared_ptr<Node> myPad = + Pad<2>({1, 1, 1, 1}, "myPad", PadBorderType::Constant, 0.0); + auto padOp = + std::static_pointer_cast<OperatorTensor>(myPad->getOperator()); - convOp->setInput(1, myWeights); - convOp->setInput(2, myBias); + convOp->setInput(1, myWeights); + convOp->setInput(2, myBias); - myPad->addChild(myConv, 0, 0); - padOp->setInput(0, myInput); + myPad->addChild(myConv, 0, 0); + padOp->setInput(0, myInput); - padOp->setDataType(DataType::Float64); - padOp->setBackend("cpu"); - convOp->setDataType(DataType::Float64); - convOp->setBackend("cpu"); + padOp->setDataType(DataType::Float64); + padOp->setBackend("cpu"); + convOp->setDataType(DataType::Float64); + convOp->setBackend("cpu"); - myPad->forward(); - myConv->forward(); - convOp->getOutput(0)->print(); + myPad->forward(); + myConv->forward(); + convOp->getOutput(0)->print(); - double *computedOutput = - static_cast<double *>(convOp->getOutput(0)->getImpl()->rawPtr()); - double *expectedOutput = - static_cast<double *>(myOutput->getImpl()->rawPtr()); - for (std::size_t i = 0; i < myOutput->size(); ++i) { - REQUIRE(std::abs(computedOutput[i] - expectedOutput[i]) < 1e-5); - } + double *computedOutput = + static_cast<double *>(convOp->getOutput(0)->getImpl()->rawPtr()); + double *expectedOutput = + static_cast<double *>(myOutput->getImpl()->rawPtr()); + for (std::size_t i = 0; i < myOutput->size(); ++i) { + REQUIRE(std::abs(computedOutput[i] - expectedOutput[i]) < 1e-5); + } - std::shared_ptr<Node> myPaddedConv = - PaddedConv(3, 4, {3, 3}, "myPaddedConv", {1, 1}, {1, 1, 1, 1}); - } - SECTION("LSTM(forward)") { - auto pop = Pop(); - auto myLSTM = LSTM(32, 64, 0, true, "ltsm"); - auto op = std::dynamic_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); - - auto microGraph = op->getMicroGraph(); - microGraph->save("lstm", false, true); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); - } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = - std::make_shared<Tensor>(Array2D<float, 16, 32>{}); - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 32, 64>{}); - std::shared_ptr<Tensor> myInitW = - std::make_shared<Tensor>(Array2D<float, 64, 32>{}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 64, 64>{}); - - pop->addChild(myLSTM, 0, 0); - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); - // Weights H - myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); - - auto g = getConnectedGraphView(myLSTM); - g->setDataType(DataType::Float32); - g->setBackend("cpu"); - - auto scheduler = SequentialScheduler(g); - scheduler.forward(true); - - g->save("lstm_outside_dims", true, true); - - microGraph->save("lstm_dims", true, true); - REQUIRE(op->dimsForwarded()); - - auto microGraphScheduler = std::dynamic_pointer_cast<MetaOperator_Op>(op) - ->getMicroGraphScheduler(); - microGraphScheduler->saveSchedulingDiagram("lstm_scheduling"); - - REQUIRE(op->getNbConsumedData(0).data == 512); - REQUIRE(op->getNbConsumedData(1).data == 32768); - REQUIRE(op->getNbProducedData(0).data == 34816); - REQUIRE(op->getNbProducedData(1).data == 34816); - REQUIRE(microGraphScheduler->getStaticScheduling(0).size() == 26); - REQUIRE(microGraphScheduler->getStaticScheduling(1).size() == 24); - REQUIRE(microGraphScheduler->getStaticScheduling(15).size() == 24); - } - SECTION("LSTM(forward_values)") { - auto myLSTM = LSTM(2, 3, 0, true, "ltsm"); - auto op = std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); - - auto microGraph = - std::dynamic_pointer_cast<MetaOperator_Op>(op)->getMicroGraph(); - microGraph->save("lstm", false, false); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); - } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}}); - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - op->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); - // Weights H - myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); - - auto g = getConnectedGraphView(myLSTM); - g->setDataType(DataType::Float32); - g->setBackend("cpu"); - - auto scheduler = SequentialScheduler(g); - scheduler.forward(); - - microGraph->save("lstm_values_dims", false, true); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.0952412, 0.0952412, 0.0952412}, - {0.25606447, 0.25606447, 0.25606447}, - {0.40323776, 0.40323776, 0.40323776}}}); - - auto microGraphScheduler = std::dynamic_pointer_cast<MetaOperator_Op>(op) - ->getMicroGraphScheduler(); - microGraphScheduler->saveSchedulingDiagram("lstm_values_scheduling"); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); - } - SECTION("LSTM(forward_values_seq)") { - auto pop = Pop(); - auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); - auto myGraph = Sequential({pop, myLSTM}); - auto op = std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + std::shared_ptr<Node> myPaddedConv = + PaddedConv(3, 4, {3, 3}, "myPaddedConv", {1, 1}, {1, 1, 1, 1}); } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); - myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); - // Weights H - myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); - myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); - - auto g = getConnectedGraphView(myLSTM); - g->compile("cpu", DataType::Float32); - - g->save("lstm_seq", true, true); - - auto scheduler = SequentialScheduler(g); - scheduler.forward(); - scheduler.saveSchedulingDiagram("lstm_seq_schedule"); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, - {0.49801484, 0.49801484, 0.49801484}, - {0.67162132, 0.67162132, 0.67162132}}}); - - myGraph->save("lstm_seq_mygraph", true, true); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); - } - SECTION("LSTM(forward_values_seq_flatten)(sequential)") { - auto pop = Pop(); - auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); - auto op = std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); - - // Here we test LSTM as it is was flatten in the graph. - // We just borrow its micro-graph into our larger myGraph graph. - auto myGraph = std::make_shared<GraphView>(); - pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - myGraph->add(op->getMicroGraph()); - myGraph->add(pop); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); - } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + SECTION("LSTM(forward)") { + auto pop = Pop(); + auto myLSTM = LSTM(32, 64, 0, true, "ltsm"); + auto op = + std::dynamic_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); + + auto microGraph = op->getMicroGraph(); + microGraph->save("lstm", false, true); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + } + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = + std::make_shared<Tensor>(Array2D<float, 16, 32>{}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 32, 64>{}); + std::shared_ptr<Tensor> myInitW = + std::make_shared<Tensor>(Array2D<float, 64, 32>{}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 64, 64>{}); + + pop->addChild(myLSTM, 0, 0); + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); + // Weights H + myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); + + auto g = getConnectedGraphView(myLSTM); + g->setDataType(DataType::Float32); + g->setBackend("cpu"); + + auto scheduler = SequentialScheduler(g); + scheduler.forward(true); + + g->save("lstm_outside_dims", true, true); + + microGraph->save("lstm_dims", true, true); + REQUIRE(op->dimsForwarded()); + + auto microGraphScheduler = + std::dynamic_pointer_cast<MetaOperator_Op>(op) + ->getMicroGraphScheduler(); + microGraphScheduler->saveSchedulingDiagram("lstm_scheduling"); + + REQUIRE(op->getNbConsumedData(0).data == 512); + REQUIRE(op->getNbConsumedData(1).data == 32768); + REQUIRE(op->getNbProducedData(0).data == 34816); + REQUIRE(op->getNbProducedData(1).data == 34816); + REQUIRE(microGraphScheduler->getStaticScheduling(0).size() == 26); + REQUIRE(microGraphScheduler->getStaticScheduling(1).size() == 24); + REQUIRE(microGraphScheduler->getStaticScheduling(15).size() == 24); } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - auto prodX = Producer(myInitW); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, 0, 1); - // Weights H - auto prodH = Producer(myInitR); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, 0, 1); - myGraph->add({prodX, prodH}); - - myGraph->setDataType(DataType::Float32); - myGraph->setBackend("cpu"); - myGraph->save("lstm_seq_flatten", true, true); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, - {0.49801484, 0.49801484, 0.49801484}, - {0.67162132, 0.67162132, 0.67162132}}}); - - auto scheduler = SequentialScheduler(myGraph); - scheduler.generateScheduling(); - scheduler.saveStaticSchedulingDiagram("lstm_static_schedule"); - scheduler.forward(true); - scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_seq"); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); - } - SECTION("LSTM(forward_values_seq_flatten)(parallel)") { - auto pop = Pop(); - auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); - auto op = std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); - - // Here we test LSTM as it is was flatten in the graph. - // We just borrow its micro-graph into our larger myGraph graph. - auto myGraph = std::make_shared<GraphView>(); - pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - myGraph->add(op->getMicroGraph()); - myGraph->add(pop); - - REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); - REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); - for (size_t i = 1; i < 9; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + SECTION("LSTM(forward_values)") { + auto myLSTM = LSTM(2, 3, 0, true, "ltsm"); + auto op = + std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); + + auto microGraph = + std::dynamic_pointer_cast<MetaOperator_Op>(op)->getMicroGraph(); + microGraph->save("lstm", false, false); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + } + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + op->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); + // Weights H + myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); + + auto g = getConnectedGraphView(myLSTM); + g->setDataType(DataType::Float32); + g->setBackend("cpu"); + + auto scheduler = SequentialScheduler(g); + scheduler.forward(); + + microGraph->save("lstm_values_dims", false, true); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.0952412, 0.0952412, 0.0952412}, + {0.25606447, 0.25606447, 0.25606447}, + {0.40323776, 0.40323776, 0.40323776}}}); + + auto microGraphScheduler = + std::dynamic_pointer_cast<MetaOperator_Op>(op) + ->getMicroGraphScheduler(); + microGraphScheduler->saveSchedulingDiagram("lstm_values_scheduling"); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); } - for (size_t i = 9; i < 17; ++i) { - REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + SECTION("LSTM(forward_values_seq)") { + auto pop = Pop(); + auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); + auto myGraph = Sequential({pop, myLSTM}); + auto op = + std::static_pointer_cast<OperatorTensor>(myLSTM->getOperator()); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + } + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + myLSTM->input(1).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(2).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(3).first->getOperator()->setOutput(0, myInitW); + myLSTM->input(4).first->getOperator()->setOutput(0, myInitW); + // Weights H + myLSTM->input(5).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(6).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(7).first->getOperator()->setOutput(0, myInitR); + myLSTM->input(8).first->getOperator()->setOutput(0, myInitR); + + auto g = getConnectedGraphView(myLSTM); + g->compile("cpu", DataType::Float32); + + g->save("lstm_seq", true, true); + + auto scheduler = SequentialScheduler(g); + scheduler.forward(); + scheduler.saveSchedulingDiagram("lstm_seq_schedule"); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, + {0.49801484, 0.49801484, 0.49801484}, + {0.67162132, 0.67162132, 0.67162132}}}); + + myGraph->save("lstm_seq_mygraph", true, true); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); } - REQUIRE(myLSTM->nbOutputs() == 2); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); - std::shared_ptr<Tensor> myInitR = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); - - pop->getOperator()->associateInput(0, myInput); - op->associateInput(17, myInit); - op->associateInput(18, myInit); - - // Weights X - auto prodX = Producer(myInitW); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, 0, 1); - prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, 0, 1); - // Weights H - auto prodH = Producer(myInitR); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, 0, 1); - prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, 0, 1); - myGraph->add({prodX, prodH}); - - myGraph->setDataType(DataType::Float32); - myGraph->setBackend("cpu"); - myGraph->save("lstm_seq_flatten", true, true); - - std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( - Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, - {0.49801484, 0.49801484, 0.49801484}, - {0.67162132, 0.67162132, 0.67162132}}}); - - auto scheduler = ParallelScheduler(myGraph); - scheduler.generateScheduling(); - scheduler.forward(true); - scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_par"); - - op->getOutput(0)->print(); - myHiddenState->print(); - - REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); - } - - SECTION("Leaky(forward)") { - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_real_distribution<float> valueDist(0.1f, 1.1f); // Random float distribution between 0 and 1 - std::uniform_int_distribution<std::size_t> dimSizeDist(std::size_t(2), std::size_t(4)); - std::uniform_int_distribution<std::size_t> nbDimsDist(std::size_t(3), std::size_t(3)); - std::uniform_int_distribution<int> boolDist(0,1); - - const std::size_t nbDims = nbDimsDist(gen); - Log::info("Nbdims : {}", nbDims); - std::vector<std::size_t> dims; - for (std::size_t i = 0; i < nbDims; ++i) { - dims.push_back(dimSizeDist(gen)); + SECTION("LSTM(forward_values_seq_flatten)(sequential)") { + auto pop = Pop(); + auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); + auto op = + std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + myGraph->add(op->getMicroGraph()); + myGraph->add(pop); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + } + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + auto prodX = Producer(myInitW); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, + 0, + 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, + 0, + 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, + 0, + 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, + 0, + 1); + // Weights H + auto prodH = Producer(myInitR); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, + 0, + 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, + 0, + 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, + 0, + 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, + 0, + 1); + myGraph->add({prodX, prodH}); + + myGraph->setDataType(DataType::Float32); + myGraph->setBackend("cpu"); + myGraph->save("lstm_seq_flatten", true, true); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, + {0.49801484, 0.49801484, 0.49801484}, + {0.67162132, 0.67162132, 0.67162132}}}); + + auto scheduler = SequentialScheduler(myGraph); + scheduler.generateScheduling(); + scheduler.saveStaticSchedulingDiagram("lstm_static_schedule"); + scheduler.forward(true); + scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_seq"); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); } - Log::info("timesteps : {}", dims[0]); - Log::info("dimensions : "); - for(auto dim: dims) { - Log::info("{}", dim); + SECTION("LSTM(forward_values_seq_flatten)(parallel)") { + auto pop = Pop(); + auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); + auto op = + std::static_pointer_cast<MetaOperator_Op>(myLSTM->getOperator()); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + myGraph->add(op->getMicroGraph()); + myGraph->add(pop); + + REQUIRE(myLSTM->nbInputs() == 3 + 8 + 8); + REQUIRE(myLSTM->inputCategory(0) == InputCategory::Data); + for (size_t i = 1; i < 9; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::Param); + } + for (size_t i = 9; i < 17; ++i) { + REQUIRE(myLSTM->inputCategory(i) == InputCategory::OptionalParam); + } + REQUIRE(myLSTM->nbOutputs() == 2); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.1, 0.1}, {0.1, 0.1}, {0.1, 0.1}}}); + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}, {0.1, 0.1, 0.1}}}); + + pop->getOperator()->associateInput(0, myInput); + op->associateInput(17, myInit); + op->associateInput(18, myInit); + + // Weights X + auto prodX = Producer(myInitW); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[1].first, + 0, + 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[2].first, + 0, + 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[3].first, + 0, + 1); + prodX->addChild(op->getMicroGraph()->getOrderedInputs()[4].first, + 0, + 1); + // Weights H + auto prodH = Producer(myInitR); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[5].first, + 0, + 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[6].first, + 0, + 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[7].first, + 0, + 1); + prodH->addChild(op->getMicroGraph()->getOrderedInputs()[8].first, + 0, + 1); + myGraph->add({prodX, prodH}); + + myGraph->setDataType(DataType::Float32); + myGraph->setBackend("cpu"); + myGraph->save("lstm_seq_flatten", true, true); + + std::shared_ptr<Tensor> myHiddenState = std::make_shared<Tensor>( + Array2D<float, 3, 3>{{{0.24439372, 0.24439372, 0.24439372}, + {0.49801484, 0.49801484, 0.49801484}, + {0.67162132, 0.67162132, 0.67162132}}}); + + auto scheduler = ParallelScheduler(myGraph); + scheduler.generateScheduling(); + scheduler.forward(true); + scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule_par"); + + op->getOutput(0)->print(); + myHiddenState->print(); + + REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); } + SECTION("Leaky(forward)(fixed)") { - const auto nbTimeSteps = dims[0]; - + std::shared_ptr<Tensor> input = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - auto myLeaky = Leaky(nbTimeSteps, 1.0, 0.9, "leaky"); - auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); - //auto stack = Stack(2); - auto mem_rec = Stack(nbTimeSteps, "mem_rec"); - auto spk_rec = Stack(nbTimeSteps, "spk_rec"); - auto pop = Pop("popinput"); - // Here we test LSTM as it is was flatten in the graph. - // We just borrow its micro-graph into our larger myGraph graph. - auto myGraph = std::make_shared<GraphView>(); + constexpr auto beta = 0.9; + constexpr auto threshold = 1.0; + auto pop = Pop("pop"); + auto leaky = Leaky(2, beta, threshold, "leaky"); - pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); - // 0 for mem 1 for stack - op->getMicroGraph()->getOrderedOutputs()[1].first->addChild(mem_rec, 0, 0); - op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(spk_rec, 0, 0); - for(auto node : op->getMicroGraph()->getOrderedOutputs()) - { - Log::info("name of output {}", node.first->name()); + REQUIRE(true); } - myGraph->add(pop); - myGraph->add(op->getMicroGraph()); - myGraph->add(mem_rec); - myGraph->add(spk_rec); - myGraph->save("mg", true, true); - - // 3 outputs - REQUIRE(myLeaky->nbInputs() == 3); - REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); - // Two spikes connected to nothing, + the Add node real output - REQUIRE(myLeaky->nbOutputs() == 4); - - std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - - //std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>( - // Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - // {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - - - // Generate input - std::shared_ptr<Tensor> T0 = std::make_shared<Tensor>(); - T0->setDataType(DataType::Float32); - T0->setBackend("cpu"); - - std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(); - expectedOutput->setDataType(DataType::Float32); - expectedOutput->setBackend("cpu"); - - - const auto nb_elements = std::accumulate(dims.cbegin(), dims.cend(), std::size_t(1), std::multiplies<std::size_t>()); - float* input = new float[nb_elements]; - float* result = new float[nb_elements]; - - for (std::size_t i = 0; i < nb_elements; ++i) { - input[i] = valueDist(gen); - } - T0->resize(dims); - T0->getImpl()->setRawPtr(input, nb_elements); - T0->print(); + SECTION("Leaky(forward)") { + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<float> valueDist( + 0.1f, + 1.1f); // Random float distribution between 0 and 1 + std::uniform_int_distribution<std::size_t> dimSizeDist(std::size_t(2), + std::size_t(4)); + std::uniform_int_distribution<std::size_t> nbDimsDist(std::size_t(3), + std::size_t(3)); + std::uniform_int_distribution<int> boolDist(0, 1); + + const std::size_t nbDims = nbDimsDist(gen); + Log::info("Nbdims : {}", nbDims); + std::vector<std::size_t> dims; + for (std::size_t i = 0; i < nbDims; ++i) { + dims.push_back(dimSizeDist(gen)); + } + Log::info("timesteps : {}", dims[0]); + Log::info("dimensions : "); + for (auto dim : dims) { + Log::info("{}", dim); + } - // Elements popped at each time step - auto nbElementsPerTimeStep = nb_elements / dims[0]; + const auto nbTimeSteps = dims[0]; + + auto myLeaky = Leaky(nbTimeSteps, 0.9, 1.0, "leaky"); + auto op = + std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); + // auto stack = Stack(2); + auto mem_rec = Stack(nbTimeSteps, "mem_rec"); + auto spk_rec = Stack(nbTimeSteps, "spk_rec"); + auto pop = Pop("popinput"); + + // Here we test LSTM as it is was flatten in the graph. + // We just borrow its micro-graph into our larger myGraph graph. + auto myGraph = std::make_shared<GraphView>(); + + pop->addChild(op->getMicroGraph()->getOrderedInputs()[0].first, 0, 0); + // 0 for mem 1 for stack + op->getMicroGraph()->getOrderedOutputs()[1].first->addChild(mem_rec, + 0, + 0); + op->getMicroGraph()->getOrderedOutputs()[0].first->addChild(spk_rec, + 0, + 0); + for (auto node : op->getMicroGraph()->getOrderedOutputs()) { + Log::info("name of output {}", node.first->name()); + } - // Init - for(int i = 0; i < nbElementsPerTimeStep; ++i) - { - result[i] = input[i]; - } + myGraph->add(pop); + myGraph->add(op->getMicroGraph()); + myGraph->add(mem_rec); + myGraph->add(spk_rec); + myGraph->save("mg", true, true); + + // 3 outputs + REQUIRE(myLeaky->nbInputs() == 3); + REQUIRE(myLeaky->inputCategory(0) == InputCategory::Data); + // Two spikes connected to nothing, + the Add node real output + REQUIRE(myLeaky->nbOutputs() == 4); + + std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>( + Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); + + // std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>( + // Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, + // {{2.0, 3.0}, {4.0, 5.0}, + // {6.0, 7.0}}}}); + + // Generate input + std::shared_ptr<Tensor> T0 = std::make_shared<Tensor>(); + T0->setDataType(DataType::Float32); + T0->setBackend("cpu"); + + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(); + expectedOutput->setDataType(DataType::Float32); + expectedOutput->setBackend("cpu"); + + const auto nb_elements = + std::accumulate(dims.cbegin(), + dims.cend(), + std::size_t(1), + std::multiplies<std::size_t>()); + float *input = new float[nb_elements]; + float *result = new float[nb_elements]; + + for (std::size_t i = 0; i < nb_elements; ++i) { + input[i] = valueDist(gen); + } + T0->resize(dims); + T0->getImpl()->setRawPtr(input, nb_elements); + T0->print(); - // Reccurence - for(int i = 1 ; i < dims[0]; ++i) - { - auto offset = nbElementsPerTimeStep * i; - auto prev = nbElementsPerTimeStep * (i-1); - for(int j = 0; j < nbElementsPerTimeStep; ++j) - { - auto reset = (result[prev+j] > 1.0 ? 1 : 0); - result[offset+j] = result[prev+j] * 0.9 + input[offset+j] - reset; + // Elements popped at each time step + auto nbElementsPerTimeStep = nb_elements / dims[0]; + // Init + for (int i = 0; i < nbElementsPerTimeStep; ++i) { + result[i] = input[i]; } - } + // Reccurence + for (int i = 1; i < dims[0]; ++i) { + auto offset = nbElementsPerTimeStep * i; + auto prev = nbElementsPerTimeStep * (i - 1); + for (int j = 0; j < nbElementsPerTimeStep; ++j) { + auto reset = (result[prev + j] > 1.0 ? 1 : 0); + result[offset + j] = + result[prev + j] * 0.9 + input[offset + j] - reset; + } + } - expectedOutput->resize(dims); - expectedOutput->getImpl()->setRawPtr(result, nb_elements); - Log::info("Expected ouptut : "); - expectedOutput->print(); + expectedOutput->resize(dims); + expectedOutput->getImpl()->setRawPtr(result, nb_elements); + Log::info("Expected ouptut : "); + expectedOutput->print(); - std::shared_ptr<Tensor> myInit = - std::make_shared<Tensor>(Array2D<float, 3, 3>{ - {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); + std::shared_ptr<Tensor> myInit = + std::make_shared<Tensor>(Array2D<float, 3, 3>{ + {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}}); - auto initMemdims = std::vector<std::size_t>(dims.begin()+1, dims.end()); - Log::info("dimensions : "); - for(auto dim: initMemdims) { + auto initMemdims = + std::vector<std::size_t>(dims.begin() + 1, dims.end()); + Log::info("dimensions : "); + for (auto dim : initMemdims) { Log::info("{}", dim); + } + std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( + Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); + + std::shared_ptr<Tensor> myInitR = + std::make_shared<Tensor>(initMemdims); + myInitR->setDataType(DataType::Float32); + myInitR->setBackend("cpu"); + uniformFiller<float>(myInitR, 0, 0); + + pop->getOperator()->associateInput(0, T0); + op->associateInput(1, myInitR); + op->associateInput(2, myInitR); + + myGraph->compile("cpu", DataType::Float32); + + auto scheduler = SequentialScheduler(myGraph); + REQUIRE_NOTHROW(scheduler.generateScheduling()); + REQUIRE_NOTHROW(scheduler.forward(true)); + + // TODO: Naming is wrong + auto mem_op = + std::static_pointer_cast<OperatorTensor>(mem_rec->getOperator()); + auto spk_op = + std::static_pointer_cast<OperatorTensor>(spk_rec->getOperator()); + // Log::info("Output of stack node and spike : "); + // mem_op->getOutput(0)->print(); + Log::info("----- Input -----"); + T0->print(); + Log::info("----- Results (expected) -----"); + expectedOutput->print(); + Log::info("----- Results -----"); + spk_op->getOutput(0)->print(); + REQUIRE(approxEq<float>(*(spk_op->getOutput(0)), *(expectedOutput))); + Log::info("Output of stack node and spike : "); + Log::info("Test Done."); } - std::shared_ptr<Tensor> myInitW = std::make_shared<Tensor>( - Array2D<float, 3, 2>{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}); - - std::shared_ptr<Tensor> myInitR = std::make_shared<Tensor>(initMemdims); - myInitR->setDataType(DataType::Float32); - myInitR->setBackend("cpu"); - uniformFiller<float>(myInitR, 0, 0); - - pop->getOperator()->associateInput(0, T0); - op->associateInput(1, myInitR); - op->associateInput(2, myInitR); - - myGraph->compile("cpu", DataType::Float32); - - auto scheduler = SequentialScheduler(myGraph); - REQUIRE_NOTHROW(scheduler.generateScheduling()); - REQUIRE_NOTHROW(scheduler.forward(true)); - - // TODO: Naming is wrong - auto mem_op = std::static_pointer_cast<OperatorTensor>(mem_rec->getOperator()); - auto spk_op = std::static_pointer_cast<OperatorTensor>(spk_rec->getOperator()); - //Log::info("Output of stack node and spike : "); - //mem_op->getOutput(0)->print(); - Log::info("----- Input -----"); - T0->print(); - Log::info("----- Results (expected) -----"); - expectedOutput->print(); - Log::info("----- Results -----"); - spk_op->getOutput(0)->print(); - REQUIRE(approxEq<float>(*(spk_op->getOutput(0)), *(expectedOutput))); - Log::info("Output of stack node and spike : "); - Log::info("Test Done."); - } } -- GitLab From 8f01fb74d0ff506a8b51efab4cb076e2aac2a0eb Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Tue, 10 Dec 2024 17:57:15 +0100 Subject: [PATCH 08/12] Add a new test for a full nn using leaky neuron --- src/operator/SubImpl.cpp | 3 - unit_tests/operator/Test_MetaOperator.cpp | 112 ++++++++++++++++++++-- 2 files changed, 102 insertions(+), 13 deletions(-) diff --git a/src/operator/SubImpl.cpp b/src/operator/SubImpl.cpp index 5c842c26..e36abe2a 100644 --- a/src/operator/SubImpl.cpp +++ b/src/operator/SubImpl.cpp @@ -29,9 +29,6 @@ void Aidge::SubImpl_cpu::forward() { // Find the correct kernel type const auto impl = Registrar<SubImpl_cpu>::create(getBestMatch(getRequiredSpec())); - Log::info("Sub Operator Kernel"); - op_.getInput(0)->print(); - op_.getInput(1)->print(); // Call kernel impl.forward(op_.getInput(0)->dims(), diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index 17064385..cf663dbb 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -10,16 +10,18 @@ ********************************************************************************/ #include <aidge/filler/Filler.hpp> +#include <aidge/operator/FC.hpp> #include <catch2/catch_test_macros.hpp> #include <cmath> #include <cstdlib> #include <memory> #include <random> -#include "aidge/backend/cpu/operator/ConvImpl.hpp" +#include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/PadImpl.hpp" #include "aidge/data/Tensor.hpp" #include "aidge/operator/Conv.hpp" +#include "aidge/operator/FC.hpp" #include "aidge/operator/Identity.hpp" #include "aidge/operator/MetaOperator.hpp" #include "aidge/operator/MetaOperatorDefs.hpp" @@ -29,6 +31,7 @@ #include "aidge/scheduler/ParallelScheduler.hpp" #include "aidge/scheduler/SequentialScheduler.hpp" #include "aidge/utils/TensorUtils.hpp" +#include "aidge/filler/Filler.hpp" using namespace Aidge; @@ -211,6 +214,7 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { PaddedConv(3, 4, {3, 3}, "myPaddedConv", {1, 1}, {1, 1, 1, 1}); } SECTION("LSTM(forward)") { + auto pop = Pop(); auto myLSTM = LSTM(32, 64, 0, true, "ltsm"); auto op = @@ -279,6 +283,7 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { REQUIRE(microGraphScheduler->getStaticScheduling(1).size() == 24); REQUIRE(microGraphScheduler->getStaticScheduling(15).size() == 24); } + SECTION("LSTM(forward_values)") { auto myLSTM = LSTM(2, 3, 0, true, "ltsm"); auto op = @@ -348,6 +353,7 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); } + SECTION("LSTM(forward_values_seq)") { auto pop = Pop(); auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); @@ -413,6 +419,7 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState)); } + SECTION("LSTM(forward_values_seq_flatten)(sequential)") { auto pop = Pop(); auto myLSTM = LSTM(2, 3, 2, true, "ltsm"); @@ -592,18 +599,103 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { } SECTION("Leaky(forward)(fixed)") { + + constexpr auto inChannels = 10; + constexpr auto outChannels = 5; - std::shared_ptr<Tensor> input = std::make_shared<Tensor>( - Array3D<float, 2, 3, 2>{{{{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}, - {{2.0, 3.0}, {4.0, 5.0}, {6.0, 7.0}}}}); - - - constexpr auto beta = 0.9; + constexpr auto beta = 0.95; constexpr auto threshold = 1.0; - auto pop = Pop("pop"); - auto leaky = Leaky(2, beta, threshold, "leaky"); + constexpr auto nbTimeSteps = 2; + + + auto myWeights = std::make_shared<Tensor>(Array2D<float, outChannels, inChannels>{{ + {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, + {1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1}, + {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 0.1, 0.2, 0.3, 0.4}, + {0.4, 0.3, 0.2, 0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5}, + {0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0}, + }}); + + auto myWeights2 = std::make_shared<Tensor>(Array2D<float, inChannels, outChannels>{{ + {0.1, 0.2, 0.3, 0.4, 0.5}, + {0.6, 0.7, 0.8, 0.9, 1.0}, + {1.0, 0.9, 0.8, 0.7, 0.6}, + {0.5, 0.4, 0.3, 0.2, 0.1}, + {0.5, 0.6, 0.7, 0.8, 0.9}, + {1.0, 0.1, 0.2, 0.3, 0.4}, + {0.4, 0.3, 0.2, 0.1, 0.0}, + {0.1, 0.2, 0.3, 0.4, 0.5}, + {0.9, 0.8, 0.7, 0.6, 0.5}, + {0.4, 0.3, 0.2, 0.1, 0.0}, + }}); + + auto myInput = std::make_shared<Tensor>(Array2D<float, 2, 10>{{ + {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, + {1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1}, + }}); + + // py/snn Torch computed result, output of fc1 at time step 1 + auto expectedOutputlif1ts1 = std::make_shared<Tensor>(Array2D<float,2,5>{{ + {3.850, 2.2000, 2.6500, 1.5000, 1.6500}, + {2.200, 3.8500, 3.4000, 1.2500, 3.3000}, + }}); + + auto expectedOutputfc2ts1 = std::make_shared<Tensor>(Array2D<float,2,10>{{ + {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, + {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, + }}); + + auto expectedOutputlif1ts2 = std::make_shared<Tensor>(Array2D<float,2,5>{{ + {6.5075, 3.2900, 4.1675, 1.9250, 2.2175}, + {3.2900, 6.5075, 5.6300, 1.4375, 5.4350}, + }}); + + // NOTE: Same output as before, because for all channels, we have a potential higher than threshold. + // Thus the lif neuron fires at every timestep for every channel. + auto expectedOutputfc2ts2 = std::make_shared<Tensor>(Array2D<float,2,10>{{ + {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, + {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, + }}); + + auto init = std::make_shared<Tensor>(Array2D<float, 2, 5>{}); + uniformFiller<float>(init, 0.0, 0.0); + + + auto fc1 = FC(inChannels, outChannels, true, "myfc"); + auto fc2 = FC(outChannels, inChannels, true, "fc2"); + // NOTE: Account for init step by adding 1 to the max timestep parameter. + auto lif1 = Leaky(nbTimeSteps+1, beta, threshold, "leaky"); + + // associateInput() does not work + fc1->input(1).first->getOperator()->setOutput(0, myWeights); + fc2->input(1).first->getOperator()->setOutput(0, myWeights2); + + auto fc1Op = std::static_pointer_cast<OperatorTensor>(fc1->getOperator()); + auto lif1Op = std::static_pointer_cast<MetaOperator_Op>(lif1->getOperator()); + auto fc2Op = std::static_pointer_cast<OperatorTensor>(fc2->getOperator()); + + fc1Op->associateInput(0, myInput); + lif1Op->associateInput(1, init); + lif1Op->associateInput(2, init); + + fc1->addChild(lif1, 0, 0); + lif1->addChild(fc2, 1, 0); + + + auto g = std::make_shared<GraphView>(); + g->add({fc1, lif1, fc2}); + g->compile("cpu", DataType::Float32); + auto scheduler = SequentialScheduler(g); - REQUIRE(true); + // Forward 1 (simulate timestep 0) + scheduler.forward(true); + REQUIRE(approxEq<float>(*(lif1Op->getOutput(0)), *(expectedOutputlif1ts1))); + REQUIRE(approxEq<float>(*(fc2Op->getOutput(0)), *(expectedOutputfc2ts1))); + + // Forward 1 (simulate timestep 1) + scheduler.forward(true); + REQUIRE(approxEq<float>(*(lif1Op->getOutput(0)), *(expectedOutputlif1ts2))); + REQUIRE(approxEq<float>(*(fc2Op->getOutput(0)), *(expectedOutputfc2ts2))); } SECTION("Leaky(forward)") { -- GitLab From 623c55c6f42ab15208c711c130bbc0b86da30895 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Wed, 18 Dec 2024 14:35:43 +0100 Subject: [PATCH 09/12] chore: Remove debug prints --- unit_tests/operator/Test_MetaOperator.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index cf663dbb..86e64c57 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -847,21 +847,8 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { REQUIRE_NOTHROW(scheduler.generateScheduling()); REQUIRE_NOTHROW(scheduler.forward(true)); - // TODO: Naming is wrong - auto mem_op = - std::static_pointer_cast<OperatorTensor>(mem_rec->getOperator()); - auto spk_op = + auto memOp = std::static_pointer_cast<OperatorTensor>(spk_rec->getOperator()); - // Log::info("Output of stack node and spike : "); - // mem_op->getOutput(0)->print(); - Log::info("----- Input -----"); - T0->print(); - Log::info("----- Results (expected) -----"); - expectedOutput->print(); - Log::info("----- Results -----"); - spk_op->getOutput(0)->print(); - REQUIRE(approxEq<float>(*(spk_op->getOutput(0)), *(expectedOutput))); - Log::info("Output of stack node and spike : "); - Log::info("Test Done."); + REQUIRE(approxEq<float>(*(memOp->getOutput(0)), *(expectedOutput))); } } -- GitLab From 948d024bcbb8b6af6cf355cd974219a6c5dc2972 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Fri, 31 Jan 2025 13:09:35 +0100 Subject: [PATCH 10/12] Format files --- include/aidge/backend/cpu.hpp | 1 - unit_tests/operator/Test_MetaOperator.cpp | 166 ++++++++++++++-------- 2 files changed, 107 insertions(+), 60 deletions(-) diff --git a/include/aidge/backend/cpu.hpp b/include/aidge/backend/cpu.hpp index 17f3b832..5db19a2b 100644 --- a/include/aidge/backend/cpu.hpp +++ b/include/aidge/backend/cpu.hpp @@ -36,7 +36,6 @@ #include "aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp" #include "aidge/backend/cpu/operator/HeavisideImpl.hpp" #include "aidge/backend/cpu/operator/LRNImpl.hpp" -#include "aidge/backend/cpu/operator/HeavisideImpl.hpp" #include "aidge/backend/cpu/operator/LeakyReLUImpl.hpp" #include "aidge/backend/cpu/operator/LnImpl.hpp" #include "aidge/backend/cpu/operator/MatMulImpl.hpp" diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index 86e64c57..d954add4 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -17,9 +17,10 @@ #include <memory> #include <random> -#include "aidge/backend/cpu/operator/ConvImpl.hpp" +#include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/PadImpl.hpp" #include "aidge/data/Tensor.hpp" +#include "aidge/filler/Filler.hpp" #include "aidge/operator/Conv.hpp" #include "aidge/operator/FC.hpp" #include "aidge/operator/Identity.hpp" @@ -31,7 +32,6 @@ #include "aidge/scheduler/ParallelScheduler.hpp" #include "aidge/scheduler/SequentialScheduler.hpp" #include "aidge/utils/TensorUtils.hpp" -#include "aidge/filler/Filler.hpp" using namespace Aidge; @@ -599,80 +599,125 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { } SECTION("Leaky(forward)(fixed)") { - + constexpr auto inChannels = 10; constexpr auto outChannels = 5; constexpr auto beta = 0.95; - constexpr auto threshold = 1.0; + constexpr auto threshold = 1.0; constexpr auto nbTimeSteps = 2; - - auto myWeights = std::make_shared<Tensor>(Array2D<float, outChannels, inChannels>{{ - {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, - {1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1}, - {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 0.1, 0.2, 0.3, 0.4}, - {0.4, 0.3, 0.2, 0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5}, - {0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0}, - }}); - - auto myWeights2 = std::make_shared<Tensor>(Array2D<float, inChannels, outChannels>{{ - {0.1, 0.2, 0.3, 0.4, 0.5}, - {0.6, 0.7, 0.8, 0.9, 1.0}, - {1.0, 0.9, 0.8, 0.7, 0.6}, - {0.5, 0.4, 0.3, 0.2, 0.1}, - {0.5, 0.6, 0.7, 0.8, 0.9}, - {1.0, 0.1, 0.2, 0.3, 0.4}, - {0.4, 0.3, 0.2, 0.1, 0.0}, - {0.1, 0.2, 0.3, 0.4, 0.5}, - {0.9, 0.8, 0.7, 0.6, 0.5}, - {0.4, 0.3, 0.2, 0.1, 0.0}, - }}); - - auto myInput = std::make_shared<Tensor>(Array2D<float, 2, 10>{{ + auto myWeights = + std::make_shared<Tensor>(Array2D<float, outChannels, inChannels>{{ + {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, + {1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1}, + {0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 0.1, 0.2, 0.3, 0.4}, + {0.4, 0.3, 0.2, 0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5}, + {0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0}, + }}); + + auto myWeights2 = + std::make_shared<Tensor>(Array2D<float, inChannels, outChannels>{{ + {0.1, 0.2, 0.3, 0.4, 0.5}, + {0.6, 0.7, 0.8, 0.9, 1.0}, + {1.0, 0.9, 0.8, 0.7, 0.6}, + {0.5, 0.4, 0.3, 0.2, 0.1}, + {0.5, 0.6, 0.7, 0.8, 0.9}, + {1.0, 0.1, 0.2, 0.3, 0.4}, + {0.4, 0.3, 0.2, 0.1, 0.0}, + {0.1, 0.2, 0.3, 0.4, 0.5}, + {0.9, 0.8, 0.7, 0.6, 0.5}, + {0.4, 0.3, 0.2, 0.1, 0.0}, + }}); + + auto myInput = std::make_shared<Tensor>(Array2D<float, 2, 10>{{ {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0}, {1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1}, }}); // py/snn Torch computed result, output of fc1 at time step 1 - auto expectedOutputlif1ts1 = std::make_shared<Tensor>(Array2D<float,2,5>{{ - {3.850, 2.2000, 2.6500, 1.5000, 1.6500}, - {2.200, 3.8500, 3.4000, 1.2500, 3.3000}, - }}); - - auto expectedOutputfc2ts1 = std::make_shared<Tensor>(Array2D<float,2,10>{{ - {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, - {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, - }}); - - auto expectedOutputlif1ts2 = std::make_shared<Tensor>(Array2D<float,2,5>{{ - {6.5075, 3.2900, 4.1675, 1.9250, 2.2175}, - {3.2900, 6.5075, 5.6300, 1.4375, 5.4350}, - }}); - - // NOTE: Same output as before, because for all channels, we have a potential higher than threshold. - // Thus the lif neuron fires at every timestep for every channel. - auto expectedOutputfc2ts2 = std::make_shared<Tensor>(Array2D<float,2,10>{{ - {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, - {1.5000, 4.0000, 4.0000, 1.5000, 3.5000, 2.0000, 1.0000, 1.5000, 3.5000, 1.0000}, - }}); + auto expectedOutputlif1ts1 = + std::make_shared<Tensor>(Array2D<float, 2, 5>{{ + {3.850, 2.2000, 2.6500, 1.5000, 1.6500}, + {2.200, 3.8500, 3.4000, 1.2500, 3.3000}, + }}); + + auto expectedOutputfc2ts1 = + std::make_shared<Tensor>(Array2D<float, 2, 10>{{ + {1.5000, + 4.0000, + 4.0000, + 1.5000, + 3.5000, + 2.0000, + 1.0000, + 1.5000, + 3.5000, + 1.0000}, + {1.5000, + 4.0000, + 4.0000, + 1.5000, + 3.5000, + 2.0000, + 1.0000, + 1.5000, + 3.5000, + 1.0000}, + }}); + + auto expectedOutputlif1ts2 = + std::make_shared<Tensor>(Array2D<float, 2, 5>{{ + {6.5075, 3.2900, 4.1675, 1.9250, 2.2175}, + {3.2900, 6.5075, 5.6300, 1.4375, 5.4350}, + }}); + + // NOTE: Same output as before, because for all channels, we have a + // potential higher than threshold. Thus the lif neuron fires at every + // timestep for every channel. + auto expectedOutputfc2ts2 = + std::make_shared<Tensor>(Array2D<float, 2, 10>{{ + {1.5000, + 4.0000, + 4.0000, + 1.5000, + 3.5000, + 2.0000, + 1.0000, + 1.5000, + 3.5000, + 1.0000}, + {1.5000, + 4.0000, + 4.0000, + 1.5000, + 3.5000, + 2.0000, + 1.0000, + 1.5000, + 3.5000, + 1.0000}, + }}); auto init = std::make_shared<Tensor>(Array2D<float, 2, 5>{}); uniformFiller<float>(init, 0.0, 0.0); - auto fc1 = FC(inChannels, outChannels, true, "myfc"); auto fc2 = FC(outChannels, inChannels, true, "fc2"); - // NOTE: Account for init step by adding 1 to the max timestep parameter. - auto lif1 = Leaky(nbTimeSteps+1, beta, threshold, "leaky"); + // NOTE: Account for init step by adding 1 to the max timestep + // parameter. + auto lif1 = Leaky(nbTimeSteps + 1, beta, threshold, "leaky"); // associateInput() does not work fc1->input(1).first->getOperator()->setOutput(0, myWeights); fc2->input(1).first->getOperator()->setOutput(0, myWeights2); - auto fc1Op = std::static_pointer_cast<OperatorTensor>(fc1->getOperator()); - auto lif1Op = std::static_pointer_cast<MetaOperator_Op>(lif1->getOperator()); - auto fc2Op = std::static_pointer_cast<OperatorTensor>(fc2->getOperator()); + auto fc1Op = + std::static_pointer_cast<OperatorTensor>(fc1->getOperator()); + auto lif1Op = + std::static_pointer_cast<MetaOperator_Op>(lif1->getOperator()); + auto fc2Op = + std::static_pointer_cast<OperatorTensor>(fc2->getOperator()); fc1Op->associateInput(0, myInput); lif1Op->associateInput(1, init); @@ -681,7 +726,6 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { fc1->addChild(lif1, 0, 0); lif1->addChild(fc2, 1, 0); - auto g = std::make_shared<GraphView>(); g->add({fc1, lif1, fc2}); g->compile("cpu", DataType::Float32); @@ -689,13 +733,17 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { // Forward 1 (simulate timestep 0) scheduler.forward(true); - REQUIRE(approxEq<float>(*(lif1Op->getOutput(0)), *(expectedOutputlif1ts1))); - REQUIRE(approxEq<float>(*(fc2Op->getOutput(0)), *(expectedOutputfc2ts1))); + REQUIRE(approxEq<float>(*(lif1Op->getOutput(0)), + *(expectedOutputlif1ts1))); + REQUIRE( + approxEq<float>(*(fc2Op->getOutput(0)), *(expectedOutputfc2ts1))); // Forward 1 (simulate timestep 1) scheduler.forward(true); - REQUIRE(approxEq<float>(*(lif1Op->getOutput(0)), *(expectedOutputlif1ts2))); - REQUIRE(approxEq<float>(*(fc2Op->getOutput(0)), *(expectedOutputfc2ts2))); + REQUIRE(approxEq<float>(*(lif1Op->getOutput(0)), + *(expectedOutputlif1ts2))); + REQUIRE( + approxEq<float>(*(fc2Op->getOutput(0)), *(expectedOutputfc2ts2))); } SECTION("Leaky(forward)") { -- GitLab From 4ca093a23785f30b7fa77f543c77a91ca49bd63c Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Fri, 31 Jan 2025 13:41:15 +0100 Subject: [PATCH 11/12] Rearrange includes --- unit_tests/operator/Test_MetaOperator.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index d954add4..81f57b13 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -9,14 +9,13 @@ * ********************************************************************************/ -#include <aidge/filler/Filler.hpp> -#include <aidge/operator/FC.hpp> -#include <catch2/catch_test_macros.hpp> #include <cmath> #include <cstdlib> #include <memory> #include <random> +#include <catch2/catch_test_macros.hpp> + #include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/PadImpl.hpp" #include "aidge/data/Tensor.hpp" -- GitLab From b36e1bcd59d637805cce04a95c975aaed7e14448 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Fri, 31 Jan 2025 14:43:08 +0100 Subject: [PATCH 12/12] randomize beta in leaky unit test --- unit_tests/operator/Test_MetaOperator.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/unit_tests/operator/Test_MetaOperator.cpp b/unit_tests/operator/Test_MetaOperator.cpp index 81f57b13..23bacda5 100644 --- a/unit_tests/operator/Test_MetaOperator.cpp +++ b/unit_tests/operator/Test_MetaOperator.cpp @@ -757,6 +757,7 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { std::uniform_int_distribution<std::size_t> nbDimsDist(std::size_t(3), std::size_t(3)); std::uniform_int_distribution<int> boolDist(0, 1); + std::uniform_real_distribution<float> betaDist(0,1); const std::size_t nbDims = nbDimsDist(gen); Log::info("Nbdims : {}", nbDims); @@ -771,8 +772,9 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { } const auto nbTimeSteps = dims[0]; + const auto beta = betaDist(gen); - auto myLeaky = Leaky(nbTimeSteps, 0.9, 1.0, "leaky"); + auto myLeaky = Leaky(nbTimeSteps, beta, 1.0, "leaky"); auto op = std::static_pointer_cast<MetaOperator_Op>(myLeaky->getOperator()); // auto stack = Stack(2); @@ -856,7 +858,7 @@ TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") { for (int j = 0; j < nbElementsPerTimeStep; ++j) { auto reset = (result[prev + j] > 1.0 ? 1 : 0); result[offset + j] = - result[prev + j] * 0.9 + input[offset + j] - reset; + result[prev + j] * beta + input[offset + j] - reset; } } -- GitLab