diff --git a/include/aidge/operator/Conv.hpp b/include/aidge/operator/Conv.hpp index 5cce541087124496437a9c87895e7cf3b0ee838f..7fa99b08461593d0149e7cb472cb607025a3b6fd 100644 --- a/include/aidge/operator/Conv.hpp +++ b/include/aidge/operator/Conv.hpp @@ -157,11 +157,11 @@ std::vector<std::pair<std::vector<Aidge::DimSize_t>, std::vector<DimSize_t>>> co weightDims.push_back(this->template getAttr<ConvAttr::KernelDims>()[i]); } std::vector<DimSize_t> weightIdxDims = std::vector<DimSize_t>(DIM+2, 0); - weightIdxDims[0] = outputIdxDims[1]; + weightIdxDims[0] = firstEltDims[1]; // Bias const std::vector<DimSize_t> biasDims{outputDims[1]}; // the number of output channel - const std::vector<DimSize_t> biasIdxDims{outputIdxDims[1]}; + const std::vector<DimSize_t> biasIdxDims{firstEltDims[1]}; // Result std::vector<std::pair<std::vector<Aidge::DimSize_t>, std::vector<DimSize_t>>> res; diff --git a/include/aidge/operator/ConvDepthWise.hpp b/include/aidge/operator/ConvDepthWise.hpp index 15110a1c75a1d4a6fdc03717bcde6b301771c9b9..cc687622916b0fd27fc2cb777bd50cbfbb7d3949 100644 --- a/include/aidge/operator/ConvDepthWise.hpp +++ b/include/aidge/operator/ConvDepthWise.hpp @@ -151,11 +151,11 @@ public: weightDims.push_back(this->template getAttr<ConvDepthWiseAttr::KernelDims>()[i]); } std::vector<DimSize_t> weightIdxDims = std::vector<DimSize_t>(DIM+2, 0); - weightIdxDims[0] = outputIdxDims[1]; + weightIdxDims[0] = firstEltDims[1]; // Bias const std::vector<DimSize_t> biasDims{outputDims[1]}; // the number of output channel - const std::vector<DimSize_t> biasIdxDims{outputIdxDims[1]}; + const std::vector<DimSize_t> biasIdxDims{firstEltDims[1]}; // Result std::vector<std::pair<std::vector<Aidge::DimSize_t>, std::vector<DimSize_t>>> res; diff --git a/include/aidge/operator/Slice.hpp b/include/aidge/operator/Slice.hpp index 26abaf291aad352ce8cc13fd17e148f358b980eb..9b93b9448fb04be616497b6961c4692a5a846303 100644 --- a/include/aidge/operator/Slice.hpp +++ b/include/aidge/operator/Slice.hpp @@ -24,25 +24,26 @@ #include "aidge/utils/Types.h" namespace Aidge { -enum class SliceAttr { Beginning, SliceDims }; +enum class SliceAttr { Starts, Ends, Axes }; class Slice_Op : public OperatorTensor, public Registrable<Slice_Op, std::string, std::unique_ptr<OperatorImpl>(const Slice_Op &)>, - public StaticAttributes<SliceAttr, std::vector<std::int32_t>, std::vector<std::int32_t>, std::vector<std::int32_t>> { + public StaticAttributes<SliceAttr, std::vector<std::size_t>, std::vector<std::size_t>, std::vector<std::size_t>> { public: static const std::string Type; Slice_Op() = delete; - using Attributes_ = StaticAttributes<SliceAttr, std::vector<std::int32_t>, std::vector<std::int32_t>, std::vector<std::int32_t>>; + using Attributes_ = StaticAttributes<SliceAttr, std::vector<std::size_t>, std::vector<std::size_t>, std::vector<std::size_t>>; template <SliceAttr e> using attr = typename Attributes_::template attr<e>; - Slice_Op(const std::vector<std::int32_t>& starts, const std::vector<std::int32_t>& ends, const std::vector<std::int32_t>& axes) + Slice_Op(const std::vector<std::size_t>& starts, const std::vector<std::size_t>& ends, const std::vector<std::size_t>& axes) : OperatorTensor(Type, 1, 0, 1), - Attributes_(attr<SliceAttr::Beginning>(beginningPos), - attr<SliceAttr::SliceDims>(sliceDims)) + Attributes_(attr<SliceAttr::Starts>(starts), + attr<SliceAttr::Ends>(ends), + attr<SliceAttr::Axes>(axes)) {} /** @@ -65,30 +66,7 @@ public: */ std::shared_ptr<Operator> clone() const override { return std::make_shared<Slice_Op>(*this); } - void computeOutputDims() override final { - if (!getInput(0) || (getInput(0)->empty())) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "Every input should be associated with a Tensor"); - } - std::vector<DimSize_t> outputDims = std::vector<DimSize_t>(getInput(0)->nbDims()); - const std::vector<DimSize_t> inputDims = getInput(0)->dims(); - - // Check that the sliced Tensor is actually part of the input Tensor - // For a 5*5 tensor ('x') and a 3*3 slice kernel ('o'): - // xxxxx xxxxx - // xxxxx xxxxx - // xxooo --> ok xxxoo --> out of bound - // xxooo xxxoo - // xxooo xxxoo - std::vector<std::size_t> beginningCoords = mInputs[0]->getCoord(this->template getAttr<SliceAttr::Beginning>()); - for (std::size_t i = 0; i < getInput(0)->nbDims(); ++i) { - if (beginningCoords[i] + this->template getAttr<SliceAttr::SliceDims>()[i] > inputDims[i]) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "ROI of Slice operator out of bounds"); - } else { - outputDims[i] = this->template getAttr<SliceAttr::SliceDims>()[i]; - } - } - mOutputs[0]->resize(outputDims); - } + void computeOutputDims() override final; void setBackend(const std::string &name) override { mImpl = Registrar<Slice_Op>::create(name)(*this); @@ -107,18 +85,18 @@ public: }; -inline std::shared_ptr<Node> Slice(const std::vector<std::int32_t> starts, - const std::vector<std::int32_t> ends, - const std::vector<std::int32_t> axes, +inline std::shared_ptr<Node> Slice(const std::vector<std::size_t> starts, + const std::vector<std::size_t> ends, + const std::vector<std::size_t> axes, const std::string &name = "") { // FIXME: properly handle default w&b initialization in every cases - return std::make_shared<Node>(std::make_shared<Slice_Op>(beginningPos, sliceDims), name); + return std::make_shared<Node>(std::make_shared<Slice_Op>(starts, ends, axes), name); } } // namespace Aidge namespace { template <> -const char *const EnumStrings<Aidge::SliceAttr>::data[] = { "Beginning", "SliceDims" }; +const char *const EnumStrings<Aidge::SliceAttr>::data[] = { "Starts", "Ends", "Axes" }; } #endif /* AIDGE_CORE_OPERATOR_RELU_H_ */ diff --git a/src/operator/Slice.cpp b/src/operator/Slice.cpp index 9ac6bd2c08fa8f77d995e852de6a5990dc73bd94..b9ba4fe36ff7b3e6c5a5d28da87eec691e933a12 100644 --- a/src/operator/Slice.cpp +++ b/src/operator/Slice.cpp @@ -8,12 +8,17 @@ * SPDX-License-Identifier: EPL-2.0 * ********************************************************************************/ +#include "aidge/operator/Slice.hpp" +#include <cassert> +#include <cstddef> #include <string> +#include <utility> +#include <vector> -#include "aidge/operator/Slice.hpp" -#include "aidge/utils/Types.h" +#include "aidge/backend/OperatorImpl.hpp" #include "aidge/utils/ErrorHandling.hpp" +#include "aidge/utils/Types.h" const std::string Aidge::Slice_Op::Type = "Slice"; @@ -25,14 +30,20 @@ void Aidge::Slice_Op::computeOutputDims() { DimSize_t nbAxes = this->template getAttr<SliceAttr::Axes>().size(); std::vector<DimSize_t> outDims = getInput(0)->dims(); - for(std::size_t i=0; i<nbAxes;++i) - { + for (std::size_t i = 0; i < nbAxes; ++i) { // For each slice operation get the params and cast them to size_t std::int64_t axis_ = this->template getAttr<SliceAttr::Axes>()[i]; std::int64_t start_ = this->template getAttr<SliceAttr::Starts>()[i]; std::int64_t end_ = this->template getAttr<SliceAttr::Ends>()[i]; - std::size_t axis = axis_>=0?axis_:axis_+getInput(0)->nbDims(); - std::size_t start = start_>=0?start_:start_+getInput(0)->dims()[axis]; - std::size_t end = end_>=0?end_:end_+getInput(0)->dims()[axis]; + std::size_t axis = axis_ >= 0 ? axis_ : axis_ + getInput(0)->nbDims(); + std::size_t start = start_ >= 0 ? start_ : start_ + getInput(0)->dims()[axis]; + std::size_t end = end_ >= 0 ? end_ : end_ + getInput(0)->dims()[axis]; + + std::size_t sliceLength = end - start + 1; + // Check if slice length is valid + if (sliceLength > getInput(0)->dims()[axis]) + AIDGE_THROW_OR_ABORT(std::runtime_error, "ROI of Slice operator out of bounds"); + outDims[axis] = sliceLength; } + mOutputs[0]->resize(outDims); } diff --git a/src/recipies/HorizontalTiling.cpp b/src/recipies/HorizontalTiling.cpp index f1d8d3bdd2acfddc26f664913b2fa6c3217b8919..48d8cfc0b9011e88dea0c1d605cb8c72bfe18d96 100644 --- a/src/recipies/HorizontalTiling.cpp +++ b/src/recipies/HorizontalTiling.cpp @@ -11,6 +11,7 @@ #include <set> #include <memory> +#include <numeric> // std::iota #include <vector> #include <utility> @@ -75,13 +76,19 @@ std::set<std::shared_ptr<Aidge::Node>> Aidge::getConvHorizontalTiling(const std: } for (IOIndex_t i = 0; currentFirstDims[axis] < outTensor->dims()[axis]; currentFirstDims[axis] += outputDims[axis], ++i) { - const auto inputDims = op->computeReceptiveField(outTensor->getIdx(currentFirstDims), outputDims, 0); + const auto inputDims = op->computeReceptiveField(currentFirstDims, outputDims, 0); auto newNode = node -> clone(); // no input associated to clones newNode -> setName(node->name() + "_" + std::to_string(currentFirstDims[axis])); clonedInputs[1] -> addChild(newNode, 0, 1); clonedInputs[2] -> addChild(newNode, 0, 2); // Slice for input and each parameter - auto slice = Slice(inputDims[0].first, inputDims[0].second, "Slice_" + std::to_string(currentFirstDims[axis])); + auto inputDimsEnd = inputDims[0].first; + for (std::size_t dim = 0; dim < inputDimsEnd.size(); ++dim) { + inputDimsEnd[dim] += inputDims[0].second[dim]; + } + std::vector<std::size_t> usedDims(inputDimsEnd.size()); + std::iota(usedDims.begin(), usedDims.end(), static_cast<std::size_t>(0)); + auto slice = Slice(inputDims[0].first, inputDimsEnd, usedDims, "Slice_" + std::to_string(currentFirstDims[axis])); slice -> addChild(newNode, 0, 0); newNode -> addChild(concat, 0, i); diff --git a/unit_tests/operator/Test_ConvDepthWise_Op.cpp b/unit_tests/operator/Test_ConvDepthWise_Op.cpp index 14d4dc537f527b32414151ee7f93e601f5a4bd8a..6008e3bfac346725935d5d8ffe87f392c49a3409 100644 --- a/unit_tests/operator/Test_ConvDepthWise_Op.cpp +++ b/unit_tests/operator/Test_ConvDepthWise_Op.cpp @@ -45,20 +45,20 @@ TEST_CASE("[core/operator] ConvDepthWise_Op(computeReceptiveField)", "[Operator] auto op4 = std::dynamic_pointer_cast<OperatorTensor>(cdw4 -> getOperator()); SECTION("Check individual receptive fields") { - auto res1 = op1->computeReceptiveField(0, {16,3,10,10}); - auto res2 = op2->computeReceptiveField(op2->getOutput(0)->getIdx({3,1,100,28}), {4,2,30,40}); - auto res3 = op3->computeReceptiveField(0, {1,1,109,109}); - auto res4 = op4->computeReceptiveField(op4->getInput(0)->getIdx({5,0,108,108}), {10,1,1,1}); + auto res1 = op1->computeReceptiveField({0,0,0,0}, {16,3,10,10}); + auto res2 = op2->computeReceptiveField({3,1,100,28}, {4,2,30,40}); + auto res3 = op3->computeReceptiveField({0,0,0,0}, {1,1,109,109}); + auto res4 = op4->computeReceptiveField({5,0,108,108}, {10,1,1,1}); - REQUIRE(((res1[0].first == 0) && (res1[0].second == std::vector<DimSize_t>({16, 3, 14, 14})))); - REQUIRE(((res2[0].first == op2->getInput(0)->getIdx({3,1,100,28})) && (res2[0].second == std::vector<DimSize_t>({4, 2, 32, 42})))); - REQUIRE(((res3[0].first == 0) && (res3[0].second == std::vector<DimSize_t>({1, 1, 218, 218})))); - REQUIRE(((res4[0].first == op4->getInput(0)->getIdx({5, 0, 108, 108})) && (res4[0].second == std::vector<DimSize_t>({10, 1, 1, 1})))); + REQUIRE(((res1[0].first == std::vector<DimSize_t>({0,0,0,0})) && (res1[0].second == std::vector<DimSize_t>({16, 3, 14, 14})))); + REQUIRE(((res2[0].first == std::vector<DimSize_t>({3,1,100,28})) && (res2[0].second == std::vector<DimSize_t>({4, 2, 32, 42})))); + REQUIRE(((res3[0].first == std::vector<DimSize_t>({0,0,0,0})) && (res3[0].second == std::vector<DimSize_t>({1, 1, 218, 218})))); + REQUIRE(((res4[0].first == std::vector<DimSize_t>({5,0,108,108})) && (res4[0].second == std::vector<DimSize_t>({10, 1, 1, 1})))); } SECTION("Check receptive field propagation") { // input: first-{5, 0, 50, 50} dims-{1, 1, 1, 1} - auto res4 = op4->computeReceptiveField(op4->getInput(0)->getIdx({5,0,50,50}), {1,1,1,1}); + auto res4 = op4->computeReceptiveField({5,0,50,50}, {1,1,1,1}); // cdw4 RF: first-{5, 0, 50, 50} dims-{1, 1, 1, 1} auto res3 = op3->computeReceptiveField(res4[0].first, res4[0].second); // cdw3 RF: first-{5, 0, 100, 100} dims-{1, 1, 2, 2} @@ -67,7 +67,7 @@ TEST_CASE("[core/operator] ConvDepthWise_Op(computeReceptiveField)", "[Operator] auto res1 = op1->computeReceptiveField(res2[0].first, res2[0].second); // cdw1 RF: first-{5, 0, 100, 100} dims-{1, 1, 8, 8} - REQUIRE(((res1[0].first == op1->getInput(0)->getIdx({5, 0, 100, 100})) && (res1[0].second == std::vector<DimSize_t>({1, 1, 8, 8})))); + REQUIRE(((res1[0].first == std::vector<DimSize_t>({5, 0, 100, 100})) && (res1[0].second == std::vector<DimSize_t>({1, 1, 8, 8})))); } } } // namespace Aidge \ No newline at end of file diff --git a/unit_tests/operator/Test_Conv_Op.cpp b/unit_tests/operator/Test_Conv_Op.cpp index 859d1d964180673e1d35fdede6fdfd78f75cfdeb..bc24fc8081d78dedf853450ff648b6d91b47c1dc 100644 --- a/unit_tests/operator/Test_Conv_Op.cpp +++ b/unit_tests/operator/Test_Conv_Op.cpp @@ -50,12 +50,12 @@ TEST_CASE("[core/operator] Conv_Op(computeReceptiveField)", "[Operator][computeR auto res3 = op3 -> computeReceptiveField({0,0,0,0}, {1,1,109,109}); auto res4 = op4 -> computeReceptiveField({5,0,108,108}, {10,10,1,1}); - REQUIRE(((res1[0].first == 0) && (res1[0].second == std::vector<DimSize_t>({16, 3, 14, 14})))); - REQUIRE(((res1[1].first == 0) && (res1[1].second == std::vector<DimSize_t>({32, 3, 5, 5})))); - REQUIRE(((res1[2].first == 0) && (res1[2].second == std::vector<DimSize_t>({32})))); - REQUIRE(((res2[0].first == op2->getInput(0)->getIdx({3,0,100,28})) && (res2[0].second == std::vector<DimSize_t>({4, 32, 32, 42})))); - REQUIRE(((res3[0].first == 0) && (res3[0].second == std::vector<DimSize_t>({1, 64, 218, 218})))); - REQUIRE(((res4[0].first == op4->getInput(0)->getIdx({5, 0, 108, 108})) && (res4[0].second == std::vector<DimSize_t>({10, 10, 1, 1})))); + REQUIRE(((res1[0].first == std::vector<DimSize_t>({0,0,0,0})) && (res1[0].second == std::vector<DimSize_t>({16, 3, 14, 14})))); + REQUIRE(((res1[1].first == std::vector<DimSize_t>({0,0,0,0})) && (res1[1].second == std::vector<DimSize_t>({32, 3, 5, 5})))); + REQUIRE(((res1[2].first == std::vector<DimSize_t>({0})) && (res1[2].second == std::vector<DimSize_t>({32})))); + REQUIRE(((res2[0].first == std::vector<DimSize_t>({3,0,100,28})) && (res2[0].second == std::vector<DimSize_t>({4, 32, 32, 42})))); + REQUIRE(((res3[0].first == std::vector<DimSize_t>({0,0,0,0})) && (res3[0].second == std::vector<DimSize_t>({1, 64, 218, 218})))); + REQUIRE(((res4[0].first == std::vector<DimSize_t>({5, 0, 108, 108})) && (res4[0].second == std::vector<DimSize_t>({10, 10, 1, 1})))); } SECTION("Check receptive field propagation") { @@ -69,7 +69,7 @@ TEST_CASE("[core/operator] Conv_Op(computeReceptiveField)", "[Operator][computeR auto res1 = op1->computeReceptiveField(res2[0].first, res2[0].second); // conv1 RF: first-{5, 0, 100, 100} dims-{1, 3, 8, 8} - REQUIRE(((res1[0].first == op1->getInput(0)->getIdx({5, 0, 100, 100})) && (res1[0].second == std::vector<DimSize_t>({1, 3, 8, 8})))); + REQUIRE(((res1[0].first == std::vector<DimSize_t>({5, 0, 100, 100})) && (res1[0].second == std::vector<DimSize_t>({1, 3, 8, 8})))); // std::cout << "conv1: {";