diff --git a/include/aidge/backend/cpu.hpp b/include/aidge/backend/cpu.hpp index 82a087f71a94ce07de987c475627945a905d7028..4e0b4ab24f9b26fe1f33a0fc2d306283992c92a6 100644 --- a/include/aidge/backend/cpu.hpp +++ b/include/aidge/backend/cpu.hpp @@ -17,7 +17,7 @@ #include "aidge/backend/cpu/operator/AvgPoolingImpl.hpp" #include "aidge/backend/cpu/operator/MaxPoolingImpl.hpp" #include "aidge/backend/cpu/operator/BatchNormImpl.hpp" -// #include "aidge/backend/cpu/operator/ConcatImpl.hpp.hpp" +#include "aidge/backend/cpu/operator/ConcatImpl.hpp.hpp" #include "aidge/backend/cpu/operator/ConvDepthWiseImpl.hpp" #include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/FCImpl.hpp" diff --git a/include/aidge/backend/cpu/operator/ConcatImpl.hpp b/include/aidge/backend/cpu/operator/ConcatImpl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1d9315e49195ce8ee6501f262025222590491860 --- /dev/null +++ b/include/aidge/backend/cpu/operator/ConcatImpl.hpp @@ -0,0 +1,75 @@ +/******************************************************************************** + * 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_CPU_OPERATOR_CONCATIMPL_H_ +#define AIDGE_CPU_OPERATOR_CONCATIMPL_H_ + +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/operator/Concat.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" +#include <memory> +#include <vector> + +namespace Aidge { +// class Concat_Op<2>; + +// compute kernel registry for forward and backward +class ConcatImplForward_cpu + : public Registrable<ConcatImplForward_cpu, std::tuple<DataType, DataType>, void(const Concat_Op::Attrs&, + const std::vector<DimSize_t>, + const std::vector<const void*>, + void*)> {}; + +class ConcatImplBackward_cpu + : public Registrable<ConcatImplBackward_cpu, std::tuple<DataType, DataType>, void(const Concat_Op::Attrs&, + const std::vector<DimSize_t>, + const std::vector<const void*>, + void*)> {}; + + +class ConcatImpl_cpu : public OperatorImpl { +private: + const Concat_Op& mOp; + std::vector<NbElts_t> mNbConsumedData; + std::array<NbElts_t, 1> mNbProducedData = {}; + +public: + ConcatImpl_cpu(const Concat_Op& op) : mOp(op), mNbConsumedData(std::vector<NbElts_t>(op.nbInputs())) {} + + static std::unique_ptr<ConcatImpl_cpu> create(const Concat_Op& op) { + return std::make_unique<ConcatImpl_cpu>(op); + } + +public: + NbElts_t getNbRequiredData(const IOIndex_t inputIdx) const override final; + + NbElts_t getNbRequiredProtected(const IOIndex_t /*inputIdx*/) const override final; + + NbElts_t getRequiredMemory(const IOIndex_t outputIdx, const std::vector<DimSize_t>& /*inputsSize*/) const override final; + + NbElts_t getNbConsumedData(const IOIndex_t inputIdx) const override final; + + NbElts_t getNbProducedData(const IOIndex_t outputIdx) const override final; + + void updateConsummerProducer() override final; + + void forward() override; + + void backward() override; +}; + +namespace { +static Registrar<Concat_Op> registrarConcatImpl_cpu("cpu", Aidge::ConcatImpl_cpu::create); +} // namespace +} // namespace Aidge + +#endif /* AIDGE_CPU_OPERATOR_CONCATIMPL_H_ */ diff --git a/include/aidge/backend/cpu/operator/ConcatImpl_forward_kernels.hpp b/include/aidge/backend/cpu/operator/ConcatImpl_forward_kernels.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4e87e3695e2835d7611e37d05c4f199b0e52ac34 --- /dev/null +++ b/include/aidge/backend/cpu/operator/ConcatImpl_forward_kernels.hpp @@ -0,0 +1,71 @@ +/******************************************************************************** + * 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_CPU_OPERATOR_CONCATIMPL_FORWARD_KERNEL_H_ +#define AIDGE_CPU_OPERATOR_CONCATIMPL_FORWARD_KERNEL_H_ + +#include <algorithm> +#include <cstddef> +#include <vector> + +#include "aidge/backend/cpu/operator/ConcatImpl.hpp" +#include "aidge/data/Data.hpp" +#include "aidge/operator/Concat.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { + +template <class I, class O> +void ConcatImpl_cpu_forward_kernel(const Concat_Op::Attrs& attrs, + const std::vector<DimSize_t> dimsFirstInput, + const std::vector<const void*> inputs_, + void* output_) +{ + // FIXME: missing Concat attributes as arguments + std::vector<const I*> inputs; + for (const auto& input_ : inputs_) { + inputs.push_back(static_cast<const I*>(input_)); + } + O* output = static_cast<O*>(output_); + + DimSize_t prodDimLower = 1; + for (DimIdx_t i = 0; i < std::get<1>(attrs); ++i) { + prodDimLower *= dimsFirstInput[i]; + } + DimSize_t prodDimHigher = 1; + for (DimIdx_t i = std::get<1>(attrs) + 1; static_cast<std::size_t>(i) < dimsFirstInput.size(); + ++i) { + prodDimHigher *= dimsFirstInput[i]; + } + + std::size_t oIndex = 0; + for (std::size_t inputId = 0; inputId < inputs.size(); ++inputId) { + for (std::size_t iIndex = 0; iIndex < prodDimLower; ++iIndex) { + std::copy(inputs[inputId] + iIndex, inputs[inputId] + iIndex + prodDimHigher, + output + oIndex); + oIndex += prodDimHigher; + } + } +} + +namespace { +static Registrar<ConcatImplForward_cpu> registrarConcatImplForward_cpu_Float32( + {DataType::Float32, DataType::Float32}, Aidge::ConcatImpl_cpu_forward_kernel<float, float>); +static Registrar<ConcatImplForward_cpu> registrarConcatImplForward_cpu_Int32( + {DataType::Int32, DataType::Int32}, Aidge::ConcatImpl_cpu_forward_kernel<int, int>); +static Registrar<ConcatImplForward_cpu> registrarConcatImplForward_cpu_Float64( + {DataType::Float64, DataType::Float64}, + Aidge::ConcatImpl_cpu_forward_kernel<double, double>); +} // namespace +} // namespace Aidge + +#endif /* AIDGE_CPU_OPERATOR_CONCATIMPL_CPU_FORWARD_KERNEL_H_ */ diff --git a/src/operator/ConcatImpl.cpp b/src/operator/ConcatImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a98f90f6582ee9e75519ce9cf4a52402b9065cb --- /dev/null +++ b/src/operator/ConcatImpl.cpp @@ -0,0 +1,86 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#include <cassert> +#include <numeric> // std::accumulate +#include <vector> + +#include "aidge/utils/Types.h" +#include "aidge/data/Data.hpp" +#include "aidge/data/Tensor.hpp" + +#include "aidge/backend/cpu/operator/ConcatImpl.hpp" +#include "aidge/backend/cpu/operator/ConcatImpl_forward_kernels.hpp" + +Aidge::NbElts_t Aidge::ConcatImpl_cpu::getNbRequiredData(const Aidge::IOIndex_t inputIdx) const { + assert(mOp.getInput(inputIdx) && "requires valid input"); + + // Requires the whole tensors + const auto& inputDims = std::static_pointer_cast<Tensor>(mOp.getInput(inputIdx))->dims(); + return std::accumulate(inputDims.begin(), inputDims.end(), NbElts_t(1), std::multiplies<NbElts_t>()); +} + +Aidge::NbElts_t Aidge::ConcatImpl_cpu::getNbRequiredProtected(const Aidge::IOIndex_t /*inputIdx*/) const { + // for the direct convolution algorithm, convolutions can be in-place, if there is no padding! + return 0; +} + +Aidge::NbElts_t Aidge::ConcatImpl_cpu::getRequiredMemory(const Aidge::IOIndex_t outputIdx, const std::vector<Aidge::DimSize_t>& /*inputsSize*/) const { + // Requires the whole tensors, regardless of available data on inputs + assert(outputIdx == 0 && "operator has only one output"); + (void) outputIdx; + + const auto& outputDims = std::static_pointer_cast<Tensor>(mOp.getOutput(0))->dims(); + return std::accumulate(outputDims.begin(), outputDims.end(), NbElts_t(1), std::multiplies<NbElts_t>()); +} + +Aidge::NbElts_t Aidge::ConcatImpl_cpu::getNbConsumedData(const Aidge::IOIndex_t inputIdx) const { + assert(inputIdx < mNbConsumedData.size()); + return mNbConsumedData[inputIdx]; +} + +Aidge::NbElts_t Aidge::ConcatImpl_cpu::getNbProducedData(const Aidge::IOIndex_t outputIdx) const { + assert(outputIdx < mNbProducedData.size()); + return mNbProducedData[outputIdx]; +} + +void Aidge::ConcatImpl_cpu::updateConsummerProducer() { + for (IOIndex_t inputIdx = 0; static_cast<NbElts_t>(inputIdx) < mNbConsumedData.size(); ++inputIdx) + mNbConsumedData[inputIdx]+= getNbRequiredData(inputIdx); // each input is consumed by the minimum amount for a forward pass + + mNbProducedData[0]+= getRequiredMemory(0, {}); + +} + +void Aidge::ConcatImpl_cpu::forward() { + assert(mOp.getInput(0) && "missing input in Concat operator"); + DataType datatypeFirstInput = mOp.getInput(0)->dataType(); + for (IOIndex_t i = 1; i < mOp.nbInputs(); ++i) { + assert(mOp.getInput(i) && "missing input in Concat operator"); + assert(mOp.getInput(i)->dataType() == datatypeFirstInput); + } + + auto kernelFunc = Registrar<ConcatImplForward_cpu>::create({ + datatypeFirstInput, + mOp.getOutput(0)->dataType()}); + + std::vector<const void*> opInputs; + for (IOIndex_t i = 0; i < mOp.nbInputs(); ++i) { + opInputs.push_back(mOp.getInput(i)->getImpl()->rawPtr()); + } + + kernelFunc(mOp.getStaticAttributes(), + mOp.getInput(0)->dims(), + opInputs, + mOp.getOutput(0)->getImpl()->rawPtr()); +} + +void Aidge::ConcatImpl_cpu::backward() { printf("Not implemented yet.\n"); } \ No newline at end of file