/******************************************************************************** * 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_CONVDEPTHWISE_H_ #define AIDGE_CORE_OPERATOR_CONVDEPTHWISE_H_ #include <array> #include <cmath> // std::floor #include <cstddef> // std::size_t #include <string> #include <utility> // std::pair #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/ArrayHelpers.hpp" #include "aidge/utils/StaticAttributes.hpp" #include "aidge/utils/Registrar.hpp" #include "aidge/utils/Types.h" namespace Aidge { enum class ConvDepthWiseAttr { StrideDims, DilationDims, KernelDims, NoBias }; template <DimIdx_t DIM> class ConvDepthWise_Op : public OperatorTensor, public Registrable<ConvDepthWise_Op<DIM>, std::string, std::shared_ptr<OperatorImpl>(const ConvDepthWise_Op<DIM> &)>, public StaticAttributes<ConvDepthWiseAttr, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, bool> { public: static const std::string Type; ConvDepthWise_Op() = delete; using Attributes_ = StaticAttributes<ConvDepthWiseAttr, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, bool>; template <ConvDepthWiseAttr e> using attr = typename Attributes_::template attr<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> &dilation_dims = create_array<DimSize_t,DIM>(1), bool no_bias=false) : OperatorTensor(Type, 1, 2, 1), Attributes_(attr<ConvDepthWiseAttr::StrideDims>(stride_dims), attr<ConvDepthWiseAttr::DilationDims>(dilation_dims), attr<ConvDepthWiseAttr::KernelDims>(kernel_dims), attr<ConvDepthWiseAttr::NoBias>(no_bias)) {} /** * @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. */ ConvDepthWise_Op(const ConvDepthWise_Op<DIM>& op); /** * @brief Clone the operator using its copy-constructor. * @see Operator::ConvDepthWise_Op */ std::shared_ptr<Operator> clone() const override { return std::make_shared<ConvDepthWise_Op<DIM>>(*this); } bool forwardDims(bool /*allowDataDependency*/ = false) override final; std::vector<std::pair<std::vector<DimSize_t>, std::vector<DimSize_t>>> computeReceptiveField(const std::vector<DimSize_t>& firstEltDims, const std::vector<DimSize_t>& outputDims, const IOIndex_t outputIdx = 0) const override; void setBackend(const std::string &name, DeviceIdx_t device = 0) override; DimSize_t nbChannels() const { if (!getInput(1)) { AIDGE_THROW_OR_ABORT(std::runtime_error, "Convolution operator has no weight Tensor associated so no specific number of channel imposed."); } return getInput(1)->template dims<DIM+2>()[0]; } static const std::vector<std::string> getInputsName(){ return {"data_input", "weight", "bias"}; } static const std::vector<std::string> getOutputsName(){ return {"data_output"}; } }; template <std::array<DimSize_t, 1>::size_type DIM> inline std::shared_ptr<Node> ConvDepthWise(const DimSize_t nbChannels, const std::array<DimSize_t, DIM> &kernelDims, const std::string& name = "", const std::array<DimSize_t, DIM> &strideDims = create_array<DimSize_t,DIM>(1), const std::array<DimSize_t, DIM> &dilationDims = create_array<DimSize_t,DIM>(1), bool noBias=false) { // 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)>>(kernelDims, strideDims, dilationDims, noBias), name); addProducer(convDW, 1, append(nbChannels, append(DimSize_t(1), kernelDims)), "w"); addProducer(convDW, 2, {(noBias ? 0 : nbChannels)}, "b"); return convDW; } // 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> ConvDepthWise( const DimSize_t nbChannels, DimSize_t const (&kernelDims)[DIM], const std::string& name = "", const std::array<DimSize_t, DIM> &strideDims = create_array<DimSize_t,DIM>(1), const std::array<DimSize_t, DIM> &dilationDims = create_array<DimSize_t,DIM>(1), bool noBias=false) { static_assert(DIM<=MaxDim,"Too many kernel dimensions required by ConvDepthWise, not supported"); return ConvDepthWise(nbChannels, to_array(kernelDims), name, strideDims, dilationDims, noBias); } } // namespace Aidge extern template class Aidge::ConvDepthWise_Op<2>; namespace { template <> const char *const EnumStrings<Aidge::ConvDepthWiseAttr>::data[] = {"StrideDims", "DilationDims", "KernelDims", "NoBias"}; } #endif /* AIDGE_CORE_OPERATOR_CONVDEPTHWISE_H_ */