From 6bb7ae3d82342169e49049b5d9905abce76b4865 Mon Sep 17 00:00:00 2001 From: Houssem Rouis <houssemeddine.rouis92@gmail.com> Date: Thu, 26 Oct 2023 18:01:28 +0200 Subject: [PATCH] add div operator --- include/aidge/backend/cpu.hpp | 1 + .../aidge/backend/cpu/operator/DivImpl.hpp | 50 +++++++ .../cpu/operator/DivImpl_forward_kernels.hpp | 51 +++++++ src/operator/DivImpl.cpp | 44 ++++++ unit_tests/operator/Test_DivImpl.cpp | 132 ++++++++++++++++++ 5 files changed, 278 insertions(+) create mode 100644 include/aidge/backend/cpu/operator/DivImpl.hpp create mode 100644 include/aidge/backend/cpu/operator/DivImpl_forward_kernels.hpp create mode 100644 src/operator/DivImpl.cpp create mode 100644 unit_tests/operator/Test_DivImpl.cpp diff --git a/include/aidge/backend/cpu.hpp b/include/aidge/backend/cpu.hpp index cc1579ea..71d84999 100644 --- a/include/aidge/backend/cpu.hpp +++ b/include/aidge/backend/cpu.hpp @@ -19,6 +19,7 @@ #include "aidge/backend/cpu/operator/BatchNormImpl.hpp" #include "aidge/backend/cpu/operator/ConvDepthWiseImpl.hpp" #include "aidge/backend/cpu/operator/ConvImpl.hpp" +#include "aidge/backend/cpu/operator/DivImpl.hpp" #include "aidge/backend/cpu/operator/FCImpl.hpp" #include "aidge/backend/cpu/operator/LeakyReLUImpl.hpp" #include "aidge/backend/cpu/operator/MatMulImpl.hpp" diff --git a/include/aidge/backend/cpu/operator/DivImpl.hpp b/include/aidge/backend/cpu/operator/DivImpl.hpp new file mode 100644 index 00000000..8d42fa97 --- /dev/null +++ b/include/aidge/backend/cpu/operator/DivImpl.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_DIVIMPL_H_ +#define AIDGE_CPU_OPERATOR_DIVIMPL_H_ + +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/operator/Div.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" +#include <memory> +#include <vector> + +namespace Aidge { +// class Div_Op; + +// compute kernel registry for forward and backward +class DivImplForward_cpu + : public Registrable<DivImplForward_cpu, std::tuple<DataType, DataType, DataType>, void(const std::size_t, const void*, const void*,void*)> { +}; +class DivImplBackward_cpu + : public Registrable<DivImplBackward_cpu, std::tuple<DataType, DataType, DataType>, void(const std::size_t, const void*, const void*, void*)> { +}; + +class DivImpl_cpu : public OperatorImpl { +public: + DivImpl_cpu(const Div_Op& op) : OperatorImpl(op) {} + + static std::unique_ptr<DivImpl_cpu> create(const Div_Op& op) { + return std::make_unique<DivImpl_cpu>(op); + } + + NbElts_t getNbRequiredProtected(const IOIndex_t inputIdx) const override final; + void forward() override; +}; + +namespace { +static Registrar<Div_Op> registrarDivImpl_cpu("cpu", Aidge::DivImpl_cpu::create); +} +} // namespace Aidge + +#endif /* AIDGE_CPU_OPERATOR_DIVIMPL_H_ */ diff --git a/include/aidge/backend/cpu/operator/DivImpl_forward_kernels.hpp b/include/aidge/backend/cpu/operator/DivImpl_forward_kernels.hpp new file mode 100644 index 00000000..3bb3975e --- /dev/null +++ b/include/aidge/backend/cpu/operator/DivImpl_forward_kernels.hpp @@ -0,0 +1,51 @@ +/******************************************************************************** + * 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_DIVIMPL_FORWARD_KERNEL_H_ +#define AIDGE_CPU_OPERATOR_DIVIMPL_FORWARD_KERNEL_H_ + +#include "aidge/utils/Registrar.hpp" +#include <cmath> +#include <iostream> +#include "aidge/backend/cpu/operator/DivImpl.hpp" + +namespace Aidge { +template <class I1, class I2, class O> +void DivImpl_cpu_forward_kernel(std::size_t inputLenght, + const void* input1_, + const void* input2_, + void* output_) { + + const I1* input_1 = static_cast<const I1*>(input1_); + const I2* input_2 = static_cast<const I2*>(input2_); + O* output = static_cast<O*>(output_); + + for (std::size_t i = 0; i < inputLenght; ++i) { + //TODO: handle Div of two tensors the same size + output[i] = input_1[i] / input_2[0]; + } +} + +namespace { +// TODO: add support for Div(float, int) +static Registrar<DivImplForward_cpu> registrarDivImplForward_cpu_Float32( + {DataType::Float32, DataType::Float32, DataType::Float32}, + Aidge::DivImpl_cpu_forward_kernel<float, float, float>); +static Registrar<DivImplForward_cpu> registrarDivImplForward_cpu_Int32( + {DataType::Int32, DataType::Int32, DataType::Int32}, + Aidge::DivImpl_cpu_forward_kernel<int, int, int>); +static Registrar<DivImplForward_cpu> registrarDivImplForward_cpu_Float64( + {DataType::Float64, DataType::Float64, DataType::Float64}, + Aidge::DivImpl_cpu_forward_kernel<double, double, double>); +} // namespace +} // namespace Aidge + +#endif /* AIDGE_CPU_OPERATOR_DIVIMPL_FORWARD_KERNEL_H_ */ diff --git a/src/operator/DivImpl.cpp b/src/operator/DivImpl.cpp new file mode 100644 index 00000000..e0d4cdf8 --- /dev/null +++ b/src/operator/DivImpl.cpp @@ -0,0 +1,44 @@ +/******************************************************************************** + * 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/Div.hpp" +#include "aidge/utils/Types.h" + +#include "aidge/backend/cpu/operator/DivImpl.hpp" +#include "aidge/backend/cpu/operator/DivImpl_forward_kernels.hpp" + +Aidge::NbElts_t Aidge::DivImpl_cpu::getNbRequiredProtected(const Aidge::IOIndex_t /*inputIdx*/) const { + // this implementation can be in-place + return 0; +} + +void Aidge::DivImpl_cpu::forward() { + assert(mOp.getInput(0) && "missing input #0"); + assert(mOp.getInput(1) && "missing input #1"); + + // Find the correct kernel type + auto kernelFunc = Registrar<DivImplForward_cpu>::create({ + mOp.getInput(0)->dataType(), + mOp.getInput(1)->dataType(), + mOp.getOutput(0)->dataType()}); + + // Call kernel + kernelFunc(std::static_pointer_cast<Tensor>(mOp.getInput(0))->size(), + mOp.getInput(0)->getImpl()->rawPtr(), + mOp.getInput(1)->getImpl()->rawPtr(), + mOp.getOutput(0)->getImpl()->rawPtr()); +} diff --git a/unit_tests/operator/Test_DivImpl.cpp b/unit_tests/operator/Test_DivImpl.cpp new file mode 100644 index 00000000..764f63c4 --- /dev/null +++ b/unit_tests/operator/Test_DivImpl.cpp @@ -0,0 +1,132 @@ +/******************************************************************************** + * 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/Div.hpp" + +#include "aidge/backend/cpu.hpp" + +#include <memory> + +using namespace Aidge; + +TEST_CASE("[cpu/operator] Div(forward)") { + SECTION("2D Tensor") { + std::shared_ptr<Tensor> input_1 = std::make_shared<Tensor>(Array2D<float,2,2> { + { + {0.07607108, 0.44075000}, + {0.19494885, 0.20071143} + } + }); + std::shared_ptr<Tensor> input_2 = std::make_shared<Tensor>(Array2D<float,1,1>{{0.5}}); + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array2D<float,2,2> { + { + {0.15214217, 0.88150001}, + {0.38989770, 0.40142286} + } + }); + + std::shared_ptr<Node> myDiv = Div(); + myDiv->getOperator()->setDatatype(DataType::Float32); + myDiv->getOperator()->setBackend("cpu"); + myDiv->getOperator()->associateInput(0, input_1); + myDiv->getOperator()->associateInput(1, input_2); + myDiv->getOperator()->computeOutputDims(); + myDiv->forward(); + + float* resPtr = static_cast<float*>(myDiv->getOperator()->getOutput(0)->getImpl()->rawPtr()); + float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr()); + for (std::size_t i = 0; i< 4; ++i) { + REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001); + } + + } + + SECTION("4D Tensor") { + std::shared_ptr<Tensor> input_1 = std::make_shared<Tensor>(Array4D<float,2,3,3,3> { + { + { + {{0.25675946, 0.36265653, 0.22386390}, + {0.30483031, 0.97449398, 0.73871714}, + {0.36169255, 0.04510212, 0.27525920}}, + + {{0.73255682, 0.03885978, 0.24181491}, + {0.14465559, 0.86070061, 0.88848090}, + {0.74408931, 0.87412918, 0.19800508}}, + + {{0.43551809, 0.73437816, 0.37513995}, + {0.25414777, 0.06396711, 0.98708153}, + {0.02140611, 0.84974837, 0.62108254}} + }, + { + {{0.86227137, 0.69357753, 0.41814715}, + {0.76048166, 0.46306920, 0.05907208}, + {0.76625377, 0.91793799, 0.92988223}}, + + {{0.34362513, 0.85009813, 0.21107805}, + {0.65575773, 0.38140792, 0.48540717}, + {0.10045588, 0.85803932, 0.23778951}}, + + {{0.30316389, 0.04176688, 0.17290735}, + {0.07942408, 0.48647392, 0.39440966}, + {0.26543915, 0.92589515, 0.83948994}} + } + } + }); + std::shared_ptr<Tensor> input_2 = std::make_shared<Tensor>(Array2D<float,1,1>{{3.0}}); + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array4D<float,2,3,3,3> { + { + { + {{0.08558649, 0.12088551, 0.07462130}, + {0.10161010, 0.32483134, 0.24623905}, + {0.12056419, 0.01503404, 0.09175307}}, + + {{0.24418561, 0.01295326, 0.08060497}, + {0.04821853, 0.28690019, 0.29616031}, + {0.24802977, 0.29137638, 0.06600169}}, + + {{0.14517270, 0.24479271, 0.12504666}, + {0.08471593, 0.02132237, 0.32902718}, + {0.00713537, 0.28324947, 0.20702751}} + }, + { + {{0.28742379, 0.23119251, 0.13938238}, + {0.25349388, 0.15435641, 0.01969069}, + {0.25541791, 0.30597934, 0.30996075}}, + + {{0.11454171, 0.28336605, 0.07035935}, + {0.21858591, 0.12713598, 0.16180240}, + {0.03348529, 0.28601310, 0.07926317}}, + + {{0.10105463, 0.01392229, 0.05763578}, + {0.02647469, 0.16215797, 0.13146989}, + {0.08847972, 0.30863172, 0.27982998}} + } + } + }); + + std::shared_ptr<Node> myDiv = Div(); + myDiv->getOperator()->setDatatype(DataType::Float32); + myDiv->getOperator()->setBackend("cpu"); + myDiv->getOperator()->associateInput(0, input_1); + myDiv->getOperator()->associateInput(1, input_2); + myDiv->getOperator()->computeOutputDims(); + myDiv->forward(); + + float* resPtr = static_cast<float*>(myDiv->getOperator()->getOutput(0)->getImpl()->rawPtr()); + float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr()); + for (std::size_t i = 0; i< 54; ++i) { + REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001); + } + } +} \ No newline at end of file -- GitLab