diff --git a/include/aidge/operator/ReduceMean.hpp b/include/aidge/operator/ReduceMean.hpp index 686ffd86c3e5e40fae2186b87572a179068b5417..10aa7356e16d569cfe290b74fcdfc7960a4e1140 100644 --- a/include/aidge/operator/ReduceMean.hpp +++ b/include/aidge/operator/ReduceMean.hpp @@ -26,7 +26,7 @@ #include "aidge/utils/Types.h" namespace Aidge { -enum class ReduceMeanAttr { Axes, KeepDims }; +enum class ReduceMeanAttr { Axes, KeepDims, NoopWithEmptyAxes }; class ReduceMean_Op : public OperatorTensor, public Registrable<ReduceMean_Op, std::string, std::shared_ptr<OperatorImpl>(const ReduceMean_Op &)> { @@ -37,6 +37,7 @@ public: private: using Attributes_ = StaticAttributes<ReduceMeanAttr, std::vector<std::int32_t>, + DimSize_t, DimSize_t>; template <ReduceMeanAttr e> using attr = typename Attributes_::template attr<e>; @@ -45,11 +46,12 @@ private: public: ReduceMean_Op() = delete; - ReduceMean_Op(const std::vector<std::int32_t>& axes, DimSize_t keep_dims) + ReduceMean_Op(const std::vector<std::int32_t>& axes, DimSize_t keep_dims, DimSize_t noop_with_empty_axes) : OperatorTensor(Type, {InputCategory::Data}, 1), mAttributes(std::make_shared<Attributes_>( attr<ReduceMeanAttr::Axes>(axes), - attr<ReduceMeanAttr::KeepDims>(keep_dims))) + attr<ReduceMeanAttr::KeepDims>(keep_dims), + attr<ReduceMeanAttr::NoopWithEmptyAxes>(noop_with_empty_axes))) {} /** @@ -82,6 +84,7 @@ public: inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; } inline std::vector<std::int32_t>& axes() const noexcept { return mAttributes -> getAttr<ReduceMeanAttr::Axes>(); } inline DimSize_t& keepDims() const noexcept { return mAttributes -> getAttr<ReduceMeanAttr::KeepDims>(); } + inline DimSize_t& noopWithEmptyAxes() const noexcept { return mAttributes -> getAttr<ReduceMeanAttr::NoopWithEmptyAxes>(); } static const std::vector<std::string> getInputsName() { @@ -103,10 +106,11 @@ public: */ inline std::shared_ptr<Node> ReduceMean(const std::vector<std::int32_t> &axes={}, DimSize_t keep_dims=1, + DimSize_t noop_with_empty_axes=0, const std::string& name = "") { // FIXME: properly handle default w&b initialization in every cases AIDGE_ASSERT(axes.size()<=MaxDim, "Too many kernel dimensions required by ReduceMean, not supported"); - return std::make_shared<Node>(std::make_shared<ReduceMean_Op>(axes, keep_dims), name); + return std::make_shared<Node>(std::make_shared<ReduceMean_Op>(axes, keep_dims, noop_with_empty_axes), name); } @@ -127,7 +131,7 @@ inline std::shared_ptr<Node> ReduceMean(const std::vector<std::int32_t> &axes={} namespace { template <> -const char *const EnumStrings<Aidge::ReduceMeanAttr>::data[] = {"axes", "keep_dims"}; +const char *const EnumStrings<Aidge::ReduceMeanAttr>::data[] = {"axes", "keep_dims", "noop_with_empty_axes"}; } #endif /* AIDGE_CORE_OPERATOR_REDUCEMEAN_H_ */ diff --git a/include/aidge/operator/ReduceSum.hpp b/include/aidge/operator/ReduceSum.hpp index 22aa01d11612ffcec4fa3ea48f791286f105373a..c179cfd1e6719667ff7de62837772f0828fc5f5b 100644 --- a/include/aidge/operator/ReduceSum.hpp +++ b/include/aidge/operator/ReduceSum.hpp @@ -26,7 +26,7 @@ #include "aidge/utils/Types.h" namespace Aidge { -enum class ReduceSumAttr { Axes, KeepDims }; +enum class ReduceSumAttr { Axes, KeepDims, NoopWithEmptyAxes }; class ReduceSum_Op : public OperatorTensor, public Registrable<ReduceSum_Op, std::string, std::shared_ptr<OperatorImpl>(const ReduceSum_Op &)> { @@ -37,6 +37,7 @@ public: private: using Attributes_ = StaticAttributes<ReduceSumAttr, std::vector<std::int32_t>, + DimSize_t, DimSize_t>; template <ReduceSumAttr e> using attr = typename Attributes_::template attr<e>; @@ -45,11 +46,12 @@ private: public: ReduceSum_Op() = delete; - ReduceSum_Op(const std::vector<std::int32_t>& axes, DimSize_t keep_dims) + ReduceSum_Op(const std::vector<std::int32_t>& axes, DimSize_t keep_dims, DimSize_t noop_with_empty_axes) : OperatorTensor(Type, {InputCategory::Data}, 1), mAttributes(std::make_shared<Attributes_>( attr<ReduceSumAttr::Axes>(axes), - attr<ReduceSumAttr::KeepDims>(keep_dims))) + attr<ReduceSumAttr::KeepDims>(keep_dims), + attr<ReduceSumAttr::NoopWithEmptyAxes>(noop_with_empty_axes))) {} /** @@ -82,6 +84,7 @@ public: inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; } inline std::vector<std::int32_t>& axes() const noexcept { return mAttributes -> getAttr<ReduceSumAttr::Axes>(); } inline DimSize_t& keepDims() const noexcept { return mAttributes -> getAttr<ReduceSumAttr::KeepDims>(); } + inline DimSize_t& noopWithEmptyAxes() const noexcept { return mAttributes -> getAttr<ReduceSumAttr::NoopWithEmptyAxes>(); } static const std::vector<std::string> getInputsName() { @@ -103,17 +106,18 @@ public: */ inline std::shared_ptr<Node> ReduceSum(const std::vector<std::int32_t> &axes={}, DimSize_t keep_dims=1, + DimSize_t noop_with_empty_axes=0, const std::string& name = "") { // FIXME: properly handle default w&b initialization in every cases AIDGE_ASSERT(axes.size()<=MaxDim, "Too many kernel dimensions required by ReduceSum, not supported"); - return std::make_shared<Node>(std::make_shared<ReduceSum_Op>(axes, keep_dims), name); + return std::make_shared<Node>(std::make_shared<ReduceSum_Op>(axes, keep_dims, noop_with_empty_axes), name); } } // namespace Aidge namespace { template <> -const char *const EnumStrings<Aidge::ReduceSumAttr>::data[] = {"axes", "keep_dims"}; +const char *const EnumStrings<Aidge::ReduceSumAttr>::data[] = {"axes", "keep_dims", "noop_with_empty_axes"}; } #endif /* AIDGE_CORE_OPERATOR_REDUCESUM_H_ */ diff --git a/python_binding/operator/pybind_ReduceMean.cpp b/python_binding/operator/pybind_ReduceMean.cpp index dae50b9af7512c5ec78f8fdf5352f527d2596bfd..e8940bad91db6e9fdb87723c60afb974497b1ca1 100644 --- a/python_binding/operator/pybind_ReduceMean.cpp +++ b/python_binding/operator/pybind_ReduceMean.cpp @@ -28,20 +28,22 @@ void declare_ReduceMeanOp(py::module &m) { const std::string pyClassName("ReduceMeanOp"); py::class_<ReduceMean_Op, std::shared_ptr<ReduceMean_Op>, OperatorTensor>( m, pyClassName.c_str(), py::multiple_inheritance()) - .def(py::init<std::vector<std::int32_t>, DimSize_t>(), py::arg("axes"), py::arg("keep_dims")) + .def(py::init<std::vector<std::int32_t>, DimSize_t, DimSize_t>(), py::arg("axes"), py::arg("keep_dims"), py::arg("noop_with_empty_axes")) .def_static("get_inputs_name", &ReduceMean_Op::getInputsName) .def_static("get_outputs_name", &ReduceMean_Op::getOutputsName) ; declare_registrable<ReduceMean_Op>(m, pyClassName); m.def("ReduceMean", [](const std::vector<int>& axes, - DimSize_t keepDims, - const std::string& name) { + DimSize_t keepDims, + DimSize_t noopWithEmptyAxes, + const std::string& name) { // AIDGE_ASSERT(axes.size() == DIM, "axes size [{}] does not match DIM [{}]", axes.size(), DIM); - return ReduceMean(axes, keepDims, name); + return ReduceMean(axes, keepDims, noopWithEmptyAxes, name); }, py::arg("axes") = std::vector<std::int32_t>(), py::arg("keep_dims") = 1, + py::arg("noop_with_empty_axes") = 0, py::arg("name") = ""); } diff --git a/python_binding/operator/pybind_ReduceSum.cpp b/python_binding/operator/pybind_ReduceSum.cpp index 5a2c3eb1f5bbccce6a84e1a453047492c67b33bd..3a71d8cf092659cf26d1960b39b3f2fbe2d4b228 100644 --- a/python_binding/operator/pybind_ReduceSum.cpp +++ b/python_binding/operator/pybind_ReduceSum.cpp @@ -28,7 +28,7 @@ void init_ReduceSum(py::module &m) { const std::string pyClassName("ReduceSumOp"); py::class_<ReduceSum_Op, std::shared_ptr<ReduceSum_Op>, OperatorTensor>( m, pyClassName.c_str(), py::multiple_inheritance()) - .def(py::init<std::vector<std::int32_t>, DimSize_t>(), py::arg("axes"), py::arg("keep_dims")) + .def(py::init<std::vector<std::int32_t>, DimSize_t, DimSize_t>(), py::arg("axes"), py::arg("keep_dims"), py::arg("noop_with_empty_axes")) .def_static("get_inputs_name", &ReduceSum_Op::getInputsName) .def_static("get_outputs_name", &ReduceSum_Op::getOutputsName) ; @@ -36,10 +36,12 @@ void init_ReduceSum(py::module &m) { m.def("ReduceSum", [](const std::vector<int>& axes, DimSize_t keepDims, + DimSize_t noopWithEmptyAxes, const std::string& name) { - return ReduceSum(axes, keepDims, name); + return ReduceSum(axes, keepDims, noopWithEmptyAxes, name); }, py::arg("axes") = std::vector<std::int32_t>(), py::arg("keep_dims") = 1, + py::arg("noop_with_empty_axes") = 0, py::arg("name") = ""); } } // namespace Aidge diff --git a/src/operator/ReduceMean.cpp b/src/operator/ReduceMean.cpp index 0e8cae9e951709a0c8e68bf04c5b1a0b9239ae21..7bbd2a60f8d7bfb3e49b507c01289646480f0b85 100644 --- a/src/operator/ReduceMean.cpp +++ b/src/operator/ReduceMean.cpp @@ -37,14 +37,20 @@ bool Aidge::ReduceMean_Op::forwardDims(bool /*allowDataDependency*/) { }); std::sort(axes.begin(), axes.end()); - if (axes.empty()) // if no axes are provided, reduce on all axes + // build output dimensions + std::vector<DimSize_t> outDims = getInput(0)->dims(); + + if (axes.empty()) { + if(mAttributes->template getAttr<ReduceMeanAttr::NoopWithEmptyAxes>()) { + mOutputs[0]->resize(outDims); + return true; + } + // if no axes are provided and NoopWithEmptyAxes is false, reduce on all axes axes.resize(getInput(0)->nbDims()); std::iota(axes.begin(), axes.end(), 0); } - // build output dimensions - std::vector<DimSize_t> outDims = getInput(0)->dims(); if (mAttributes->template getAttr<ReduceMeanAttr::KeepDims>()) { std::for_each(axes.cbegin(), axes.cend(), [&outDims] (const std::int32_t& val) { outDims[val] = 1; }); } diff --git a/src/operator/ReduceSum.cpp b/src/operator/ReduceSum.cpp index 317292632504cd63cb21a6827c0dc1fb87af2a42..aa8271f4c1696d46274e536e14d255525d848f80 100644 --- a/src/operator/ReduceSum.cpp +++ b/src/operator/ReduceSum.cpp @@ -37,14 +37,20 @@ bool Aidge::ReduceSum_Op::forwardDims(bool /*allowDataDependency*/) { }); std::sort(axes.begin(), axes.end()); - if (axes.empty()) // if no axes are provided, reduce on all axes + // build output dimensions + std::vector<DimSize_t> outDims = getInput(0)->dims(); + + if (axes.empty()) { + if(mAttributes->template getAttr<ReduceSumAttr::NoopWithEmptyAxes>()) { + mOutputs[0]->resize(outDims); + return true; + } + // if no axes are provided and NoopWithEmptyAxes is false, reduce on all axes axes.resize(getInput(0)->nbDims()); std::iota(axes.begin(), axes.end(), 0); } - // build output dimensions - std::vector<DimSize_t> outDims = getInput(0)->dims(); if (mAttributes->template getAttr<ReduceSumAttr::KeepDims>()) { std::for_each(axes.cbegin(), axes.cend(), [&outDims] (const std::int32_t& val) { outDims[val] = 1; }); }