/******************************************************************************** * 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_REDUCEMEAN_H_ #define AIDGE_CORE_OPERATOR_REDUCEMEAN_H_ #include <algorithm> // std::for_each #include <array> #include <cmath> #include <cstdint> // std::int32_t #include <numeric> #include <vector> #include "aidge/data/Tensor.hpp" #include "aidge/graph/Node.hpp" #include "aidge/operator/OperatorTensor.hpp" #include "aidge/operator/Producer.hpp" #include "aidge/utils/StaticAttributes.hpp" #include "aidge/utils/Registrar.hpp" #include "aidge/utils/Types.h" namespace Aidge { enum class ReduceMeanAttr { Axes, KeepDims }; template <DimIdx_t DIM> class ReduceMean_Op : public OperatorTensor, public Registrable<ReduceMean_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const ReduceMean_Op<DIM> &)>, public StaticAttributes<ReduceMeanAttr, std::array<std::int32_t, DIM>, DimSize_t> { public: static const std::string Type; ReduceMean_Op() = delete; using Attributes_ = StaticAttributes<ReduceMeanAttr, std::array<std::int32_t, DIM>, DimSize_t>; template <ReduceMeanAttr e> using attr = typename Attributes_::template attr<e>; constexpr ReduceMean_Op(const std::array<std::int32_t, DIM> &axes, DimSize_t keep_dims) : OperatorTensor(Type, 1, 0, 1), Attributes_(attr<ReduceMeanAttr::Axes>(axes), attr<ReduceMeanAttr::KeepDims>(keep_dims)) {} /** * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ ReduceMean_Op(const ReduceMean_Op<DIM>& op) : OperatorTensor(op), Attributes_(op) { mImpl = op.mImpl ? Registrar<ReduceMean_Op<DIM>>::create(mOutputs[0]->getImpl()->backend())(*this) : nullptr; } /** * @brief Clone the operator using its copy-constructor. * @see Operator::ReduceMean_Op */ std::shared_ptr<Operator> clone() const override { return std::make_shared<ReduceMean_Op<DIM>>(*this); } void computeOutputDims() override final { if (!getInput(0)) { AIDGE_THROW_OR_ABORT(std::runtime_error, "Every input should be associated with a Tensor"); } if (!getInput(0)->empty()) { // make Axes attribute positive std::array<std::int32_t, DIM>& axes = this->template getAttr<ReduceMeanAttr::Axes>(); std::for_each(axes.begin(), axes.end(), [&] (std::int32_t& val) { if (val < 0) val+=static_cast<std::int32_t>(getInput(0)->nbDims()); }); std::sort(axes.begin(), axes.end()); // build output dimensions std::vector<DimSize_t> outDims = getInput(0)->dims(); if (this->template getAttr<ReduceMeanAttr::KeepDims>()) { std::for_each(axes.begin(), axes.end(), [&outDims] (const std::int32_t& val) { outDims[val] = 1; }); } else { for (auto it = axes.crbegin(); it != axes.crend(); ++it) outDims.erase(outDims.begin() + static_cast<std::size_t>(*it)); } if(outDims.size()>0) mOutputs[0]->resize(outDims); else mOutputs[0]->resize({1}); } } void setBackend(const std::string &name, DeviceIdx_t device = 0) override { mImpl = Registrar<ReduceMean_Op<DIM>>::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"}; } }; template <std::array<DimSize_t, 1>::size_type DIM> inline std::shared_ptr<Node> ReduceMean(const std::array<std::int32_t, DIM> &axes, DimSize_t keep_dims=1, const std::string& name = "") { // FIXME: properly handle default w&b initialization in every cases static_assert(DIM<=MaxDim,"Too many kernel dimensions required by ReduceMean, not supported"); return std::make_shared<Node>(std::make_shared<ReduceMean_Op<static_cast<DimIdx_t>(DIM)>>(axes, keep_dims), name); } // helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction template <DimSize_t DIM> inline std::shared_ptr<Node> ReduceMean( std::int32_t const (&axes)[DIM], DimSize_t keep_dims = 1, const std::string& name = "") { static_assert(DIM<=MaxDim,"Too many kernel dimensions required by ReduceMean, not supported"); return ReduceMean(to_array(axes), keep_dims, name); } template <DimIdx_t DIM> const std::string ReduceMean_Op<DIM>::Type = "ReduceMean"; } // namespace Aidge namespace { template <> const char *const EnumStrings<Aidge::ReduceMeanAttr>::data[] = {"Axes", "KeepDims"}; } #endif /* AIDGE_CORE_OPERATOR_REDUCEMEAN_H_ */