diff --git a/include/aidge/aidge.hpp b/include/aidge/aidge.hpp index 6c4ca93ce28c0a8c769606f07b1badee676423fd..84c5404491223746af89e0bb6f8a7c9a40017133 100644 --- a/include/aidge/aidge.hpp +++ b/include/aidge/aidge.hpp @@ -44,6 +44,7 @@ #include "aidge/operator/FC.hpp" #include "aidge/operator/Gather.hpp" #include "aidge/operator/GenericOperator.hpp" +#include "aidge/operator/GlobalAveragePooling.hpp" #include "aidge/operator/MatMul.hpp" #include "aidge/operator/MaxPooling.hpp" #include "aidge/operator/MetaOperator.hpp" diff --git a/include/aidge/operator/GlobalAveragePooling.hpp b/include/aidge/operator/GlobalAveragePooling.hpp new file mode 100644 index 0000000000000000000000000000000000000000..71b332bf1dacae1990a0d0ea89c139ce7be38ec2 --- /dev/null +++ b/include/aidge/operator/GlobalAveragePooling.hpp @@ -0,0 +1,66 @@ +/******************************************************************************** + * 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_CORE_OPERATOR_GLOBAL_AVERAGE_POOLING_H_ +#define AIDGE_CORE_OPERATOR_GLOBAL_AVERAGE_POOLING_H_ + +#include <memory> + +#include "aidge/utils/Registrar.hpp" +#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/data/Tensor.hpp" +#include "aidge/data/Data.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge +{ + + /** + * @brief Description for the tensor data structure. + * @details Sets the properties of the tensor without actually containing any data. + * Contains a pointer to an actual contiguous implementation of data. + */ + class GlobalAveragePooling_Op : public OperatorTensor, + public Registrable<GlobalAveragePooling_Op, std::string, std::unique_ptr<OperatorImpl>(const GlobalAveragePooling_Op &)> + { + public: + static const std::string Type ; + + GlobalAveragePooling_Op() : OperatorTensor(Type, 1, 0, 1) {} + + GlobalAveragePooling_Op(const GlobalAveragePooling_Op &op) : OperatorTensor(op) + { + mImpl = op.mImpl ? Registrar<GlobalAveragePooling_Op>::create(op.mOutputs[0]->getImpl()->backend())(*this) : nullptr; + } + + std::shared_ptr<Operator> clone() const override { return std::make_shared<GlobalAveragePooling_Op>(*this); } + + void computeOutputDims() override final; + + void setBackend(const std::string &name, DeviceIdx_t device = 0) override + { + mImpl = Registrar<GlobalAveragePooling_Op>::create(name)(*this); + mOutputs[0]->setBackend(name, device); + } + + static const std::vector<std::string> getInputsName() { return {"data_input"}; } + static const std::vector<std::string> getOutputsName() { return {"data_output"}; } + }; + + inline std::shared_ptr<Node> GlobalAveragePooling(const std::string &name = "") + { + return std::make_shared<Node>(std::make_shared<GlobalAveragePooling_Op>(), name); + } +} + +#endif /* AIDGE_CORE_OPERATOR_GLOBAL_AVERAGE_POOLING_H_ */ \ No newline at end of file diff --git a/python_binding/operator/pybind_GlobalAveragePooling.cpp b/python_binding/operator/pybind_GlobalAveragePooling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f5cd4d05a4ff87475214c9bc646dc507be3d55c --- /dev/null +++ b/python_binding/operator/pybind_GlobalAveragePooling.cpp @@ -0,0 +1,28 @@ +/******************************************************************************** + * 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 <pybind11/pybind11.h> + +#include "aidge/operator/GlobalAveragePooling.hpp" +#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/utils/Attributes.hpp" + +namespace py = pybind11; +namespace Aidge { + +void init_GlobalAveragePooling(py::module& m) { + py::class_<GlobalAveragePooling_Op, std::shared_ptr<GlobalAveragePooling_Op>, OperatorTensor, Attributes>(m, "GlobalAveragePooling", py::multiple_inheritance()) + .def("get_inputs_name", &GlobalAveragePooling_Op::getInputsName) + .def("get_outputs_name", &GlobalAveragePooling_Op::getOutputsName); + + m.def("Hardmax", &Hardmax, py::arg("name") = ""); +} +} // namespace Aidge \ No newline at end of file diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp index ebf73e85583d3300ce68078dc8236001a4db1c96..40ebc92aa872baacb2e7a87060f560d05d615cff 100644 --- a/python_binding/pybind_core.cpp +++ b/python_binding/pybind_core.cpp @@ -37,6 +37,7 @@ void init_Erf(py::module&); void init_FC(py::module&); void init_Gather(py::module&); void init_GenericOperator(py::module&); +void init_GlobalAveragePooling(py::module&); void init_LeakyReLU(py::module&); void init_MatMul(py::module&); void init_MaxPooling(py::module&); @@ -95,6 +96,7 @@ void init_Aidge(py::module& m){ init_FC(m); init_Gather(m); init_GenericOperator(m); + init_GlobalAveragePooling(m); init_LeakyReLU(m); init_MatMul(m); init_MaxPooling(m); diff --git a/src/operator/GlobalAveragePooling.cpp b/src/operator/GlobalAveragePooling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39b5fa65a507be6c42feec38ba39d2e3f2ab2e5b --- /dev/null +++ b/src/operator/GlobalAveragePooling.cpp @@ -0,0 +1,36 @@ +/******************************************************************************** + * 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 <vector> + +#include "aidge/operator/GlobalAveragePooling.hpp" + +const std::string Aidge::GlobalAveragePooling_Op::Type = "GlobalAveragePooling"; + +void Aidge::GlobalAveragePooling_Op::computeOutputDims() +{ + // error checking + if (!getInput(0)) + { + AIDGE_THROW_OR_ABORT(std::runtime_error, "At least one input was not connected"); + } + else if (getInput(0)->dims().size() < 3) + { + AIDGE_THROW_OR_ABORT(std::runtime_error, "GlobalAveragePool needs at least 3 dimensions input, number of input dim : %lu", getInput(0)->dims().size()); + } + else + { + // Global average pooling takes each filter, averages its values and uses it as an output(Much like a fancier flatten). + //1st dim is batch 2nd is number of filter + const std::vector<DimSize_t> out_dims(getInput(0)->dims().at(0), getInput(0)->dims().at(1)); + mOutputs[0]->resize(out_dims); + } +} diff --git a/unit_tests/operator/Test_GlobalAveragePooling_Op.cpp b/unit_tests/operator/Test_GlobalAveragePooling_Op.cpp new file mode 100644 index 0000000000000000000000000000000000000000..355aeb20ba4b5884b01ba0ea84b7db145d7a0829 --- /dev/null +++ b/unit_tests/operator/Test_GlobalAveragePooling_Op.cpp @@ -0,0 +1,79 @@ +/******************************************************************************** + * 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 <cstddef> // std::size_t +#include <memory> +#include <random> // std::random_device, std::mt19937, std::uniform_int_distribution +#include <vector> + +#include "aidge/data/Tensor.hpp" +#include "aidge/operator/GlobalAveragePooling.hpp" +#include "aidge/operator/OperatorTensor.hpp" + +namespace Aidge +{ + TEST_CASE("[core/operator] GlobalAveragePooling_Op(computeOutputDims)", "[GlobalAveragePooling][computeOutputDims]") + { + constexpr std::uint16_t NB_TRIALS = 10; + // Create a random number generator + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<std::size_t> dimsDist(1, 10); + std::uniform_int_distribution<std::size_t> inf3DimsDistribution(0, 2); + std::uniform_int_distribution<std::size_t> sup3DimsDistribution(3, 10); + + // Create the GlobalAveragePooling Operator + std::shared_ptr<Node> myGlobAvgPool = GlobalAveragePooling(); + auto op = std::static_pointer_cast<OperatorTensor>(myGlobAvgPool->getOperator()); + + // input_0 + std::shared_ptr<Tensor> input_T = std::make_shared<Tensor>(); + SECTION("input association") + { + REQUIRE_THROWS(op->computeOutputDims()); + } + op->associateInput(0, input_T); + + SECTION("nbDim < 3") + { + const std::size_t nb_dims = inf3DimsDistribution(gen) + 1; + for (uint16_t trial; trial < NB_TRIALS; ++trial) + { + std::vector<std::size_t> dims0(nb_dims); + for (uint16_t i; i < nb_dims; ++i) + { + dims0[i] = dimsDist(gen) + 1; + } + + input_T->resize(dims0); + REQUIRE_THROWS(op->computeOutputDims()); + } + } + + SECTION("nbDim > 3") + { + const std::size_t nb_dims = inf3DimsDistribution(gen) + 1; + for (uint16_t trial; trial < NB_TRIALS; ++trial) + { + std::vector<std::size_t> dims0(nb_dims); + for (uint16_t i; i < nb_dims; ++i) + { + dims0[i] = dimsDist(gen) + 1; + } + + input_T->resize(dims0); + REQUIRE_NOTHROW(op->computeOutputDims()); + REQUIRE((op->getOutput(0)->dims().size()) == static_cast<size_t>(2)); + } + } + } +} // namespace Aidge