From 661f01fa8cd304b5596e1e1a1fe6d23e9d1f9044 Mon Sep 17 00:00:00 2001 From: Olivier BICHLER <olivier.bichler@cea.fr> Date: Fri, 22 Sep 2023 09:32:00 +0200 Subject: [PATCH] Removed padding from conv and pool and added Pad operator --- include/aidge/operator/AvgPooling.hpp | 31 ++- include/aidge/operator/Conv.hpp | 23 +-- include/aidge/operator/ConvDepthWise.hpp | 25 +-- include/aidge/operator/MaxPooling.hpp | 30 ++- include/aidge/operator/Pad.hpp | 230 +++++++++++++++++++++++ 5 files changed, 268 insertions(+), 71 deletions(-) create mode 100644 include/aidge/operator/Pad.hpp diff --git a/include/aidge/operator/AvgPooling.hpp b/include/aidge/operator/AvgPooling.hpp index bf76bd458..8bf5e21d1 100644 --- a/include/aidge/operator/AvgPooling.hpp +++ b/include/aidge/operator/AvgPooling.hpp @@ -26,15 +26,14 @@ #include "aidge/utils/Types.h" namespace Aidge { -enum class AvgPoolingParam { StrideDims, KernelDims, PaddingDims }; +enum class AvgPoolingParam { StrideDims, KernelDims }; template <DimIdx_t DIM> class AvgPooling_Op : public Operator, public Registrable<AvgPooling_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const AvgPooling_Op<DIM> &)>, public Parameterizable<AvgPoolingParam, std::array<DimSize_t, DIM>, - std::array<DimSize_t, DIM>, - std::array<DimSize_t, (DIM<<1) >> { + std::array<DimSize_t, DIM>> { private: // FIXME: change accessibility std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>(); @@ -47,19 +46,15 @@ public: using Parameterizable_ = Parameterizable<AvgPoolingParam, std::array<DimSize_t, DIM>, - std::array<DimSize_t, DIM>, - std::array<DimSize_t, (DIM<<1)> >; + std::array<DimSize_t, DIM>>; template <AvgPoolingParam e> using param = typename Parameterizable_::template param<e>; constexpr AvgPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims, - const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1)) : Operator(Type), Parameterizable_(param<AvgPoolingParam::StrideDims>(stride_dims), - param<AvgPoolingParam::KernelDims>(kernel_dims), - param<AvgPoolingParam::PaddingDims>(padding_dims)), - mOutput(std::make_shared<Tensor>()) { + param<AvgPoolingParam::KernelDims>(kernel_dims)) { setDatatype(DataType::Float32); } @@ -78,9 +73,7 @@ public: for (std::size_t dim = 0; dim < this->template get<AvgPoolingParam::KernelDims>().size() ; ++dim) { outputDims[dim+2] = 1 + static_cast<DimSize_t>( std::floor(static_cast<float>(mInput->dims()[dim+2] - - this->template get<AvgPoolingParam::KernelDims>()[dim] + - this->template get<AvgPoolingParam::PaddingDims>()[dim] + - this->template get<AvgPoolingParam::PaddingDims>()[dim+DIM]) / + this->template get<AvgPoolingParam::KernelDims>()[dim]) / static_cast<float>(this->template get<AvgPoolingParam::StrideDims>()[dim]))); } outputDims[1] = mInput->dims()[1]; @@ -147,11 +140,10 @@ public: template <std::array<DimSize_t, 1>::size_type DIM> inline std::shared_ptr<Node> AvgPooling(const std::array<DimSize_t, DIM> &kernel_dims, const std::string& name = "", - const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) { + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1)) { // FIXME: properly handle default w&b initialization in every cases static_assert(DIM<=MaxDim,"Too many kernel dimensions required by AvgPooling, not supported"); - auto avgPool = std::make_shared<Node>(std::make_shared<AvgPooling_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, padding_dims), name); + auto avgPool = std::make_shared<Node>(std::make_shared<AvgPooling_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims), name); return avgPool; } @@ -159,17 +151,16 @@ template <DimSize_t DIM> inline std::shared_ptr<Node> AvgPooling( DimSize_t const (&kernel_dims)[DIM], const std::string& name = "", - const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) { + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1)) { static_assert(DIM<=MaxDim,"Too many kernel dimensions required by AvgPooling, not supported"); - return AvgPooling(to_array(kernel_dims), name, stride_dims, padding_dims); + return AvgPooling(to_array(kernel_dims), name, stride_dims); } } // namespace Aidge namespace { template <> const char *const EnumStrings<Aidge::AvgPoolingParam>::data[] = {"StrideDims", - "KernelDims", "PaddingDims"}; + "KernelDims"}; } #endif /* AIDGE_CORE_OPERATOR_AVGPOOLING_H_ */ diff --git a/include/aidge/operator/Conv.hpp b/include/aidge/operator/Conv.hpp index 1edc94b96..69bd8cd5b 100644 --- a/include/aidge/operator/Conv.hpp +++ b/include/aidge/operator/Conv.hpp @@ -26,13 +26,13 @@ #include "aidge/utils/Types.h" namespace Aidge { -enum class ConvParam { StrideDims, DilationDims, InChannels, OutChannels, KernelDims, PaddingDims }; +enum class ConvParam { StrideDims, DilationDims, InChannels, OutChannels, KernelDims }; template <DimIdx_t DIM> class Conv_Op : public Operator, public Registrable<Conv_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const Conv_Op<DIM> &)>, public Parameterizable<ConvParam, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, DimSize_t, - DimSize_t, std::array<DimSize_t, DIM>, std::array<DimSize_t, (DIM<<1) >> { + DimSize_t, std::array<DimSize_t, DIM>> { public: // FIXME: change accessibility std::array<std::shared_ptr<Tensor>, 3> mInputs = {std::make_shared<Tensor>(), std::make_shared<Tensor>(), @@ -45,7 +45,7 @@ public: Conv_Op() = delete; using Parameterizable_ = Parameterizable<ConvParam, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, - DimSize_t, DimSize_t, std::array<DimSize_t, DIM>, std::array<DimSize_t, (DIM<<1) >>; + DimSize_t, DimSize_t, std::array<DimSize_t, DIM>>; template <ConvParam e> using param = typename Parameterizable_::template param<e>; @@ -53,16 +53,13 @@ public: DimSize_t out_channels, const std::array<DimSize_t, DIM> &kernel_dims, const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0), const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1)) : Operator(Type), Parameterizable_(param<ConvParam::StrideDims>(stride_dims), param<ConvParam::DilationDims>(dilation_dims), param<ConvParam::InChannels>(in_channels), param<ConvParam::OutChannels>(out_channels), - param<ConvParam::KernelDims>(kernel_dims), - param<ConvParam::PaddingDims>(padding_dims)), - mOutput(std::make_shared<Tensor>()) { + param<ConvParam::KernelDims>(kernel_dims)) { setDatatype(DataType::Float32); } @@ -96,9 +93,7 @@ public: 1; outputDims[dim+2] = 1 + static_cast<DimSize_t>( - floor(static_cast<float>(mInputs[0]->dims()[dim+2] - kernelExtent + - this->template get<ConvParam::PaddingDims>()[dim] + - this->template get<ConvParam::PaddingDims>()[dim+DIM]) / + floor(static_cast<float>(mInputs[0]->dims()[dim+2] - kernelExtent) / static_cast<float>(this->template get<ConvParam::StrideDims>()[dim]))); } @@ -168,11 +163,10 @@ inline std::shared_ptr<Node> Conv(DimSize_t in_channels, const std::array<DimSize_t, DIM> &kernel_dims, const std::string& name = "", const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0), const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1)) { // FIXME: properly handle default w&b initialization in every cases static_assert(DIM<=MaxDim,"Too many kernel dimensions required by Conv, not supported"); - auto conv = std::make_shared<Node>(std::make_shared<Conv_Op<static_cast<DimIdx_t>(DIM)>>(in_channels, out_channels, kernel_dims, stride_dims, padding_dims, dilation_dims), name); + auto conv = std::make_shared<Node>(std::make_shared<Conv_Op<static_cast<DimIdx_t>(DIM)>>(in_channels, out_channels, kernel_dims, stride_dims, dilation_dims), name); // addProducer(conv, 1, append(append(kernel_dims, in_channels), out_channels), "w"); addProducer(conv, 1, append(out_channels, append(in_channels, kernel_dims)), "w"); addProducer(conv, 2, {out_channels}, "b"); @@ -186,17 +180,16 @@ inline std::shared_ptr<Node> Conv( DimSize_t const (&kernel_dims)[DIM], const std::string& name = "", const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0), const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1)) { static_assert(DIM<=MaxDim,"Too many kernel dimensions required by Conv, not supported"); - return Conv(in_channels, out_channels, to_array(kernel_dims), name, stride_dims, padding_dims, dilation_dims); + return Conv(in_channels, out_channels, to_array(kernel_dims), name, stride_dims, dilation_dims); } } // namespace Aidge namespace { template <> const char *const EnumStrings<Aidge::ConvParam>::data[] = {"StrideDims", "DilationDims", "InChannels", "OutChannels", - "KernelDims", "PaddingDims"}; + "KernelDims"}; } #endif /* AIDGE_CORE_OPERATOR_CONV_H_ */ diff --git a/include/aidge/operator/ConvDepthWise.hpp b/include/aidge/operator/ConvDepthWise.hpp index 95a2ff55b..9519cb2f5 100644 --- a/include/aidge/operator/ConvDepthWise.hpp +++ b/include/aidge/operator/ConvDepthWise.hpp @@ -26,7 +26,7 @@ #include "aidge/utils/Types.h" namespace Aidge { -enum class ConvDepthWiseParam { StrideDims, DilationDims, Channels, KernelDims, PaddingDims }; +enum class ConvDepthWiseParam { StrideDims, DilationDims, Channels, KernelDims }; template <DimIdx_t DIM> class ConvDepthWise_Op : public Operator, @@ -35,8 +35,7 @@ class ConvDepthWise_Op : public Operator, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, DimSize_t, - std::array<DimSize_t, DIM>, - std::array<DimSize_t, (DIM<<1) >> { + std::array<DimSize_t, DIM>> { public: // FIXME: change accessibility std::array<std::shared_ptr<Tensor>, 3> mInputs = {std::make_shared<Tensor>(), std::make_shared<Tensor>(), @@ -52,22 +51,18 @@ class ConvDepthWise_Op : public Operator, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, DimSize_t, - std::array<DimSize_t, DIM>, - std::array<DimSize_t, (DIM<<1) >>; + std::array<DimSize_t, DIM>>; template <ConvDepthWiseParam e> using param = typename Parameterizable_::template param<e>; constexpr ConvDepthWise_Op(const std::array<DimSize_t, DIM> &kernel_dims, const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0), const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1)) : Operator(Type), Parameterizable_(param<ConvDepthWiseParam::StrideDims>(stride_dims), param<ConvDepthWiseParam::DilationDims>(dilation_dims), param<ConvDepthWiseParam::Channels>(0), - param<ConvDepthWiseParam::KernelDims>(kernel_dims), - param<ConvDepthWiseParam::PaddingDims>(padding_dims)), - mOutput(std::make_shared<Tensor>()) { + param<ConvDepthWiseParam::KernelDims>(kernel_dims)) { setDatatype(DataType::Float32); } @@ -88,9 +83,7 @@ class ConvDepthWise_Op : public Operator, 1; outputDims[dim+2] = 1 + static_cast<DimSize_t>( - floor(static_cast<float>(mInputs[0]->dims()[dim+2] - kernelExtent + - this->template get<ConvDepthWiseParam::PaddingDims>()[dim] + - this->template get<ConvDepthWiseParam::PaddingDims>()[dim+DIM]) / + floor(static_cast<float>(mInputs[0]->dims()[dim+2] - kernelExtent) / static_cast<float>(this->template get<ConvDepthWiseParam::StrideDims>()[dim]))); } this->template get<ConvDepthWiseParam::Channels>() = mInputs[0]->dims()[1]; @@ -167,11 +160,10 @@ template <std::array<DimSize_t, 1>::size_type DIM> inline std::shared_ptr<Node> ConvDepthWise(const std::array<DimSize_t, DIM> &kernel_dims, const std::string& name = "", const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0), const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1)) { // FIXME: properly handle default w&b initialization in every cases static_assert(DIM<=MaxDim,"Too many kernel dimensions required by ConvDepthWise, not supported"); - auto convDW = std::make_shared<Node>(std::make_shared<ConvDepthWise_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, padding_dims, dilation_dims), name); + auto convDW = std::make_shared<Node>(std::make_shared<ConvDepthWise_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, dilation_dims), name); addProducer(convDW, 1, std::array<DimSize_t,0>({}), "w"); addProducer(convDW, 2, std::array<DimSize_t,0>({}), "b"); return convDW; @@ -182,17 +174,16 @@ inline std::shared_ptr<Node> ConvDepthWise( DimSize_t const (&kernel_dims)[DIM], const std::string& name = "", const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0), const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1)) { static_assert(DIM<=MaxDim,"Too many kernel dimensions required by ConvDepthWise, not supported"); - return ConvDepthWise(to_array(kernel_dims), name, stride_dims, padding_dims, dilation_dims); + return ConvDepthWise(to_array(kernel_dims), name, stride_dims, dilation_dims); } } // namespace Aidge namespace { template <> const char *const EnumStrings<Aidge::ConvDepthWiseParam>::data[] = {"StrideDims", "DilationDims", "Channels", - "KernelDims", "PaddingDims"}; + "KernelDims"}; } #endif /* AIDGE_CORE_OPERATOR_CONVDEPTHWISE_H_ */ diff --git a/include/aidge/operator/MaxPooling.hpp b/include/aidge/operator/MaxPooling.hpp index 073243e80..80378fd2b 100644 --- a/include/aidge/operator/MaxPooling.hpp +++ b/include/aidge/operator/MaxPooling.hpp @@ -26,15 +26,14 @@ #include "aidge/utils/Types.h" namespace Aidge { -enum class MaxPoolingParam { StrideDims, KernelDims, PaddingDims }; +enum class MaxPoolingParam { StrideDims, KernelDims }; template <DimIdx_t DIM> class MaxPooling_Op : public Operator, public Registrable<MaxPooling_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const MaxPooling_Op<DIM> &)>, public Parameterizable<MaxPoolingParam, std::array<DimSize_t, DIM>, - std::array<DimSize_t, DIM>, - std::array<DimSize_t, (DIM<<1) >> { + std::array<DimSize_t, DIM>> { private: // FIXME: change accessibility std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>(); @@ -47,18 +46,15 @@ public: using Parameterizable_ = Parameterizable<MaxPoolingParam, std::array<DimSize_t, DIM>, - std::array<DimSize_t, DIM>, - std::array<DimSize_t, (DIM<<1)> >; + std::array<DimSize_t, DIM>>; template <MaxPoolingParam e> using param = typename Parameterizable_::template param<e>; constexpr MaxPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims, - const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1)) : Operator(Type), Parameterizable_(param<MaxPoolingParam::StrideDims>(stride_dims), - param<MaxPoolingParam::KernelDims>(kernel_dims), - param<MaxPoolingParam::PaddingDims>(padding_dims)), + param<MaxPoolingParam::KernelDims>(kernel_dims)), mOutput(std::make_shared<Tensor>()) { setDatatype(DataType::Float32); } @@ -78,9 +74,7 @@ public: for (std::size_t dim = 0; dim < this->template get<MaxPoolingParam::KernelDims>().size() ; ++dim) { outputDims[dim+2] = 1 + static_cast<DimSize_t>( std::floor(static_cast<float>(mInput->dims()[dim+2] - - this->template get<MaxPoolingParam::KernelDims>()[dim] + - this->template get<MaxPoolingParam::PaddingDims>()[dim] + - this->template get<MaxPoolingParam::PaddingDims>()[dim+DIM]) / + this->template get<MaxPoolingParam::KernelDims>()[dim]) / static_cast<float>(this->template get<MaxPoolingParam::StrideDims>()[dim]))); } outputDims[1] = mInput->dims()[1]; @@ -147,11 +141,10 @@ public: template <std::array<DimSize_t, 1>::size_type DIM> inline std::shared_ptr<Node> MaxPooling(const std::array<DimSize_t, DIM> &kernel_dims, const std::string& name = "", - const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) { + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1)) { // FIXME: properly handle default w&b initialization in every cases static_assert(DIM<=MaxDim,"Too many kernel dimensions required by MaxPooling, not supported"); - auto avgPool = std::make_shared<Node>(std::make_shared<MaxPooling_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, padding_dims), name); + auto avgPool = std::make_shared<Node>(std::make_shared<MaxPooling_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims), name); return avgPool; } @@ -159,16 +152,15 @@ template <DimSize_t DIM> inline std::shared_ptr<Node> MaxPooling( DimSize_t const (&kernel_dims)[DIM], const std::string& name = "", - const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), - const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0)) { + const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1)) { static_assert(DIM<=MaxDim,"Too many kernel dimensions required by MaxPooling, not supported"); - return MaxPooling(to_array(kernel_dims), name, stride_dims, padding_dims); + return MaxPooling(to_array(kernel_dims), name, stride_dims); } } // namespace Aidge namespace { template <> -const char *const EnumStrings<Aidge::MaxPoolingParam>::data[] = {"StrideDims", "KernelDims", "PaddingDims"}; +const char *const EnumStrings<Aidge::MaxPoolingParam>::data[] = {"StrideDims", "KernelDims"}; } #endif /* AIDGE_CORE_OPERATOR_MAXPOOLING_H_ */ diff --git a/include/aidge/operator/Pad.hpp b/include/aidge/operator/Pad.hpp new file mode 100644 index 000000000..e8e75d31e --- /dev/null +++ b/include/aidge/operator/Pad.hpp @@ -0,0 +1,230 @@ +/******************************************************************************** + * 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_PAD_H_ +#define AIDGE_CORE_OPERATOR_PAD_H_ + +#include <array> +#include <numeric> +#include <vector> +#include <cmath> + +#include "aidge/data/Tensor.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/operator/Operator.hpp" +#include "aidge/operator/Producer.hpp" +#include "aidge/utils/Parameter.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { +enum class PadParam { BeginEndTuples, Type, Value }; +enum class PadParamType { Constant, Replicate, Reflect, Wrap }; + +template <DimIdx_t DIM> +class Pad_Op : public Operator, + public Registrable<Pad_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const Pad_Op<DIM> &)>, + public Parameterizable<PadParam, + std::array<std::array<DimSize_t, 2>, DIM>, + PadParamType, + double> { +private: + // FIXME: change accessibility + std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>(); + const std::shared_ptr<Tensor> mOutput = std::make_shared<Tensor>(); + +public: + static constexpr const char *Type = "Pad"; + + Pad_Op() = delete; + + using Parameterizable_ = Parameterizable<PadParam, + std::array<std::array<DimSize_t, 2>, DIM>, + PadParamType>; + template <PadParam e> + using param = typename Parameterizable_::template param<e>; + + constexpr Pad_Op(const std::array<std::array<DimSize_t, 2>, DIM> &beginEndTuples, + const PadParamType &type = PadParamType::Constant, + double value = 0.0) + : Operator(Type), + Parameterizable_(param<PadParam::BeginEndTuples>(beginEndTuples), + param<PadParam::Type>(type), + param<PadParam::Value>(value)) { + setDatatype(DataType::Float32); + } + + /** + * @brief Copy-constructor. Copy the operator parameters and its output tensor(s), but not its input tensors (the new operator has no input associated). + * @param op Operator to copy. + */ + Pad_Op(const Pad_Op& op) + : Operator(Type), + Parameterizable_(op), + mOutput(std::make_shared<Tensor>(*op.mOutput)) + { + // cpy-ctor + setDatatype(op.mOutput->dataType()); + } + + /** + * @brief Clone the operator using its copy-constructor. + * @see Operator::Pad_Op + * @param op Operator to copy. + */ + Operator* clone() const override { + return new Pad_Op<DIM>(*static_cast<const Pad_Op<DIM>*>(this)); + } + + constexpr void associateInput(const IOIndex_t inputIdx, std::shared_ptr<Data> data) override final { + assert(inputIdx < 1 && "operators supports only 3 inputs"); + (void) inputIdx; // avoid unused warning + assert(strcmp(data->type(), Tensor::Type) == 0 && "input data must be of Tensor type"); + + mInput = std::dynamic_pointer_cast<Tensor>(data); + } + + constexpr void computeOutputDims() override final { + if (!mInput->empty()) { + std::array<DimSize_t, DIM + 2> outputDims = {}; + + for (std::size_t dim = 0; dim < DIM; ++dim) { + outputDims[dim+2] = this->template get<PadParam::BeginEndTuples>()[dim][0] + + this->template get<PadParam::BeginEndTuples>()[dim][1]; + } + outputDims[1] = mInput->dims()[1]; + outputDims[0] = mInput->dims()[0]; + mOutput->resize(outputDims); + } + } + + bool outputDimsForwarded() const override final { return !(mOutput->empty()); } + + + inline Tensor& input(const IOIndex_t inputIdx) const override final { + assert(inputIdx == 0 && "operators supports only 1 inputs"); + (void) inputIdx; // avoid unused warning + return *(mInput.get()); + } + inline Tensor& output(const IOIndex_t /*outputIdx*/) const override final { return *(mOutput.get()); } + + + inline std::shared_ptr<Tensor> getInput(const IOIndex_t inputIdx) const override final { + assert(inputIdx == 0 && "Pad Operators supports only 1 inputs"); + (void) inputIdx; // avoid unused warning + return mInput; + } + inline std::shared_ptr<Tensor> getOutput(const IOIndex_t outputIdx) const override final { + assert(outputIdx == 0 && "Pad Operators has only 1 outputs"); + (void) outputIdx; // avoid unused warning + return mOutput; + } + + + std::shared_ptr<Data> getRawInput(const IOIndex_t inputIdx) const override final { + assert(inputIdx == 0 && "operators supports only 1 inputs"); + (void) inputIdx; // avoid unused warning + return std::static_pointer_cast<Data>(mInput); + } + std::shared_ptr<Data> getRawOutput(const IOIndex_t outputIdx) const override final { + assert(outputIdx == 0 && "operator supports only 1 output"); + (void) outputIdx; // avoid unused warning + return std::static_pointer_cast<Data>(mOutput); + } + + + void setBackend(const std::string &name) { + mImpl = Registrar<Pad_Op<DIM>>::create(name)(*this); + mOutput->setBackend(name); + + // FIXME: temporary workaround + mInput->setBackend(name); + } + + void setDatatype(const DataType &datatype) { + mOutput->setDatatype(datatype); + + // FIXME: temporary workaround + mInput->setDatatype(datatype); + } + + inline IOIndex_t nbInputs() const noexcept override final { return 1; } + inline IOIndex_t nbDataInputs() const noexcept override final { return 1; } + inline IOIndex_t nbOutputs() const noexcept override final { return 1; } +}; + +template <std::array<DimSize_t, 1>::size_type DIM> +inline std::shared_ptr<Node> Pad(const std::array<std::array<DimSize_t, 2>, DIM> &beginEndTuples, + const std::string& name = "", + const PadParamType &type = PadParamType::Constant, + double value = 0.0) +{ + static_assert(DIM<=MaxDim,"Too many kernel dimensions required by Pad, not supported"); + auto pad = std::make_shared<Node>(std::make_shared<Pad_Op<static_cast<DimIdx_t>(DIM)>>(beginEndTuples, type, value), name); + return pad; +} + +template <std::array<DimSize_t, 1>::size_type DIM> +inline std::shared_ptr<Node> Pad(const std::array<DimSize_t, DIM> &dimBeginEnd, + const std::string& name = "", + const PadParamType &type = PadParamType::Constant, + double value = 0.0) +{ + static_assert(DIM<=MaxDim,"Too many kernel dimensions required by Pad, not supported"); + std::array<std::array<DimSize_t, 2>, DIM> beginEndTuples; + for (size_t i = 0; i < DIM; ++i) { + beginEndTuples[i] = {dimBeginEnd[i], dimBeginEnd[i]}; + } + auto pad = std::make_shared<Node>(std::make_shared<Pad_Op<static_cast<DimIdx_t>(DIM)>>(beginEndTuples, type, value), name); + return pad; +} + +template <std::array<DimSize_t, 1>::size_type DIM> +inline std::shared_ptr<Node> ZeroPad(const std::array<std::array<DimSize_t, 2>, DIM> &beginEndTuples, + const std::string& name = "") +{ + static_assert(DIM<=MaxDim,"Too many kernel dimensions required by Pad, not supported"); + auto pad = std::make_shared<Node>(std::make_shared<Pad_Op<static_cast<DimIdx_t>(DIM)>>(beginEndTuples, PadParamType::Constant, 0.0), name); + return pad; +} + +template <std::array<DimSize_t, 1>::size_type DIM> +inline std::shared_ptr<Node> ZeroPad(const std::array<DimSize_t, DIM> &dimBeginEnd, + const std::string& name = "") +{ + static_assert(DIM<=MaxDim,"Too many kernel dimensions required by Pad, not supported"); + std::array<std::array<DimSize_t, 2>, DIM> beginEndTuples; + for (size_t i = 0; i < DIM; ++i) { + beginEndTuples[i] = {dimBeginEnd[i], dimBeginEnd[i]}; + } + auto pad = std::make_shared<Node>(std::make_shared<Pad_Op<static_cast<DimIdx_t>(DIM)>>(beginEndTuples, PadParamType::Constant, 0.0), name); + return pad; +} + +template <DimSize_t DIM> +inline std::shared_ptr<Node> Pad( + std::array<DimSize_t, 2> const (&beginEndTuples)[DIM], + const std::string& name = "", + const std::array<DimSize_t, DIM> &type = PadParamType::Constant, + double value = 0.0) +{ + static_assert(DIM<=MaxDim,"Too many kernel dimensions required by Pad, not supported"); + return Pad(to_array(beginEndTuples), name, type, value); +} +} // namespace Aidge + +namespace { +template <> +const char *const EnumStrings<Aidge::PadParam>::data[] = {"BeginEndTuples", "Type", "Value"}; +const char *const EnumStrings<Aidge::PadParamType>::data[] = {"Constant", "Replicate", "Reflect", "Wrap"}; +} + +#endif /* AIDGE_CORE_OPERATOR_PAD_H_ */ -- GitLab