From 62a6a58d9f99cf92a697a680f5fd77bcc01ad9fe Mon Sep 17 00:00:00 2001 From: hrouis <houssemeddine.rouis92@gmail.com> Date: Mon, 13 Nov 2023 13:34:49 +0100 Subject: [PATCH] add Erf operator --- .../aidge/backend/cpu/operator/ErfImpl.hpp | 50 +++++++++++ .../cpu/operator/ErfImpl_forward_kernels.hpp | 45 ++++++++++ src/operator/ErfImpl.cpp | 41 +++++++++ unit_tests/operator/Test_ErfImpl.cpp | 88 +++++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 include/aidge/backend/cpu/operator/ErfImpl.hpp create mode 100644 include/aidge/backend/cpu/operator/ErfImpl_forward_kernels.hpp create mode 100644 src/operator/ErfImpl.cpp create mode 100644 unit_tests/operator/Test_ErfImpl.cpp diff --git a/include/aidge/backend/cpu/operator/ErfImpl.hpp b/include/aidge/backend/cpu/operator/ErfImpl.hpp new file mode 100644 index 00000000..5c0a6fd4 --- /dev/null +++ b/include/aidge/backend/cpu/operator/ErfImpl.hpp @@ -0,0 +1,50 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#ifndef AIDGE_CPU_OPERATOR_ERFIMPL_H_ +#define AIDGE_CPU_OPERATOR_ERFIMPL_H_ + +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/operator/Erf.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" +#include <memory> +#include <vector> + +namespace Aidge { +// class Erf_Op; + +// compute kernel registry for forward and backward +class ErfImplForward_cpu + : public Registrable<ErfImplForward_cpu, std::tuple<DataType, DataType>, void(const std::size_t, const void*, void*)> { +}; +class ErfImplBackward_cpu + : public Registrable<ErfImplBackward_cpu, std::tuple<DataType, DataType>, void(const std::size_t, const void*, void*)> { +}; + +class ErfImpl_cpu : public OperatorImpl { +public: + ErfImpl_cpu(const Erf_Op& op) : OperatorImpl(op) {} + + static std::unique_ptr<ErfImpl_cpu> create(const Erf_Op& op) { + return std::make_unique<ErfImpl_cpu>(op); + } + + NbElts_t getNbRequiredProtected(const IOIndex_t inputIdx) const override final; + void forward() override; +}; + +namespace { +static Registrar<Erf_Op> registrarErfImpl_cpu("cpu", Aidge::ErfImpl_cpu::create); +} +} // namespace Aidge + +#endif /* AIDGE_CPU_OPERATOR_ERFIMPL_H_ */ diff --git a/include/aidge/backend/cpu/operator/ErfImpl_forward_kernels.hpp b/include/aidge/backend/cpu/operator/ErfImpl_forward_kernels.hpp new file mode 100644 index 00000000..bb92401b --- /dev/null +++ b/include/aidge/backend/cpu/operator/ErfImpl_forward_kernels.hpp @@ -0,0 +1,45 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#ifndef AIDGE_CPU_OPERATOR_ERFIMPL_FORWARD_KERNEL_H_ +#define AIDGE_CPU_OPERATOR_ERFIMPL_FORWARD_KERNEL_H_ + +#include <cmath> + +#include "aidge/utils/Registrar.hpp" + +#include "aidge/backend/cpu/operator/ErfImpl.hpp" + +namespace Aidge { +template <class I, class O> +void ErfImpl_cpu_forward_kernel(std::size_t inputLenght, + const void* input_, + void* output_) { + + const I* input = static_cast<const I*>(input_); + O* output = static_cast<O*>(output_); + + for (std::size_t i = 0; i < inputLenght; ++i) { + output[i] = std::erf(input[i]); + } +} + +namespace { +static Registrar<ErfImplForward_cpu> registrarErfImplForward_cpu_Float32( + {DataType::Float32, DataType::Float32}, Aidge::ErfImpl_cpu_forward_kernel<float, float>); +static Registrar<ErfImplForward_cpu> registrarErfImplForward_cpu_Int32( + {DataType::Int32, DataType::Int32}, Aidge::ErfImpl_cpu_forward_kernel<int, int>); +static Registrar<ErfImplForward_cpu> registrarErfImplForward_cpu_Float64( + {DataType::Float64, DataType::Float64}, Aidge::ErfImpl_cpu_forward_kernel<double, double>); +} // namespace +} // namespace Aidge + +#endif /* AIDGE_CPU_OPERATOR_ERFIMPL_FORWARD_KERNEL_H_ */ diff --git a/src/operator/ErfImpl.cpp b/src/operator/ErfImpl.cpp new file mode 100644 index 00000000..dc50233e --- /dev/null +++ b/src/operator/ErfImpl.cpp @@ -0,0 +1,41 @@ +/******************************************************************************** + * 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/Erf.hpp" +#include "aidge/utils/Types.h" + +#include "aidge/backend/cpu/operator/ErfImpl.hpp" +#include "aidge/backend/cpu/operator/ErfImpl_forward_kernels.hpp" + +Aidge::NbElts_t Aidge::ErfImpl_cpu::getNbRequiredProtected(const Aidge::IOIndex_t /*inputIdx*/) const { + // this implementation can be in-place + return 0; +} + +void Aidge::ErfImpl_cpu::forward() { + assert(mOp.getInput(0) && "missing input #0"); + + // Find the correct kernel type + auto kernelFunc = Registrar<ErfImplForward_cpu>::create({ + mOp.getInput(0)->dataType(), + mOp.getOutput(0)->dataType()}); + + // Call kernel + kernelFunc(mOp.getInput(0)->size(), + mOp.getInput(0)->getImpl()->rawPtr(), + mOp.getOutput(0)->getImpl()->rawPtr()); +} diff --git a/unit_tests/operator/Test_ErfImpl.cpp b/unit_tests/operator/Test_ErfImpl.cpp new file mode 100644 index 00000000..9d550310 --- /dev/null +++ b/unit_tests/operator/Test_ErfImpl.cpp @@ -0,0 +1,88 @@ +/******************************************************************************** + * 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(); + myErf->getOperator()->setDatatype(DataType::Float32); + myErf->getOperator()->setBackend("cpu"); + myErf->getOperator()->associateInput(0,input0); + myErf->getOperator()->computeOutputDims(); + myErf->forward(); + + float* resPtr = static_cast<float*>(myErf->getOperator()->getOutput(0)->getImpl()->rawPtr()); + float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr()); + for (std::size_t i = 0; i< 10; ++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(); + myErf->getOperator()->setDatatype(DataType::Float32); + myErf->getOperator()->setBackend("cpu"); + myErf->getOperator()->associateInput(0,input0); + myErf->getOperator()->computeOutputDims(); + myErf->forward(); + + float* resPtr = static_cast<float*>(myErf->getOperator()->getOutput(0)->getImpl()->rawPtr()); + float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr()); + for (std::size_t i = 0; i< 12; ++i) { + REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001); + } + } +} \ No newline at end of file -- GitLab