Skip to content
Snippets Groups Projects
Commit 98980f31 authored by Maxence Naud's avatar Maxence Naud
Browse files

[Upd] 'computeReceptiveField()' and its tests

parent 117af588
No related branches found
No related tags found
No related merge requests found
......@@ -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;
......
......@@ -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;
......
......@@ -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_ */
......@@ -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);
}
......@@ -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);
......
......@@ -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
......@@ -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: {";
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment