Skip to content
Snippets Groups Projects
Commit acc6473b authored by Olivier BICHLER's avatar Olivier BICHLER
Browse files

Merge branch 'dev' into backend_export

parents b6581483 1d2dd4dc
No related branches found
No related tags found
2 merge requests!212Version 0.3.0,!186Refactor OperatorImpl for backend/export
Pipeline #55413 failed
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "aidge/operator/ArgMax.hpp" #include "aidge/operator/ArgMax.hpp"
#include "aidge/operator/AvgPooling.hpp" #include "aidge/operator/AvgPooling.hpp"
#include "aidge/operator/BatchNorm.hpp" #include "aidge/operator/BatchNorm.hpp"
#include "aidge/operator/BitShift.hpp"
#include "aidge/operator/Concat.hpp" #include "aidge/operator/Concat.hpp"
#include "aidge/operator/Conv.hpp" #include "aidge/operator/Conv.hpp"
#include "aidge/operator/ConvDepthWise.hpp" #include "aidge/operator/ConvDepthWise.hpp"
......
/********************************************************************************
* 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_BITSHIFT_H_
#define AIDGE_CORE_OPERATOR_BITSHIFT_H_
#include <memory>
#include <string>
#include <vector>
#include "aidge/utils/Registrar.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/graph/Node.hpp"
#include "aidge/utils/Types.h"
#include "aidge/utils/StaticAttributes.hpp"
namespace Aidge {
enum class BitShiftAttr { BitShiftdirection };
/**
* @brief Tensor BitShift Operator
*/
class BitShift_Op : public OperatorTensor,
public Registrable<BitShift_Op, std::string, std::shared_ptr<OperatorImpl>(const BitShift_Op&)> {
public:
enum BitShiftDirection {left,right};
static const std::string Type;
private:
using Attributes_ = StaticAttributes<BitShiftAttr,BitShiftDirection>;
template <BitShiftAttr e> using attr = typename Attributes_::template attr<e>;
const std::shared_ptr<Attributes_> mAttributes;
public:
BitShift_Op(BitShiftDirection direction)
: OperatorTensor(Type, {InputCategory::Data, InputCategory::Data}, 1),
mAttributes(std::make_shared<Attributes_>(
attr<BitShiftAttr::BitShiftdirection>(direction)))
{}
/**¨PPPP
* @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.
*/
BitShift_Op(const BitShift_Op& op)
: OperatorTensor(op),mAttributes(op.mAttributes)
{
if (op.mImpl) {
SET_IMPL_MACRO(BitShift_Op, *this, op.backend());
} else {
mImpl = nullptr;
}
}
/**
* @brief Clone the operator using its copy-constructor.
* @see Operator::BitShift_Op
*/
std::shared_ptr<Operator> clone() const override {
return std::make_shared<BitShift_Op>(*this);
}
bool forwardDims(bool allowDataDependency = false) override final;
/**
* @brief Setter to specify which backend to use
*
* @return Boolean
*/
void setBackend(const std::string& name, DeviceIdx_t device = 0) override;
/**
* @brief Getter to retrieve Attributes of the bitshift class
*
* @return Attributes
*/
inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
/**
* @brief Retrieve the direction in which the shift should be applied (right or left)
*
* @return BitShiftDirection
*/
inline BitShiftDirection& direction() const noexcept { return mAttributes ->template getAttr<BitShiftAttr::BitShiftdirection>(); }
static const std::vector<std::string> getInputsName(){
return {"InputTensor", "ShiftAmount"};
}
static const std::vector<std::string> getOutputsName(){
return {"OutputTensor"};
}
};
/**
* @brief The bitwise shift operator performs an element-wise operation between the input tensor and the shift tensor in
the direction specified by "direction"
* @param[in] direction Direction of the bitshift (Left or Right)
* @param[in] name Name of the node
* @return std::shared_ptr<Node>
*/
inline std::shared_ptr<Node> BitShift(const BitShift_Op::BitShiftDirection direction, const std::string& name = "") {
return std::make_shared<Node>(std::make_shared<BitShift_Op>(direction), name);
}
} // namespace Aidge
namespace {
template <>
const char *const EnumStrings<Aidge::BitShiftAttr>::data[] = {"BitShiftdirection"};
}
#endif /* AIDGE_CORE_OPERATOR_BITSHIFT_H_ */
/********************************************************************************
* 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 <pybind11/pybind11.h>
#include <string>
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/data/Tensor.hpp"
#include "aidge/operator/BitShift.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/utils/Types.h"
namespace py = pybind11;
namespace Aidge {
void init_BitShift(py::module &m) {
// Binding for BitShiftOp class
auto pyBitShiftOp = py::class_<BitShift_Op, std::shared_ptr<BitShift_Op>, OperatorTensor>(m, "BitShiftOp", py::multiple_inheritance(),R"mydelimiter(
BitShiftOp is a tensor operator that performs bitwise shifts on tensor elements.
This class allows shifting tensor values either to the left or right based on the
specified direction. The direction can be accessed and controlled using the
BitShiftDirection enum.
:param direction: direction of the bit shift (BitShiftDirection.Left or BitShiftDirection.Right)
:type direction: BitShiftDirection
:param name: name of the node.
)mydelimiter")
.def(py::init<BitShift_Op::BitShiftDirection>(), py::arg("direction"))
.def("direction", &BitShift_Op::direction, "Get the direction of the bit shift (left or right).")
.def_static("get_inputs_name", &BitShift_Op::getInputsName, "Get the names of the input tensors.")
.def_static("get_outputs_name", &BitShift_Op::getOutputsName, "Get the names of the output tensors.");
// Enum binding under BitShiftOp class
py::enum_<BitShift_Op::BitShiftDirection>(pyBitShiftOp, "BitShiftDirection")
.value("Right", BitShift_Op::BitShiftDirection::right)
.value("Left", BitShift_Op::BitShiftDirection::left)
.export_values();
// Binding for the BitShift function
m.def("BitShift", &BitShift, py::arg("direction") = BitShift_Op::BitShiftDirection::right, py::arg("name") = "",
R"mydelimiter(
BitShiftOp is a tensor operator that performs bitwise shifts on tensor elements.
This class allows shifting tensor values either to the left or right based on the
specified direction. The direction can be accessed and controlled using the
BitShiftDirection enum.
:param direction: direction of the bit shift (BitShiftDirection.Left or BitShiftDirection.Right)
:type direction: BitShiftDirection
:param name: name of the node.
)mydelimiter");
}
} // namespace Aidge
\ No newline at end of file
...@@ -33,6 +33,7 @@ void init_And(py::module&); ...@@ -33,6 +33,7 @@ void init_And(py::module&);
void init_ArgMax(py::module&); void init_ArgMax(py::module&);
void init_AvgPooling(py::module&); void init_AvgPooling(py::module&);
void init_BatchNorm(py::module&); void init_BatchNorm(py::module&);
void init_BitShift(py::module&);
void init_Concat(py::module&); void init_Concat(py::module&);
void init_ConstantOfShape(py::module&); void init_ConstantOfShape(py::module&);
void init_Conv(py::module&); void init_Conv(py::module&);
...@@ -115,6 +116,7 @@ void init_Aidge(py::module& m) { ...@@ -115,6 +116,7 @@ void init_Aidge(py::module& m) {
init_ArgMax(m); init_ArgMax(m);
init_AvgPooling(m); init_AvgPooling(m);
init_BatchNorm(m); init_BatchNorm(m);
init_BitShift(m);
init_Concat(m); init_Concat(m);
init_Conv(m); init_Conv(m);
init_ConvDepthWise(m); init_ConvDepthWise(m);
......
/********************************************************************************
* 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 <cstddef> // std::size_t
#include <memory>
#include <stdexcept> // std::runtime_error
#include <string>
#include <vector>
#include "aidge/operator/BitShift.hpp"
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/data/Tensor.hpp"
#include "aidge/utils/ErrorHandling.hpp"
#include "aidge/utils/Types.h"
const std::string Aidge::BitShift_Op::Type = "BitShift";
bool Aidge::BitShift_Op::forwardDims(bool /*allowDataDependency*/) {
if (!inputsAssociated()) {
return false;
}
const std::vector<std::size_t>& inputsDims0 = getInput(0)->dims();
const std::vector<std::size_t>& inputsDims1 = getInput(1)->dims();
std::vector<std::size_t> outDims = (inputsDims0.size() >= inputsDims1.size()) ? inputsDims0 : inputsDims1;
const std::vector<std::size_t>& lowDims = (inputsDims0.size() < inputsDims1.size()) ? inputsDims0 : inputsDims1;
std::size_t out_id = outDims.size() - 1;
std::size_t low_id = lowDims.size() - 1;
std::size_t i = 0;
while (i++ < lowDims.size()) {
if (outDims[out_id] == 1) {
outDims[out_id] = lowDims[low_id];
}
else if ((lowDims[low_id] != 1) && (lowDims[low_id] != outDims[out_id])) {
AIDGE_THROW_OR_ABORT(std::runtime_error, "Incompatible Tensor shape for BitShift Operation: {} for input#0 vs {} for input#1",
inputsDims0, inputsDims1);
}
--out_id;
--low_id;
}
mOutputs[0]->resize(outDims);
return true;
}
void Aidge::BitShift_Op::setBackend(const std::string &name, Aidge::DeviceIdx_t device) {
SET_IMPL_MACRO(BitShift_Op, *this, name);
mOutputs[0]->setBackend(name, device);
}
/********************************************************************************
* 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 <catch2/catch_test_macros.hpp>
#include <cstddef> // std::size_t
#include <memory>
#include <random> // std::random_device, std::mt19937, std::uniform_int_distribution
#include <vector>
#include "aidge/data/Tensor.hpp"
#include "aidge/operator/BitShift.hpp"
#include "aidge/operator/OperatorTensor.hpp"
namespace Aidge {
TEST_CASE("[core/operator] BitShift_Op(forwardDims)", "[BitShift][forwardDims]")
{
constexpr std::uint16_t NBTRIALS = 10;
// Create a random number generator
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<std::size_t> dimsDist(1, 10);
std::uniform_int_distribution<std::size_t> nbDimsDist(1, 5);
// Create Shift Operator
std::shared_ptr<Node> myShift = BitShift(BitShift_Op::BitShiftDirection::right);
auto op = std::static_pointer_cast<OperatorTensor>(myShift-> getOperator());
// input_0
std::shared_ptr<Tensor> T0 = std::make_shared<Tensor>();
op -> associateInput(0,T0);
// input_1
std::shared_ptr<Tensor> T1 = std::make_shared<Tensor>();
op -> associateInput(1,T1);
SECTION("BitShifOP Test dimensions [Scalar]") {
// a scalar is compatible with any other Tensor
// input_1
T1->resize({});
for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
// input_0
const std::size_t nb_dims = nbDimsDist(gen);
std::vector<std::size_t> dims(nb_dims);
for (std::size_t i = 0; i < nb_dims; ++i) {
dims[i] = dimsDist(gen);
}
T0->resize(dims);
REQUIRE_NOTHROW(op->forwardDims());
REQUIRE((op->getOutput(0)->dims()) == dims);
}
}
SECTION("BitShifOP Test dimensions [Same Size]") {
for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
const std::size_t nb_dims = nbDimsDist(gen) + 1;
std::vector<std::size_t> dims0(nb_dims);
for (std::size_t i = 0; i < nb_dims; ++i) {
dims0[i] = dimsDist(gen) + 1;
}
T0->resize(dims0);
T1->resize(dims0);
REQUIRE_NOTHROW(op->forwardDims());
REQUIRE((op->getOutput(0)->dims()) == dims0);
}
}
SECTION("BitShifOP Test dimensions [Broadcast]") {
for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
const std::size_t nb_dims = nbDimsDist(gen) + 1;
std::vector<std::size_t> dims0(nb_dims);
for (std::size_t i = 0; i < nb_dims; ++i) {
dims0[i] = dimsDist(gen) + 2;
}
std::vector<std::size_t> dimsOut = dims0;
std::vector<std::size_t> dims1 = dims0;
for (std::size_t i = 0; i < nb_dims; ++i) {
if (dimsDist(gen) <= 5) {
dims1[i] = 1;
}
}
dims1.erase(dims1.cbegin(), dims1.cbegin() + std::min(nbDimsDist(gen), nb_dims-1));
T0->resize(dims0);
T1->resize(dims1);
REQUIRE_NOTHROW(op->forwardDims());
REQUIRE((op->getOutput(0)->dims()) == dimsOut);
}
}
SECTION("BitShifOP Test dimensions [Wrong Dimensions]") {
for (std::uint16_t trial = 0; trial < NBTRIALS; ++trial) {
const std::size_t nb_dims = nbDimsDist(gen) + 1;
std::vector<std::size_t> dims0(nb_dims);
for (std::size_t i = 0; i < nb_dims; ++i) {
dims0[i] = dimsDist(gen) + 2;
}
std::vector<std::size_t> dimsOut = dims0;
std::vector<std::size_t> dims1 = dims0;
for (std::size_t i = 0; i < nb_dims; ++i) {
if (dimsDist(gen) <= 5) {
dims1[i] = 1;
}
}
dims1.erase(dims1.cbegin(), dims1.cbegin() + std::min(nbDimsDist(gen), nb_dims-1));
T0->resize(dims0);
T1->resize(dims1);
std::vector<std::size_t> dims1_wrong = dims1;
for (std::size_t i = 0; i < dims1.size(); ++i) {
++dims1_wrong[i];
}
T1->resize(dims1_wrong);
REQUIRE(dims0 != dims1_wrong);
REQUIRE_THROWS(op->forwardDims());
}
}
}
} // namespace Aidge
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