From e5fab1bce2d040a1a66cab52f655998b617f9945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20KUBLER?= <gregoire.kubler@proton.me> Date: Tue, 10 Sep 2024 14:14:16 +0200 Subject: [PATCH] feat : operator constant of shape --- include/aidge/backend/cpu.hpp | 1 + .../cpu/operator/ConstantOfShapeImpl.hpp | 52 ++++++++ .../ConstantOfShapeImpl_forward_kernels.hpp | 78 ++++++++++++ src/operator/ConstantOfShapeImpl.cpp | 40 ++++++ .../operator/Test_ConstantOfShapeImpl.cpp | 120 ++++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 include/aidge/backend/cpu/operator/ConstantOfShapeImpl.hpp create mode 100644 include/aidge/backend/cpu/operator/ConstantOfShapeImpl_forward_kernels.hpp create mode 100644 src/operator/ConstantOfShapeImpl.cpp create mode 100644 unit_tests/operator/Test_ConstantOfShapeImpl.cpp diff --git a/include/aidge/backend/cpu.hpp b/include/aidge/backend/cpu.hpp index 4134f5c5..963895c1 100644 --- a/include/aidge/backend/cpu.hpp +++ b/include/aidge/backend/cpu.hpp @@ -21,6 +21,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/ConstantOfShapeImpl.hpp" #include "aidge/backend/cpu/operator/DivImpl.hpp" #include "aidge/backend/cpu/operator/ErfImpl.hpp" #include "aidge/backend/cpu/operator/FCImpl.hpp" diff --git a/include/aidge/backend/cpu/operator/ConstantOfShapeImpl.hpp b/include/aidge/backend/cpu/operator/ConstantOfShapeImpl.hpp new file mode 100644 index 00000000..80efb31d --- /dev/null +++ b/include/aidge/backend/cpu/operator/ConstantOfShapeImpl.hpp @@ -0,0 +1,52 @@ +/******************************************************************************** + * 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_CONSTANTOFSHAPEIMPL_H_ +#define AIDGE_CPU_OPERATOR_CONSTANTOFSHAPEIMPL_H_ + +#include <cstddef> +#include <memory> +#include <vector> + +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/operator/ConstantOfShape.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { +// class ConstantOfShape_op; + +class ConstantOfShapeImplForward_cpu + : public Registrable< + ConstantOfShapeImplForward_cpu, std::tuple<DataType>, + void(const std::vector<DimSize_t>, const Tensor&, void *)> {}; + +class ConstantOfShapeImpl_cpu : public OperatorImpl { +public: + ConstantOfShapeImpl_cpu(const ConstantOfShape_Op &op) + : OperatorImpl(op, "cpu") {} + + static std::unique_ptr<ConstantOfShapeImpl_cpu> + create(const ConstantOfShapeImpl_cpu &op) { + return std::make_unique<ConstantOfShapeImpl_cpu>(op); + } + + void forward() override; +}; + +namespace { +static Registrar<ConstantOfShape_Op> registrarConstantOfShapeImpl_cpu( + "cpu", Aidge::ConstantOfShapeImpl_cpu::create); +} +} // namespace Aidge + +#endif /* _AIDGE_CPU_OPERATOR_CONSTANTOFSHAPEIMPL_H_ */ + diff --git a/include/aidge/backend/cpu/operator/ConstantOfShapeImpl_forward_kernels.hpp b/include/aidge/backend/cpu/operator/ConstantOfShapeImpl_forward_kernels.hpp new file mode 100644 index 00000000..59a3475e --- /dev/null +++ b/include/aidge/backend/cpu/operator/ConstantOfShapeImpl_forward_kernels.hpp @@ -0,0 +1,78 @@ +/******************************************************************************** + * 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_CONSTANTOFSHAPEIMPL_FORWARD_KERNEL_H_ +#define AIDGE_CPU_OPERATOR_CONSTANTOFSHAPEIMPL_FORWARD_KERNEL_H_ + +#include <aidge/data/Tensor.hpp> +#include <aidge/data/half.hpp> +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <functional> // std::multiplies +#include <numeric> // std::accumulate +#include <vector> + +#include "aidge/backend/cpu/operator/ConstantOfShapeImpl.hpp" +#include "aidge/data/Data.hpp" +#include "aidge/utils/ErrorHandling.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { +template <class O> +void ConstantOfShapeimpl_cpu_forward_kernel( + const std::vector<DimSize_t> output_dims, const Tensor &value, + void *output_) { + + O *output = static_cast<O *>(output_); + O val; + std::copy(static_cast<O *>(value.getImpl()->hostPtr()), + static_cast<O *>(value.getImpl()->hostPtr()) + + static_cast<NbElts_t>(1), + &val); + const size_t output_size = std::accumulate( + output_dims.begin(), output_dims.end(), 1, std::multiplies<DimSize_t>()); + for (size_t i = 0; i < output_size; ++i) { + output[i] = val; + } +} + +// Then we add the Registrar declaration for different input/output types +namespace { +static Registrar<ConstantOfShapeImplForward_cpu> + registrarConstantOfShapeImplForward_cpu_Float16( + {DataType::Float16}, + Aidge::ConstantOfShapeimpl_cpu_forward_kernel<half_float::half>); +static Registrar<ConstantOfShapeImplForward_cpu> + registrarConstantOfShapeImplForward_cpu_Float32( + {DataType::Float32}, + Aidge::ConstantOfShapeimpl_cpu_forward_kernel<float>); +static Registrar<ConstantOfShapeImplForward_cpu> + registrarConstantOfShapeImplForward_cpu_Float64( + {DataType::Float64}, + Aidge::ConstantOfShapeimpl_cpu_forward_kernel<double>); +static Registrar<ConstantOfShapeImplForward_cpu> + registrarConstantOfShapeImplForward_cpu_Int16( + {DataType::Int16}, + Aidge::ConstantOfShapeimpl_cpu_forward_kernel<std::int16_t>); +static Registrar<ConstantOfShapeImplForward_cpu> + registrarConstantOfShapeImplForward_cpu_Int32( + {DataType::Int32}, + Aidge::ConstantOfShapeimpl_cpu_forward_kernel<std::int32_t>); +static Registrar<ConstantOfShapeImplForward_cpu> + registrarConstantOfShapeImplForward_cpu_Int64( + {DataType::Int64}, Aidge::ConstantOfShapeimpl_cpu_forward_kernel <std::int64_t>); +} // namespace +} // namespace Aidge + +#endif /* AIDGE_CPU_OPERATOR_CONSTANTOFSHAPEIMPL_FORWARD_KERNEL_H_ */ + diff --git a/src/operator/ConstantOfShapeImpl.cpp b/src/operator/ConstantOfShapeImpl.cpp new file mode 100644 index 00000000..7d727c04 --- /dev/null +++ b/src/operator/ConstantOfShapeImpl.cpp @@ -0,0 +1,40 @@ +/******************************************************************************** + * Copyright (c) 2024 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 "aidge/backend/cpu/operator/ConstantOfShapeImpl.hpp" + +#include <functional> +#include <memory> +#include <vector> + +#include "aidge/backend/cpu/operator/ConstantOfShapeImpl_forward_kernels.hpp" +#include "aidge/data/Data.hpp" +#include "aidge/data/Tensor.hpp" +#include "aidge/operator/ConstantOfShape.hpp" +#include "aidge/utils/ErrorHandling.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" + +void Aidge::ConstantOfShapeImpl_cpu::forward() { + const ConstantOfShape_Op &op_ = static_cast<const ConstantOfShape_Op &>(mOp); + // Check if input is provided + AIDGE_ASSERT(op_.getInput(0), "{} : Missing input 0", __func__); + + // Create the forward kernal with the wanted types + auto kernelFunc = Registrar<ConstantOfShapeImplForward_cpu>::create( + {op_.getOutput(0)->dataType()}); + + // Call kernel + kernelFunc(op_.getOutput(0)->dims(), + op_.value(), + op_.getOutput(0)->getImpl()->rawPtr()); +} + diff --git a/unit_tests/operator/Test_ConstantOfShapeImpl.cpp b/unit_tests/operator/Test_ConstantOfShapeImpl.cpp new file mode 100644 index 00000000..42505d38 --- /dev/null +++ b/unit_tests/operator/Test_ConstantOfShapeImpl.cpp @@ -0,0 +1,120 @@ +/******************************************************************************** + * 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 <algorithm> +#include <chrono> +#include <cmath> +#include <cstddef> // std::size_t +#include <cstdint> // std::uint16_t +#include <iostream> +#include <memory> +#include <numeric> // std::accumulate +#include <ostream> +#include <random> // std::random_device, std::mt19937, std::uniform_real_distribution + +#include "catch2/internal/catch_compiler_capabilities.hpp" +#include "catch2/internal/catch_enforce.hpp" +#include <catch2/catch_test_macros.hpp> +#include <catch2/generators/catch_generators_random.hpp> + +#include "aidge/data/Tensor.hpp" +#include "aidge/operator/ConstantOfShape.hpp" +#include "aidge/utils/TensorUtils.hpp" +#include <aidge/data/Data.hpp> +#include <aidge/data/half.hpp> +#include <aidge/filler/Filler.hpp> +#include <aidge/operator/OperatorTensor.hpp> +#include <aidge/operator/Reshape.hpp> +#include <aidge/utils/TensorUtils.hpp> +#include <aidge/utils/Types.h> + +namespace Aidge { +TEST_CASE("[cpu/operator] ConstantOfShape", "[ConstantOfShape][CPU]") { + constexpr std::uint16_t NBTRIALS = 10; + // Create a random number generator + auto random_seed = Catch::Generators::Detail::getSeed; + std::mt19937 gen(random_seed()); + std::uniform_real_distribution<float> valueDist( + 0.1f, 1.1f); // Random float distribution between 0 and 1 + std::uniform_int_distribution<DimSize_t> input_tensor_size_dist( + std::size_t(1), std::size_t(10)); + std::uniform_int_distribution<int64_t> input_tensor_values_dist( + std::size_t(1), std::size_t(7)); + std::uniform_real_distribution<double> operator_attr_value_dist(-100., 100.); + + /////////////////////////////////////////////// + // SETUP FUNCTIONS + auto generate_input_tensor = + [&gen, &input_tensor_size_dist, + &input_tensor_values_dist]() -> std::shared_ptr<Tensor> { + std::vector<DimSize_t> input_dims; + input_dims.push_back(input_tensor_size_dist(gen)); + + auto result = std::make_shared<Tensor>(input_dims); + result->setDataType(DataType::Int64); + result->setBackend("cpu"); + for (DimSize_t i = 0; i < result->size(); ++i) { + result->set<int64_t>(i, input_tensor_values_dist(gen)); + } + return result; + }; + + auto generate_random_operator = + [&gen, + &operator_attr_value_dist]() -> std::shared_ptr<ConstantOfShape_Op> { + auto node = ConstantOfShape(Tensor(operator_attr_value_dist(gen))); + auto op = std::static_pointer_cast<ConstantOfShape_Op>(node->getOperator()); + op->setDataType(DataType::Float64); + op->setBackend("cpu"); + return op; + }; + + auto generate_output_tensor = [](std::shared_ptr<Tensor> input_tensor, + std::shared_ptr<ConstantOfShape_Op> op) { + std::vector<DimSize_t> output_dims; + output_dims.reserve(input_tensor->size()); + for (DimSize_t i = 0; i < input_tensor->size(); ++i) { + output_dims.push_back(input_tensor->get<int64_t>(i)); + } + auto result = std::make_shared<Tensor>(output_dims); + result->setDataType(op->value().dataType()); + result->setBackend("cpu"); + constantFiller(result, op->value().get<double>(0)); + return result; + }; + + ///////////////////////////////////// + // BENCHMARKING + std::chrono::time_point<std::chrono::system_clock> start; + std::chrono::time_point<std::chrono::system_clock> end; + std::chrono::duration<double, std::micro> duration{}; + int number_of_operation{0}; + + SECTION("ConstantOfShapeImpl_cpu::forward()") { + for (int i = 0; i < NBTRIALS; ++i) { + auto input_T = generate_input_tensor(); + std::shared_ptr<ConstantOfShape_Op> op = generate_random_operator(); + auto output_T = generate_output_tensor(input_T, op); + op->associateInput(0, input_T); + + REQUIRE(op->forwardDims(true)); + REQUIRE_NOTHROW(op->forward()); + + CHECK(output_T->nbDims() == op->getOutput(0)->nbDims()); + for (DimIdx_t i = 0; i < output_T->nbDims(); ++i) { + CHECK(output_T->dims().at(i) == op->getOutput(0)->dims().at(i)); + } + CHECK(approxEq<double>(*output_T, *op->getOutput(0))); + } + } +} +} // namespace Aidge + -- GitLab