Skip to content
Snippets Groups Projects
Commit 7fadc33e authored by Grégoire Kubler's avatar Grégoire Kubler
Browse files

Merge remote-tracking branch 'EclipseRepo/dev' into feat/support_ASAN

parents 422a9cb6 5ff8d30b
No related branches found
No related tags found
3 merge requests!50version 0.2.0,!47Draft: TEST_CI_FORK_DO_NOT_MERGE,!42feat/operator_globalAveragePooling
Showing
with 2450 additions and 722 deletions
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <cassert>
#include <chrono> // std::chrono::milliseconds
#include <numeric> // std::accumulate
#include <thread> // std::this_thread::sleep_for
#include <vector>
#include "aidge/operator/Tanh.hpp"
#include "aidge/utils/Types.h"
#include "aidge/backend/cpu/data/GetCPUPtr.h"
#include "aidge/backend/cpu/operator/TanhImpl.hpp"
#include "aidge/backend/cpu/operator/TanhImpl_forward_kernels.hpp"
Aidge::NbElts_t Aidge::TanhImpl_cpu::getNbRequiredProtected(const Aidge::IOIndex_t /*inputIdx*/) const {
// this implementation can be in-place
return 0;
}
void Aidge::TanhImpl_cpu::forward() {
assert(std::static_pointer_cast<Tensor>(mOp.getRawInput(0)) && "missing input #0");
// Find the correct kernel type
auto kernelFunc = Registrar<TanhImplForward_cpu>::create({
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dataType(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dataType()});
// Call kernel
kernelFunc(std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->size(),
getCPUPtr(mOp.getRawInput(0)),
getCPUPtr(mOp.getRawOutput(0)));
}
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <cassert>
#include <chrono> // std::chrono::milliseconds
#include <numeric> // std::accumulate
#include <thread> // std::this_thread::sleep_for
#include <vector>
#include "aidge/utils/Types.h"
#include "aidge/operator/Transpose.hpp"
#include "aidge/backend/cpu/operator/TransposeImpl.hpp"
#include "aidge/backend/cpu/operator/TransposeImpl_forward_kernels.hpp"
Aidge::NbElts_t Aidge::TransposeImpl2D_cpu::getNbRequiredProtected(IOIndex_t /*inputIdx*/) const {
// this implementation can be in-place
return 0;
}
Aidge::NbElts_t Aidge::TransposeImpl3D_cpu::getNbRequiredProtected(IOIndex_t /*inputIdx*/) const {
// this implementation can be in-place
return 0;
}
Aidge::NbElts_t Aidge::TransposeImpl4D_cpu::getNbRequiredProtected(IOIndex_t /*inputIdx*/) const {
// this implementation can be in-place
return 0;
}
Aidge::NbElts_t Aidge::TransposeImpl5D_cpu::getNbRequiredProtected(IOIndex_t /*inputIdx*/) const {
// this implementation can be in-place
return 0;
}
Aidge::NbElts_t Aidge::TransposeImpl6D_cpu::getNbRequiredProtected(IOIndex_t /*inputIdx*/) const {
// this implementation can be in-place
return 0;
}
void Aidge::TransposeImpl2D_cpu::forward() {
// Find the correct kernel type
auto kernelFunc =
Registrar<TransposeImpl2DForward_cpu>::create({
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dataType(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dataType()});
// auto attr = dynamic_cast<const Transpose_Op<2>&>(mOp).getStaticAttributes();
// std::vector<DimIdx_t> outDimsOrder;
// outDimsOrder.reserve(std::get<0>(attr).size()); // Reserve space for the new vector
// std::transform(std::get<0>(attr).begin(), std::get<0>(attr).end(), std::back_inserter(outDimsOrder),
// [](int intValue) { return static_cast<DimIdx_t>(intValue); });
// Call kernel
kernelFunc(dynamic_cast<const Transpose_Op<2>&>(mOp).getStaticAttributes(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->getImpl()->rawPtr(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->getImpl()->rawPtr());
}
void Aidge::TransposeImpl3D_cpu::forward() {
// Find the correct kernel type
auto kernelFunc =
Registrar<TransposeImpl3DForward_cpu>::create({
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dataType(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dataType()});
// Call kernel
kernelFunc(dynamic_cast<const Transpose_Op<3>&>(mOp).getStaticAttributes(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->getImpl()->rawPtr(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->getImpl()->rawPtr());
}
void Aidge::TransposeImpl4D_cpu::forward() {
// Find the correct kernel type
auto kernelFunc =
Registrar<TransposeImpl4DForward_cpu>::create({
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dataType(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dataType()});
// Call kernel
kernelFunc(dynamic_cast<const Transpose_Op<4>&>(mOp).getStaticAttributes(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->getImpl()->rawPtr(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->getImpl()->rawPtr());
}
void Aidge::TransposeImpl5D_cpu::forward() {
// Find the correct kernel type
auto kernelFunc =
Registrar<TransposeImpl5DForward_cpu>::create({
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dataType(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dataType()});
// Call kernel
kernelFunc(dynamic_cast<const Transpose_Op<5>&>(mOp).getStaticAttributes(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->getImpl()->rawPtr(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->getImpl()->rawPtr());
}
void Aidge::TransposeImpl6D_cpu::forward() {
// Find the correct kernel type
auto kernelFunc =
Registrar<TransposeImpl6DForward_cpu>::create({
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dataType(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dataType()});
// Call kernel
kernelFunc(dynamic_cast<const Transpose_Op<6>&>(mOp).getStaticAttributes(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->dims(),
std::static_pointer_cast<Tensor>(mOp.getRawInput(0))->getImpl()->rawPtr(),
std::static_pointer_cast<Tensor>(mOp.getRawOutput(0))->getImpl()->rawPtr());
}
\ No newline at end of file
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "aidge/data/Tensor.hpp"
#include "aidge/backend/cpu/data/TensorImpl.hpp"
using namespace Aidge;
TEST_CASE("Tensor creation") {
SECTION("from const array") {
Tensor x = Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}};
Tensor xCopy = Array3D<int, 2, 2, 2>{{{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}}};
Tensor xFloat =
Array3D<float, 2, 2, 2>{{{{1., 2.}, {3., 4.}}, {{5., 6.}, {7., 8.}}}};
SECTION("Tensor features") {
REQUIRE(x.nbDims() == 3);
REQUIRE(x.dims()[0] == 2);
REQUIRE(x.dims()[1] == 2);
REQUIRE(x.dims()[2] == 2);
REQUIRE(x.size() == 8);
}
SECTION("Access to array") {
REQUIRE(static_cast<int *>(x.getImpl()->rawPtr())[0] == 1);
REQUIRE(static_cast<int *>(x.getImpl()->rawPtr())[7] == 8);
}
SECTION("get function") {
REQUIRE(x.get<int>({0, 0, 0}) == 1);
REQUIRE(x.get<int>({0, 0, 1}) == 2);
REQUIRE(x.get<int>({0, 1, 1}) == 4);
REQUIRE(x.get<int>({1, 1, 0}) == 7);
x.set<int>({1, 1, 1}, 36);
REQUIRE(x.get<int>({1, 1, 1}) == 36);
}
SECTION("Pretty printing for debug") { REQUIRE_NOTHROW(x.print()); }
SECTION("Tensor (in)equality") {
REQUIRE(x == xCopy);
REQUIRE_FALSE(x == xFloat);
}
}
}
...@@ -117,4 +117,63 @@ TEST_CASE("[cpu/operator] Add(forward)", "[Add][CPU]") { ...@@ -117,4 +117,63 @@ TEST_CASE("[cpu/operator] Add(forward)", "[Add][CPU]") {
REQUIRE(*op->getOutput(0) == *expectedOutput); REQUIRE(*op->getOutput(0) == *expectedOutput);
} }
SECTION("Broadcasting") {
std::shared_ptr<Tensor> input_0 = std::make_shared<Tensor>(Array4D<int,3,1,3,2> {
{ //
{ //
{{0, 1},{2, 3},{4, 5}} //
}, //
{ //
{{6, 7},{8, 9},{10, 11}} //
}, //
{ //
{{12, 13},{14, 15},{16, 17}} //
} //
} //
}); //
std::shared_ptr<Tensor> input_1 = std::make_shared<Tensor>(Array4D<int,1,3,3,2> {
{ //
{ //
{{20, 21},{22, 23},{24, 25}}, //
{{26, 27},{28, 29},{30, 31}}, //
{{32, 33},{34, 35},{36, 37}} //
} //
} //
}); //
std::shared_ptr<Tensor> input_2 = std::make_shared<Tensor>(Array1D<int,2> {{100,200}});
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array4D<int,3,3,3,2> {
{ //
{ //
{{ 120, 222},{ 124, 226},{ 128, 230}}, //
{{ 126, 228},{ 130, 232},{ 134, 236}}, //
{{ 132, 234},{ 136, 238},{ 140, 242}} //
}, //
{ //
{{ 126, 228},{ 130, 232},{ 134, 236}}, //
{{ 132, 234},{ 136, 238},{ 140, 242}}, //
{{ 138, 240},{ 142, 244},{ 146, 248}} //
}, //
{ //
{{ 132, 234},{ 136, 238},{140, 242}}, //
{{ 138, 240},{ 142, 244},{146, 248}}, //
{{ 144, 246},{ 148, 250},{152, 254}} //
} //
} //
}); //
std::shared_ptr<Node> myAdd = Add(3);
auto op = std::static_pointer_cast<OperatorTensor>(myAdd -> getOperator());
op->associateInput(0, input_0);
op->associateInput(1, input_1);
op->associateInput(2, input_2);
op->setDataType(DataType::Int32);
op->setBackend("cpu");
op->computeOutputDims();
myAdd->forward();
op->getOutput(0)->print();
expectedOutput->print();
REQUIRE(*op->getOutput(0) == *expectedOutput);
}
} }
\ No newline at end of file
This diff is collapsed.
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <catch2/catch_test_macros.hpp>
#include "aidge/data/Tensor.hpp"
#include "aidge/operator/Erf.hpp"
#include "aidge/backend/cpu.hpp"
#include <memory>
using namespace Aidge;
TEST_CASE("[cpu/operator] Erf(forward)") {
SECTION("1D Tensor") {
std::shared_ptr<Tensor> input0 = std::make_shared<Tensor>(Array1D<float,10> {
{0.41384590, 0.43120754, 0.93762982, 0.31049860, 0.77547199, 0.09514862,
0.16145366, 0.42776686, 0.43487436, 0.41170865}
});
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array1D<float,10> {
{0.44163144, 0.45801866, 0.81516320, 0.33941913, 0.72722000, 0.10704061,
0.18061027, 0.45479023, 0.46144873, 0.43959764}
});
std::shared_ptr<Node> myErf = Erf();
auto op = std::static_pointer_cast<OperatorTensor>(myErf -> getOperator());
op->associateInput(0,input0);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myErf->forward();
float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
}
}
SECTION("3D Tensor") {
std::shared_ptr<Tensor> input0 = std::make_shared<Tensor>(Array3D<float,2,2,3> {
{
{
{0.97037154, 0.86208081, 0.77767169},
{0.38160080, 0.11422747, 0.77284443},
},
{
{0.51592529, 0.72543722, 0.54641193},
{0.93866944, 0.97767913, 0.34172094}
}
}
});
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array3D<float,2,2,3> {
{
{
{0.83003384, 0.77721894, 0.72857803},
{0.41057193, 0.12833349, 0.72559172},
},
{
{0.53438270, 0.69507217, 0.56032562},
{0.81564975, 0.83322692, 0.37109339}
}
}
});
std::shared_ptr<Node> myErf = Erf();
auto op = std::static_pointer_cast<OperatorTensor>(myErf -> getOperator());
op->associateInput(0,input0);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myErf->forward();
float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
}
}
}
\ No newline at end of file
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <catch2/catch_test_macros.hpp>
#include "aidge/data/Tensor.hpp"
#include "aidge/operator/Gather.hpp"
#include "aidge/backend/cpu.hpp"
#include <memory>
using namespace Aidge;
TEST_CASE("[cpu/operator] Gather(forward)") {
SECTION("2D Tensor axis 0") {
std::shared_ptr<Tensor> input = std::make_shared<Tensor>(Array2D<int,3,3> {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
});
std::shared_ptr<Tensor> indexes = std::make_shared<Tensor>(Array2D<int,1,2> {
{
{1, 2}
}
});
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array3D<int,1,2,3> {
{
{
{4, 5, 6},
{7, 8, 9}
}
}
});
std::shared_ptr<Node> myGather = Gather({1, 2}, {1, 2}, 0);
auto op = std::static_pointer_cast<OperatorTensor>(myGather -> getOperator());
op->associateInput(0,input);
// op->associateInput(1,indexes);
op->setDataType(DataType::Int32);
op->setBackend("cpu");
op->computeOutputDims();
myGather->forward();
op->getOutput(0)->print();
expectedOutput->print();
REQUIRE(*(op->getOutput(0)) == *expectedOutput);
}
SECTION("2D Tensor axis 1") {
std::shared_ptr<Tensor> input = std::make_shared<Tensor>(Array2D<int,3,3> {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
});
std::shared_ptr<Tensor> indexes = std::make_shared<Tensor>(Array2D<int,1,2> {
{
{0, 2}
}
});
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array3D<int,3,1,2> {
{
{
{1, 3}
},
{
{4, 6}
},
{
{7, 9}
}
}
});
std::shared_ptr<Node> myGather = Gather({0, 2}, {1, 2}, 1);
auto op = std::static_pointer_cast<OperatorTensor>(myGather -> getOperator());
op->associateInput(0,input);
// op->associateInput(1,indexes);
op->setDataType(DataType::Int32);
op->setBackend("cpu");
op->computeOutputDims();
myGather->forward();
REQUIRE(*(op->getOutput(0)) == *expectedOutput);
}
}
\ No newline at end of file
...@@ -10,102 +10,281 @@ ...@@ -10,102 +10,281 @@
********************************************************************************/ ********************************************************************************/
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <cstddef> // std::size_t
#include <cstdint> // std::uint16_t
#include <chrono>
#include <iostream>
#include <memory> #include <memory>
#include <random> // std::random_device, std::mt19937, std::uniform_real_distribution
#include "aidge/data/Tensor.hpp" #include "aidge/data/Tensor.hpp"
#include "aidge/operator/MatMul.hpp" #include "aidge/operator/MatMul.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/utils/TensorUtils.hpp"
#include "aidge/backend/cpu/operator/MatMulImpl.hpp" #include "aidge/backend/cpu/operator/MatMulImpl.hpp"
using namespace Aidge; namespace Aidge {
TEST_CASE("[cpu/operator] MatMul(forward)", "[MatMul][CPU]") { TEST_CASE("[cpu/operator] MatMul(forward)", "[MatMul][CPU]") {
// Test MatMul forward with batch size = 2 and feature size = 75 const std::uint16_t NBTRIALS = 10;
std::shared_ptr<Tensor> myWeights = std::make_shared<Tensor>(Array2D<int, 5, 75>{ // Create a random number generator
{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, std::random_device rd;
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, std::mt19937 gen(rd());
9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, std::uniform_real_distribution<float> dis(0.0, 1.0); // Random float distribution between 0 and 1
13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, std::uniform_int_distribution<std::size_t> distDims(10, 100);
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, std::uniform_int_distribution<std::size_t> distNbMatrix(1, 5);
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, // Create MatMul Operator
13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, std::shared_ptr<Node> myMatMul = MatMul();
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}});
std::shared_ptr<Tensor> myOutput = std::make_shared<Tensor>(Array2D<int, 2, 5>{
{{23600, 23600, 23600, 23600, 23600}, {68600, 68600, 68600, 68600, 68600}}});
std::shared_ptr<Node> myMatMul = MatMul(75, 5, "mymatmul");
auto op = std::static_pointer_cast<OperatorTensor>(myMatMul -> getOperator()); auto op = std::static_pointer_cast<OperatorTensor>(myMatMul -> getOperator());
op->associateInput(1, myWeights);
// To measure execution time of 'MatMul_Op::forward()' member function call
SECTION("2D input") { std::chrono::time_point<std::chrono::system_clock> start;
std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>(Array2D<int, 2, 75>{ std::chrono::time_point<std::chrono::system_clock> end;
{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, std::chrono::duration<double, std::micro> duration;
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, SECTION("2-D Tensors") {
57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74}, std::size_t totalComputation = 0;
{75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, // generate Tensors dimensions
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, const std::size_t dim0 = distDims(gen);
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, const std::size_t dim1 = distDims(gen);
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149}}}); const std::size_t dim2 = distDims(gen);
op->associateInput(0, myInput); totalComputation += dim0*dim1*dim2;
op->setDataType(DataType::Int32);
op->setBackend("cpu"); // Create and populate the array with random float values
op->computeOutputDims(); float bigArray1[dim0][dim1];
myMatMul->forward(); for (int i = 0; i < dim0; ++i) {
REQUIRE(*(op->getOutput(0)) == *myOutput); for (int j = 0; j < dim1; ++j) {
bigArray1[i][j] = dis(gen); // Generate random float value
}
}
float bigArray2[dim1][dim2];
for (int i = 0; i < dim1; ++i) {
for (int j = 0; j < dim2; ++j) {
bigArray2[i][j] = dis(gen); // Generate random float value
}
}
float res[dim0][dim2];
for (int i = 0; i < dim0; ++i) {
for (int j = 0; j < dim2; ++j) {
float sum = 0.0;
for (int k = 0; k < dim1; ++k) {
sum += bigArray1[i][k] * bigArray2[k][j];
}
res[i][j] = sum;
}
}
// Convert bigArray1 to Tensor
std::shared_ptr<Tensor> T1 = std::make_shared<Tensor>(DataType::Float32);
T1 -> resize({dim0,dim1});
T1 -> setBackend("cpu");
T1 -> getImpl() -> setRawPtr(&bigArray1[0][0], dim0*dim1);
// Convert bigArray2 to Tensor
std::shared_ptr<Tensor> T2 = std::make_shared<Tensor>(DataType::Float32);
T2 -> resize({dim1,dim2});
T2 -> setBackend("cpu");
T2 -> getImpl() -> setRawPtr(&bigArray2[0][0], dim1*dim2);
// convert res to Tensor
std::shared_ptr<Tensor> Tres = std::make_shared<Tensor>(DataType::Float32);
Tres -> resize({dim0,dim2});
Tres -> setBackend("cpu");
Tres -> getImpl() -> setRawPtr(&res[0][0], dim0*dim2);
op->associateInput(0, T1);
op->associateInput(1, T2);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
start = std::chrono::system_clock::now();
myMatMul->forward();
end = std::chrono::system_clock::now();
duration += std::chrono::duration_cast<std::chrono::microseconds>(end - start);
REQUIRE(approxEq<float>(*(op->getOutput(0)), *Tres));
}
std::cout << "multiplications over time spent: " << totalComputation/duration.count() << std::endl;
std::cout << "total time: " << duration.count() << std::endl;
} }
SECTION("4D input") {
std::shared_ptr<Tensor> myInput = SECTION("3-D Tensors") {
std::make_shared<Tensor>(Array4D<int, 2, 3, 5, 5>{{{{{0, 1, 2, 3, 4}, std::size_t totalComputation = 0;
{5, 6, 7, 8, 9}, duration = std::chrono::duration<double, std::micro>::zero();
{10, 11, 12, 13, 14}, for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
{15, 16, 17, 18, 19}, // generate Tensors dimensions
{20, 21, 22, 23, 24}}, const std::size_t dimNb = distNbMatrix(gen);
{{25, 26, 27, 28, 29}, const std::size_t dim0 = distDims(gen);
{30, 31, 32, 33, 34}, const std::size_t dim1 = distDims(gen);
{35, 36, 37, 38, 39}, const std::size_t dim2 = distDims(gen);
{40, 41, 42, 43, 44}, totalComputation += dim0*dim1*dim2*dimNb;
{45, 46, 47, 48, 49}},
{{50, 51, 52, 53, 54}, // Create and populate the array with random float values
{55, 56, 57, 58, 59}, float bigArray1[dimNb][dim0][dim1];
{60, 61, 62, 63, 64}, for (std::size_t n = 0; n < dimNb; ++n) {
{65, 66, 67, 68, 69}, for (std::size_t i = 0; i < dim0; ++i) {
{70, 71, 72, 73, 74}}}, for (std::size_t j = 0; j < dim1; ++j) {
{{{75, 76, 77, 78, 79}, bigArray1[n][i][j] = dis(gen); // Generate random float value
{80, 81, 82, 83, 84}, }
{85, 86, 87, 88, 89}, }
{90, 91, 92, 93, 94}, }
{95, 96, 97, 98, 99}}, float bigArray2[dimNb][dim1][dim2];
{{100, 101, 102, 103, 104}, for (std::size_t n = 0; n < dimNb; ++n) {
{105, 106, 107, 108, 109}, for (int i = 0; i < dim1; ++i) {
{110, 111, 112, 113, 114}, for (int j = 0; j < dim2; ++j) {
{115, 116, 117, 118, 119}, bigArray2[n][i][j] = dis(gen); // Generate random float value
{120, 121, 122, 123, 124}}, }
{{125, 126, 127, 128, 129}, }
{130, 131, 132, 133, 134}, }
{135, 136, 137, 138, 139}, float res[dimNb][dim0][dim2];
{140, 141, 142, 143, 144}, for (std::size_t n = 0; n < dimNb; ++n) {
{145, 146, 147, 148, 149}}}}}); for (int i = 0; i < dim0; ++i) {
op->associateInput(0, myInput); for (int j = 0; j < dim2; ++j) {
op->setDataType(DataType::Int32); float sum = 0.0;
for (int k = 0; k < dim1; ++k) {
sum += bigArray1[n][i][k] * bigArray2[n][k][j];
}
res[n][i][j] = sum;
}
}
}
// Convert bigArray1 to Tensor
std::shared_ptr<Tensor> T1 = std::make_shared<Tensor>(DataType::Float32);
T1 -> resize({dimNb,dim0,dim1});
T1 -> setBackend("cpu");
T1 -> getImpl() -> setRawPtr(&bigArray1[0][0], dimNb*dim0*dim1);
// Convert bigArray2 to Tensor
std::shared_ptr<Tensor> T2 = std::make_shared<Tensor>(DataType::Float32);
T2 -> resize({dimNb,dim1,dim2});
T2 -> setBackend("cpu");
T2 -> getImpl() -> setRawPtr(&bigArray2[0][0], dimNb*dim1*dim2);
// convert res to Tensor
std::shared_ptr<Tensor> Tres = std::make_shared<Tensor>(DataType::Float32);
Tres -> resize({dimNb,dim0,dim2});
Tres -> setBackend("cpu");
Tres -> getImpl() -> setRawPtr(&res[0][0], dimNb*dim0*dim2);
op->associateInput(0, T1);
op->associateInput(1, T2);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
start = std::chrono::system_clock::now();
myMatMul->forward();
end = std::chrono::system_clock::now();
duration += std::chrono::duration_cast<std::chrono::microseconds>(end - start);
REQUIRE(approxEq<float>(*(op->getOutput(0)), *Tres));
}
std::cout << "multiplications over time spent: " << totalComputation/duration.count() << std::endl;
std::cout << "total time: " << duration.count() << std::endl;
}
SECTION("4-D Tensors") {
std::size_t totalComputation = 0;
duration = std::chrono::duration<double, std::micro>::zero();
for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
// generate Tensors dimensions
const std::size_t dimNb1 = distNbMatrix(gen);
const std::size_t dimNb2 = distNbMatrix(gen);
const std::size_t dim0 = distDims(gen);
const std::size_t dim1 = distDims(gen);
const std::size_t dim2 = distDims(gen);
totalComputation += dim0*dim1*dim2*dimNb1*dimNb2;
// Create and populate the array with random float values
float bigArray1[dimNb1][dimNb2][dim0][dim1];
for (std::size_t n1 = 0; n1 < dimNb1; ++n1) {
for (std::size_t n2 = 0; n2 < dimNb2; ++n2) {
for (std::size_t i = 0; i < dim0; ++i) {
for (std::size_t j = 0; j < dim1; ++j) {
bigArray1[n1][n2][i][j] = dis(gen); // Generate random float value
}
}
}
}
float bigArray2[dimNb1][dimNb2][dim1][dim2];
for (std::size_t n1 = 0; n1 < dimNb1; ++n1) {
for (std::size_t n2 = 0; n2 < dimNb2; ++n2) {
for (std::size_t i = 0; i < dim1; ++i) {
for (std::size_t j = 0; j < dim2; ++j) {
bigArray2[n1][n2][i][j] = dis(gen); // Generate random float value
}
}
}
}
float res[dimNb1][dimNb2][dim0][dim2];
for (std::size_t n1 = 0; n1 < dimNb1; ++n1) {
for (std::size_t n2 = 0; n2 < dimNb2; ++n2) {
for (int i = 0; i < dim0; ++i) {
for (int j = 0; j < dim2; ++j) {
float sum = 0.0;
for (int k = 0; k < dim1; ++k) {
sum += bigArray1[n1][n2][i][k] * bigArray2[n1][n2][k][j];
}
res[n1][n2][i][j] = sum;
}
}
}
}
// Convert bigArray1 to Tensor
std::shared_ptr<Tensor> T1 = std::make_shared<Tensor>(DataType::Float32);
T1 -> resize({dimNb1,dimNb2,dim0,dim1});
T1 -> setBackend("cpu");
T1 -> getImpl() -> setRawPtr(&bigArray1[0][0], dimNb1*dimNb2*dim0*dim1);
// Convert bigArray2 to Tensor
std::shared_ptr<Tensor> T2 = std::make_shared<Tensor>(DataType::Float32);
T2 -> resize({dimNb1,dimNb2,dim1,dim2});
T2 -> setBackend("cpu");
T2 -> getImpl() -> setRawPtr(&bigArray2[0][0], dimNb1*dimNb2*dim1*dim2);
// convert res to Tensor
std::shared_ptr<Tensor> Tres = std::make_shared<Tensor>(DataType::Float32);
Tres -> resize({dimNb1,dimNb2,dim0,dim2});
Tres -> setBackend("cpu");
Tres -> getImpl() -> setRawPtr(&res[0][0], dimNb1*dimNb2*dim0*dim2);
op->associateInput(0, T1);
op->associateInput(1, T2);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
start = std::chrono::system_clock::now();
myMatMul->forward();
end = std::chrono::system_clock::now();
duration += std::chrono::duration_cast<std::chrono::microseconds>(end - start);
REQUIRE(approxEq<float>(*(op->getOutput(0)), *Tres));
}
std::cout << "multiplications over time spent: " << totalComputation/duration.count() << std::endl;
std::cout << "total time: " << duration.count() << std::endl;
}
SECTION("+2-D / 1-D") {
// allows to test both computation with a 1-D Tensor and broadcasting
// input_0
std::shared_ptr<Tensor> T0 = std::make_shared<Tensor>();
op->associateInput(0,T0);
const std::size_t dim0 = distNbMatrix(gen);
const std::size_t dim1 = distNbMatrix(gen) + 1;
const std::size_t dim2 = distNbMatrix(gen);
const std::size_t dim3 = distNbMatrix(gen);
T0->resize({dim0,dim1,dim2,dim3});
T0->setDataType(DataType::Float32);
T0->setBackend("cpu");
// input_1
std::shared_ptr<Tensor> T1 = std::make_shared<Tensor>();
op -> associateInput(1,T1);
T1->resize({dim3});
T1->setDataType(DataType::Float32);
T1->setBackend("cpu");
op->setDataType(DataType::Float32);
op->setBackend("cpu"); op->setBackend("cpu");
op->computeOutputDims(); op->computeOutputDims();
myMatMul->forward(); myMatMul->forward();
REQUIRE(*(op->getOutput(0)) == *myOutput);
}
// std::cout << static_cast<Tensor>((*myMatMul->getOperator())["weight"])[0][0][0][0] << std::endl; }
} }
\ No newline at end of file } // namespace Aidge
\ No newline at end of file
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
#include "aidge/utils/TensorUtils.hpp"
#include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/ConvImpl.hpp"
#include "aidge/backend/cpu/operator/PadImpl.hpp" #include "aidge/backend/cpu/operator/PadImpl.hpp"
#include "aidge/data/Tensor.hpp" #include "aidge/data/Tensor.hpp"
...@@ -21,10 +22,12 @@ ...@@ -21,10 +22,12 @@
#include "aidge/operator/MetaOperator.hpp" #include "aidge/operator/MetaOperator.hpp"
#include "aidge/operator/MetaOperatorDefs.hpp" #include "aidge/operator/MetaOperatorDefs.hpp"
#include "aidge/operator/Pad.hpp" #include "aidge/operator/Pad.hpp"
#include "aidge/operator/Pop.hpp"
using namespace Aidge; using namespace Aidge;
TEST_CASE("[cpu/operator] MetaOperator/PaddedConv(forward)", "[MetaOperator][PaddedConv][CPU]") { TEST_CASE("[cpu/operator] MetaOperator", "[MetaOperator][CPU]") {
SECTION("PaddedConv(forward)") {
std::shared_ptr<Tensor> myWeights = std::make_shared<Tensor>( std::shared_ptr<Tensor> myWeights = std::make_shared<Tensor>(
Array4D<double, 4, 3, 3, 3>{{{{{6.20986394e-01, 1.19775136e-03, 7.22876095e-02}, Array4D<double, 4, 3, 3, 3>{{{{{6.20986394e-01, 1.19775136e-03, 7.22876095e-02},
{1.16492919e-01, 8.21634093e-02, 1.17413265e-01}, {1.16492919e-01, 8.21634093e-02, 1.17413265e-01},
...@@ -187,4 +190,240 @@ TEST_CASE("[cpu/operator] MetaOperator/PaddedConv(forward)", "[MetaOperator][Pad ...@@ -187,4 +190,240 @@ TEST_CASE("[cpu/operator] MetaOperator/PaddedConv(forward)", "[MetaOperator][Pad
std::shared_ptr<Node> myPaddedConv = 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::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->nbData() == 1);
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, 1, 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, true);
g->save("lstm_outside_dims", true, true);
microGraph->save("lstm_dims", true, true);
REQUIRE(op->outputDimsForwarded());
auto microGraphScheduler = std::dynamic_pointer_cast<MetaOperator_Op>(op)->getMicroGraphScheduler();
microGraphScheduler->saveSchedulingDiagram("lstm_scheduling");
REQUIRE(op->getNbConsumedData(0) == 512);
REQUIRE(op->getNbConsumedData(1) == 32768);
REQUIRE(op->getNbProducedData(0) == 1088);
REQUIRE(op->getNbProducedData(1) == 1088);
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->nbData() == 1);
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->nbData() == 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->setDataType(DataType::Float32);
g->setBackend("cpu");
g->save("lstm_seq", true, true);
auto scheduler = SequentialScheduler(g);
scheduler.forward(true, true);
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)") {
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->nbData() == 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
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.forward(true, true);
scheduler.saveSchedulingDiagram("lstm_seq_flatten_schedule");
op->getOutput(0)->print();
myHiddenState->print();
REQUIRE(approxEq<float>(*(op->getOutput(0)), *myHiddenState));
}
} }
\ No newline at end of file
This diff is collapsed.
...@@ -150,12 +150,15 @@ TEST_CASE("[cpu/operator] PaddedConv(forward)", "[PaddedConv][CPU]") { ...@@ -150,12 +150,15 @@ TEST_CASE("[cpu/operator] PaddedConv(forward)", "[PaddedConv][CPU]") {
}); });
myConv->getOperator()->associateInput(0,myInput); myConv->getOperator()->associateInput(0,myInput);
myConv->getOperator()->associateInput(1,myWeights); myConv->input(1).first->getOperator()->setOutput(0, myWeights);
myConv->getOperator()->associateInput(2,myBias); myConv->input(2).first->getOperator()->setOutput(0, myBias);
myConv->getOperator()->setDataType(DataType::Int32);
myConv->getOperator()->setBackend("cpu"); auto g = getConnectedGraphView(myConv);
op->computeOutputDims(); g->setDataType(DataType::Int32);
myConv->forward(); g->setBackend("cpu");
auto scheduler = SequentialScheduler(g);
scheduler.forward();
REQUIRE(*(op->getOutput(0)) == *myOutput); REQUIRE(*(op->getOutput(0)) == *myOutput);
} }
...@@ -309,12 +312,15 @@ TEST_CASE("[cpu/operator] PaddedConv(forward)", "[PaddedConv][CPU]") { ...@@ -309,12 +312,15 @@ TEST_CASE("[cpu/operator] PaddedConv(forward)", "[PaddedConv][CPU]") {
}); });
myConv->getOperator()->associateInput(0,myInput); myConv->getOperator()->associateInput(0,myInput);
myConv->getOperator()->associateInput(1,myWeights); myConv->input(1).first->getOperator()->setOutput(0, myWeights);
myConv->getOperator()->associateInput(2,myBias); myConv->input(2).first->getOperator()->setOutput(0, myBias);
myConv->getOperator()->setDataType(DataType::Int32);
myConv->getOperator()->setBackend("cpu"); auto g = getConnectedGraphView(myConv);
op->computeOutputDims(); g->setDataType(DataType::Int32);
myConv->forward(); g->setBackend("cpu");
auto scheduler = SequentialScheduler(g);
scheduler.forward();
REQUIRE(*(op->getOutput(0)) == *myOutput); REQUIRE(*(op->getOutput(0)) == *myOutput);
} }
......
This diff is collapsed.
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <catch2/catch_test_macros.hpp>
#include <memory>
#include "aidge/data/Tensor.hpp"
#include "aidge/operator/ReduceMean.hpp"
#include "aidge/operator/Conv.hpp"
#include "aidge/backend/cpu.hpp"
using namespace Aidge;
TEST_CASE("[cpu/operator] ReduceMean(forward)", "[ReduceMean][CPU]") {
SECTION("KeepDims") {
SECTION("test 1") {
std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>(Array3D<float,3,2,2> {
{
{
{ 5.0, 1.0 },
{ 20.0, 2.0 }
},
{
{ 30.0, 1.0 },
{ 40.0, 2.0 }
},
{
{ 55.0, 1.0 },
{ 60.0, 2.0 }
}
}
});
Tensor myOutput = Tensor(Array3D<float,3,1,2> {
{
{{ 12.5, 1.5 }},
{{ 35.0, 1.5 }},
{{ 57.5, 1.5 }}
}
});
std::shared_ptr<Node> myReduceMean = ReduceMean({1}, 1);
auto op = std::static_pointer_cast<OperatorTensor>(myReduceMean -> getOperator());
op->associateInput(0,myInput);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myReduceMean->forward();
op->getOutput(0)->print();
REQUIRE(*(op->getOutput(0)) == myOutput);
}
SECTION("test 2") {
std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>(Array3D<float,3,3,2> {
{
{
{ 0.0, 0.0 },
{ 1.0, 1.0 },
{ 2.0, 2.0 }
},
{
{ 3.0, 3.0 },
{ 4.0, 4.0 },
{ 5.0, 5.0 }
},
{
{ 6.0, 6.0 },
{ 7.0, 7.0 },
{ 8.0, 8.0 }
}
}
});
Tensor myOutput = Tensor(Array3D<float,3,1,1> {
{
{{ 1.0 }},
{{ 4.0 }},
{{ 7.0 }}
}
});
std::shared_ptr<Node> myReduceMean = ReduceMean({1, 2}, 1);
auto op = std::static_pointer_cast<OperatorTensor>(myReduceMean -> getOperator());
op->associateInput(0,myInput);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myReduceMean->forward();
myOutput.print();
op->getOutput(0)->print();
REQUIRE(*(op->getOutput(0)) == myOutput);
}
}
SECTION("not_KeepDims") {
std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>(Array3D<float,3,2,2> {
{
{
{ 5.0, 1.0 },
{ 20.0, 2.0 }
},
{
{ 30.0, 1.0 },
{ 40.0, 2.0 }
},
{
{ 55.0, 1.0 },
{ 60.0, 2.0 }
}
}
});
std::shared_ptr<Tensor> myOutput = std::make_shared<Tensor>(Array2D<float,3,2> {
{
{ 12.5, 1.5 },
{ 35.0, 1.5 },
{ 57.5, 1.5 }
}
});
std::shared_ptr<Node> myReduceMean = ReduceMean({1}, 0);
auto op = std::static_pointer_cast<OperatorTensor>(myReduceMean -> getOperator());
op->associateInput(0,myInput);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myReduceMean->forward();
op->getOutput(0)->print();
REQUIRE(*(op->getOutput(0)) == *myOutput);
}
SECTION("all_axes") {
std::shared_ptr<Tensor> myInput = std::make_shared<Tensor>(Array3D<float,3,2,2> {
{
{
{ 5.0, 1.0 },
{ 20.0, 2.0 }
},
{
{ 30.0, 1.0 },
{ 40.0, 2.0 }
},
{
{ 55.0, 1.0 },
{ 60.0, 2.0 }
}
}
});
std::shared_ptr<Tensor> myOutput = std::make_shared<Tensor>(Array1D<float,1> {
{18.25}
});
std::shared_ptr<Node> myReduceMean = ReduceMean({0, 1, 2}, 0);
auto op = std::static_pointer_cast<OperatorTensor>(myReduceMean -> getOperator());
op->associateInput(0,myInput);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myReduceMean->forward();
op->getOutput(0)->print();
REQUIRE(*(op->getOutput(0)) == *myOutput);
}
}
\ No newline at end of file
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include <catch2/catch_test_macros.hpp>
#include "aidge/data/Tensor.hpp"
#include "aidge/operator/Reshape.hpp"
#include "aidge/backend/cpu.hpp"
#include <memory>
using namespace Aidge;
TEST_CASE("[cpu/operator] Reshape(forward)") {
SECTION("1D Tensor") {
std::shared_ptr<Tensor> input = std::make_shared<Tensor>(Array1D<float,6> {
{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}
});
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array2D<float,2,3> {
{
{1.0, 2.0, 3.0},
{4.0, 5.0, 6.0}
}
});
std::shared_ptr<Node> myReshape = Reshape({2, 3});
auto op = std::static_pointer_cast<OperatorTensor>(myReshape -> getOperator());
op->associateInput(0, input);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myReshape->forward();
REQUIRE(*(op->getOutput(0)) == *expectedOutput);
}
SECTION("2D Tensor") {
std::shared_ptr<Tensor> input = std::make_shared<Tensor>(Array2D<float,2,3> {
{
{1.0, 2.0, 3.0},
{4.0, 5.0, 6.0}
}
});
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array2D<float,3,2> {
{
{1.0, 2.0},
{3.0, 4.0},
{5.0, 6.0}
}
});
std::shared_ptr<Node> myReshape = Reshape({3, 2});
auto op = std::static_pointer_cast<OperatorTensor>(myReshape -> getOperator());
op->associateInput(0, input);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->computeOutputDims();
myReshape->forward();
REQUIRE(*(op->getOutput(0)) == *expectedOutput);
}
}
\ No newline at end of file
...@@ -163,4 +163,4 @@ TEST_CASE("[cpu/operator] Slice(forward)", "[Slice][CPU]") { ...@@ -163,4 +163,4 @@ TEST_CASE("[cpu/operator] Slice(forward)", "[Slice][CPU]") {
REQUIRE(op->getOutput(0)->dims() == expectedOutput->dims()); REQUIRE(op->getOutput(0)->dims() == expectedOutput->dims());
REQUIRE(op->getOutput(0)->dataType() == expectedOutput->dataType()); REQUIRE(op->getOutput(0)->dataType() == expectedOutput->dataType());
} }
} }
\ No newline at end of file
...@@ -41,15 +41,15 @@ TEST_CASE("[cpu/operator] Softmax(forward)", "[Softmax][CPU]") { ...@@ -41,15 +41,15 @@ TEST_CASE("[cpu/operator] Softmax(forward)", "[Softmax][CPU]") {
std::shared_ptr<Node> mySoftmax = Softmax(1); std::shared_ptr<Node> mySoftmax = Softmax(1);
auto op = std::static_pointer_cast<OperatorTensor>(mySoftmax -> getOperator()); auto op = std::static_pointer_cast<OperatorTensor>(mySoftmax -> getOperator());
mySoftmax->getOperator()->associateInput(0,input); op->associateInput(0,input);
mySoftmax->getOperator()->setDataType(DataType::Float32); op->setDataType(DataType::Float32);
mySoftmax->getOperator()->setBackend("cpu"); op->setBackend("cpu");
op->computeOutputDims(); op->computeOutputDims();
mySoftmax->forward(); mySoftmax->forward();
float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr()); float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr()); float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
for (std::size_t i = 0; i< 20; ++i) { for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001); REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
} }
...@@ -110,17 +110,16 @@ TEST_CASE("[cpu/operator] Softmax(forward)", "[Softmax][CPU]") { ...@@ -110,17 +110,16 @@ TEST_CASE("[cpu/operator] Softmax(forward)", "[Softmax][CPU]") {
std::shared_ptr<Node> mySoftmax = Softmax(1); std::shared_ptr<Node> mySoftmax = Softmax(1);
auto op = std::static_pointer_cast<OperatorTensor>(mySoftmax -> getOperator()); auto op = std::static_pointer_cast<OperatorTensor>(mySoftmax -> getOperator());
mySoftmax->getOperator()->associateInput(0,input); op->associateInput(0,input);
mySoftmax->getOperator()->setDataType(DataType::Float32); op->setDataType(DataType::Float32);
mySoftmax->getOperator()->setBackend("cpu"); op->setBackend("cpu");
op->computeOutputDims(); op->computeOutputDims();
mySoftmax->forward(); mySoftmax->forward();
float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr()); float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr()); float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
for (std::size_t i = 0; i< 54; ++i) { for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001); REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
} }
// REQUIRE(*mySoftmax->getOperator()->getOutput(0) == *expectedOutput);
} }
} }
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include "aidge/recipies/Recipies.hpp" #include "aidge/recipes/Recipes.hpp"
#include "aidge/operator/Conv.hpp" #include "aidge/operator/Conv.hpp"
#include "aidge/operator/Producer.hpp" #include "aidge/operator/Producer.hpp"
#include "aidge/graph/OpArgs.hpp" #include "aidge/graph/OpArgs.hpp"
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment