Skip to content
Snippets Groups Projects
Forked from Eclipse Projects / aidge / aidge_core
1225 commits behind the upstream repository.
  • Maxence Naud's avatar
    dce1e8e5
    Update conv and convdepth wise operators · dce1e8e5
    Maxence Naud authored
    - Move code definition in an external cpp file in src directory
    - Remove InChannels, OutChannels, NbChannels from the list of attributes as they are only used for creating the associated Producer. They are kept as parameters of the Operator factory function to continue creating Weight and Bias Producers automatically. The number of in/out channels is now based on the Weight parameter
    - 'Conv_Op::inChannels()', 'Conv_Op::outChannels()', 'ConvDepthWise::nbChannels()' functons added
    dce1e8e5
    History
    Update conv and convdepth wise operators
    Maxence Naud authored
    - Move code definition in an external cpp file in src directory
    - Remove InChannels, OutChannels, NbChannels from the list of attributes as they are only used for creating the associated Producer. They are kept as parameters of the Operator factory function to continue creating Weight and Bias Producers automatically. The number of in/out channels is now based on the Weight parameter
    - 'Conv_Op::inChannels()', 'Conv_Op::outChannels()', 'ConvDepthWise::nbChannels()' functons added
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ConvDepthWise.hpp 6.18 KiB
/********************************************************************************
 * 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_ */